添加项目文件。

This commit is contained in:
Huoji's
2025-03-06 04:05:03 +08:00
parent 0c7b46b967
commit 2ca572e225
887 changed files with 331879 additions and 0 deletions

60
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,60 @@
{
"files.associations": {
"iostream": "cpp",
"xstring": "cpp",
"algorithm": "cpp",
"atomic": "cpp",
"bit": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"exception": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"list": "cpp",
"map": "cpp",
"memory": "cpp",
"new": "cpp",
"ostream": "cpp",
"set": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"utility": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocinfo": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstddef": "cpp",
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp"
}
}

31
ai_anti_malware.sln Normal file
View File

@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.35731.53
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ai_anti_malware", "ai_anti_malware\ai_anti_malware.vcxproj", "{E12C93D6-6150-484D-85E1-7A644E393D5A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E12C93D6-6150-484D-85E1-7A644E393D5A}.Debug|x64.ActiveCfg = Debug|x64
{E12C93D6-6150-484D-85E1-7A644E393D5A}.Debug|x64.Build.0 = Debug|x64
{E12C93D6-6150-484D-85E1-7A644E393D5A}.Debug|x86.ActiveCfg = Debug|Win32
{E12C93D6-6150-484D-85E1-7A644E393D5A}.Debug|x86.Build.0 = Debug|Win32
{E12C93D6-6150-484D-85E1-7A644E393D5A}.Release|x64.ActiveCfg = Release|x64
{E12C93D6-6150-484D-85E1-7A644E393D5A}.Release|x64.Build.0 = Release|x64
{E12C93D6-6150-484D-85E1-7A644E393D5A}.Release|x86.ActiveCfg = Release|Win32
{E12C93D6-6150-484D-85E1-7A644E393D5A}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {4B304E25-0491-4346-8FCB-7E30DDEB2E43}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,48 @@
// ai_anti_malware.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include "head.h"
auto getPeInfo(std::string inputFilePath) -> std::shared_ptr<BasicPeInfo> {
auto sampleInfo = std::make_shared<BasicPeInfo>();
sampleInfo->inputFilePath =
"E:\\对战平台\\CrowAntiCheat\\CrowAntiCheat\\client\\Console_"
"Test\\Release\\Console_Test.exe";
sampleInfo->peBuffer =
peconv::load_pe_module((const char*)sampleInfo->inputFilePath.c_str(),
sampleInfo->peSize, false, false);
sampleInfo->ntHead64 = peconv::get_nt_hdrs64((BYTE*)sampleInfo->peBuffer);
sampleInfo->ntHead32 = peconv::get_nt_hdrs32((BYTE*)sampleInfo->peBuffer);
sampleInfo->isX64 = peconv::is64bit((BYTE*)sampleInfo->peBuffer);
sampleInfo->RecImageBase =
sampleInfo->isX64
? (DWORD64)sampleInfo->ntHead64->OptionalHeader.ImageBase
: (DWORD)sampleInfo->ntHead32->OptionalHeader.ImageBase;
sampleInfo->isRelocated = peconv::relocate_module(
(BYTE*)sampleInfo->peBuffer, sampleInfo->peSize, sampleInfo->RecImageBase);
sampleInfo->entryPoint =
sampleInfo->isX64
? sampleInfo->ntHead64->OptionalHeader.AddressOfEntryPoint
: sampleInfo->ntHead32->OptionalHeader.AddressOfEntryPoint;
sampleInfo->imageEnd =
sampleInfo->RecImageBase +
(sampleInfo->isX64 ? sampleInfo->ntHead64->OptionalHeader.SizeOfImage
: sampleInfo->ntHead32->OptionalHeader.SizeOfImage);
return sampleInfo;
}
int main() {
auto sampleInfo = getPeInfo(
"E:\\对战平台\\CrowAntiCheat\\CrowAntiCheat\\client\\Console_"
"Test\\Release\\Console_Test.exe");
printf("input new file %s \n", sampleInfo->inputFilePath);
printf("is x64: %d\n", sampleInfo->isX64);
printf("is relocated: %d\n", sampleInfo->isRelocated);
printf("RecImageBase: %llx\n", sampleInfo->RecImageBase);
auto sandbox = std::make_shared<Sandbox>();
sandbox->InitEnv(sampleInfo);
sandbox->Run();
system("pause");
return 0;
}

View File

@@ -0,0 +1,187 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{e12c93d6-6150-484d-85e1-7a644e393d5a}</ProjectGuid>
<RootNamespace>aiantimalware</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)ai_anti_malware\libpeconv\libpeconv\;$(SolutionDir)ai_anti_malware\libpeconv\libpeconv\include;$(SolutionDir)ai_anti_malware\libpeconv\;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>false</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ai_anti_malware.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\buffer_util.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\caves.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\delayed_imports_loader.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\exported_func.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\exports_lookup.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\exports_mapper.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\file_util.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\find_base.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\fix_dot_net_ep.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\fix_imports.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\function_resolver.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\hooks.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\imports_loader.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\imports_uneraser.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\load_config_util.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\peb_lookup.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\pe_dumper.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\pe_hdrs_helper.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\pe_loader.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\pe_mode_detector.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\pe_raw_to_virtual.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\pe_virtual_to_raw.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\relocate.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\remote_pe_reader.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\resource_parser.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\resource_util.cpp" />
<ClCompile Include="libpeconv\libpeconv\src\util.cpp" />
<ClCompile Include="sandbox.cpp" />
<ClCompile Include="sandbox_callbacks.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="head.h" />
<ClInclude Include="libpeconv\libpeconv\src\fix_dot_net_ep.h" />
<ClInclude Include="libpeconv\libpeconv\src\ntddk.h" />
<ClInclude Include="native_struct.h" />
<ClInclude Include="sandbox.h" />
<ClInclude Include="sandbox_callbacks.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="源文件\sandbox">
<UniqueIdentifier>{9204f3c4-f3df-47b3-9cfc-42fcc5dd6ca9}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\sandbox">
<UniqueIdentifier>{41d9dd76-a1a6-4627-b982-cbdb41cf0f7b}</UniqueIdentifier>
</Filter>
<Filter Include="头文件\libpe">
<UniqueIdentifier>{38ea362d-55dc-410e-92f1-3a44ced4dc2d}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ai_anti_malware.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="sandbox.cpp">
<Filter>源文件\sandbox</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\buffer_util.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\caves.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\delayed_imports_loader.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\exported_func.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\exports_lookup.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\exports_mapper.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\file_util.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\find_base.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\fix_dot_net_ep.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\fix_imports.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\function_resolver.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\hooks.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\imports_loader.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\imports_uneraser.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\load_config_util.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\pe_dumper.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\pe_hdrs_helper.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\pe_loader.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\pe_mode_detector.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\pe_raw_to_virtual.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\pe_virtual_to_raw.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\peb_lookup.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\relocate.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\remote_pe_reader.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\resource_parser.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\resource_util.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="libpeconv\libpeconv\src\util.cpp">
<Filter>头文件\libpe</Filter>
</ClCompile>
<ClCompile Include="sandbox_callbacks.cpp">
<Filter>源文件\sandbox</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="head.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="sandbox.h">
<Filter>头文件\sandbox</Filter>
</ClInclude>
<ClInclude Include="libpeconv\libpeconv\src\fix_dot_net_ep.h">
<Filter>头文件\libpe</Filter>
</ClInclude>
<ClInclude Include="libpeconv\libpeconv\src\ntddk.h">
<Filter>头文件\libpe</Filter>
</ClInclude>
<ClInclude Include="native_struct.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="sandbox_callbacks.h">
<Filter>头文件\sandbox</Filter>
</ClInclude>
</ItemGroup>
</Project>

Binary file not shown.

View File

@@ -0,0 +1,937 @@
#ifndef CAPSTONE_ARM_H
#define CAPSTONE_ARM_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
/// ARM shift type
typedef enum arm_shifter {
ARM_SFT_INVALID = 0,
ARM_SFT_ASR, ///< shift with immediate const
ARM_SFT_LSL, ///< shift with immediate const
ARM_SFT_LSR, ///< shift with immediate const
ARM_SFT_ROR, ///< shift with immediate const
ARM_SFT_RRX, ///< shift with immediate const
ARM_SFT_ASR_REG, ///< shift with register
ARM_SFT_LSL_REG, ///< shift with register
ARM_SFT_LSR_REG, ///< shift with register
ARM_SFT_ROR_REG, ///< shift with register
ARM_SFT_RRX_REG, ///< shift with register
} arm_shifter;
/// ARM condition code
typedef enum arm_cc {
ARM_CC_INVALID = 0,
ARM_CC_EQ, ///< Equal Equal
ARM_CC_NE, ///< Not equal Not equal, or unordered
ARM_CC_HS, ///< Carry set >, ==, or unordered
ARM_CC_LO, ///< Carry clear Less than
ARM_CC_MI, ///< Minus, negative Less than
ARM_CC_PL, ///< Plus, positive or zero >, ==, or unordered
ARM_CC_VS, ///< Overflow Unordered
ARM_CC_VC, ///< No overflow Not unordered
ARM_CC_HI, ///< Unsigned higher Greater than, or unordered
ARM_CC_LS, ///< Unsigned lower or same Less than or equal
ARM_CC_GE, ///< Greater than or equal Greater than or equal
ARM_CC_LT, ///< Less than Less than, or unordered
ARM_CC_GT, ///< Greater than Greater than
ARM_CC_LE, ///< Less than or equal <, ==, or unordered
ARM_CC_AL ///< Always (unconditional) Always (unconditional)
} arm_cc;
typedef enum arm_sysreg {
/// Special registers for MSR
ARM_SYSREG_INVALID = 0,
// SPSR* registers can be OR combined
ARM_SYSREG_SPSR_C = 1,
ARM_SYSREG_SPSR_X = 2,
ARM_SYSREG_SPSR_S = 4,
ARM_SYSREG_SPSR_F = 8,
// CPSR* registers can be OR combined
ARM_SYSREG_CPSR_C = 16,
ARM_SYSREG_CPSR_X = 32,
ARM_SYSREG_CPSR_S = 64,
ARM_SYSREG_CPSR_F = 128,
// independent registers
ARM_SYSREG_APSR = 256,
ARM_SYSREG_APSR_G,
ARM_SYSREG_APSR_NZCVQ,
ARM_SYSREG_APSR_NZCVQG,
ARM_SYSREG_IAPSR,
ARM_SYSREG_IAPSR_G,
ARM_SYSREG_IAPSR_NZCVQG,
ARM_SYSREG_IAPSR_NZCVQ,
ARM_SYSREG_EAPSR,
ARM_SYSREG_EAPSR_G,
ARM_SYSREG_EAPSR_NZCVQG,
ARM_SYSREG_EAPSR_NZCVQ,
ARM_SYSREG_XPSR,
ARM_SYSREG_XPSR_G,
ARM_SYSREG_XPSR_NZCVQG,
ARM_SYSREG_XPSR_NZCVQ,
ARM_SYSREG_IPSR,
ARM_SYSREG_EPSR,
ARM_SYSREG_IEPSR,
ARM_SYSREG_MSP,
ARM_SYSREG_PSP,
ARM_SYSREG_PRIMASK,
ARM_SYSREG_BASEPRI,
ARM_SYSREG_BASEPRI_MAX,
ARM_SYSREG_FAULTMASK,
ARM_SYSREG_CONTROL,
// Banked Registers
ARM_SYSREG_R8_USR,
ARM_SYSREG_R9_USR,
ARM_SYSREG_R10_USR,
ARM_SYSREG_R11_USR,
ARM_SYSREG_R12_USR,
ARM_SYSREG_SP_USR,
ARM_SYSREG_LR_USR,
ARM_SYSREG_R8_FIQ,
ARM_SYSREG_R9_FIQ,
ARM_SYSREG_R10_FIQ,
ARM_SYSREG_R11_FIQ,
ARM_SYSREG_R12_FIQ,
ARM_SYSREG_SP_FIQ,
ARM_SYSREG_LR_FIQ,
ARM_SYSREG_LR_IRQ,
ARM_SYSREG_SP_IRQ,
ARM_SYSREG_LR_SVC,
ARM_SYSREG_SP_SVC,
ARM_SYSREG_LR_ABT,
ARM_SYSREG_SP_ABT,
ARM_SYSREG_LR_UND,
ARM_SYSREG_SP_UND,
ARM_SYSREG_LR_MON,
ARM_SYSREG_SP_MON,
ARM_SYSREG_ELR_HYP,
ARM_SYSREG_SP_HYP,
ARM_SYSREG_SPSR_FIQ,
ARM_SYSREG_SPSR_IRQ,
ARM_SYSREG_SPSR_SVC,
ARM_SYSREG_SPSR_ABT,
ARM_SYSREG_SPSR_UND,
ARM_SYSREG_SPSR_MON,
ARM_SYSREG_SPSR_HYP,
} arm_sysreg;
/// The memory barrier constants map directly to the 4-bit encoding of
/// the option field for Memory Barrier operations.
typedef enum arm_mem_barrier {
ARM_MB_INVALID = 0,
ARM_MB_RESERVED_0,
ARM_MB_OSHLD,
ARM_MB_OSHST,
ARM_MB_OSH,
ARM_MB_RESERVED_4,
ARM_MB_NSHLD,
ARM_MB_NSHST,
ARM_MB_NSH,
ARM_MB_RESERVED_8,
ARM_MB_ISHLD,
ARM_MB_ISHST,
ARM_MB_ISH,
ARM_MB_RESERVED_12,
ARM_MB_LD,
ARM_MB_ST,
ARM_MB_SY,
} arm_mem_barrier;
/// Operand type for instruction's operands
typedef enum arm_op_type {
ARM_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
ARM_OP_REG, ///< = CS_OP_REG (Register operand).
ARM_OP_IMM, ///< = CS_OP_IMM (Immediate operand).
ARM_OP_MEM, ///< = CS_OP_MEM (Memory operand).
ARM_OP_FP, ///< = CS_OP_FP (Floating-Point operand).
ARM_OP_CIMM = 64, ///< C-Immediate (coprocessor registers)
ARM_OP_PIMM, ///< P-Immediate (coprocessor registers)
ARM_OP_SETEND, ///< operand for SETEND instruction
ARM_OP_SYSREG, ///< MSR/MRS special register operand
} arm_op_type;
/// Operand type for SETEND instruction
typedef enum arm_setend_type {
ARM_SETEND_INVALID = 0, ///< Uninitialized.
ARM_SETEND_BE, ///< BE operand.
ARM_SETEND_LE, ///< LE operand
} arm_setend_type;
typedef enum arm_cpsmode_type {
ARM_CPSMODE_INVALID = 0,
ARM_CPSMODE_IE = 2,
ARM_CPSMODE_ID = 3
} arm_cpsmode_type;
/// Operand type for SETEND instruction
typedef enum arm_cpsflag_type {
ARM_CPSFLAG_INVALID = 0,
ARM_CPSFLAG_F = 1,
ARM_CPSFLAG_I = 2,
ARM_CPSFLAG_A = 4,
ARM_CPSFLAG_NONE = 16, ///< no flag
} arm_cpsflag_type;
/// Data type for elements of vector instructions.
typedef enum arm_vectordata_type {
ARM_VECTORDATA_INVALID = 0,
// Integer type
ARM_VECTORDATA_I8,
ARM_VECTORDATA_I16,
ARM_VECTORDATA_I32,
ARM_VECTORDATA_I64,
// Signed integer type
ARM_VECTORDATA_S8,
ARM_VECTORDATA_S16,
ARM_VECTORDATA_S32,
ARM_VECTORDATA_S64,
// Unsigned integer type
ARM_VECTORDATA_U8,
ARM_VECTORDATA_U16,
ARM_VECTORDATA_U32,
ARM_VECTORDATA_U64,
// Data type for VMUL/VMULL
ARM_VECTORDATA_P8,
// Floating type
ARM_VECTORDATA_F32,
ARM_VECTORDATA_F64,
// Convert float <-> float
ARM_VECTORDATA_F16F64, // f16.f64
ARM_VECTORDATA_F64F16, // f64.f16
ARM_VECTORDATA_F32F16, // f32.f16
ARM_VECTORDATA_F16F32, // f32.f16
ARM_VECTORDATA_F64F32, // f64.f32
ARM_VECTORDATA_F32F64, // f32.f64
// Convert integer <-> float
ARM_VECTORDATA_S32F32, // s32.f32
ARM_VECTORDATA_U32F32, // u32.f32
ARM_VECTORDATA_F32S32, // f32.s32
ARM_VECTORDATA_F32U32, // f32.u32
ARM_VECTORDATA_F64S16, // f64.s16
ARM_VECTORDATA_F32S16, // f32.s16
ARM_VECTORDATA_F64S32, // f64.s32
ARM_VECTORDATA_S16F64, // s16.f64
ARM_VECTORDATA_S16F32, // s16.f64
ARM_VECTORDATA_S32F64, // s32.f64
ARM_VECTORDATA_U16F64, // u16.f64
ARM_VECTORDATA_U16F32, // u16.f32
ARM_VECTORDATA_U32F64, // u32.f64
ARM_VECTORDATA_F64U16, // f64.u16
ARM_VECTORDATA_F32U16, // f32.u16
ARM_VECTORDATA_F64U32, // f64.u32
} arm_vectordata_type;
/// ARM registers
typedef enum arm_reg {
ARM_REG_INVALID = 0,
ARM_REG_APSR,
ARM_REG_APSR_NZCV,
ARM_REG_CPSR,
ARM_REG_FPEXC,
ARM_REG_FPINST,
ARM_REG_FPSCR,
ARM_REG_FPSCR_NZCV,
ARM_REG_FPSID,
ARM_REG_ITSTATE,
ARM_REG_LR,
ARM_REG_PC,
ARM_REG_SP,
ARM_REG_SPSR,
ARM_REG_D0,
ARM_REG_D1,
ARM_REG_D2,
ARM_REG_D3,
ARM_REG_D4,
ARM_REG_D5,
ARM_REG_D6,
ARM_REG_D7,
ARM_REG_D8,
ARM_REG_D9,
ARM_REG_D10,
ARM_REG_D11,
ARM_REG_D12,
ARM_REG_D13,
ARM_REG_D14,
ARM_REG_D15,
ARM_REG_D16,
ARM_REG_D17,
ARM_REG_D18,
ARM_REG_D19,
ARM_REG_D20,
ARM_REG_D21,
ARM_REG_D22,
ARM_REG_D23,
ARM_REG_D24,
ARM_REG_D25,
ARM_REG_D26,
ARM_REG_D27,
ARM_REG_D28,
ARM_REG_D29,
ARM_REG_D30,
ARM_REG_D31,
ARM_REG_FPINST2,
ARM_REG_MVFR0,
ARM_REG_MVFR1,
ARM_REG_MVFR2,
ARM_REG_Q0,
ARM_REG_Q1,
ARM_REG_Q2,
ARM_REG_Q3,
ARM_REG_Q4,
ARM_REG_Q5,
ARM_REG_Q6,
ARM_REG_Q7,
ARM_REG_Q8,
ARM_REG_Q9,
ARM_REG_Q10,
ARM_REG_Q11,
ARM_REG_Q12,
ARM_REG_Q13,
ARM_REG_Q14,
ARM_REG_Q15,
ARM_REG_R0,
ARM_REG_R1,
ARM_REG_R2,
ARM_REG_R3,
ARM_REG_R4,
ARM_REG_R5,
ARM_REG_R6,
ARM_REG_R7,
ARM_REG_R8,
ARM_REG_R9,
ARM_REG_R10,
ARM_REG_R11,
ARM_REG_R12,
ARM_REG_S0,
ARM_REG_S1,
ARM_REG_S2,
ARM_REG_S3,
ARM_REG_S4,
ARM_REG_S5,
ARM_REG_S6,
ARM_REG_S7,
ARM_REG_S8,
ARM_REG_S9,
ARM_REG_S10,
ARM_REG_S11,
ARM_REG_S12,
ARM_REG_S13,
ARM_REG_S14,
ARM_REG_S15,
ARM_REG_S16,
ARM_REG_S17,
ARM_REG_S18,
ARM_REG_S19,
ARM_REG_S20,
ARM_REG_S21,
ARM_REG_S22,
ARM_REG_S23,
ARM_REG_S24,
ARM_REG_S25,
ARM_REG_S26,
ARM_REG_S27,
ARM_REG_S28,
ARM_REG_S29,
ARM_REG_S30,
ARM_REG_S31,
ARM_REG_ENDING, // <-- mark the end of the list or registers
// alias registers
ARM_REG_R13 = ARM_REG_SP,
ARM_REG_R14 = ARM_REG_LR,
ARM_REG_R15 = ARM_REG_PC,
ARM_REG_SB = ARM_REG_R9,
ARM_REG_SL = ARM_REG_R10,
ARM_REG_FP = ARM_REG_R11,
ARM_REG_IP = ARM_REG_R12,
} arm_reg;
/// Instruction's operand referring to memory
/// This is associated with ARM_OP_MEM operand type above
typedef struct arm_op_mem {
arm_reg base; ///< base register
arm_reg index; ///< index register
int scale; ///< scale for index register (can be 1, or -1)
int disp; ///< displacement/offset value
/// left-shift on index register, or 0 if irrelevant
/// NOTE: this value can also be fetched via operand.shift.value
int lshift;
} arm_op_mem;
/// Instruction operand
typedef struct cs_arm_op {
int vector_index; ///< Vector Index for some vector operands (or -1 if irrelevant)
struct {
arm_shifter type;
unsigned int value;
} shift;
arm_op_type type; ///< operand type
union {
int reg; ///< register value for REG/SYSREG operand
int32_t imm; ///< immediate value for C-IMM, P-IMM or IMM operand
double fp; ///< floating point value for FP operand
arm_op_mem mem; ///< base/index/scale/disp value for MEM operand
arm_setend_type setend; ///< SETEND instruction's operand type
};
/// in some instructions, an operand can be subtracted or added to
/// the base register,
/// if TRUE, this operand is subtracted. otherwise, it is added.
bool subtracted;
/// How is this operand accessed? (READ, WRITE or READ|WRITE)
/// This field is combined of cs_ac_type.
/// NOTE: this field is irrelevant if engine is compiled in DIET mode.
uint8_t access;
/// Neon lane index for NEON instructions (or -1 if irrelevant)
int8_t neon_lane;
} cs_arm_op;
/// Instruction structure
typedef struct cs_arm {
bool usermode; ///< User-mode registers to be loaded (for LDM/STM instructions)
int vector_size; ///< Scalar size for vector instructions
arm_vectordata_type vector_data; ///< Data type for elements of vector instructions
arm_cpsmode_type cps_mode; ///< CPS mode for CPS instruction
arm_cpsflag_type cps_flag; ///< CPS mode for CPS instruction
arm_cc cc; ///< conditional code for this insn
bool update_flags; ///< does this insn update flags?
bool writeback; ///< does this insn write-back?
arm_mem_barrier mem_barrier; ///< Option for some memory barrier instructions
/// Number of operands of this instruction,
/// or 0 when instruction has no operand.
uint8_t op_count;
cs_arm_op operands[36]; ///< operands for this instruction.
} cs_arm;
/// ARM instruction
typedef enum arm_insn {
ARM_INS_INVALID = 0,
ARM_INS_ADC,
ARM_INS_ADD,
ARM_INS_ADR,
ARM_INS_AESD,
ARM_INS_AESE,
ARM_INS_AESIMC,
ARM_INS_AESMC,
ARM_INS_AND,
ARM_INS_BFC,
ARM_INS_BFI,
ARM_INS_BIC,
ARM_INS_BKPT,
ARM_INS_BL,
ARM_INS_BLX,
ARM_INS_BX,
ARM_INS_BXJ,
ARM_INS_B,
ARM_INS_CDP,
ARM_INS_CDP2,
ARM_INS_CLREX,
ARM_INS_CLZ,
ARM_INS_CMN,
ARM_INS_CMP,
ARM_INS_CPS,
ARM_INS_CRC32B,
ARM_INS_CRC32CB,
ARM_INS_CRC32CH,
ARM_INS_CRC32CW,
ARM_INS_CRC32H,
ARM_INS_CRC32W,
ARM_INS_DBG,
ARM_INS_DMB,
ARM_INS_DSB,
ARM_INS_EOR,
ARM_INS_ERET,
ARM_INS_VMOV,
ARM_INS_FLDMDBX,
ARM_INS_FLDMIAX,
ARM_INS_VMRS,
ARM_INS_FSTMDBX,
ARM_INS_FSTMIAX,
ARM_INS_HINT,
ARM_INS_HLT,
ARM_INS_HVC,
ARM_INS_ISB,
ARM_INS_LDA,
ARM_INS_LDAB,
ARM_INS_LDAEX,
ARM_INS_LDAEXB,
ARM_INS_LDAEXD,
ARM_INS_LDAEXH,
ARM_INS_LDAH,
ARM_INS_LDC2L,
ARM_INS_LDC2,
ARM_INS_LDCL,
ARM_INS_LDC,
ARM_INS_LDMDA,
ARM_INS_LDMDB,
ARM_INS_LDM,
ARM_INS_LDMIB,
ARM_INS_LDRBT,
ARM_INS_LDRB,
ARM_INS_LDRD,
ARM_INS_LDREX,
ARM_INS_LDREXB,
ARM_INS_LDREXD,
ARM_INS_LDREXH,
ARM_INS_LDRH,
ARM_INS_LDRHT,
ARM_INS_LDRSB,
ARM_INS_LDRSBT,
ARM_INS_LDRSH,
ARM_INS_LDRSHT,
ARM_INS_LDRT,
ARM_INS_LDR,
ARM_INS_MCR,
ARM_INS_MCR2,
ARM_INS_MCRR,
ARM_INS_MCRR2,
ARM_INS_MLA,
ARM_INS_MLS,
ARM_INS_MOV,
ARM_INS_MOVT,
ARM_INS_MOVW,
ARM_INS_MRC,
ARM_INS_MRC2,
ARM_INS_MRRC,
ARM_INS_MRRC2,
ARM_INS_MRS,
ARM_INS_MSR,
ARM_INS_MUL,
ARM_INS_MVN,
ARM_INS_ORR,
ARM_INS_PKHBT,
ARM_INS_PKHTB,
ARM_INS_PLDW,
ARM_INS_PLD,
ARM_INS_PLI,
ARM_INS_QADD,
ARM_INS_QADD16,
ARM_INS_QADD8,
ARM_INS_QASX,
ARM_INS_QDADD,
ARM_INS_QDSUB,
ARM_INS_QSAX,
ARM_INS_QSUB,
ARM_INS_QSUB16,
ARM_INS_QSUB8,
ARM_INS_RBIT,
ARM_INS_REV,
ARM_INS_REV16,
ARM_INS_REVSH,
ARM_INS_RFEDA,
ARM_INS_RFEDB,
ARM_INS_RFEIA,
ARM_INS_RFEIB,
ARM_INS_RSB,
ARM_INS_RSC,
ARM_INS_SADD16,
ARM_INS_SADD8,
ARM_INS_SASX,
ARM_INS_SBC,
ARM_INS_SBFX,
ARM_INS_SDIV,
ARM_INS_SEL,
ARM_INS_SETEND,
ARM_INS_SHA1C,
ARM_INS_SHA1H,
ARM_INS_SHA1M,
ARM_INS_SHA1P,
ARM_INS_SHA1SU0,
ARM_INS_SHA1SU1,
ARM_INS_SHA256H,
ARM_INS_SHA256H2,
ARM_INS_SHA256SU0,
ARM_INS_SHA256SU1,
ARM_INS_SHADD16,
ARM_INS_SHADD8,
ARM_INS_SHASX,
ARM_INS_SHSAX,
ARM_INS_SHSUB16,
ARM_INS_SHSUB8,
ARM_INS_SMC,
ARM_INS_SMLABB,
ARM_INS_SMLABT,
ARM_INS_SMLAD,
ARM_INS_SMLADX,
ARM_INS_SMLAL,
ARM_INS_SMLALBB,
ARM_INS_SMLALBT,
ARM_INS_SMLALD,
ARM_INS_SMLALDX,
ARM_INS_SMLALTB,
ARM_INS_SMLALTT,
ARM_INS_SMLATB,
ARM_INS_SMLATT,
ARM_INS_SMLAWB,
ARM_INS_SMLAWT,
ARM_INS_SMLSD,
ARM_INS_SMLSDX,
ARM_INS_SMLSLD,
ARM_INS_SMLSLDX,
ARM_INS_SMMLA,
ARM_INS_SMMLAR,
ARM_INS_SMMLS,
ARM_INS_SMMLSR,
ARM_INS_SMMUL,
ARM_INS_SMMULR,
ARM_INS_SMUAD,
ARM_INS_SMUADX,
ARM_INS_SMULBB,
ARM_INS_SMULBT,
ARM_INS_SMULL,
ARM_INS_SMULTB,
ARM_INS_SMULTT,
ARM_INS_SMULWB,
ARM_INS_SMULWT,
ARM_INS_SMUSD,
ARM_INS_SMUSDX,
ARM_INS_SRSDA,
ARM_INS_SRSDB,
ARM_INS_SRSIA,
ARM_INS_SRSIB,
ARM_INS_SSAT,
ARM_INS_SSAT16,
ARM_INS_SSAX,
ARM_INS_SSUB16,
ARM_INS_SSUB8,
ARM_INS_STC2L,
ARM_INS_STC2,
ARM_INS_STCL,
ARM_INS_STC,
ARM_INS_STL,
ARM_INS_STLB,
ARM_INS_STLEX,
ARM_INS_STLEXB,
ARM_INS_STLEXD,
ARM_INS_STLEXH,
ARM_INS_STLH,
ARM_INS_STMDA,
ARM_INS_STMDB,
ARM_INS_STM,
ARM_INS_STMIB,
ARM_INS_STRBT,
ARM_INS_STRB,
ARM_INS_STRD,
ARM_INS_STREX,
ARM_INS_STREXB,
ARM_INS_STREXD,
ARM_INS_STREXH,
ARM_INS_STRH,
ARM_INS_STRHT,
ARM_INS_STRT,
ARM_INS_STR,
ARM_INS_SUB,
ARM_INS_SVC,
ARM_INS_SWP,
ARM_INS_SWPB,
ARM_INS_SXTAB,
ARM_INS_SXTAB16,
ARM_INS_SXTAH,
ARM_INS_SXTB,
ARM_INS_SXTB16,
ARM_INS_SXTH,
ARM_INS_TEQ,
ARM_INS_TRAP,
ARM_INS_TST,
ARM_INS_UADD16,
ARM_INS_UADD8,
ARM_INS_UASX,
ARM_INS_UBFX,
ARM_INS_UDF,
ARM_INS_UDIV,
ARM_INS_UHADD16,
ARM_INS_UHADD8,
ARM_INS_UHASX,
ARM_INS_UHSAX,
ARM_INS_UHSUB16,
ARM_INS_UHSUB8,
ARM_INS_UMAAL,
ARM_INS_UMLAL,
ARM_INS_UMULL,
ARM_INS_UQADD16,
ARM_INS_UQADD8,
ARM_INS_UQASX,
ARM_INS_UQSAX,
ARM_INS_UQSUB16,
ARM_INS_UQSUB8,
ARM_INS_USAD8,
ARM_INS_USADA8,
ARM_INS_USAT,
ARM_INS_USAT16,
ARM_INS_USAX,
ARM_INS_USUB16,
ARM_INS_USUB8,
ARM_INS_UXTAB,
ARM_INS_UXTAB16,
ARM_INS_UXTAH,
ARM_INS_UXTB,
ARM_INS_UXTB16,
ARM_INS_UXTH,
ARM_INS_VABAL,
ARM_INS_VABA,
ARM_INS_VABDL,
ARM_INS_VABD,
ARM_INS_VABS,
ARM_INS_VACGE,
ARM_INS_VACGT,
ARM_INS_VADD,
ARM_INS_VADDHN,
ARM_INS_VADDL,
ARM_INS_VADDW,
ARM_INS_VAND,
ARM_INS_VBIC,
ARM_INS_VBIF,
ARM_INS_VBIT,
ARM_INS_VBSL,
ARM_INS_VCEQ,
ARM_INS_VCGE,
ARM_INS_VCGT,
ARM_INS_VCLE,
ARM_INS_VCLS,
ARM_INS_VCLT,
ARM_INS_VCLZ,
ARM_INS_VCMP,
ARM_INS_VCMPE,
ARM_INS_VCNT,
ARM_INS_VCVTA,
ARM_INS_VCVTB,
ARM_INS_VCVT,
ARM_INS_VCVTM,
ARM_INS_VCVTN,
ARM_INS_VCVTP,
ARM_INS_VCVTT,
ARM_INS_VDIV,
ARM_INS_VDUP,
ARM_INS_VEOR,
ARM_INS_VEXT,
ARM_INS_VFMA,
ARM_INS_VFMS,
ARM_INS_VFNMA,
ARM_INS_VFNMS,
ARM_INS_VHADD,
ARM_INS_VHSUB,
ARM_INS_VLD1,
ARM_INS_VLD2,
ARM_INS_VLD3,
ARM_INS_VLD4,
ARM_INS_VLDMDB,
ARM_INS_VLDMIA,
ARM_INS_VLDR,
ARM_INS_VMAXNM,
ARM_INS_VMAX,
ARM_INS_VMINNM,
ARM_INS_VMIN,
ARM_INS_VMLA,
ARM_INS_VMLAL,
ARM_INS_VMLS,
ARM_INS_VMLSL,
ARM_INS_VMOVL,
ARM_INS_VMOVN,
ARM_INS_VMSR,
ARM_INS_VMUL,
ARM_INS_VMULL,
ARM_INS_VMVN,
ARM_INS_VNEG,
ARM_INS_VNMLA,
ARM_INS_VNMLS,
ARM_INS_VNMUL,
ARM_INS_VORN,
ARM_INS_VORR,
ARM_INS_VPADAL,
ARM_INS_VPADDL,
ARM_INS_VPADD,
ARM_INS_VPMAX,
ARM_INS_VPMIN,
ARM_INS_VQABS,
ARM_INS_VQADD,
ARM_INS_VQDMLAL,
ARM_INS_VQDMLSL,
ARM_INS_VQDMULH,
ARM_INS_VQDMULL,
ARM_INS_VQMOVUN,
ARM_INS_VQMOVN,
ARM_INS_VQNEG,
ARM_INS_VQRDMULH,
ARM_INS_VQRSHL,
ARM_INS_VQRSHRN,
ARM_INS_VQRSHRUN,
ARM_INS_VQSHL,
ARM_INS_VQSHLU,
ARM_INS_VQSHRN,
ARM_INS_VQSHRUN,
ARM_INS_VQSUB,
ARM_INS_VRADDHN,
ARM_INS_VRECPE,
ARM_INS_VRECPS,
ARM_INS_VREV16,
ARM_INS_VREV32,
ARM_INS_VREV64,
ARM_INS_VRHADD,
ARM_INS_VRINTA,
ARM_INS_VRINTM,
ARM_INS_VRINTN,
ARM_INS_VRINTP,
ARM_INS_VRINTR,
ARM_INS_VRINTX,
ARM_INS_VRINTZ,
ARM_INS_VRSHL,
ARM_INS_VRSHRN,
ARM_INS_VRSHR,
ARM_INS_VRSQRTE,
ARM_INS_VRSQRTS,
ARM_INS_VRSRA,
ARM_INS_VRSUBHN,
ARM_INS_VSELEQ,
ARM_INS_VSELGE,
ARM_INS_VSELGT,
ARM_INS_VSELVS,
ARM_INS_VSHLL,
ARM_INS_VSHL,
ARM_INS_VSHRN,
ARM_INS_VSHR,
ARM_INS_VSLI,
ARM_INS_VSQRT,
ARM_INS_VSRA,
ARM_INS_VSRI,
ARM_INS_VST1,
ARM_INS_VST2,
ARM_INS_VST3,
ARM_INS_VST4,
ARM_INS_VSTMDB,
ARM_INS_VSTMIA,
ARM_INS_VSTR,
ARM_INS_VSUB,
ARM_INS_VSUBHN,
ARM_INS_VSUBL,
ARM_INS_VSUBW,
ARM_INS_VSWP,
ARM_INS_VTBL,
ARM_INS_VTBX,
ARM_INS_VCVTR,
ARM_INS_VTRN,
ARM_INS_VTST,
ARM_INS_VUZP,
ARM_INS_VZIP,
ARM_INS_ADDW,
ARM_INS_ASR,
ARM_INS_DCPS1,
ARM_INS_DCPS2,
ARM_INS_DCPS3,
ARM_INS_IT,
ARM_INS_LSL,
ARM_INS_LSR,
ARM_INS_ORN,
ARM_INS_ROR,
ARM_INS_RRX,
ARM_INS_SUBW,
ARM_INS_TBB,
ARM_INS_TBH,
ARM_INS_CBNZ,
ARM_INS_CBZ,
ARM_INS_POP,
ARM_INS_PUSH,
// special instructions
ARM_INS_NOP,
ARM_INS_YIELD,
ARM_INS_WFE,
ARM_INS_WFI,
ARM_INS_SEV,
ARM_INS_SEVL,
ARM_INS_VPUSH,
ARM_INS_VPOP,
ARM_INS_ENDING, // <-- mark the end of the list of instructions
} arm_insn;
/// Group of ARM instructions
typedef enum arm_insn_group {
ARM_GRP_INVALID = 0, ///< = CS_GRP_INVALID
// Generic groups
// all jump instructions (conditional+direct+indirect jumps)
ARM_GRP_JUMP, ///< = CS_GRP_JUMP
ARM_GRP_CALL, ///< = CS_GRP_CALL
ARM_GRP_INT = 4, ///< = CS_GRP_INT
ARM_GRP_PRIVILEGE = 6, ///< = CS_GRP_PRIVILEGE
ARM_GRP_BRANCH_RELATIVE, ///< = CS_GRP_BRANCH_RELATIVE
// Architecture-specific groups
ARM_GRP_CRYPTO = 128,
ARM_GRP_DATABARRIER,
ARM_GRP_DIVIDE,
ARM_GRP_FPARMV8,
ARM_GRP_MULTPRO,
ARM_GRP_NEON,
ARM_GRP_T2EXTRACTPACK,
ARM_GRP_THUMB2DSP,
ARM_GRP_TRUSTZONE,
ARM_GRP_V4T,
ARM_GRP_V5T,
ARM_GRP_V5TE,
ARM_GRP_V6,
ARM_GRP_V6T2,
ARM_GRP_V7,
ARM_GRP_V8,
ARM_GRP_VFP2,
ARM_GRP_VFP3,
ARM_GRP_VFP4,
ARM_GRP_ARM,
ARM_GRP_MCLASS,
ARM_GRP_NOTMCLASS,
ARM_GRP_THUMB,
ARM_GRP_THUMB1ONLY,
ARM_GRP_THUMB2,
ARM_GRP_PREV8,
ARM_GRP_FPVMLX,
ARM_GRP_MULOPS,
ARM_GRP_CRC,
ARM_GRP_DPVFP,
ARM_GRP_V6M,
ARM_GRP_VIRTUALIZATION,
ARM_GRP_ENDING,
} arm_insn_group;
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,766 @@
#ifndef CAPSTONE_ENGINE_H
#define CAPSTONE_ENGINE_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2016 */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h>
#if defined(CAPSTONE_HAS_OSXKERNEL)
#include <libkern/libkern.h>
#else
#include <stdlib.h>
#include <stdio.h>
#endif
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#pragma warning(disable:4100)
#define CAPSTONE_API __cdecl
#ifdef CAPSTONE_SHARED
#define CAPSTONE_EXPORT __declspec(dllexport)
#else // defined(CAPSTONE_STATIC)
#define CAPSTONE_EXPORT
#endif
#else
#define CAPSTONE_API
#if defined(__GNUC__) && !defined(CAPSTONE_STATIC)
#define CAPSTONE_EXPORT __attribute__((visibility("default")))
#else // defined(CAPSTONE_STATIC)
#define CAPSTONE_EXPORT
#endif
#endif
#ifdef __GNUC__
#define CAPSTONE_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define CAPSTONE_DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement CAPSTONE_DEPRECATED for this compiler")
#define CAPSTONE_DEPRECATED
#endif
// Capstone API version
#define CS_API_MAJOR 4
#define CS_API_MINOR 0
// Version for bleeding edge code of the Github's "next" branch.
// Use this if you want the absolutely latest development code.
// This version number will be bumped up whenever we have a new major change.
#define CS_NEXT_VERSION 5
// Capstone package version
#define CS_VERSION_MAJOR CS_API_MAJOR
#define CS_VERSION_MINOR CS_API_MINOR
#define CS_VERSION_EXTRA 2
/// Macro to create combined version which can be compared to
/// result of cs_version() API.
#define CS_MAKE_VERSION(major, minor) ((major << 8) + minor)
/// Maximum size of an instruction mnemonic string.
#define CS_MNEMONIC_SIZE 32
// Handle using with all API
typedef size_t csh;
/// Architecture type
typedef enum cs_arch {
CS_ARCH_ARM = 0, ///< ARM architecture (including Thumb, Thumb-2)
CS_ARCH_ARM64, ///< ARM-64, also called AArch64
CS_ARCH_MIPS, ///< Mips architecture
CS_ARCH_X86, ///< X86 architecture (including x86 & x86-64)
CS_ARCH_PPC, ///< PowerPC architecture
CS_ARCH_SPARC, ///< Sparc architecture
CS_ARCH_SYSZ, ///< SystemZ architecture
CS_ARCH_XCORE, ///< XCore architecture
CS_ARCH_M68K, ///< 68K architecture
CS_ARCH_TMS320C64X, ///< TMS320C64x architecture
CS_ARCH_M680X, ///< 680X architecture
CS_ARCH_EVM, ///< Ethereum architecture
CS_ARCH_MAX,
CS_ARCH_ALL = 0xFFFF, // All architectures - for cs_support()
} cs_arch;
// Support value to verify diet mode of the engine.
// If cs_support(CS_SUPPORT_DIET) return True, the engine was compiled
// in diet mode.
#define CS_SUPPORT_DIET (CS_ARCH_ALL + 1)
// Support value to verify X86 reduce mode of the engine.
// If cs_support(CS_SUPPORT_X86_REDUCE) return True, the engine was compiled
// in X86 reduce mode.
#define CS_SUPPORT_X86_REDUCE (CS_ARCH_ALL + 2)
/// Mode type
typedef enum cs_mode {
CS_MODE_LITTLE_ENDIAN = 0, ///< little-endian mode (default mode)
CS_MODE_ARM = 0, ///< 32-bit ARM
CS_MODE_16 = 1 << 1, ///< 16-bit mode (X86)
CS_MODE_32 = 1 << 2, ///< 32-bit mode (X86)
CS_MODE_64 = 1 << 3, ///< 64-bit mode (X86, PPC)
CS_MODE_THUMB = 1 << 4, ///< ARM's Thumb mode, including Thumb-2
CS_MODE_MCLASS = 1 << 5, ///< ARM's Cortex-M series
CS_MODE_V8 = 1 << 6, ///< ARMv8 A32 encodings for ARM
CS_MODE_MICRO = 1 << 4, ///< MicroMips mode (MIPS)
CS_MODE_MIPS3 = 1 << 5, ///< Mips III ISA
CS_MODE_MIPS32R6 = 1 << 6, ///< Mips32r6 ISA
CS_MODE_MIPS2 = 1 << 7, ///< Mips II ISA
CS_MODE_V9 = 1 << 4, ///< SparcV9 mode (Sparc)
CS_MODE_QPX = 1 << 4, ///< Quad Processing eXtensions mode (PPC)
CS_MODE_M68K_000 = 1 << 1, ///< M68K 68000 mode
CS_MODE_M68K_010 = 1 << 2, ///< M68K 68010 mode
CS_MODE_M68K_020 = 1 << 3, ///< M68K 68020 mode
CS_MODE_M68K_030 = 1 << 4, ///< M68K 68030 mode
CS_MODE_M68K_040 = 1 << 5, ///< M68K 68040 mode
CS_MODE_M68K_060 = 1 << 6, ///< M68K 68060 mode
CS_MODE_BIG_ENDIAN = 1 << 31, ///< big-endian mode
CS_MODE_MIPS32 = CS_MODE_32, ///< Mips32 ISA (Mips)
CS_MODE_MIPS64 = CS_MODE_64, ///< Mips64 ISA (Mips)
CS_MODE_M680X_6301 = 1 << 1, ///< M680X Hitachi 6301,6303 mode
CS_MODE_M680X_6309 = 1 << 2, ///< M680X Hitachi 6309 mode
CS_MODE_M680X_6800 = 1 << 3, ///< M680X Motorola 6800,6802 mode
CS_MODE_M680X_6801 = 1 << 4, ///< M680X Motorola 6801,6803 mode
CS_MODE_M680X_6805 = 1 << 5, ///< M680X Motorola/Freescale 6805 mode
CS_MODE_M680X_6808 = 1 << 6, ///< M680X Motorola/Freescale/NXP 68HC08 mode
CS_MODE_M680X_6809 = 1 << 7, ///< M680X Motorola 6809 mode
CS_MODE_M680X_6811 = 1 << 8, ///< M680X Motorola/Freescale/NXP 68HC11 mode
CS_MODE_M680X_CPU12 = 1 << 9, ///< M680X Motorola/Freescale/NXP CPU12
///< used on M68HC12/HCS12
CS_MODE_M680X_HCS08 = 1 << 10, ///< M680X Freescale/NXP HCS08 mode
} cs_mode;
typedef void* (CAPSTONE_API *cs_malloc_t)(size_t size);
typedef void* (CAPSTONE_API *cs_calloc_t)(size_t nmemb, size_t size);
typedef void* (CAPSTONE_API *cs_realloc_t)(void *ptr, size_t size);
typedef void (CAPSTONE_API *cs_free_t)(void *ptr);
typedef int (CAPSTONE_API *cs_vsnprintf_t)(char *str, size_t size, const char *format, va_list ap);
/// User-defined dynamic memory related functions: malloc/calloc/realloc/free/vsnprintf()
/// By default, Capstone uses system's malloc(), calloc(), realloc(), free() & vsnprintf().
typedef struct cs_opt_mem {
cs_malloc_t malloc;
cs_calloc_t calloc;
cs_realloc_t realloc;
cs_free_t free;
cs_vsnprintf_t vsnprintf;
} cs_opt_mem;
/// Customize mnemonic for instructions with alternative name.
/// To reset existing customized instruction to its default mnemonic,
/// call cs_option(CS_OPT_MNEMONIC) again with the same @id and NULL value
/// for @mnemonic.
typedef struct cs_opt_mnem {
/// ID of instruction to be customized.
unsigned int id;
/// Customized instruction mnemonic.
const char *mnemonic;
} cs_opt_mnem;
/// Runtime option for the disassembled engine
typedef enum cs_opt_type {
CS_OPT_INVALID = 0, ///< No option specified
CS_OPT_SYNTAX, ///< Assembly output syntax
CS_OPT_DETAIL, ///< Break down instruction structure into details
CS_OPT_MODE, ///< Change engine's mode at run-time
CS_OPT_MEM, ///< User-defined dynamic memory related functions
CS_OPT_SKIPDATA, ///< Skip data when disassembling. Then engine is in SKIPDATA mode.
CS_OPT_SKIPDATA_SETUP, ///< Setup user-defined function for SKIPDATA option
CS_OPT_MNEMONIC, ///< Customize instruction mnemonic
CS_OPT_UNSIGNED, ///< print immediate operands in unsigned form
} cs_opt_type;
/// Runtime option value (associated with option type above)
typedef enum cs_opt_value {
CS_OPT_OFF = 0, ///< Turn OFF an option - default for CS_OPT_DETAIL, CS_OPT_SKIPDATA, CS_OPT_UNSIGNED.
CS_OPT_ON = 3, ///< Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA).
CS_OPT_SYNTAX_DEFAULT = 0, ///< Default asm syntax (CS_OPT_SYNTAX).
CS_OPT_SYNTAX_INTEL, ///< X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX).
CS_OPT_SYNTAX_ATT, ///< X86 ATT asm syntax (CS_OPT_SYNTAX).
CS_OPT_SYNTAX_NOREGNAME, ///< Prints register name with only number (CS_OPT_SYNTAX)
CS_OPT_SYNTAX_MASM, ///< X86 Intel Masm syntax (CS_OPT_SYNTAX).
} cs_opt_value;
/// Common instruction operand types - to be consistent across all architectures.
typedef enum cs_op_type {
CS_OP_INVALID = 0, ///< uninitialized/invalid operand.
CS_OP_REG, ///< Register operand.
CS_OP_IMM, ///< Immediate operand.
CS_OP_MEM, ///< Memory operand.
CS_OP_FP, ///< Floating-Point operand.
} cs_op_type;
/// Common instruction operand access types - to be consistent across all architectures.
/// It is possible to combine access types, for example: CS_AC_READ | CS_AC_WRITE
typedef enum cs_ac_type {
CS_AC_INVALID = 0, ///< Uninitialized/invalid access type.
CS_AC_READ = 1 << 0, ///< Operand read from memory or register.
CS_AC_WRITE = 1 << 1, ///< Operand write to memory or register.
} cs_ac_type;
/// Common instruction groups - to be consistent across all architectures.
typedef enum cs_group_type {
CS_GRP_INVALID = 0, ///< uninitialized/invalid group.
CS_GRP_JUMP, ///< all jump instructions (conditional+direct+indirect jumps)
CS_GRP_CALL, ///< all call instructions
CS_GRP_RET, ///< all return instructions
CS_GRP_INT, ///< all interrupt instructions (int+syscall)
CS_GRP_IRET, ///< all interrupt return instructions
CS_GRP_PRIVILEGE, ///< all privileged instructions
CS_GRP_BRANCH_RELATIVE, ///< all relative branching instructions
} cs_group_type;
/**
User-defined callback function for SKIPDATA option.
See tests/test_skipdata.c for sample code demonstrating this API.
@code: the input buffer containing code to be disassembled.
This is the same buffer passed to cs_disasm().
@code_size: size (in bytes) of the above @code buffer.
@offset: the position of the currently-examining byte in the input
buffer @code mentioned above.
@user_data: user-data passed to cs_option() via @user_data field in
cs_opt_skipdata struct below.
@return: return number of bytes to skip, or 0 to immediately stop disassembling.
*/
typedef size_t (CAPSTONE_API *cs_skipdata_cb_t)(const uint8_t *code, size_t code_size, size_t offset, void *user_data);
/// User-customized setup for SKIPDATA option
typedef struct cs_opt_skipdata {
/// Capstone considers data to skip as special "instructions".
/// User can specify the string for this instruction's "mnemonic" here.
/// By default (if @mnemonic is NULL), Capstone use ".byte".
const char *mnemonic;
/// User-defined callback function to be called when Capstone hits data.
/// If the returned value from this callback is positive (>0), Capstone
/// will skip exactly that number of bytes & continue. Otherwise, if
/// the callback returns 0, Capstone stops disassembling and returns
/// immediately from cs_disasm()
/// NOTE: if this callback pointer is NULL, Capstone would skip a number
/// of bytes depending on architectures, as following:
/// Arm: 2 bytes (Thumb mode) or 4 bytes.
/// Arm64: 4 bytes.
/// Mips: 4 bytes.
/// M680x: 1 byte.
/// PowerPC: 4 bytes.
/// Sparc: 4 bytes.
/// SystemZ: 2 bytes.
/// X86: 1 bytes.
/// XCore: 2 bytes.
/// EVM: 1 bytes.
cs_skipdata_cb_t callback; // default value is NULL
/// User-defined data to be passed to @callback function pointer.
void *user_data;
} cs_opt_skipdata;
#include "arm.h"
#include "arm64.h"
#include "m68k.h"
#include "mips.h"
#include "ppc.h"
#include "sparc.h"
#include "systemz.h"
#include "x86.h"
#include "xcore.h"
#include "tms320c64x.h"
#include "m680x.h"
#include "evm.h"
/// NOTE: All information in cs_detail is only available when CS_OPT_DETAIL = CS_OPT_ON
/// Initialized as memset(., 0, offsetof(cs_detail, ARCH)+sizeof(cs_ARCH))
/// by ARCH_getInstruction in arch/ARCH/ARCHDisassembler.c
/// if cs_detail changes, in particular if a field is added after the union,
/// then update arch/ARCH/ARCHDisassembler.c accordingly
typedef struct cs_detail {
uint16_t regs_read[12]; ///< list of implicit registers read by this insn
uint8_t regs_read_count; ///< number of implicit registers read by this insn
uint16_t regs_write[20]; ///< list of implicit registers modified by this insn
uint8_t regs_write_count; ///< number of implicit registers modified by this insn
uint8_t groups[8]; ///< list of group this instruction belong to
uint8_t groups_count; ///< number of groups this insn belongs to
/// Architecture-specific instruction info
union {
cs_x86 x86; ///< X86 architecture, including 16-bit, 32-bit & 64-bit mode
cs_arm64 arm64; ///< ARM64 architecture (aka AArch64)
cs_arm arm; ///< ARM architecture (including Thumb/Thumb2)
cs_m68k m68k; ///< M68K architecture
cs_mips mips; ///< MIPS architecture
cs_ppc ppc; ///< PowerPC architecture
cs_sparc sparc; ///< Sparc architecture
cs_sysz sysz; ///< SystemZ architecture
cs_xcore xcore; ///< XCore architecture
cs_tms320c64x tms320c64x; ///< TMS320C64x architecture
cs_m680x m680x; ///< M680X architecture
cs_evm evm; ///< Ethereum architecture
};
} cs_detail;
/// Detail information of disassembled instruction
typedef struct cs_insn {
/// Instruction ID (basically a numeric ID for the instruction mnemonic)
/// Find the instruction id in the '[ARCH]_insn' enum in the header file
/// of corresponding architecture, such as 'arm_insn' in arm.h for ARM,
/// 'x86_insn' in x86.h for X86, etc...
/// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
/// NOTE: in Skipdata mode, "data" instruction has 0 for this id field.
unsigned int id;
/// Address (EIP) of this instruction
/// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
uint64_t address;
/// Size of this instruction
/// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
uint16_t size;
/// Machine bytes of this instruction, with number of bytes indicated by @size above
/// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
uint8_t bytes[16];
/// Ascii text of instruction mnemonic
/// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
char mnemonic[CS_MNEMONIC_SIZE];
/// Ascii text of instruction operands
/// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
char op_str[160];
/// Pointer to cs_detail.
/// NOTE: detail pointer is only valid when both requirements below are met:
/// (1) CS_OP_DETAIL = CS_OPT_ON
/// (2) Engine is not in Skipdata mode (CS_OP_SKIPDATA option set to CS_OPT_ON)
///
/// NOTE 2: when in Skipdata mode, or when detail mode is OFF, even if this pointer
/// is not NULL, its content is still irrelevant.
cs_detail *detail;
} cs_insn;
/// Calculate the offset of a disassembled instruction in its buffer, given its position
/// in its array of disassembled insn
/// NOTE: this macro works with position (>=1), not index
#define CS_INSN_OFFSET(insns, post) (insns[post - 1].address - insns[0].address)
/// All type of errors encountered by Capstone API.
/// These are values returned by cs_errno()
typedef enum cs_err {
CS_ERR_OK = 0, ///< No error: everything was fine
CS_ERR_MEM, ///< Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
CS_ERR_ARCH, ///< Unsupported architecture: cs_open()
CS_ERR_HANDLE, ///< Invalid handle: cs_op_count(), cs_op_index()
CS_ERR_CSH, ///< Invalid csh argument: cs_close(), cs_errno(), cs_option()
CS_ERR_MODE, ///< Invalid/unsupported mode: cs_open()
CS_ERR_OPTION, ///< Invalid/unsupported option: cs_option()
CS_ERR_DETAIL, ///< Information is unavailable because detail option is OFF
CS_ERR_MEMSETUP, ///< Dynamic memory management uninitialized (see CS_OPT_MEM)
CS_ERR_VERSION, ///< Unsupported version (bindings)
CS_ERR_DIET, ///< Access irrelevant data in "diet" engine
CS_ERR_SKIPDATA, ///< Access irrelevant data for "data" instruction in SKIPDATA mode
CS_ERR_X86_ATT, ///< X86 AT&T syntax is unsupported (opt-out at compile time)
CS_ERR_X86_INTEL, ///< X86 Intel syntax is unsupported (opt-out at compile time)
CS_ERR_X86_MASM, ///< X86 Masm syntax is unsupported (opt-out at compile time)
} cs_err;
/**
Return combined API version & major and minor version numbers.
@major: major number of API version
@minor: minor number of API version
@return hexical number as (major << 8 | minor), which encodes both
major & minor versions.
NOTE: This returned value can be compared with version number made
with macro CS_MAKE_VERSION
For example, second API version would return 1 in @major, and 1 in @minor
The return value would be 0x0101
NOTE: if you only care about returned value, but not major and minor values,
set both @major & @minor arguments to NULL.
*/
CAPSTONE_EXPORT
unsigned int CAPSTONE_API cs_version(int *major, int *minor);
/**
This API can be used to either ask for archs supported by this library,
or check to see if the library was compile with 'diet' option (or called
in 'diet' mode).
To check if a particular arch is supported by this library, set @query to
arch mode (CS_ARCH_* value).
To verify if this library supports all the archs, use CS_ARCH_ALL.
To check if this library is in 'diet' mode, set @query to CS_SUPPORT_DIET.
@return True if this library supports the given arch, or in 'diet' mode.
*/
CAPSTONE_EXPORT
bool CAPSTONE_API cs_support(int query);
/**
Initialize CS handle: this must be done before any usage of CS.
@arch: architecture type (CS_ARCH_*)
@mode: hardware mode. This is combined of CS_MODE_*
@handle: pointer to handle, which will be updated at return time
@return CS_ERR_OK on success, or other value on failure (refer to cs_err enum
for detailed error).
*/
CAPSTONE_EXPORT
cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle);
/**
Close CS handle: MUST do to release the handle when it is not used anymore.
NOTE: this must be only called when there is no longer usage of Capstone,
not even access to cs_insn array. The reason is the this API releases some
cached memory, thus access to any Capstone API after cs_close() might crash
your application.
In fact,this API invalidate @handle by ZERO out its value (i.e *handle = 0).
@handle: pointer to a handle returned by cs_open()
@return CS_ERR_OK on success, or other value on failure (refer to cs_err enum
for detailed error).
*/
CAPSTONE_EXPORT
cs_err CAPSTONE_API cs_close(csh *handle);
/**
Set option for disassembling engine at runtime
@handle: handle returned by cs_open()
@type: type of option to be set
@value: option value corresponding with @type
@return: CS_ERR_OK on success, or other value on failure.
Refer to cs_err enum for detailed error.
NOTE: in the case of CS_OPT_MEM, handle's value can be anything,
so that cs_option(handle, CS_OPT_MEM, value) can (i.e must) be called
even before cs_open()
*/
CAPSTONE_EXPORT
cs_err CAPSTONE_API cs_option(csh handle, cs_opt_type type, size_t value);
/**
Report the last error number when some API function fail.
Like glibc's errno, cs_errno might not retain its old value once accessed.
@handle: handle returned by cs_open()
@return: error code of cs_err enum type (CS_ERR_*, see above)
*/
CAPSTONE_EXPORT
cs_err CAPSTONE_API cs_errno(csh handle);
/**
Return a string describing given error code.
@code: error code (see CS_ERR_* above)
@return: returns a pointer to a string that describes the error code
passed in the argument @code
*/
CAPSTONE_EXPORT
const char * CAPSTONE_API cs_strerror(cs_err code);
/**
Disassemble binary code, given the code buffer, size, address and number
of instructions to be decoded.
This API dynamically allocate memory to contain disassembled instruction.
Resulting instructions will be put into @*insn
NOTE 1: this API will automatically determine memory needed to contain
output disassembled instructions in @insn.
NOTE 2: caller must free the allocated memory itself to avoid memory leaking.
NOTE 3: for system with scarce memory to be dynamically allocated such as
OS kernel or firmware, the API cs_disasm_iter() might be a better choice than
cs_disasm(). The reason is that with cs_disasm(), based on limited available
memory, we have to calculate in advance how many instructions to be disassembled,
which complicates things. This is especially troublesome for the case @count=0,
when cs_disasm() runs uncontrollably (until either end of input buffer, or
when it encounters an invalid instruction).
@handle: handle returned by cs_open()
@code: buffer containing raw binary code to be disassembled.
@code_size: size of the above code buffer.
@address: address of the first instruction in given raw code buffer.
@insn: array of instructions filled in by this API.
NOTE: @insn will be allocated by this function, and should be freed
with cs_free() API.
@count: number of instructions to be disassembled, or 0 to get all of them
@return: the number of successfully disassembled instructions,
or 0 if this function failed to disassemble the given code
On failure, call cs_errno() for error code.
*/
CAPSTONE_EXPORT
size_t CAPSTONE_API cs_disasm(csh handle,
const uint8_t *code, size_t code_size,
uint64_t address,
size_t count,
cs_insn **insn);
/**
Deprecated function - to be retired in the next version!
Use cs_disasm() instead of cs_disasm_ex()
*/
CAPSTONE_EXPORT
CAPSTONE_DEPRECATED
size_t CAPSTONE_API cs_disasm_ex(csh handle,
const uint8_t *code, size_t code_size,
uint64_t address,
size_t count,
cs_insn **insn);
/**
Free memory allocated by cs_malloc() or cs_disasm() (argument @insn)
@insn: pointer returned by @insn argument in cs_disasm() or cs_malloc()
@count: number of cs_insn structures returned by cs_disasm(), or 1
to free memory allocated by cs_malloc().
*/
CAPSTONE_EXPORT
void CAPSTONE_API cs_free(cs_insn *insn, size_t count);
/**
Allocate memory for 1 instruction to be used by cs_disasm_iter().
@handle: handle returned by cs_open()
NOTE: when no longer in use, you can reclaim the memory allocated for
this instruction with cs_free(insn, 1)
*/
CAPSTONE_EXPORT
cs_insn * CAPSTONE_API cs_malloc(csh handle);
/**
Fast API to disassemble binary code, given the code buffer, size, address
and number of instructions to be decoded.
This API puts the resulting instruction into a given cache in @insn.
See tests/test_iter.c for sample code demonstrating this API.
NOTE 1: this API will update @code, @size & @address to point to the next
instruction in the input buffer. Therefore, it is convenient to use
cs_disasm_iter() inside a loop to quickly iterate all the instructions.
While decoding one instruction at a time can also be achieved with
cs_disasm(count=1), some benchmarks shown that cs_disasm_iter() can be 30%
faster on random input.
NOTE 2: the cache in @insn can be created with cs_malloc() API.
NOTE 3: for system with scarce memory to be dynamically allocated such as
OS kernel or firmware, this API is recommended over cs_disasm(), which
allocates memory based on the number of instructions to be disassembled.
The reason is that with cs_disasm(), based on limited available memory,
we have to calculate in advance how many instructions to be disassembled,
which complicates things. This is especially troublesome for the case
@count=0, when cs_disasm() runs uncontrollably (until either end of input
buffer, or when it encounters an invalid instruction).
@handle: handle returned by cs_open()
@code: buffer containing raw binary code to be disassembled
@size: size of above code
@address: address of the first insn in given raw code buffer
@insn: pointer to instruction to be filled in by this API.
@return: true if this API successfully decode 1 instruction,
or false otherwise.
On failure, call cs_errno() for error code.
*/
CAPSTONE_EXPORT
bool CAPSTONE_API cs_disasm_iter(csh handle,
const uint8_t **code, size_t *size,
uint64_t *address, cs_insn *insn);
/**
Return friendly name of register in a string.
Find the instruction id from header file of corresponding architecture (arm.h for ARM,
x86.h for X86, ...)
WARN: when in 'diet' mode, this API is irrelevant because engine does not
store register name.
@handle: handle returned by cs_open()
@reg_id: register id
@return: string name of the register, or NULL if @reg_id is invalid.
*/
CAPSTONE_EXPORT
const char * CAPSTONE_API cs_reg_name(csh handle, unsigned int reg_id);
/**
Return friendly name of an instruction in a string.
Find the instruction id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...)
WARN: when in 'diet' mode, this API is irrelevant because the engine does not
store instruction name.
@handle: handle returned by cs_open()
@insn_id: instruction id
@return: string name of the instruction, or NULL if @insn_id is invalid.
*/
CAPSTONE_EXPORT
const char * CAPSTONE_API cs_insn_name(csh handle, unsigned int insn_id);
/**
Return friendly name of a group id (that an instruction can belong to)
Find the group id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...)
WARN: when in 'diet' mode, this API is irrelevant because the engine does not
store group name.
@handle: handle returned by cs_open()
@group_id: group id
@return: string name of the group, or NULL if @group_id is invalid.
*/
CAPSTONE_EXPORT
const char * CAPSTONE_API cs_group_name(csh handle, unsigned int group_id);
/**
Check if a disassembled instruction belong to a particular group.
Find the group id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...)
Internally, this simply verifies if @group_id matches any member of insn->groups array.
NOTE: this API is only valid when detail option is ON (which is OFF by default).
WARN: when in 'diet' mode, this API is irrelevant because the engine does not
update @groups array.
@handle: handle returned by cs_open()
@insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter()
@group_id: group that you want to check if this instruction belong to.
@return: true if this instruction indeed belongs to the given group, or false otherwise.
*/
CAPSTONE_EXPORT
bool CAPSTONE_API cs_insn_group(csh handle, const cs_insn *insn, unsigned int group_id);
/**
Check if a disassembled instruction IMPLICITLY used a particular register.
Find the register id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...)
Internally, this simply verifies if @reg_id matches any member of insn->regs_read array.
NOTE: this API is only valid when detail option is ON (which is OFF by default)
WARN: when in 'diet' mode, this API is irrelevant because the engine does not
update @regs_read array.
@insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter()
@reg_id: register that you want to check if this instruction used it.
@return: true if this instruction indeed implicitly used the given register, or false otherwise.
*/
CAPSTONE_EXPORT
bool CAPSTONE_API cs_reg_read(csh handle, const cs_insn *insn, unsigned int reg_id);
/**
Check if a disassembled instruction IMPLICITLY modified a particular register.
Find the register id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...)
Internally, this simply verifies if @reg_id matches any member of insn->regs_write array.
NOTE: this API is only valid when detail option is ON (which is OFF by default)
WARN: when in 'diet' mode, this API is irrelevant because the engine does not
update @regs_write array.
@insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter()
@reg_id: register that you want to check if this instruction modified it.
@return: true if this instruction indeed implicitly modified the given register, or false otherwise.
*/
CAPSTONE_EXPORT
bool CAPSTONE_API cs_reg_write(csh handle, const cs_insn *insn, unsigned int reg_id);
/**
Count the number of operands of a given type.
Find the operand type in header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...)
NOTE: this API is only valid when detail option is ON (which is OFF by default)
@handle: handle returned by cs_open()
@insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter()
@op_type: Operand type to be found.
@return: number of operands of given type @op_type in instruction @insn,
or -1 on failure.
*/
CAPSTONE_EXPORT
int CAPSTONE_API cs_op_count(csh handle, const cs_insn *insn, unsigned int op_type);
/**
Retrieve the position of operand of given type in <arch>.operands[] array.
Later, the operand can be accessed using the returned position.
Find the operand type in header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...)
NOTE: this API is only valid when detail option is ON (which is OFF by default)
@handle: handle returned by cs_open()
@insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter()
@op_type: Operand type to be found.
@position: position of the operand to be found. This must be in the range
[1, cs_op_count(handle, insn, op_type)]
@return: index of operand of given type @op_type in <arch>.operands[] array
in instruction @insn, or -1 on failure.
*/
CAPSTONE_EXPORT
int CAPSTONE_API cs_op_index(csh handle, const cs_insn *insn, unsigned int op_type,
unsigned int position);
/// Type of array to keep the list of registers
typedef uint16_t cs_regs[64];
/**
Retrieve all the registers accessed by an instruction, either explicitly or
implicitly.
WARN: when in 'diet' mode, this API is irrelevant because engine does not
store registers.
@handle: handle returned by cs_open()
@insn: disassembled instruction structure returned from cs_disasm() or cs_disasm_iter()
@regs_read: on return, this array contains all registers read by instruction.
@regs_read_count: number of registers kept inside @regs_read array.
@regs_write: on return, this array contains all registers written by instruction.
@regs_write_count: number of registers kept inside @regs_write array.
@return CS_ERR_OK on success, or other value on failure (refer to cs_err enum
for detailed error).
*/
CAPSTONE_EXPORT
cs_err CAPSTONE_API cs_regs_access(csh handle, const cs_insn *insn,
cs_regs regs_read, uint8_t *regs_read_count,
cs_regs regs_write, uint8_t *regs_write_count);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,188 @@
#ifndef CAPSTONE_EVM_H
#define CAPSTONE_EVM_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2018 */
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
/// Instruction structure
typedef struct cs_evm {
unsigned char pop; ///< number of items popped from the stack
unsigned char push; ///< number of items pushed into the stack
unsigned int fee; ///< gas fee for the instruction
} cs_evm;
/// EVM instruction
typedef enum evm_insn {
EVM_INS_STOP = 0,
EVM_INS_ADD = 1,
EVM_INS_MUL = 2,
EVM_INS_SUB = 3,
EVM_INS_DIV = 4,
EVM_INS_SDIV = 5,
EVM_INS_MOD = 6,
EVM_INS_SMOD = 7,
EVM_INS_ADDMOD = 8,
EVM_INS_MULMOD = 9,
EVM_INS_EXP = 10,
EVM_INS_SIGNEXTEND = 11,
EVM_INS_LT = 16,
EVM_INS_GT = 17,
EVM_INS_SLT = 18,
EVM_INS_SGT = 19,
EVM_INS_EQ = 20,
EVM_INS_ISZERO = 21,
EVM_INS_AND = 22,
EVM_INS_OR = 23,
EVM_INS_XOR = 24,
EVM_INS_NOT = 25,
EVM_INS_BYTE = 26,
EVM_INS_SHA3 = 32,
EVM_INS_ADDRESS = 48,
EVM_INS_BALANCE = 49,
EVM_INS_ORIGIN = 50,
EVM_INS_CALLER = 51,
EVM_INS_CALLVALUE = 52,
EVM_INS_CALLDATALOAD = 53,
EVM_INS_CALLDATASIZE = 54,
EVM_INS_CALLDATACOPY = 55,
EVM_INS_CODESIZE = 56,
EVM_INS_CODECOPY = 57,
EVM_INS_GASPRICE = 58,
EVM_INS_EXTCODESIZE = 59,
EVM_INS_EXTCODECOPY = 60,
EVM_INS_RETURNDATASIZE = 61,
EVM_INS_RETURNDATACOPY = 62,
EVM_INS_BLOCKHASH = 64,
EVM_INS_COINBASE = 65,
EVM_INS_TIMESTAMP = 66,
EVM_INS_NUMBER = 67,
EVM_INS_DIFFICULTY = 68,
EVM_INS_GASLIMIT = 69,
EVM_INS_POP = 80,
EVM_INS_MLOAD = 81,
EVM_INS_MSTORE = 82,
EVM_INS_MSTORE8 = 83,
EVM_INS_SLOAD = 84,
EVM_INS_SSTORE = 85,
EVM_INS_JUMP = 86,
EVM_INS_JUMPI = 87,
EVM_INS_PC = 88,
EVM_INS_MSIZE = 89,
EVM_INS_GAS = 90,
EVM_INS_JUMPDEST = 91,
EVM_INS_PUSH1 = 96,
EVM_INS_PUSH2 = 97,
EVM_INS_PUSH3 = 98,
EVM_INS_PUSH4 = 99,
EVM_INS_PUSH5 = 100,
EVM_INS_PUSH6 = 101,
EVM_INS_PUSH7 = 102,
EVM_INS_PUSH8 = 103,
EVM_INS_PUSH9 = 104,
EVM_INS_PUSH10 = 105,
EVM_INS_PUSH11 = 106,
EVM_INS_PUSH12 = 107,
EVM_INS_PUSH13 = 108,
EVM_INS_PUSH14 = 109,
EVM_INS_PUSH15 = 110,
EVM_INS_PUSH16 = 111,
EVM_INS_PUSH17 = 112,
EVM_INS_PUSH18 = 113,
EVM_INS_PUSH19 = 114,
EVM_INS_PUSH20 = 115,
EVM_INS_PUSH21 = 116,
EVM_INS_PUSH22 = 117,
EVM_INS_PUSH23 = 118,
EVM_INS_PUSH24 = 119,
EVM_INS_PUSH25 = 120,
EVM_INS_PUSH26 = 121,
EVM_INS_PUSH27 = 122,
EVM_INS_PUSH28 = 123,
EVM_INS_PUSH29 = 124,
EVM_INS_PUSH30 = 125,
EVM_INS_PUSH31 = 126,
EVM_INS_PUSH32 = 127,
EVM_INS_DUP1 = 128,
EVM_INS_DUP2 = 129,
EVM_INS_DUP3 = 130,
EVM_INS_DUP4 = 131,
EVM_INS_DUP5 = 132,
EVM_INS_DUP6 = 133,
EVM_INS_DUP7 = 134,
EVM_INS_DUP8 = 135,
EVM_INS_DUP9 = 136,
EVM_INS_DUP10 = 137,
EVM_INS_DUP11 = 138,
EVM_INS_DUP12 = 139,
EVM_INS_DUP13 = 140,
EVM_INS_DUP14 = 141,
EVM_INS_DUP15 = 142,
EVM_INS_DUP16 = 143,
EVM_INS_SWAP1 = 144,
EVM_INS_SWAP2 = 145,
EVM_INS_SWAP3 = 146,
EVM_INS_SWAP4 = 147,
EVM_INS_SWAP5 = 148,
EVM_INS_SWAP6 = 149,
EVM_INS_SWAP7 = 150,
EVM_INS_SWAP8 = 151,
EVM_INS_SWAP9 = 152,
EVM_INS_SWAP10 = 153,
EVM_INS_SWAP11 = 154,
EVM_INS_SWAP12 = 155,
EVM_INS_SWAP13 = 156,
EVM_INS_SWAP14 = 157,
EVM_INS_SWAP15 = 158,
EVM_INS_SWAP16 = 159,
EVM_INS_LOG0 = 160,
EVM_INS_LOG1 = 161,
EVM_INS_LOG2 = 162,
EVM_INS_LOG3 = 163,
EVM_INS_LOG4 = 164,
EVM_INS_CREATE = 240,
EVM_INS_CALL = 241,
EVM_INS_CALLCODE = 242,
EVM_INS_RETURN = 243,
EVM_INS_DELEGATECALL = 244,
EVM_INS_CALLBLACKBOX = 245,
EVM_INS_STATICCALL = 250,
EVM_INS_REVERT = 253,
EVM_INS_SUICIDE = 255,
EVM_INS_INVALID = 512,
EVM_INS_ENDING, // <-- mark the end of the list of instructions
} evm_insn;
/// Group of EVM instructions
typedef enum evm_insn_group {
EVM_GRP_INVALID = 0, ///< = CS_GRP_INVALID
EVM_GRP_JUMP, ///< all jump instructions
EVM_GRP_MATH = 8, ///< math instructions
EVM_GRP_STACK_WRITE, ///< instructions write to stack
EVM_GRP_STACK_READ, ///< instructions read from stack
EVM_GRP_MEM_WRITE, ///< instructions write to memory
EVM_GRP_MEM_READ, ///< instructions read from memory
EVM_GRP_STORE_WRITE, ///< instructions write to storage
EVM_GRP_STORE_READ, ///< instructions read from storage
EVM_GRP_HALT, ///< instructions halt execution
EVM_GRP_ENDING, ///< <-- mark the end of the list of groups
} evm_insn_group;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,537 @@
#ifndef CAPSTONE_M680X_H
#define CAPSTONE_M680X_H
/* Capstone Disassembly Engine */
/* M680X Backend by Wolfgang Schwotzer <wolfgang.schwotzer@gmx.net> 2017 */
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
#define M680X_OPERAND_COUNT 9
/// M680X registers and special registers
typedef enum m680x_reg {
M680X_REG_INVALID = 0,
M680X_REG_A, ///< M6800/1/2/3/9, HD6301/9
M680X_REG_B, ///< M6800/1/2/3/9, HD6301/9
M680X_REG_E, ///< HD6309
M680X_REG_F, ///< HD6309
M680X_REG_0, ///< HD6309
M680X_REG_D, ///< M6801/3/9, HD6301/9
M680X_REG_W, ///< HD6309
M680X_REG_CC, ///< M6800/1/2/3/9, M6301/9
M680X_REG_DP, ///< M6809/M6309
M680X_REG_MD, ///< M6309
M680X_REG_HX, ///< M6808
M680X_REG_H, ///< M6808
M680X_REG_X, ///< M6800/1/2/3/9, M6301/9
M680X_REG_Y, ///< M6809/M6309
M680X_REG_S, ///< M6809/M6309
M680X_REG_U, ///< M6809/M6309
M680X_REG_V, ///< M6309
M680X_REG_Q, ///< M6309
M680X_REG_PC, ///< M6800/1/2/3/9, M6301/9
M680X_REG_TMP2, ///< CPU12
M680X_REG_TMP3, ///< CPU12
M680X_REG_ENDING, ///< <-- mark the end of the list of registers
} m680x_reg;
/// Operand type for instruction's operands
typedef enum m680x_op_type {
M680X_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
M680X_OP_REGISTER, ///< = Register operand.
M680X_OP_IMMEDIATE, ///< = Immediate operand.
M680X_OP_INDEXED, ///< = Indexed addressing operand.
M680X_OP_EXTENDED, ///< = Extended addressing operand.
M680X_OP_DIRECT, ///< = Direct addressing operand.
M680X_OP_RELATIVE, ///< = Relative addressing operand.
M680X_OP_CONSTANT, ///< = constant operand (Displayed as number only).
///< Used e.g. for a bit index or page number.
} m680x_op_type;
// Supported bit values for mem.idx.offset_bits
#define M680X_OFFSET_NONE 0
#define M680X_OFFSET_BITS_5 5
#define M680X_OFFSET_BITS_8 8
#define M680X_OFFSET_BITS_9 9
#define M680X_OFFSET_BITS_16 16
// Supported bit flags for mem.idx.flags
// These flags can be combined
#define M680X_IDX_INDIRECT 1
#define M680X_IDX_NO_COMMA 2
#define M680X_IDX_POST_INC_DEC 4
/// Instruction's operand referring to indexed addressing
typedef struct m680x_op_idx {
m680x_reg base_reg; ///< base register (or M680X_REG_INVALID if
///< irrelevant)
m680x_reg offset_reg; ///< offset register (or M680X_REG_INVALID if
///< irrelevant)
int16_t offset; ///< 5-,8- or 16-bit offset. See also offset_bits.
uint16_t offset_addr; ///< = offset addr. if base_reg == M680X_REG_PC.
///< calculated as offset + PC
uint8_t offset_bits; ///< offset width in bits for indexed addressing
int8_t inc_dec; ///< inc. or dec. value:
///< 0: no inc-/decrement
///< 1 .. 8: increment by 1 .. 8
///< -1 .. -8: decrement by 1 .. 8
///< if flag M680X_IDX_POST_INC_DEC set it is post
///< inc-/decrement otherwise pre inc-/decrement
uint8_t flags; ///< 8-bit flags (see above)
} m680x_op_idx;
/// Instruction's memory operand referring to relative addressing (Bcc/LBcc)
typedef struct m680x_op_rel {
uint16_t address; ///< The absolute address.
///< calculated as PC + offset. PC is the first
///< address after the instruction.
int16_t offset; ///< the offset/displacement value
} m680x_op_rel;
/// Instruction's operand referring to extended addressing
typedef struct m680x_op_ext {
uint16_t address; ///< The absolute address
bool indirect; ///< true if extended indirect addressing
} m680x_op_ext;
/// Instruction operand
typedef struct cs_m680x_op {
m680x_op_type type;
union {
int32_t imm; ///< immediate value for IMM operand
m680x_reg reg; ///< register value for REG operand
m680x_op_idx idx; ///< Indexed addressing operand
m680x_op_rel rel; ///< Relative address. operand (Bcc/LBcc)
m680x_op_ext ext; ///< Extended address
uint8_t direct_addr; ///<</ Direct address (lower 8-bit)
uint8_t const_val; ///< constant value (bit index, page nr.)
};
uint8_t size; ///< size of this operand (in bytes)
/// How is this operand accessed? (READ, WRITE or READ|WRITE)
/// This field is combined of cs_ac_type.
/// NOTE: this field is irrelevant if engine is compiled in DIET
uint8_t access;
} cs_m680x_op;
/// Group of M680X instructions
typedef enum m680x_group_type {
M680X_GRP_INVALID = 0, /// = CS_GRP_INVALID
// Generic groups
// all jump instructions (conditional+direct+indirect jumps)
M680X_GRP_JUMP, ///< = CS_GRP_JUMP
// all call instructions
M680X_GRP_CALL, ///< = CS_GRP_CALL
// all return instructions
M680X_GRP_RET, ///< = CS_GRP_RET
// all interrupt instructions (int+syscall)
M680X_GRP_INT, ///< = CS_GRP_INT
// all interrupt return instructions
M680X_GRP_IRET, ///< = CS_GRP_IRET
// all privileged instructions
M680X_GRP_PRIV, ///< = CS_GRP_PRIVILEDGE; not used
// all relative branching instructions
M680X_GRP_BRAREL, ///< = CS_GRP_BRANCH_RELATIVE
// Architecture-specific groups
M680X_GRP_ENDING, // <-- mark the end of the list of groups
} m680x_group_type;
// M680X instruction flags:
/// The first (register) operand is part of the
/// instruction mnemonic
#define M680X_FIRST_OP_IN_MNEM 1
/// The second (register) operand is part of the
/// instruction mnemonic
#define M680X_SECOND_OP_IN_MNEM 2
/// The M680X instruction and it's operands
typedef struct cs_m680x {
uint8_t flags; ///< See: M680X instruction flags
uint8_t op_count; ///< number of operands for the instruction or 0
cs_m680x_op operands[M680X_OPERAND_COUNT]; ///< operands for this insn.
} cs_m680x;
/// M680X instruction IDs
typedef enum m680x_insn {
M680X_INS_INVLD = 0,
M680X_INS_ABA, ///< M6800/1/2/3
M680X_INS_ABX,
M680X_INS_ABY,
M680X_INS_ADC,
M680X_INS_ADCA,
M680X_INS_ADCB,
M680X_INS_ADCD,
M680X_INS_ADCR,
M680X_INS_ADD,
M680X_INS_ADDA,
M680X_INS_ADDB,
M680X_INS_ADDD,
M680X_INS_ADDE,
M680X_INS_ADDF,
M680X_INS_ADDR,
M680X_INS_ADDW,
M680X_INS_AIM,
M680X_INS_AIS,
M680X_INS_AIX,
M680X_INS_AND,
M680X_INS_ANDA,
M680X_INS_ANDB,
M680X_INS_ANDCC,
M680X_INS_ANDD,
M680X_INS_ANDR,
M680X_INS_ASL,
M680X_INS_ASLA,
M680X_INS_ASLB,
M680X_INS_ASLD, ///< or LSLD
M680X_INS_ASR,
M680X_INS_ASRA,
M680X_INS_ASRB,
M680X_INS_ASRD,
M680X_INS_ASRX,
M680X_INS_BAND,
M680X_INS_BCC, ///< or BHS
M680X_INS_BCLR,
M680X_INS_BCS, ///< or BLO
M680X_INS_BEOR,
M680X_INS_BEQ,
M680X_INS_BGE,
M680X_INS_BGND,
M680X_INS_BGT,
M680X_INS_BHCC,
M680X_INS_BHCS,
M680X_INS_BHI,
M680X_INS_BIAND,
M680X_INS_BIEOR,
M680X_INS_BIH,
M680X_INS_BIL,
M680X_INS_BIOR,
M680X_INS_BIT,
M680X_INS_BITA,
M680X_INS_BITB,
M680X_INS_BITD,
M680X_INS_BITMD,
M680X_INS_BLE,
M680X_INS_BLS,
M680X_INS_BLT,
M680X_INS_BMC,
M680X_INS_BMI,
M680X_INS_BMS,
M680X_INS_BNE,
M680X_INS_BOR,
M680X_INS_BPL,
M680X_INS_BRCLR,
M680X_INS_BRSET,
M680X_INS_BRA,
M680X_INS_BRN,
M680X_INS_BSET,
M680X_INS_BSR,
M680X_INS_BVC,
M680X_INS_BVS,
M680X_INS_CALL,
M680X_INS_CBA, ///< M6800/1/2/3
M680X_INS_CBEQ,
M680X_INS_CBEQA,
M680X_INS_CBEQX,
M680X_INS_CLC, ///< M6800/1/2/3
M680X_INS_CLI, ///< M6800/1/2/3
M680X_INS_CLR,
M680X_INS_CLRA,
M680X_INS_CLRB,
M680X_INS_CLRD,
M680X_INS_CLRE,
M680X_INS_CLRF,
M680X_INS_CLRH,
M680X_INS_CLRW,
M680X_INS_CLRX,
M680X_INS_CLV, ///< M6800/1/2/3
M680X_INS_CMP,
M680X_INS_CMPA,
M680X_INS_CMPB,
M680X_INS_CMPD,
M680X_INS_CMPE,
M680X_INS_CMPF,
M680X_INS_CMPR,
M680X_INS_CMPS,
M680X_INS_CMPU,
M680X_INS_CMPW,
M680X_INS_CMPX,
M680X_INS_CMPY,
M680X_INS_COM,
M680X_INS_COMA,
M680X_INS_COMB,
M680X_INS_COMD,
M680X_INS_COME,
M680X_INS_COMF,
M680X_INS_COMW,
M680X_INS_COMX,
M680X_INS_CPD,
M680X_INS_CPHX,
M680X_INS_CPS,
M680X_INS_CPX, ///< M6800/1/2/3
M680X_INS_CPY,
M680X_INS_CWAI,
M680X_INS_DAA,
M680X_INS_DBEQ,
M680X_INS_DBNE,
M680X_INS_DBNZ,
M680X_INS_DBNZA,
M680X_INS_DBNZX,
M680X_INS_DEC,
M680X_INS_DECA,
M680X_INS_DECB,
M680X_INS_DECD,
M680X_INS_DECE,
M680X_INS_DECF,
M680X_INS_DECW,
M680X_INS_DECX,
M680X_INS_DES, ///< M6800/1/2/3
M680X_INS_DEX, ///< M6800/1/2/3
M680X_INS_DEY,
M680X_INS_DIV,
M680X_INS_DIVD,
M680X_INS_DIVQ,
M680X_INS_EDIV,
M680X_INS_EDIVS,
M680X_INS_EIM,
M680X_INS_EMACS,
M680X_INS_EMAXD,
M680X_INS_EMAXM,
M680X_INS_EMIND,
M680X_INS_EMINM,
M680X_INS_EMUL,
M680X_INS_EMULS,
M680X_INS_EOR,
M680X_INS_EORA,
M680X_INS_EORB,
M680X_INS_EORD,
M680X_INS_EORR,
M680X_INS_ETBL,
M680X_INS_EXG,
M680X_INS_FDIV,
M680X_INS_IBEQ,
M680X_INS_IBNE,
M680X_INS_IDIV,
M680X_INS_IDIVS,
M680X_INS_ILLGL,
M680X_INS_INC,
M680X_INS_INCA,
M680X_INS_INCB,
M680X_INS_INCD,
M680X_INS_INCE,
M680X_INS_INCF,
M680X_INS_INCW,
M680X_INS_INCX,
M680X_INS_INS, ///< M6800/1/2/3
M680X_INS_INX, ///< M6800/1/2/3
M680X_INS_INY,
M680X_INS_JMP,
M680X_INS_JSR,
M680X_INS_LBCC, ///< or LBHS
M680X_INS_LBCS, ///< or LBLO
M680X_INS_LBEQ,
M680X_INS_LBGE,
M680X_INS_LBGT,
M680X_INS_LBHI,
M680X_INS_LBLE,
M680X_INS_LBLS,
M680X_INS_LBLT,
M680X_INS_LBMI,
M680X_INS_LBNE,
M680X_INS_LBPL,
M680X_INS_LBRA,
M680X_INS_LBRN,
M680X_INS_LBSR,
M680X_INS_LBVC,
M680X_INS_LBVS,
M680X_INS_LDA,
M680X_INS_LDAA, ///< M6800/1/2/3
M680X_INS_LDAB, ///< M6800/1/2/3
M680X_INS_LDB,
M680X_INS_LDBT,
M680X_INS_LDD,
M680X_INS_LDE,
M680X_INS_LDF,
M680X_INS_LDHX,
M680X_INS_LDMD,
M680X_INS_LDQ,
M680X_INS_LDS,
M680X_INS_LDU,
M680X_INS_LDW,
M680X_INS_LDX,
M680X_INS_LDY,
M680X_INS_LEAS,
M680X_INS_LEAU,
M680X_INS_LEAX,
M680X_INS_LEAY,
M680X_INS_LSL,
M680X_INS_LSLA,
M680X_INS_LSLB,
M680X_INS_LSLD,
M680X_INS_LSLX,
M680X_INS_LSR,
M680X_INS_LSRA,
M680X_INS_LSRB,
M680X_INS_LSRD, ///< or ASRD
M680X_INS_LSRW,
M680X_INS_LSRX,
M680X_INS_MAXA,
M680X_INS_MAXM,
M680X_INS_MEM,
M680X_INS_MINA,
M680X_INS_MINM,
M680X_INS_MOV,
M680X_INS_MOVB,
M680X_INS_MOVW,
M680X_INS_MUL,
M680X_INS_MULD,
M680X_INS_NEG,
M680X_INS_NEGA,
M680X_INS_NEGB,
M680X_INS_NEGD,
M680X_INS_NEGX,
M680X_INS_NOP,
M680X_INS_NSA,
M680X_INS_OIM,
M680X_INS_ORA,
M680X_INS_ORAA, ///< M6800/1/2/3
M680X_INS_ORAB, ///< M6800/1/2/3
M680X_INS_ORB,
M680X_INS_ORCC,
M680X_INS_ORD,
M680X_INS_ORR,
M680X_INS_PSHA, ///< M6800/1/2/3
M680X_INS_PSHB, ///< M6800/1/2/3
M680X_INS_PSHC,
M680X_INS_PSHD,
M680X_INS_PSHH,
M680X_INS_PSHS,
M680X_INS_PSHSW,
M680X_INS_PSHU,
M680X_INS_PSHUW,
M680X_INS_PSHX, ///< M6800/1/2/3
M680X_INS_PSHY,
M680X_INS_PULA, ///< M6800/1/2/3
M680X_INS_PULB, ///< M6800/1/2/3
M680X_INS_PULC,
M680X_INS_PULD,
M680X_INS_PULH,
M680X_INS_PULS,
M680X_INS_PULSW,
M680X_INS_PULU,
M680X_INS_PULUW,
M680X_INS_PULX, ///< M6800/1/2/3
M680X_INS_PULY,
M680X_INS_REV,
M680X_INS_REVW,
M680X_INS_ROL,
M680X_INS_ROLA,
M680X_INS_ROLB,
M680X_INS_ROLD,
M680X_INS_ROLW,
M680X_INS_ROLX,
M680X_INS_ROR,
M680X_INS_RORA,
M680X_INS_RORB,
M680X_INS_RORD,
M680X_INS_RORW,
M680X_INS_RORX,
M680X_INS_RSP,
M680X_INS_RTC,
M680X_INS_RTI,
M680X_INS_RTS,
M680X_INS_SBA, ///< M6800/1/2/3
M680X_INS_SBC,
M680X_INS_SBCA,
M680X_INS_SBCB,
M680X_INS_SBCD,
M680X_INS_SBCR,
M680X_INS_SEC,
M680X_INS_SEI,
M680X_INS_SEV,
M680X_INS_SEX,
M680X_INS_SEXW,
M680X_INS_SLP,
M680X_INS_STA,
M680X_INS_STAA, ///< M6800/1/2/3
M680X_INS_STAB, ///< M6800/1/2/3
M680X_INS_STB,
M680X_INS_STBT,
M680X_INS_STD,
M680X_INS_STE,
M680X_INS_STF,
M680X_INS_STOP,
M680X_INS_STHX,
M680X_INS_STQ,
M680X_INS_STS,
M680X_INS_STU,
M680X_INS_STW,
M680X_INS_STX,
M680X_INS_STY,
M680X_INS_SUB,
M680X_INS_SUBA,
M680X_INS_SUBB,
M680X_INS_SUBD,
M680X_INS_SUBE,
M680X_INS_SUBF,
M680X_INS_SUBR,
M680X_INS_SUBW,
M680X_INS_SWI,
M680X_INS_SWI2,
M680X_INS_SWI3,
M680X_INS_SYNC,
M680X_INS_TAB, ///< M6800/1/2/3
M680X_INS_TAP, ///< M6800/1/2/3
M680X_INS_TAX,
M680X_INS_TBA, ///< M6800/1/2/3
M680X_INS_TBEQ,
M680X_INS_TBL,
M680X_INS_TBNE,
M680X_INS_TEST,
M680X_INS_TFM,
M680X_INS_TFR,
M680X_INS_TIM,
M680X_INS_TPA, ///< M6800/1/2/3
M680X_INS_TST,
M680X_INS_TSTA,
M680X_INS_TSTB,
M680X_INS_TSTD,
M680X_INS_TSTE,
M680X_INS_TSTF,
M680X_INS_TSTW,
M680X_INS_TSTX,
M680X_INS_TSX, ///< M6800/1/2/3
M680X_INS_TSY,
M680X_INS_TXA,
M680X_INS_TXS, ///< M6800/1/2/3
M680X_INS_TYS,
M680X_INS_WAI, ///< M6800/1/2/3
M680X_INS_WAIT,
M680X_INS_WAV,
M680X_INS_WAVR,
M680X_INS_XGDX, ///< HD6301
M680X_INS_XGDY,
M680X_INS_ENDING, // <-- mark the end of the list of instructions
} m680x_insn;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,613 @@
#ifndef CAPSTONE_M68K_H
#define CAPSTONE_M68K_H
/* Capstone Disassembly Engine */
/* By Daniel Collin <daniel@collin.com>, 2015-2016 */
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
#define M68K_OPERAND_COUNT 4
/// M68K registers and special registers
typedef enum m68k_reg {
M68K_REG_INVALID = 0,
M68K_REG_D0,
M68K_REG_D1,
M68K_REG_D2,
M68K_REG_D3,
M68K_REG_D4,
M68K_REG_D5,
M68K_REG_D6,
M68K_REG_D7,
M68K_REG_A0,
M68K_REG_A1,
M68K_REG_A2,
M68K_REG_A3,
M68K_REG_A4,
M68K_REG_A5,
M68K_REG_A6,
M68K_REG_A7,
M68K_REG_FP0,
M68K_REG_FP1,
M68K_REG_FP2,
M68K_REG_FP3,
M68K_REG_FP4,
M68K_REG_FP5,
M68K_REG_FP6,
M68K_REG_FP7,
M68K_REG_PC,
M68K_REG_SR,
M68K_REG_CCR,
M68K_REG_SFC,
M68K_REG_DFC,
M68K_REG_USP,
M68K_REG_VBR,
M68K_REG_CACR,
M68K_REG_CAAR,
M68K_REG_MSP,
M68K_REG_ISP,
M68K_REG_TC,
M68K_REG_ITT0,
M68K_REG_ITT1,
M68K_REG_DTT0,
M68K_REG_DTT1,
M68K_REG_MMUSR,
M68K_REG_URP,
M68K_REG_SRP,
M68K_REG_FPCR,
M68K_REG_FPSR,
M68K_REG_FPIAR,
M68K_REG_ENDING, // <-- mark the end of the list of registers
} m68k_reg;
/// M68K Addressing Modes
typedef enum m68k_address_mode {
M68K_AM_NONE = 0, ///< No address mode.
M68K_AM_REG_DIRECT_DATA, ///< Register Direct - Data
M68K_AM_REG_DIRECT_ADDR, ///< Register Direct - Address
M68K_AM_REGI_ADDR, ///< Register Indirect - Address
M68K_AM_REGI_ADDR_POST_INC, ///< Register Indirect - Address with Postincrement
M68K_AM_REGI_ADDR_PRE_DEC, ///< Register Indirect - Address with Predecrement
M68K_AM_REGI_ADDR_DISP, ///< Register Indirect - Address with Displacement
M68K_AM_AREGI_INDEX_8_BIT_DISP, ///< Address Register Indirect With Index- 8-bit displacement
M68K_AM_AREGI_INDEX_BASE_DISP, ///< Address Register Indirect With Index- Base displacement
M68K_AM_MEMI_POST_INDEX, ///< Memory indirect - Postindex
M68K_AM_MEMI_PRE_INDEX, ///< Memory indirect - Preindex
M68K_AM_PCI_DISP, ///< Program Counter Indirect - with Displacement
M68K_AM_PCI_INDEX_8_BIT_DISP, ///< Program Counter Indirect with Index - with 8-Bit Displacement
M68K_AM_PCI_INDEX_BASE_DISP, ///< Program Counter Indirect with Index - with Base Displacement
M68K_AM_PC_MEMI_POST_INDEX, ///< Program Counter Memory Indirect - Postindexed
M68K_AM_PC_MEMI_PRE_INDEX, ///< Program Counter Memory Indirect - Preindexed
M68K_AM_ABSOLUTE_DATA_SHORT, ///< Absolute Data Addressing - Short
M68K_AM_ABSOLUTE_DATA_LONG, ///< Absolute Data Addressing - Long
M68K_AM_IMMEDIATE, ///< Immediate value
M68K_AM_BRANCH_DISPLACEMENT, ///< Address as displacement from (PC+2) used by branches
} m68k_address_mode;
/// Operand type for instruction's operands
typedef enum m68k_op_type {
M68K_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
M68K_OP_REG, ///< = CS_OP_REG (Register operand).
M68K_OP_IMM, ///< = CS_OP_IMM (Immediate operand).
M68K_OP_MEM, ///< = CS_OP_MEM (Memory operand).
M68K_OP_FP_SINGLE, ///< single precision Floating-Point operand
M68K_OP_FP_DOUBLE, ///< double precision Floating-Point operand
M68K_OP_REG_BITS, ///< Register bits move
M68K_OP_REG_PAIR, ///< Register pair in the same op (upper 4 bits for first reg, lower for second)
M68K_OP_BR_DISP, ///< Branch displacement
} m68k_op_type;
/// Instruction's operand referring to memory
/// This is associated with M68K_OP_MEM operand type above
typedef struct m68k_op_mem {
m68k_reg base_reg; ///< base register (or M68K_REG_INVALID if irrelevant)
m68k_reg index_reg; ///< index register (or M68K_REG_INVALID if irrelevant)
m68k_reg in_base_reg; ///< indirect base register (or M68K_REG_INVALID if irrelevant)
uint32_t in_disp; ///< indirect displacement
uint32_t out_disp; ///< other displacement
int16_t disp; ///< displacement value
uint8_t scale; ///< scale for index register
uint8_t bitfield; ///< set to true if the two values below should be used
uint8_t width; ///< used for bf* instructions
uint8_t offset; ///< used for bf* instructions
uint8_t index_size; ///< 0 = w, 1 = l
} m68k_op_mem;
/// Operand type for instruction's operands
typedef enum m68k_op_br_disp_size {
M68K_OP_BR_DISP_SIZE_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
M68K_OP_BR_DISP_SIZE_BYTE = 1, ///< signed 8-bit displacement
M68K_OP_BR_DISP_SIZE_WORD = 2, ///< signed 16-bit displacement
M68K_OP_BR_DISP_SIZE_LONG = 4, ///< signed 32-bit displacement
} m68k_op_br_disp_size;
typedef struct m68k_op_br_disp {
int32_t disp; ///< displacement value
uint8_t disp_size; ///< Size from m68k_op_br_disp_size type above
} m68k_op_br_disp;
/// Register pair in one operand.
typedef struct cs_m68k_op_reg_pair {
m68k_reg reg_0;
m68k_reg reg_1;
} cs_m68k_op_reg_pair;
/// Instruction operand
typedef struct cs_m68k_op {
union {
uint64_t imm; ///< immediate value for IMM operand
double dimm; ///< double imm
float simm; ///< float imm
m68k_reg reg; ///< register value for REG operand
cs_m68k_op_reg_pair reg_pair; ///< register pair in one operand
};
m68k_op_mem mem; ///< data when operand is targeting memory
m68k_op_br_disp br_disp; ///< data when operand is a branch displacement
uint32_t register_bits; ///< register bits for movem etc. (always in d0-d7, a0-a7, fp0 - fp7 order)
m68k_op_type type;
m68k_address_mode address_mode; ///< M68K addressing mode for this op
} cs_m68k_op;
/// Operation size of the CPU instructions
typedef enum m68k_cpu_size {
M68K_CPU_SIZE_NONE = 0, ///< unsized or unspecified
M68K_CPU_SIZE_BYTE = 1, ///< 1 byte in size
M68K_CPU_SIZE_WORD = 2, ///< 2 bytes in size
M68K_CPU_SIZE_LONG = 4, ///< 4 bytes in size
} m68k_cpu_size;
/// Operation size of the FPU instructions (Notice that FPU instruction can also use CPU sizes if needed)
typedef enum m68k_fpu_size {
M68K_FPU_SIZE_NONE = 0, ///< unsized like fsave/frestore
M68K_FPU_SIZE_SINGLE = 4, ///< 4 byte in size (single float)
M68K_FPU_SIZE_DOUBLE = 8, ///< 8 byte in size (double)
M68K_FPU_SIZE_EXTENDED = 12, ///< 12 byte in size (extended real format)
} m68k_fpu_size;
/// Type of size that is being used for the current instruction
typedef enum m68k_size_type {
M68K_SIZE_TYPE_INVALID = 0,
M68K_SIZE_TYPE_CPU,
M68K_SIZE_TYPE_FPU,
} m68k_size_type;
/// Operation size of the current instruction (NOT the actually size of instruction)
typedef struct m68k_op_size {
m68k_size_type type;
union {
m68k_cpu_size cpu_size;
m68k_fpu_size fpu_size;
};
} m68k_op_size;
/// The M68K instruction and it's operands
typedef struct cs_m68k {
// Number of operands of this instruction or 0 when instruction has no operand.
cs_m68k_op operands[M68K_OPERAND_COUNT]; ///< operands for this instruction.
m68k_op_size op_size; ///< size of data operand works on in bytes (.b, .w, .l, etc)
uint8_t op_count; ///< number of operands for the instruction
} cs_m68k;
/// M68K instruction
typedef enum m68k_insn {
M68K_INS_INVALID = 0,
M68K_INS_ABCD,
M68K_INS_ADD,
M68K_INS_ADDA,
M68K_INS_ADDI,
M68K_INS_ADDQ,
M68K_INS_ADDX,
M68K_INS_AND,
M68K_INS_ANDI,
M68K_INS_ASL,
M68K_INS_ASR,
M68K_INS_BHS,
M68K_INS_BLO,
M68K_INS_BHI,
M68K_INS_BLS,
M68K_INS_BCC,
M68K_INS_BCS,
M68K_INS_BNE,
M68K_INS_BEQ,
M68K_INS_BVC,
M68K_INS_BVS,
M68K_INS_BPL,
M68K_INS_BMI,
M68K_INS_BGE,
M68K_INS_BLT,
M68K_INS_BGT,
M68K_INS_BLE,
M68K_INS_BRA,
M68K_INS_BSR,
M68K_INS_BCHG,
M68K_INS_BCLR,
M68K_INS_BSET,
M68K_INS_BTST,
M68K_INS_BFCHG,
M68K_INS_BFCLR,
M68K_INS_BFEXTS,
M68K_INS_BFEXTU,
M68K_INS_BFFFO,
M68K_INS_BFINS,
M68K_INS_BFSET,
M68K_INS_BFTST,
M68K_INS_BKPT,
M68K_INS_CALLM,
M68K_INS_CAS,
M68K_INS_CAS2,
M68K_INS_CHK,
M68K_INS_CHK2,
M68K_INS_CLR,
M68K_INS_CMP,
M68K_INS_CMPA,
M68K_INS_CMPI,
M68K_INS_CMPM,
M68K_INS_CMP2,
M68K_INS_CINVL,
M68K_INS_CINVP,
M68K_INS_CINVA,
M68K_INS_CPUSHL,
M68K_INS_CPUSHP,
M68K_INS_CPUSHA,
M68K_INS_DBT,
M68K_INS_DBF,
M68K_INS_DBHI,
M68K_INS_DBLS,
M68K_INS_DBCC,
M68K_INS_DBCS,
M68K_INS_DBNE,
M68K_INS_DBEQ,
M68K_INS_DBVC,
M68K_INS_DBVS,
M68K_INS_DBPL,
M68K_INS_DBMI,
M68K_INS_DBGE,
M68K_INS_DBLT,
M68K_INS_DBGT,
M68K_INS_DBLE,
M68K_INS_DBRA,
M68K_INS_DIVS,
M68K_INS_DIVSL,
M68K_INS_DIVU,
M68K_INS_DIVUL,
M68K_INS_EOR,
M68K_INS_EORI,
M68K_INS_EXG,
M68K_INS_EXT,
M68K_INS_EXTB,
M68K_INS_FABS,
M68K_INS_FSABS,
M68K_INS_FDABS,
M68K_INS_FACOS,
M68K_INS_FADD,
M68K_INS_FSADD,
M68K_INS_FDADD,
M68K_INS_FASIN,
M68K_INS_FATAN,
M68K_INS_FATANH,
M68K_INS_FBF,
M68K_INS_FBEQ,
M68K_INS_FBOGT,
M68K_INS_FBOGE,
M68K_INS_FBOLT,
M68K_INS_FBOLE,
M68K_INS_FBOGL,
M68K_INS_FBOR,
M68K_INS_FBUN,
M68K_INS_FBUEQ,
M68K_INS_FBUGT,
M68K_INS_FBUGE,
M68K_INS_FBULT,
M68K_INS_FBULE,
M68K_INS_FBNE,
M68K_INS_FBT,
M68K_INS_FBSF,
M68K_INS_FBSEQ,
M68K_INS_FBGT,
M68K_INS_FBGE,
M68K_INS_FBLT,
M68K_INS_FBLE,
M68K_INS_FBGL,
M68K_INS_FBGLE,
M68K_INS_FBNGLE,
M68K_INS_FBNGL,
M68K_INS_FBNLE,
M68K_INS_FBNLT,
M68K_INS_FBNGE,
M68K_INS_FBNGT,
M68K_INS_FBSNE,
M68K_INS_FBST,
M68K_INS_FCMP,
M68K_INS_FCOS,
M68K_INS_FCOSH,
M68K_INS_FDBF,
M68K_INS_FDBEQ,
M68K_INS_FDBOGT,
M68K_INS_FDBOGE,
M68K_INS_FDBOLT,
M68K_INS_FDBOLE,
M68K_INS_FDBOGL,
M68K_INS_FDBOR,
M68K_INS_FDBUN,
M68K_INS_FDBUEQ,
M68K_INS_FDBUGT,
M68K_INS_FDBUGE,
M68K_INS_FDBULT,
M68K_INS_FDBULE,
M68K_INS_FDBNE,
M68K_INS_FDBT,
M68K_INS_FDBSF,
M68K_INS_FDBSEQ,
M68K_INS_FDBGT,
M68K_INS_FDBGE,
M68K_INS_FDBLT,
M68K_INS_FDBLE,
M68K_INS_FDBGL,
M68K_INS_FDBGLE,
M68K_INS_FDBNGLE,
M68K_INS_FDBNGL,
M68K_INS_FDBNLE,
M68K_INS_FDBNLT,
M68K_INS_FDBNGE,
M68K_INS_FDBNGT,
M68K_INS_FDBSNE,
M68K_INS_FDBST,
M68K_INS_FDIV,
M68K_INS_FSDIV,
M68K_INS_FDDIV,
M68K_INS_FETOX,
M68K_INS_FETOXM1,
M68K_INS_FGETEXP,
M68K_INS_FGETMAN,
M68K_INS_FINT,
M68K_INS_FINTRZ,
M68K_INS_FLOG10,
M68K_INS_FLOG2,
M68K_INS_FLOGN,
M68K_INS_FLOGNP1,
M68K_INS_FMOD,
M68K_INS_FMOVE,
M68K_INS_FSMOVE,
M68K_INS_FDMOVE,
M68K_INS_FMOVECR,
M68K_INS_FMOVEM,
M68K_INS_FMUL,
M68K_INS_FSMUL,
M68K_INS_FDMUL,
M68K_INS_FNEG,
M68K_INS_FSNEG,
M68K_INS_FDNEG,
M68K_INS_FNOP,
M68K_INS_FREM,
M68K_INS_FRESTORE,
M68K_INS_FSAVE,
M68K_INS_FSCALE,
M68K_INS_FSGLDIV,
M68K_INS_FSGLMUL,
M68K_INS_FSIN,
M68K_INS_FSINCOS,
M68K_INS_FSINH,
M68K_INS_FSQRT,
M68K_INS_FSSQRT,
M68K_INS_FDSQRT,
M68K_INS_FSF,
M68K_INS_FSBEQ,
M68K_INS_FSOGT,
M68K_INS_FSOGE,
M68K_INS_FSOLT,
M68K_INS_FSOLE,
M68K_INS_FSOGL,
M68K_INS_FSOR,
M68K_INS_FSUN,
M68K_INS_FSUEQ,
M68K_INS_FSUGT,
M68K_INS_FSUGE,
M68K_INS_FSULT,
M68K_INS_FSULE,
M68K_INS_FSNE,
M68K_INS_FST,
M68K_INS_FSSF,
M68K_INS_FSSEQ,
M68K_INS_FSGT,
M68K_INS_FSGE,
M68K_INS_FSLT,
M68K_INS_FSLE,
M68K_INS_FSGL,
M68K_INS_FSGLE,
M68K_INS_FSNGLE,
M68K_INS_FSNGL,
M68K_INS_FSNLE,
M68K_INS_FSNLT,
M68K_INS_FSNGE,
M68K_INS_FSNGT,
M68K_INS_FSSNE,
M68K_INS_FSST,
M68K_INS_FSUB,
M68K_INS_FSSUB,
M68K_INS_FDSUB,
M68K_INS_FTAN,
M68K_INS_FTANH,
M68K_INS_FTENTOX,
M68K_INS_FTRAPF,
M68K_INS_FTRAPEQ,
M68K_INS_FTRAPOGT,
M68K_INS_FTRAPOGE,
M68K_INS_FTRAPOLT,
M68K_INS_FTRAPOLE,
M68K_INS_FTRAPOGL,
M68K_INS_FTRAPOR,
M68K_INS_FTRAPUN,
M68K_INS_FTRAPUEQ,
M68K_INS_FTRAPUGT,
M68K_INS_FTRAPUGE,
M68K_INS_FTRAPULT,
M68K_INS_FTRAPULE,
M68K_INS_FTRAPNE,
M68K_INS_FTRAPT,
M68K_INS_FTRAPSF,
M68K_INS_FTRAPSEQ,
M68K_INS_FTRAPGT,
M68K_INS_FTRAPGE,
M68K_INS_FTRAPLT,
M68K_INS_FTRAPLE,
M68K_INS_FTRAPGL,
M68K_INS_FTRAPGLE,
M68K_INS_FTRAPNGLE,
M68K_INS_FTRAPNGL,
M68K_INS_FTRAPNLE,
M68K_INS_FTRAPNLT,
M68K_INS_FTRAPNGE,
M68K_INS_FTRAPNGT,
M68K_INS_FTRAPSNE,
M68K_INS_FTRAPST,
M68K_INS_FTST,
M68K_INS_FTWOTOX,
M68K_INS_HALT,
M68K_INS_ILLEGAL,
M68K_INS_JMP,
M68K_INS_JSR,
M68K_INS_LEA,
M68K_INS_LINK,
M68K_INS_LPSTOP,
M68K_INS_LSL,
M68K_INS_LSR,
M68K_INS_MOVE,
M68K_INS_MOVEA,
M68K_INS_MOVEC,
M68K_INS_MOVEM,
M68K_INS_MOVEP,
M68K_INS_MOVEQ,
M68K_INS_MOVES,
M68K_INS_MOVE16,
M68K_INS_MULS,
M68K_INS_MULU,
M68K_INS_NBCD,
M68K_INS_NEG,
M68K_INS_NEGX,
M68K_INS_NOP,
M68K_INS_NOT,
M68K_INS_OR,
M68K_INS_ORI,
M68K_INS_PACK,
M68K_INS_PEA,
M68K_INS_PFLUSH,
M68K_INS_PFLUSHA,
M68K_INS_PFLUSHAN,
M68K_INS_PFLUSHN,
M68K_INS_PLOADR,
M68K_INS_PLOADW,
M68K_INS_PLPAR,
M68K_INS_PLPAW,
M68K_INS_PMOVE,
M68K_INS_PMOVEFD,
M68K_INS_PTESTR,
M68K_INS_PTESTW,
M68K_INS_PULSE,
M68K_INS_REMS,
M68K_INS_REMU,
M68K_INS_RESET,
M68K_INS_ROL,
M68K_INS_ROR,
M68K_INS_ROXL,
M68K_INS_ROXR,
M68K_INS_RTD,
M68K_INS_RTE,
M68K_INS_RTM,
M68K_INS_RTR,
M68K_INS_RTS,
M68K_INS_SBCD,
M68K_INS_ST,
M68K_INS_SF,
M68K_INS_SHI,
M68K_INS_SLS,
M68K_INS_SCC,
M68K_INS_SHS,
M68K_INS_SCS,
M68K_INS_SLO,
M68K_INS_SNE,
M68K_INS_SEQ,
M68K_INS_SVC,
M68K_INS_SVS,
M68K_INS_SPL,
M68K_INS_SMI,
M68K_INS_SGE,
M68K_INS_SLT,
M68K_INS_SGT,
M68K_INS_SLE,
M68K_INS_STOP,
M68K_INS_SUB,
M68K_INS_SUBA,
M68K_INS_SUBI,
M68K_INS_SUBQ,
M68K_INS_SUBX,
M68K_INS_SWAP,
M68K_INS_TAS,
M68K_INS_TRAP,
M68K_INS_TRAPV,
M68K_INS_TRAPT,
M68K_INS_TRAPF,
M68K_INS_TRAPHI,
M68K_INS_TRAPLS,
M68K_INS_TRAPCC,
M68K_INS_TRAPHS,
M68K_INS_TRAPCS,
M68K_INS_TRAPLO,
M68K_INS_TRAPNE,
M68K_INS_TRAPEQ,
M68K_INS_TRAPVC,
M68K_INS_TRAPVS,
M68K_INS_TRAPPL,
M68K_INS_TRAPMI,
M68K_INS_TRAPGE,
M68K_INS_TRAPLT,
M68K_INS_TRAPGT,
M68K_INS_TRAPLE,
M68K_INS_TST,
M68K_INS_UNLK,
M68K_INS_UNPK,
M68K_INS_ENDING, // <-- mark the end of the list of instructions
} m68k_insn;
/// Group of M68K instructions
typedef enum m68k_group_type {
M68K_GRP_INVALID = 0, ///< CS_GRUP_INVALID
M68K_GRP_JUMP, ///< = CS_GRP_JUMP
M68K_GRP_RET = 3, ///< = CS_GRP_RET
M68K_GRP_IRET = 5, ///< = CS_GRP_IRET
M68K_GRP_BRANCH_RELATIVE = 7, ///< = CS_GRP_BRANCH_RELATIVE
M68K_GRP_ENDING,// <-- mark the end of the list of groups
} m68k_group_type;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,956 @@
#ifndef CAPSTONE_MIPS_H
#define CAPSTONE_MIPS_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
// GCC MIPS toolchain has a default macro called "mips" which breaks
// compilation
#undef mips
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
/// Operand type for instruction's operands
typedef enum mips_op_type {
MIPS_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
MIPS_OP_REG, ///< = CS_OP_REG (Register operand).
MIPS_OP_IMM, ///< = CS_OP_IMM (Immediate operand).
MIPS_OP_MEM, ///< = CS_OP_MEM (Memory operand).
} mips_op_type;
/// MIPS registers
typedef enum mips_reg {
MIPS_REG_INVALID = 0,
// General purpose registers
MIPS_REG_PC,
MIPS_REG_0,
MIPS_REG_1,
MIPS_REG_2,
MIPS_REG_3,
MIPS_REG_4,
MIPS_REG_5,
MIPS_REG_6,
MIPS_REG_7,
MIPS_REG_8,
MIPS_REG_9,
MIPS_REG_10,
MIPS_REG_11,
MIPS_REG_12,
MIPS_REG_13,
MIPS_REG_14,
MIPS_REG_15,
MIPS_REG_16,
MIPS_REG_17,
MIPS_REG_18,
MIPS_REG_19,
MIPS_REG_20,
MIPS_REG_21,
MIPS_REG_22,
MIPS_REG_23,
MIPS_REG_24,
MIPS_REG_25,
MIPS_REG_26,
MIPS_REG_27,
MIPS_REG_28,
MIPS_REG_29,
MIPS_REG_30,
MIPS_REG_31,
// DSP registers
MIPS_REG_DSPCCOND,
MIPS_REG_DSPCARRY,
MIPS_REG_DSPEFI,
MIPS_REG_DSPOUTFLAG,
MIPS_REG_DSPOUTFLAG16_19,
MIPS_REG_DSPOUTFLAG20,
MIPS_REG_DSPOUTFLAG21,
MIPS_REG_DSPOUTFLAG22,
MIPS_REG_DSPOUTFLAG23,
MIPS_REG_DSPPOS,
MIPS_REG_DSPSCOUNT,
// ACC registers
MIPS_REG_AC0,
MIPS_REG_AC1,
MIPS_REG_AC2,
MIPS_REG_AC3,
// COP registers
MIPS_REG_CC0,
MIPS_REG_CC1,
MIPS_REG_CC2,
MIPS_REG_CC3,
MIPS_REG_CC4,
MIPS_REG_CC5,
MIPS_REG_CC6,
MIPS_REG_CC7,
// FPU registers
MIPS_REG_F0,
MIPS_REG_F1,
MIPS_REG_F2,
MIPS_REG_F3,
MIPS_REG_F4,
MIPS_REG_F5,
MIPS_REG_F6,
MIPS_REG_F7,
MIPS_REG_F8,
MIPS_REG_F9,
MIPS_REG_F10,
MIPS_REG_F11,
MIPS_REG_F12,
MIPS_REG_F13,
MIPS_REG_F14,
MIPS_REG_F15,
MIPS_REG_F16,
MIPS_REG_F17,
MIPS_REG_F18,
MIPS_REG_F19,
MIPS_REG_F20,
MIPS_REG_F21,
MIPS_REG_F22,
MIPS_REG_F23,
MIPS_REG_F24,
MIPS_REG_F25,
MIPS_REG_F26,
MIPS_REG_F27,
MIPS_REG_F28,
MIPS_REG_F29,
MIPS_REG_F30,
MIPS_REG_F31,
MIPS_REG_FCC0,
MIPS_REG_FCC1,
MIPS_REG_FCC2,
MIPS_REG_FCC3,
MIPS_REG_FCC4,
MIPS_REG_FCC5,
MIPS_REG_FCC6,
MIPS_REG_FCC7,
// AFPR128
MIPS_REG_W0,
MIPS_REG_W1,
MIPS_REG_W2,
MIPS_REG_W3,
MIPS_REG_W4,
MIPS_REG_W5,
MIPS_REG_W6,
MIPS_REG_W7,
MIPS_REG_W8,
MIPS_REG_W9,
MIPS_REG_W10,
MIPS_REG_W11,
MIPS_REG_W12,
MIPS_REG_W13,
MIPS_REG_W14,
MIPS_REG_W15,
MIPS_REG_W16,
MIPS_REG_W17,
MIPS_REG_W18,
MIPS_REG_W19,
MIPS_REG_W20,
MIPS_REG_W21,
MIPS_REG_W22,
MIPS_REG_W23,
MIPS_REG_W24,
MIPS_REG_W25,
MIPS_REG_W26,
MIPS_REG_W27,
MIPS_REG_W28,
MIPS_REG_W29,
MIPS_REG_W30,
MIPS_REG_W31,
MIPS_REG_HI,
MIPS_REG_LO,
MIPS_REG_P0,
MIPS_REG_P1,
MIPS_REG_P2,
MIPS_REG_MPL0,
MIPS_REG_MPL1,
MIPS_REG_MPL2,
MIPS_REG_ENDING, // <-- mark the end of the list or registers
// alias registers
MIPS_REG_ZERO = MIPS_REG_0,
MIPS_REG_AT = MIPS_REG_1,
MIPS_REG_V0 = MIPS_REG_2,
MIPS_REG_V1 = MIPS_REG_3,
MIPS_REG_A0 = MIPS_REG_4,
MIPS_REG_A1 = MIPS_REG_5,
MIPS_REG_A2 = MIPS_REG_6,
MIPS_REG_A3 = MIPS_REG_7,
MIPS_REG_T0 = MIPS_REG_8,
MIPS_REG_T1 = MIPS_REG_9,
MIPS_REG_T2 = MIPS_REG_10,
MIPS_REG_T3 = MIPS_REG_11,
MIPS_REG_T4 = MIPS_REG_12,
MIPS_REG_T5 = MIPS_REG_13,
MIPS_REG_T6 = MIPS_REG_14,
MIPS_REG_T7 = MIPS_REG_15,
MIPS_REG_S0 = MIPS_REG_16,
MIPS_REG_S1 = MIPS_REG_17,
MIPS_REG_S2 = MIPS_REG_18,
MIPS_REG_S3 = MIPS_REG_19,
MIPS_REG_S4 = MIPS_REG_20,
MIPS_REG_S5 = MIPS_REG_21,
MIPS_REG_S6 = MIPS_REG_22,
MIPS_REG_S7 = MIPS_REG_23,
MIPS_REG_T8 = MIPS_REG_24,
MIPS_REG_T9 = MIPS_REG_25,
MIPS_REG_K0 = MIPS_REG_26,
MIPS_REG_K1 = MIPS_REG_27,
MIPS_REG_GP = MIPS_REG_28,
MIPS_REG_SP = MIPS_REG_29,
MIPS_REG_FP = MIPS_REG_30, MIPS_REG_S8 = MIPS_REG_30,
MIPS_REG_RA = MIPS_REG_31,
MIPS_REG_HI0 = MIPS_REG_AC0,
MIPS_REG_HI1 = MIPS_REG_AC1,
MIPS_REG_HI2 = MIPS_REG_AC2,
MIPS_REG_HI3 = MIPS_REG_AC3,
MIPS_REG_LO0 = MIPS_REG_HI0,
MIPS_REG_LO1 = MIPS_REG_HI1,
MIPS_REG_LO2 = MIPS_REG_HI2,
MIPS_REG_LO3 = MIPS_REG_HI3,
} mips_reg;
/// Instruction's operand referring to memory
/// This is associated with MIPS_OP_MEM operand type above
typedef struct mips_op_mem {
mips_reg base; ///< base register
int64_t disp; ///< displacement/offset value
} mips_op_mem;
/// Instruction operand
typedef struct cs_mips_op {
mips_op_type type; ///< operand type
union {
mips_reg reg; ///< register value for REG operand
int64_t imm; ///< immediate value for IMM operand
mips_op_mem mem; ///< base/index/scale/disp value for MEM operand
};
} cs_mips_op;
/// Instruction structure
typedef struct cs_mips {
/// Number of operands of this instruction,
/// or 0 when instruction has no operand.
uint8_t op_count;
cs_mips_op operands[10]; ///< operands for this instruction.
} cs_mips;
/// MIPS instruction
typedef enum mips_insn {
MIPS_INS_INVALID = 0,
MIPS_INS_ABSQ_S,
MIPS_INS_ADD,
MIPS_INS_ADDIUPC,
MIPS_INS_ADDIUR1SP,
MIPS_INS_ADDIUR2,
MIPS_INS_ADDIUS5,
MIPS_INS_ADDIUSP,
MIPS_INS_ADDQH,
MIPS_INS_ADDQH_R,
MIPS_INS_ADDQ,
MIPS_INS_ADDQ_S,
MIPS_INS_ADDSC,
MIPS_INS_ADDS_A,
MIPS_INS_ADDS_S,
MIPS_INS_ADDS_U,
MIPS_INS_ADDU16,
MIPS_INS_ADDUH,
MIPS_INS_ADDUH_R,
MIPS_INS_ADDU,
MIPS_INS_ADDU_S,
MIPS_INS_ADDVI,
MIPS_INS_ADDV,
MIPS_INS_ADDWC,
MIPS_INS_ADD_A,
MIPS_INS_ADDI,
MIPS_INS_ADDIU,
MIPS_INS_ALIGN,
MIPS_INS_ALUIPC,
MIPS_INS_AND,
MIPS_INS_AND16,
MIPS_INS_ANDI16,
MIPS_INS_ANDI,
MIPS_INS_APPEND,
MIPS_INS_ASUB_S,
MIPS_INS_ASUB_U,
MIPS_INS_AUI,
MIPS_INS_AUIPC,
MIPS_INS_AVER_S,
MIPS_INS_AVER_U,
MIPS_INS_AVE_S,
MIPS_INS_AVE_U,
MIPS_INS_B16,
MIPS_INS_BADDU,
MIPS_INS_BAL,
MIPS_INS_BALC,
MIPS_INS_BALIGN,
MIPS_INS_BBIT0,
MIPS_INS_BBIT032,
MIPS_INS_BBIT1,
MIPS_INS_BBIT132,
MIPS_INS_BC,
MIPS_INS_BC0F,
MIPS_INS_BC0FL,
MIPS_INS_BC0T,
MIPS_INS_BC0TL,
MIPS_INS_BC1EQZ,
MIPS_INS_BC1F,
MIPS_INS_BC1FL,
MIPS_INS_BC1NEZ,
MIPS_INS_BC1T,
MIPS_INS_BC1TL,
MIPS_INS_BC2EQZ,
MIPS_INS_BC2F,
MIPS_INS_BC2FL,
MIPS_INS_BC2NEZ,
MIPS_INS_BC2T,
MIPS_INS_BC2TL,
MIPS_INS_BC3F,
MIPS_INS_BC3FL,
MIPS_INS_BC3T,
MIPS_INS_BC3TL,
MIPS_INS_BCLRI,
MIPS_INS_BCLR,
MIPS_INS_BEQ,
MIPS_INS_BEQC,
MIPS_INS_BEQL,
MIPS_INS_BEQZ16,
MIPS_INS_BEQZALC,
MIPS_INS_BEQZC,
MIPS_INS_BGEC,
MIPS_INS_BGEUC,
MIPS_INS_BGEZ,
MIPS_INS_BGEZAL,
MIPS_INS_BGEZALC,
MIPS_INS_BGEZALL,
MIPS_INS_BGEZALS,
MIPS_INS_BGEZC,
MIPS_INS_BGEZL,
MIPS_INS_BGTZ,
MIPS_INS_BGTZALC,
MIPS_INS_BGTZC,
MIPS_INS_BGTZL,
MIPS_INS_BINSLI,
MIPS_INS_BINSL,
MIPS_INS_BINSRI,
MIPS_INS_BINSR,
MIPS_INS_BITREV,
MIPS_INS_BITSWAP,
MIPS_INS_BLEZ,
MIPS_INS_BLEZALC,
MIPS_INS_BLEZC,
MIPS_INS_BLEZL,
MIPS_INS_BLTC,
MIPS_INS_BLTUC,
MIPS_INS_BLTZ,
MIPS_INS_BLTZAL,
MIPS_INS_BLTZALC,
MIPS_INS_BLTZALL,
MIPS_INS_BLTZALS,
MIPS_INS_BLTZC,
MIPS_INS_BLTZL,
MIPS_INS_BMNZI,
MIPS_INS_BMNZ,
MIPS_INS_BMZI,
MIPS_INS_BMZ,
MIPS_INS_BNE,
MIPS_INS_BNEC,
MIPS_INS_BNEGI,
MIPS_INS_BNEG,
MIPS_INS_BNEL,
MIPS_INS_BNEZ16,
MIPS_INS_BNEZALC,
MIPS_INS_BNEZC,
MIPS_INS_BNVC,
MIPS_INS_BNZ,
MIPS_INS_BOVC,
MIPS_INS_BPOSGE32,
MIPS_INS_BREAK,
MIPS_INS_BREAK16,
MIPS_INS_BSELI,
MIPS_INS_BSEL,
MIPS_INS_BSETI,
MIPS_INS_BSET,
MIPS_INS_BZ,
MIPS_INS_BEQZ,
MIPS_INS_B,
MIPS_INS_BNEZ,
MIPS_INS_BTEQZ,
MIPS_INS_BTNEZ,
MIPS_INS_CACHE,
MIPS_INS_CEIL,
MIPS_INS_CEQI,
MIPS_INS_CEQ,
MIPS_INS_CFC1,
MIPS_INS_CFCMSA,
MIPS_INS_CINS,
MIPS_INS_CINS32,
MIPS_INS_CLASS,
MIPS_INS_CLEI_S,
MIPS_INS_CLEI_U,
MIPS_INS_CLE_S,
MIPS_INS_CLE_U,
MIPS_INS_CLO,
MIPS_INS_CLTI_S,
MIPS_INS_CLTI_U,
MIPS_INS_CLT_S,
MIPS_INS_CLT_U,
MIPS_INS_CLZ,
MIPS_INS_CMPGDU,
MIPS_INS_CMPGU,
MIPS_INS_CMPU,
MIPS_INS_CMP,
MIPS_INS_COPY_S,
MIPS_INS_COPY_U,
MIPS_INS_CTC1,
MIPS_INS_CTCMSA,
MIPS_INS_CVT,
MIPS_INS_C,
MIPS_INS_CMPI,
MIPS_INS_DADD,
MIPS_INS_DADDI,
MIPS_INS_DADDIU,
MIPS_INS_DADDU,
MIPS_INS_DAHI,
MIPS_INS_DALIGN,
MIPS_INS_DATI,
MIPS_INS_DAUI,
MIPS_INS_DBITSWAP,
MIPS_INS_DCLO,
MIPS_INS_DCLZ,
MIPS_INS_DDIV,
MIPS_INS_DDIVU,
MIPS_INS_DERET,
MIPS_INS_DEXT,
MIPS_INS_DEXTM,
MIPS_INS_DEXTU,
MIPS_INS_DI,
MIPS_INS_DINS,
MIPS_INS_DINSM,
MIPS_INS_DINSU,
MIPS_INS_DIV,
MIPS_INS_DIVU,
MIPS_INS_DIV_S,
MIPS_INS_DIV_U,
MIPS_INS_DLSA,
MIPS_INS_DMFC0,
MIPS_INS_DMFC1,
MIPS_INS_DMFC2,
MIPS_INS_DMOD,
MIPS_INS_DMODU,
MIPS_INS_DMTC0,
MIPS_INS_DMTC1,
MIPS_INS_DMTC2,
MIPS_INS_DMUH,
MIPS_INS_DMUHU,
MIPS_INS_DMUL,
MIPS_INS_DMULT,
MIPS_INS_DMULTU,
MIPS_INS_DMULU,
MIPS_INS_DOTP_S,
MIPS_INS_DOTP_U,
MIPS_INS_DPADD_S,
MIPS_INS_DPADD_U,
MIPS_INS_DPAQX_SA,
MIPS_INS_DPAQX_S,
MIPS_INS_DPAQ_SA,
MIPS_INS_DPAQ_S,
MIPS_INS_DPAU,
MIPS_INS_DPAX,
MIPS_INS_DPA,
MIPS_INS_DPOP,
MIPS_INS_DPSQX_SA,
MIPS_INS_DPSQX_S,
MIPS_INS_DPSQ_SA,
MIPS_INS_DPSQ_S,
MIPS_INS_DPSUB_S,
MIPS_INS_DPSUB_U,
MIPS_INS_DPSU,
MIPS_INS_DPSX,
MIPS_INS_DPS,
MIPS_INS_DROTR,
MIPS_INS_DROTR32,
MIPS_INS_DROTRV,
MIPS_INS_DSBH,
MIPS_INS_DSHD,
MIPS_INS_DSLL,
MIPS_INS_DSLL32,
MIPS_INS_DSLLV,
MIPS_INS_DSRA,
MIPS_INS_DSRA32,
MIPS_INS_DSRAV,
MIPS_INS_DSRL,
MIPS_INS_DSRL32,
MIPS_INS_DSRLV,
MIPS_INS_DSUB,
MIPS_INS_DSUBU,
MIPS_INS_EHB,
MIPS_INS_EI,
MIPS_INS_ERET,
MIPS_INS_EXT,
MIPS_INS_EXTP,
MIPS_INS_EXTPDP,
MIPS_INS_EXTPDPV,
MIPS_INS_EXTPV,
MIPS_INS_EXTRV_RS,
MIPS_INS_EXTRV_R,
MIPS_INS_EXTRV_S,
MIPS_INS_EXTRV,
MIPS_INS_EXTR_RS,
MIPS_INS_EXTR_R,
MIPS_INS_EXTR_S,
MIPS_INS_EXTR,
MIPS_INS_EXTS,
MIPS_INS_EXTS32,
MIPS_INS_ABS,
MIPS_INS_FADD,
MIPS_INS_FCAF,
MIPS_INS_FCEQ,
MIPS_INS_FCLASS,
MIPS_INS_FCLE,
MIPS_INS_FCLT,
MIPS_INS_FCNE,
MIPS_INS_FCOR,
MIPS_INS_FCUEQ,
MIPS_INS_FCULE,
MIPS_INS_FCULT,
MIPS_INS_FCUNE,
MIPS_INS_FCUN,
MIPS_INS_FDIV,
MIPS_INS_FEXDO,
MIPS_INS_FEXP2,
MIPS_INS_FEXUPL,
MIPS_INS_FEXUPR,
MIPS_INS_FFINT_S,
MIPS_INS_FFINT_U,
MIPS_INS_FFQL,
MIPS_INS_FFQR,
MIPS_INS_FILL,
MIPS_INS_FLOG2,
MIPS_INS_FLOOR,
MIPS_INS_FMADD,
MIPS_INS_FMAX_A,
MIPS_INS_FMAX,
MIPS_INS_FMIN_A,
MIPS_INS_FMIN,
MIPS_INS_MOV,
MIPS_INS_FMSUB,
MIPS_INS_FMUL,
MIPS_INS_MUL,
MIPS_INS_NEG,
MIPS_INS_FRCP,
MIPS_INS_FRINT,
MIPS_INS_FRSQRT,
MIPS_INS_FSAF,
MIPS_INS_FSEQ,
MIPS_INS_FSLE,
MIPS_INS_FSLT,
MIPS_INS_FSNE,
MIPS_INS_FSOR,
MIPS_INS_FSQRT,
MIPS_INS_SQRT,
MIPS_INS_FSUB,
MIPS_INS_SUB,
MIPS_INS_FSUEQ,
MIPS_INS_FSULE,
MIPS_INS_FSULT,
MIPS_INS_FSUNE,
MIPS_INS_FSUN,
MIPS_INS_FTINT_S,
MIPS_INS_FTINT_U,
MIPS_INS_FTQ,
MIPS_INS_FTRUNC_S,
MIPS_INS_FTRUNC_U,
MIPS_INS_HADD_S,
MIPS_INS_HADD_U,
MIPS_INS_HSUB_S,
MIPS_INS_HSUB_U,
MIPS_INS_ILVEV,
MIPS_INS_ILVL,
MIPS_INS_ILVOD,
MIPS_INS_ILVR,
MIPS_INS_INS,
MIPS_INS_INSERT,
MIPS_INS_INSV,
MIPS_INS_INSVE,
MIPS_INS_J,
MIPS_INS_JAL,
MIPS_INS_JALR,
MIPS_INS_JALRS16,
MIPS_INS_JALRS,
MIPS_INS_JALS,
MIPS_INS_JALX,
MIPS_INS_JIALC,
MIPS_INS_JIC,
MIPS_INS_JR,
MIPS_INS_JR16,
MIPS_INS_JRADDIUSP,
MIPS_INS_JRC,
MIPS_INS_JALRC,
MIPS_INS_LB,
MIPS_INS_LBU16,
MIPS_INS_LBUX,
MIPS_INS_LBU,
MIPS_INS_LD,
MIPS_INS_LDC1,
MIPS_INS_LDC2,
MIPS_INS_LDC3,
MIPS_INS_LDI,
MIPS_INS_LDL,
MIPS_INS_LDPC,
MIPS_INS_LDR,
MIPS_INS_LDXC1,
MIPS_INS_LH,
MIPS_INS_LHU16,
MIPS_INS_LHX,
MIPS_INS_LHU,
MIPS_INS_LI16,
MIPS_INS_LL,
MIPS_INS_LLD,
MIPS_INS_LSA,
MIPS_INS_LUXC1,
MIPS_INS_LUI,
MIPS_INS_LW,
MIPS_INS_LW16,
MIPS_INS_LWC1,
MIPS_INS_LWC2,
MIPS_INS_LWC3,
MIPS_INS_LWL,
MIPS_INS_LWM16,
MIPS_INS_LWM32,
MIPS_INS_LWPC,
MIPS_INS_LWP,
MIPS_INS_LWR,
MIPS_INS_LWUPC,
MIPS_INS_LWU,
MIPS_INS_LWX,
MIPS_INS_LWXC1,
MIPS_INS_LWXS,
MIPS_INS_LI,
MIPS_INS_MADD,
MIPS_INS_MADDF,
MIPS_INS_MADDR_Q,
MIPS_INS_MADDU,
MIPS_INS_MADDV,
MIPS_INS_MADD_Q,
MIPS_INS_MAQ_SA,
MIPS_INS_MAQ_S,
MIPS_INS_MAXA,
MIPS_INS_MAXI_S,
MIPS_INS_MAXI_U,
MIPS_INS_MAX_A,
MIPS_INS_MAX,
MIPS_INS_MAX_S,
MIPS_INS_MAX_U,
MIPS_INS_MFC0,
MIPS_INS_MFC1,
MIPS_INS_MFC2,
MIPS_INS_MFHC1,
MIPS_INS_MFHI,
MIPS_INS_MFLO,
MIPS_INS_MINA,
MIPS_INS_MINI_S,
MIPS_INS_MINI_U,
MIPS_INS_MIN_A,
MIPS_INS_MIN,
MIPS_INS_MIN_S,
MIPS_INS_MIN_U,
MIPS_INS_MOD,
MIPS_INS_MODSUB,
MIPS_INS_MODU,
MIPS_INS_MOD_S,
MIPS_INS_MOD_U,
MIPS_INS_MOVE,
MIPS_INS_MOVEP,
MIPS_INS_MOVF,
MIPS_INS_MOVN,
MIPS_INS_MOVT,
MIPS_INS_MOVZ,
MIPS_INS_MSUB,
MIPS_INS_MSUBF,
MIPS_INS_MSUBR_Q,
MIPS_INS_MSUBU,
MIPS_INS_MSUBV,
MIPS_INS_MSUB_Q,
MIPS_INS_MTC0,
MIPS_INS_MTC1,
MIPS_INS_MTC2,
MIPS_INS_MTHC1,
MIPS_INS_MTHI,
MIPS_INS_MTHLIP,
MIPS_INS_MTLO,
MIPS_INS_MTM0,
MIPS_INS_MTM1,
MIPS_INS_MTM2,
MIPS_INS_MTP0,
MIPS_INS_MTP1,
MIPS_INS_MTP2,
MIPS_INS_MUH,
MIPS_INS_MUHU,
MIPS_INS_MULEQ_S,
MIPS_INS_MULEU_S,
MIPS_INS_MULQ_RS,
MIPS_INS_MULQ_S,
MIPS_INS_MULR_Q,
MIPS_INS_MULSAQ_S,
MIPS_INS_MULSA,
MIPS_INS_MULT,
MIPS_INS_MULTU,
MIPS_INS_MULU,
MIPS_INS_MULV,
MIPS_INS_MUL_Q,
MIPS_INS_MUL_S,
MIPS_INS_NLOC,
MIPS_INS_NLZC,
MIPS_INS_NMADD,
MIPS_INS_NMSUB,
MIPS_INS_NOR,
MIPS_INS_NORI,
MIPS_INS_NOT16,
MIPS_INS_NOT,
MIPS_INS_OR,
MIPS_INS_OR16,
MIPS_INS_ORI,
MIPS_INS_PACKRL,
MIPS_INS_PAUSE,
MIPS_INS_PCKEV,
MIPS_INS_PCKOD,
MIPS_INS_PCNT,
MIPS_INS_PICK,
MIPS_INS_POP,
MIPS_INS_PRECEQU,
MIPS_INS_PRECEQ,
MIPS_INS_PRECEU,
MIPS_INS_PRECRQU_S,
MIPS_INS_PRECRQ,
MIPS_INS_PRECRQ_RS,
MIPS_INS_PRECR,
MIPS_INS_PRECR_SRA,
MIPS_INS_PRECR_SRA_R,
MIPS_INS_PREF,
MIPS_INS_PREPEND,
MIPS_INS_RADDU,
MIPS_INS_RDDSP,
MIPS_INS_RDHWR,
MIPS_INS_REPLV,
MIPS_INS_REPL,
MIPS_INS_RINT,
MIPS_INS_ROTR,
MIPS_INS_ROTRV,
MIPS_INS_ROUND,
MIPS_INS_SAT_S,
MIPS_INS_SAT_U,
MIPS_INS_SB,
MIPS_INS_SB16,
MIPS_INS_SC,
MIPS_INS_SCD,
MIPS_INS_SD,
MIPS_INS_SDBBP,
MIPS_INS_SDBBP16,
MIPS_INS_SDC1,
MIPS_INS_SDC2,
MIPS_INS_SDC3,
MIPS_INS_SDL,
MIPS_INS_SDR,
MIPS_INS_SDXC1,
MIPS_INS_SEB,
MIPS_INS_SEH,
MIPS_INS_SELEQZ,
MIPS_INS_SELNEZ,
MIPS_INS_SEL,
MIPS_INS_SEQ,
MIPS_INS_SEQI,
MIPS_INS_SH,
MIPS_INS_SH16,
MIPS_INS_SHF,
MIPS_INS_SHILO,
MIPS_INS_SHILOV,
MIPS_INS_SHLLV,
MIPS_INS_SHLLV_S,
MIPS_INS_SHLL,
MIPS_INS_SHLL_S,
MIPS_INS_SHRAV,
MIPS_INS_SHRAV_R,
MIPS_INS_SHRA,
MIPS_INS_SHRA_R,
MIPS_INS_SHRLV,
MIPS_INS_SHRL,
MIPS_INS_SLDI,
MIPS_INS_SLD,
MIPS_INS_SLL,
MIPS_INS_SLL16,
MIPS_INS_SLLI,
MIPS_INS_SLLV,
MIPS_INS_SLT,
MIPS_INS_SLTI,
MIPS_INS_SLTIU,
MIPS_INS_SLTU,
MIPS_INS_SNE,
MIPS_INS_SNEI,
MIPS_INS_SPLATI,
MIPS_INS_SPLAT,
MIPS_INS_SRA,
MIPS_INS_SRAI,
MIPS_INS_SRARI,
MIPS_INS_SRAR,
MIPS_INS_SRAV,
MIPS_INS_SRL,
MIPS_INS_SRL16,
MIPS_INS_SRLI,
MIPS_INS_SRLRI,
MIPS_INS_SRLR,
MIPS_INS_SRLV,
MIPS_INS_SSNOP,
MIPS_INS_ST,
MIPS_INS_SUBQH,
MIPS_INS_SUBQH_R,
MIPS_INS_SUBQ,
MIPS_INS_SUBQ_S,
MIPS_INS_SUBSUS_U,
MIPS_INS_SUBSUU_S,
MIPS_INS_SUBS_S,
MIPS_INS_SUBS_U,
MIPS_INS_SUBU16,
MIPS_INS_SUBUH,
MIPS_INS_SUBUH_R,
MIPS_INS_SUBU,
MIPS_INS_SUBU_S,
MIPS_INS_SUBVI,
MIPS_INS_SUBV,
MIPS_INS_SUXC1,
MIPS_INS_SW,
MIPS_INS_SW16,
MIPS_INS_SWC1,
MIPS_INS_SWC2,
MIPS_INS_SWC3,
MIPS_INS_SWL,
MIPS_INS_SWM16,
MIPS_INS_SWM32,
MIPS_INS_SWP,
MIPS_INS_SWR,
MIPS_INS_SWXC1,
MIPS_INS_SYNC,
MIPS_INS_SYNCI,
MIPS_INS_SYSCALL,
MIPS_INS_TEQ,
MIPS_INS_TEQI,
MIPS_INS_TGE,
MIPS_INS_TGEI,
MIPS_INS_TGEIU,
MIPS_INS_TGEU,
MIPS_INS_TLBP,
MIPS_INS_TLBR,
MIPS_INS_TLBWI,
MIPS_INS_TLBWR,
MIPS_INS_TLT,
MIPS_INS_TLTI,
MIPS_INS_TLTIU,
MIPS_INS_TLTU,
MIPS_INS_TNE,
MIPS_INS_TNEI,
MIPS_INS_TRUNC,
MIPS_INS_V3MULU,
MIPS_INS_VMM0,
MIPS_INS_VMULU,
MIPS_INS_VSHF,
MIPS_INS_WAIT,
MIPS_INS_WRDSP,
MIPS_INS_WSBH,
MIPS_INS_XOR,
MIPS_INS_XOR16,
MIPS_INS_XORI,
//> some alias instructions
MIPS_INS_NOP,
MIPS_INS_NEGU,
//> special instructions
MIPS_INS_JALR_HB, // jump and link with Hazard Barrier
MIPS_INS_JR_HB, // jump register with Hazard Barrier
MIPS_INS_ENDING,
} mips_insn;
/// Group of MIPS instructions
typedef enum mips_insn_group {
MIPS_GRP_INVALID = 0, ///< = CS_GRP_INVALID
// Generic groups
// all jump instructions (conditional+direct+indirect jumps)
MIPS_GRP_JUMP, ///< = CS_GRP_JUMP
// all call instructions
MIPS_GRP_CALL, ///< = CS_GRP_CALL
// all return instructions
MIPS_GRP_RET, ///< = CS_GRP_RET
// all interrupt instructions (int+syscall)
MIPS_GRP_INT, ///< = CS_GRP_INT
// all interrupt return instructions
MIPS_GRP_IRET, ///< = CS_GRP_IRET
// all privileged instructions
MIPS_GRP_PRIVILEGE, ///< = CS_GRP_PRIVILEGE
// all relative branching instructions
MIPS_GRP_BRANCH_RELATIVE, ///< = CS_GRP_BRANCH_RELATIVE
// Architecture-specific groups
MIPS_GRP_BITCOUNT = 128,
MIPS_GRP_DSP,
MIPS_GRP_DSPR2,
MIPS_GRP_FPIDX,
MIPS_GRP_MSA,
MIPS_GRP_MIPS32R2,
MIPS_GRP_MIPS64,
MIPS_GRP_MIPS64R2,
MIPS_GRP_SEINREG,
MIPS_GRP_STDENC,
MIPS_GRP_SWAP,
MIPS_GRP_MICROMIPS,
MIPS_GRP_MIPS16MODE,
MIPS_GRP_FP64BIT,
MIPS_GRP_NONANSFPMATH,
MIPS_GRP_NOTFP64BIT,
MIPS_GRP_NOTINMICROMIPS,
MIPS_GRP_NOTNACL,
MIPS_GRP_NOTMIPS32R6,
MIPS_GRP_NOTMIPS64R6,
MIPS_GRP_CNMIPS,
MIPS_GRP_MIPS32,
MIPS_GRP_MIPS32R6,
MIPS_GRP_MIPS64R6,
MIPS_GRP_MIPS2,
MIPS_GRP_MIPS3,
MIPS_GRP_MIPS3_32,
MIPS_GRP_MIPS3_32R2,
MIPS_GRP_MIPS4_32,
MIPS_GRP_MIPS4_32R2,
MIPS_GRP_MIPS5_32R2,
MIPS_GRP_GP32BIT,
MIPS_GRP_GP64BIT,
MIPS_GRP_ENDING,
} mips_insn_group;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,122 @@
/* Capstone Disassembly Engine */
/* By Axel Souchet & Nguyen Anh Quynh, 2014 */
#ifndef CAPSTONE_PLATFORM_H
#define CAPSTONE_PLATFORM_H
// handle C99 issue (for pre-2013 VisualStudio)
#if !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
// MSVC
// stdbool.h
#if (_MSC_VER < 1800) || defined(_KERNEL_MODE)
// this system does not have stdbool.h
#ifndef __cplusplus
typedef unsigned char bool;
#define false 0
#define true 1
#endif // __cplusplus
#else
// VisualStudio 2013+ -> C99 is supported
#include <stdbool.h>
#endif // (_MSC_VER < 1800) || defined(_KERNEL_MODE)
#else
// not MSVC -> C99 is supported
#include <stdbool.h>
#endif // !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
// handle inttypes.h / stdint.h compatibility
#if defined(_WIN32_WCE) && (_WIN32_WCE < 0x800)
#include "windowsce/stdint.h"
#endif // defined(_WIN32_WCE) && (_WIN32_WCE < 0x800)
#if defined(CAPSTONE_HAS_OSXKERNEL) || (defined(_MSC_VER) && (_MSC_VER <= 1700 || defined(_KERNEL_MODE)))
// this system does not have inttypes.h
#if defined(_MSC_VER) && (_MSC_VER <= 1600 || defined(_KERNEL_MODE))
// this system does not have stdint.h
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#endif // defined(_MSC_VER) && (_MSC_VER <= 1600 || defined(_KERNEL_MODE))
#if defined(_MSC_VER) && (_MSC_VER < 1600 || defined(_KERNEL_MODE))
#define INT8_MIN (-127i8 - 1)
#define INT16_MIN (-32767i16 - 1)
#define INT32_MIN (-2147483647i32 - 1)
#define INT64_MIN (-9223372036854775807i64 - 1)
#define INT8_MAX 127i8
#define INT16_MAX 32767i16
#define INT32_MAX 2147483647i32
#define INT64_MAX 9223372036854775807i64
#define UINT8_MAX 0xffui8
#define UINT16_MAX 0xffffui16
#define UINT32_MAX 0xffffffffui32
#define UINT64_MAX 0xffffffffffffffffui64
#endif // defined(_MSC_VER) && (_MSC_VER < 1600 || defined(_KERNEL_MODE))
#ifdef CAPSTONE_HAS_OSXKERNEL
// this system has stdint.h
#include <stdint.h>
#endif
#define __PRI_8_LENGTH_MODIFIER__ "hh"
#define __PRI_64_LENGTH_MODIFIER__ "ll"
#define PRId8 __PRI_8_LENGTH_MODIFIER__ "d"
#define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i"
#define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o"
#define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u"
#define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x"
#define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X"
#define PRId16 "hd"
#define PRIi16 "hi"
#define PRIo16 "ho"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hX"
#if defined(_MSC_VER) && _MSC_VER <= 1700
#define PRId32 "ld"
#define PRIi32 "li"
#define PRIo32 "lo"
#define PRIu32 "lu"
#define PRIx32 "lx"
#define PRIX32 "lX"
#else // OSX
#define PRId32 "d"
#define PRIi32 "i"
#define PRIo32 "o"
#define PRIu32 "u"
#define PRIx32 "x"
#define PRIX32 "X"
#endif // defined(_MSC_VER) && _MSC_VER <= 1700
#if defined(_MSC_VER) && _MSC_VER <= 1700
// redefine functions from inttypes.h used in cstool
#define strtoull _strtoui64
#endif
#define PRId64 __PRI_64_LENGTH_MODIFIER__ "d"
#define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i"
#define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o"
#define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u"
#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x"
#define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X"
#else
// this system has inttypes.h by default
#include <inttypes.h>
#endif // defined(CAPSTONE_HAS_OSXKERNEL) || (defined(_MSC_VER) && (_MSC_VER <= 1700 || defined(_KERNEL_MODE)))
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,520 @@
#ifndef CAPSTONE_SPARC_H
#define CAPSTONE_SPARC_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2015 */
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
// GCC SPARC toolchain has a default macro called "sparc" which breaks
// compilation
#undef sparc
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
/// Enums corresponding to Sparc condition codes, both icc's and fcc's.
typedef enum sparc_cc {
SPARC_CC_INVALID = 0, ///< invalid CC (default)
// Integer condition codes
SPARC_CC_ICC_A = 8+256, ///< Always
SPARC_CC_ICC_N = 0+256, ///< Never
SPARC_CC_ICC_NE = 9+256, ///< Not Equal
SPARC_CC_ICC_E = 1+256, ///< Equal
SPARC_CC_ICC_G = 10+256, ///< Greater
SPARC_CC_ICC_LE = 2+256, ///< Less or Equal
SPARC_CC_ICC_GE = 11+256, ///< Greater or Equal
SPARC_CC_ICC_L = 3+256, ///< Less
SPARC_CC_ICC_GU = 12+256, ///< Greater Unsigned
SPARC_CC_ICC_LEU = 4+256, ///< Less or Equal Unsigned
SPARC_CC_ICC_CC = 13+256, ///< Carry Clear/Great or Equal Unsigned
SPARC_CC_ICC_CS = 5+256, ///< Carry Set/Less Unsigned
SPARC_CC_ICC_POS = 14+256, ///< Positive
SPARC_CC_ICC_NEG = 6+256, ///< Negative
SPARC_CC_ICC_VC = 15+256, ///< Overflow Clear
SPARC_CC_ICC_VS = 7+256, ///< Overflow Set
// Floating condition codes
SPARC_CC_FCC_A = 8+16+256, ///< Always
SPARC_CC_FCC_N = 0+16+256, ///< Never
SPARC_CC_FCC_U = 7+16+256, ///< Unordered
SPARC_CC_FCC_G = 6+16+256, ///< Greater
SPARC_CC_FCC_UG = 5+16+256, ///< Unordered or Greater
SPARC_CC_FCC_L = 4+16+256, ///< Less
SPARC_CC_FCC_UL = 3+16+256, ///< Unordered or Less
SPARC_CC_FCC_LG = 2+16+256, ///< Less or Greater
SPARC_CC_FCC_NE = 1+16+256, ///< Not Equal
SPARC_CC_FCC_E = 9+16+256, ///< Equal
SPARC_CC_FCC_UE = 10+16+256, ///< Unordered or Equal
SPARC_CC_FCC_GE = 11+16+256, ///< Greater or Equal
SPARC_CC_FCC_UGE = 12+16+256, ///< Unordered or Greater or Equal
SPARC_CC_FCC_LE = 13+16+256, ///< Less or Equal
SPARC_CC_FCC_ULE = 14+16+256, ///< Unordered or Less or Equal
SPARC_CC_FCC_O = 15+16+256, ///< Ordered
} sparc_cc;
/// Branch hint
typedef enum sparc_hint {
SPARC_HINT_INVALID = 0, ///< no hint
SPARC_HINT_A = 1 << 0, ///< annul delay slot instruction
SPARC_HINT_PT = 1 << 1, ///< branch taken
SPARC_HINT_PN = 1 << 2, ///< branch NOT taken
} sparc_hint;
/// Operand type for instruction's operands
typedef enum sparc_op_type {
SPARC_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
SPARC_OP_REG, ///< = CS_OP_REG (Register operand).
SPARC_OP_IMM, ///< = CS_OP_IMM (Immediate operand).
SPARC_OP_MEM, ///< = CS_OP_MEM (Memory operand).
} sparc_op_type;
/// SPARC registers
typedef enum sparc_reg {
SPARC_REG_INVALID = 0,
SPARC_REG_F0,
SPARC_REG_F1,
SPARC_REG_F2,
SPARC_REG_F3,
SPARC_REG_F4,
SPARC_REG_F5,
SPARC_REG_F6,
SPARC_REG_F7,
SPARC_REG_F8,
SPARC_REG_F9,
SPARC_REG_F10,
SPARC_REG_F11,
SPARC_REG_F12,
SPARC_REG_F13,
SPARC_REG_F14,
SPARC_REG_F15,
SPARC_REG_F16,
SPARC_REG_F17,
SPARC_REG_F18,
SPARC_REG_F19,
SPARC_REG_F20,
SPARC_REG_F21,
SPARC_REG_F22,
SPARC_REG_F23,
SPARC_REG_F24,
SPARC_REG_F25,
SPARC_REG_F26,
SPARC_REG_F27,
SPARC_REG_F28,
SPARC_REG_F29,
SPARC_REG_F30,
SPARC_REG_F31,
SPARC_REG_F32,
SPARC_REG_F34,
SPARC_REG_F36,
SPARC_REG_F38,
SPARC_REG_F40,
SPARC_REG_F42,
SPARC_REG_F44,
SPARC_REG_F46,
SPARC_REG_F48,
SPARC_REG_F50,
SPARC_REG_F52,
SPARC_REG_F54,
SPARC_REG_F56,
SPARC_REG_F58,
SPARC_REG_F60,
SPARC_REG_F62,
SPARC_REG_FCC0, // Floating condition codes
SPARC_REG_FCC1,
SPARC_REG_FCC2,
SPARC_REG_FCC3,
SPARC_REG_FP,
SPARC_REG_G0,
SPARC_REG_G1,
SPARC_REG_G2,
SPARC_REG_G3,
SPARC_REG_G4,
SPARC_REG_G5,
SPARC_REG_G6,
SPARC_REG_G7,
SPARC_REG_I0,
SPARC_REG_I1,
SPARC_REG_I2,
SPARC_REG_I3,
SPARC_REG_I4,
SPARC_REG_I5,
SPARC_REG_I7,
SPARC_REG_ICC, // Integer condition codes
SPARC_REG_L0,
SPARC_REG_L1,
SPARC_REG_L2,
SPARC_REG_L3,
SPARC_REG_L4,
SPARC_REG_L5,
SPARC_REG_L6,
SPARC_REG_L7,
SPARC_REG_O0,
SPARC_REG_O1,
SPARC_REG_O2,
SPARC_REG_O3,
SPARC_REG_O4,
SPARC_REG_O5,
SPARC_REG_O7,
SPARC_REG_SP,
SPARC_REG_Y,
// special register
SPARC_REG_XCC,
SPARC_REG_ENDING, // <-- mark the end of the list of registers
// extras
SPARC_REG_O6 = SPARC_REG_SP,
SPARC_REG_I6 = SPARC_REG_FP,
} sparc_reg;
/// Instruction's operand referring to memory
/// This is associated with SPARC_OP_MEM operand type above
typedef struct sparc_op_mem {
uint8_t base; ///< base register, can be safely interpreted as
///< a value of type `sparc_reg`, but it is only
///< one byte wide
uint8_t index; ///< index register, same conditions apply here
int32_t disp; ///< displacement/offset value
} sparc_op_mem;
/// Instruction operand
typedef struct cs_sparc_op {
sparc_op_type type; ///< operand type
union {
sparc_reg reg; ///< register value for REG operand
int64_t imm; ///< immediate value for IMM operand
sparc_op_mem mem; ///< base/disp value for MEM operand
};
} cs_sparc_op;
/// Instruction structure
typedef struct cs_sparc {
sparc_cc cc; ///< code condition for this insn
sparc_hint hint; ///< branch hint: encoding as bitwise OR of sparc_hint.
/// Number of operands of this instruction,
/// or 0 when instruction has no operand.
uint8_t op_count;
cs_sparc_op operands[4]; ///< operands for this instruction.
} cs_sparc;
/// SPARC instruction
typedef enum sparc_insn {
SPARC_INS_INVALID = 0,
SPARC_INS_ADDCC,
SPARC_INS_ADDX,
SPARC_INS_ADDXCC,
SPARC_INS_ADDXC,
SPARC_INS_ADDXCCC,
SPARC_INS_ADD,
SPARC_INS_ALIGNADDR,
SPARC_INS_ALIGNADDRL,
SPARC_INS_ANDCC,
SPARC_INS_ANDNCC,
SPARC_INS_ANDN,
SPARC_INS_AND,
SPARC_INS_ARRAY16,
SPARC_INS_ARRAY32,
SPARC_INS_ARRAY8,
SPARC_INS_B,
SPARC_INS_JMP,
SPARC_INS_BMASK,
SPARC_INS_FB,
SPARC_INS_BRGEZ,
SPARC_INS_BRGZ,
SPARC_INS_BRLEZ,
SPARC_INS_BRLZ,
SPARC_INS_BRNZ,
SPARC_INS_BRZ,
SPARC_INS_BSHUFFLE,
SPARC_INS_CALL,
SPARC_INS_CASX,
SPARC_INS_CAS,
SPARC_INS_CMASK16,
SPARC_INS_CMASK32,
SPARC_INS_CMASK8,
SPARC_INS_CMP,
SPARC_INS_EDGE16,
SPARC_INS_EDGE16L,
SPARC_INS_EDGE16LN,
SPARC_INS_EDGE16N,
SPARC_INS_EDGE32,
SPARC_INS_EDGE32L,
SPARC_INS_EDGE32LN,
SPARC_INS_EDGE32N,
SPARC_INS_EDGE8,
SPARC_INS_EDGE8L,
SPARC_INS_EDGE8LN,
SPARC_INS_EDGE8N,
SPARC_INS_FABSD,
SPARC_INS_FABSQ,
SPARC_INS_FABSS,
SPARC_INS_FADDD,
SPARC_INS_FADDQ,
SPARC_INS_FADDS,
SPARC_INS_FALIGNDATA,
SPARC_INS_FAND,
SPARC_INS_FANDNOT1,
SPARC_INS_FANDNOT1S,
SPARC_INS_FANDNOT2,
SPARC_INS_FANDNOT2S,
SPARC_INS_FANDS,
SPARC_INS_FCHKSM16,
SPARC_INS_FCMPD,
SPARC_INS_FCMPEQ16,
SPARC_INS_FCMPEQ32,
SPARC_INS_FCMPGT16,
SPARC_INS_FCMPGT32,
SPARC_INS_FCMPLE16,
SPARC_INS_FCMPLE32,
SPARC_INS_FCMPNE16,
SPARC_INS_FCMPNE32,
SPARC_INS_FCMPQ,
SPARC_INS_FCMPS,
SPARC_INS_FDIVD,
SPARC_INS_FDIVQ,
SPARC_INS_FDIVS,
SPARC_INS_FDMULQ,
SPARC_INS_FDTOI,
SPARC_INS_FDTOQ,
SPARC_INS_FDTOS,
SPARC_INS_FDTOX,
SPARC_INS_FEXPAND,
SPARC_INS_FHADDD,
SPARC_INS_FHADDS,
SPARC_INS_FHSUBD,
SPARC_INS_FHSUBS,
SPARC_INS_FITOD,
SPARC_INS_FITOQ,
SPARC_INS_FITOS,
SPARC_INS_FLCMPD,
SPARC_INS_FLCMPS,
SPARC_INS_FLUSHW,
SPARC_INS_FMEAN16,
SPARC_INS_FMOVD,
SPARC_INS_FMOVQ,
SPARC_INS_FMOVRDGEZ,
SPARC_INS_FMOVRQGEZ,
SPARC_INS_FMOVRSGEZ,
SPARC_INS_FMOVRDGZ,
SPARC_INS_FMOVRQGZ,
SPARC_INS_FMOVRSGZ,
SPARC_INS_FMOVRDLEZ,
SPARC_INS_FMOVRQLEZ,
SPARC_INS_FMOVRSLEZ,
SPARC_INS_FMOVRDLZ,
SPARC_INS_FMOVRQLZ,
SPARC_INS_FMOVRSLZ,
SPARC_INS_FMOVRDNZ,
SPARC_INS_FMOVRQNZ,
SPARC_INS_FMOVRSNZ,
SPARC_INS_FMOVRDZ,
SPARC_INS_FMOVRQZ,
SPARC_INS_FMOVRSZ,
SPARC_INS_FMOVS,
SPARC_INS_FMUL8SUX16,
SPARC_INS_FMUL8ULX16,
SPARC_INS_FMUL8X16,
SPARC_INS_FMUL8X16AL,
SPARC_INS_FMUL8X16AU,
SPARC_INS_FMULD,
SPARC_INS_FMULD8SUX16,
SPARC_INS_FMULD8ULX16,
SPARC_INS_FMULQ,
SPARC_INS_FMULS,
SPARC_INS_FNADDD,
SPARC_INS_FNADDS,
SPARC_INS_FNAND,
SPARC_INS_FNANDS,
SPARC_INS_FNEGD,
SPARC_INS_FNEGQ,
SPARC_INS_FNEGS,
SPARC_INS_FNHADDD,
SPARC_INS_FNHADDS,
SPARC_INS_FNOR,
SPARC_INS_FNORS,
SPARC_INS_FNOT1,
SPARC_INS_FNOT1S,
SPARC_INS_FNOT2,
SPARC_INS_FNOT2S,
SPARC_INS_FONE,
SPARC_INS_FONES,
SPARC_INS_FOR,
SPARC_INS_FORNOT1,
SPARC_INS_FORNOT1S,
SPARC_INS_FORNOT2,
SPARC_INS_FORNOT2S,
SPARC_INS_FORS,
SPARC_INS_FPACK16,
SPARC_INS_FPACK32,
SPARC_INS_FPACKFIX,
SPARC_INS_FPADD16,
SPARC_INS_FPADD16S,
SPARC_INS_FPADD32,
SPARC_INS_FPADD32S,
SPARC_INS_FPADD64,
SPARC_INS_FPMERGE,
SPARC_INS_FPSUB16,
SPARC_INS_FPSUB16S,
SPARC_INS_FPSUB32,
SPARC_INS_FPSUB32S,
SPARC_INS_FQTOD,
SPARC_INS_FQTOI,
SPARC_INS_FQTOS,
SPARC_INS_FQTOX,
SPARC_INS_FSLAS16,
SPARC_INS_FSLAS32,
SPARC_INS_FSLL16,
SPARC_INS_FSLL32,
SPARC_INS_FSMULD,
SPARC_INS_FSQRTD,
SPARC_INS_FSQRTQ,
SPARC_INS_FSQRTS,
SPARC_INS_FSRA16,
SPARC_INS_FSRA32,
SPARC_INS_FSRC1,
SPARC_INS_FSRC1S,
SPARC_INS_FSRC2,
SPARC_INS_FSRC2S,
SPARC_INS_FSRL16,
SPARC_INS_FSRL32,
SPARC_INS_FSTOD,
SPARC_INS_FSTOI,
SPARC_INS_FSTOQ,
SPARC_INS_FSTOX,
SPARC_INS_FSUBD,
SPARC_INS_FSUBQ,
SPARC_INS_FSUBS,
SPARC_INS_FXNOR,
SPARC_INS_FXNORS,
SPARC_INS_FXOR,
SPARC_INS_FXORS,
SPARC_INS_FXTOD,
SPARC_INS_FXTOQ,
SPARC_INS_FXTOS,
SPARC_INS_FZERO,
SPARC_INS_FZEROS,
SPARC_INS_JMPL,
SPARC_INS_LDD,
SPARC_INS_LD,
SPARC_INS_LDQ,
SPARC_INS_LDSB,
SPARC_INS_LDSH,
SPARC_INS_LDSW,
SPARC_INS_LDUB,
SPARC_INS_LDUH,
SPARC_INS_LDX,
SPARC_INS_LZCNT,
SPARC_INS_MEMBAR,
SPARC_INS_MOVDTOX,
SPARC_INS_MOV,
SPARC_INS_MOVRGEZ,
SPARC_INS_MOVRGZ,
SPARC_INS_MOVRLEZ,
SPARC_INS_MOVRLZ,
SPARC_INS_MOVRNZ,
SPARC_INS_MOVRZ,
SPARC_INS_MOVSTOSW,
SPARC_INS_MOVSTOUW,
SPARC_INS_MULX,
SPARC_INS_NOP,
SPARC_INS_ORCC,
SPARC_INS_ORNCC,
SPARC_INS_ORN,
SPARC_INS_OR,
SPARC_INS_PDIST,
SPARC_INS_PDISTN,
SPARC_INS_POPC,
SPARC_INS_RD,
SPARC_INS_RESTORE,
SPARC_INS_RETT,
SPARC_INS_SAVE,
SPARC_INS_SDIVCC,
SPARC_INS_SDIVX,
SPARC_INS_SDIV,
SPARC_INS_SETHI,
SPARC_INS_SHUTDOWN,
SPARC_INS_SIAM,
SPARC_INS_SLLX,
SPARC_INS_SLL,
SPARC_INS_SMULCC,
SPARC_INS_SMUL,
SPARC_INS_SRAX,
SPARC_INS_SRA,
SPARC_INS_SRLX,
SPARC_INS_SRL,
SPARC_INS_STBAR,
SPARC_INS_STB,
SPARC_INS_STD,
SPARC_INS_ST,
SPARC_INS_STH,
SPARC_INS_STQ,
SPARC_INS_STX,
SPARC_INS_SUBCC,
SPARC_INS_SUBX,
SPARC_INS_SUBXCC,
SPARC_INS_SUB,
SPARC_INS_SWAP,
SPARC_INS_TADDCCTV,
SPARC_INS_TADDCC,
SPARC_INS_T,
SPARC_INS_TSUBCCTV,
SPARC_INS_TSUBCC,
SPARC_INS_UDIVCC,
SPARC_INS_UDIVX,
SPARC_INS_UDIV,
SPARC_INS_UMULCC,
SPARC_INS_UMULXHI,
SPARC_INS_UMUL,
SPARC_INS_UNIMP,
SPARC_INS_FCMPED,
SPARC_INS_FCMPEQ,
SPARC_INS_FCMPES,
SPARC_INS_WR,
SPARC_INS_XMULX,
SPARC_INS_XMULXHI,
SPARC_INS_XNORCC,
SPARC_INS_XNOR,
SPARC_INS_XORCC,
SPARC_INS_XOR,
// alias instructions
SPARC_INS_RET,
SPARC_INS_RETL,
SPARC_INS_ENDING, // <-- mark the end of the list of instructions
} sparc_insn;
/// Group of SPARC instructions
typedef enum sparc_insn_group {
SPARC_GRP_INVALID = 0, ///< = CS_GRP_INVALID
// Generic groups
// all jump instructions (conditional+direct+indirect jumps)
SPARC_GRP_JUMP, ///< = CS_GRP_JUMP
// Architecture-specific groups
SPARC_GRP_HARDQUAD = 128,
SPARC_GRP_V9,
SPARC_GRP_VIS,
SPARC_GRP_VIS2,
SPARC_GRP_VIS3,
SPARC_GRP_32BIT,
SPARC_GRP_64BIT,
SPARC_GRP_ENDING, // <-- mark the end of the list of groups
} sparc_insn_group;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,830 @@
#ifndef CAPSTONE_SYSTEMZ_H
#define CAPSTONE_SYSTEMZ_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2015 */
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
/// Enums corresponding to SystemZ condition codes
typedef enum sysz_cc {
SYSZ_CC_INVALID = 0, ///< invalid CC (default)
SYSZ_CC_O,
SYSZ_CC_H,
SYSZ_CC_NLE,
SYSZ_CC_L,
SYSZ_CC_NHE,
SYSZ_CC_LH,
SYSZ_CC_NE,
SYSZ_CC_E,
SYSZ_CC_NLH,
SYSZ_CC_HE,
SYSZ_CC_NL,
SYSZ_CC_LE,
SYSZ_CC_NH,
SYSZ_CC_NO,
} sysz_cc;
/// Operand type for instruction's operands
typedef enum sysz_op_type {
SYSZ_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
SYSZ_OP_REG, ///< = CS_OP_REG (Register operand).
SYSZ_OP_IMM, ///< = CS_OP_IMM (Immediate operand).
SYSZ_OP_MEM, ///< = CS_OP_MEM (Memory operand).
SYSZ_OP_ACREG = 64, ///< Access register operand.
} sysz_op_type;
/// SystemZ registers
typedef enum sysz_reg {
SYSZ_REG_INVALID = 0,
SYSZ_REG_0,
SYSZ_REG_1,
SYSZ_REG_2,
SYSZ_REG_3,
SYSZ_REG_4,
SYSZ_REG_5,
SYSZ_REG_6,
SYSZ_REG_7,
SYSZ_REG_8,
SYSZ_REG_9,
SYSZ_REG_10,
SYSZ_REG_11,
SYSZ_REG_12,
SYSZ_REG_13,
SYSZ_REG_14,
SYSZ_REG_15,
SYSZ_REG_CC,
SYSZ_REG_F0,
SYSZ_REG_F1,
SYSZ_REG_F2,
SYSZ_REG_F3,
SYSZ_REG_F4,
SYSZ_REG_F5,
SYSZ_REG_F6,
SYSZ_REG_F7,
SYSZ_REG_F8,
SYSZ_REG_F9,
SYSZ_REG_F10,
SYSZ_REG_F11,
SYSZ_REG_F12,
SYSZ_REG_F13,
SYSZ_REG_F14,
SYSZ_REG_F15,
SYSZ_REG_R0L,
SYSZ_REG_ENDING,
} sysz_reg;
/// Instruction's operand referring to memory
/// This is associated with SYSZ_OP_MEM operand type above
typedef struct sysz_op_mem {
uint8_t base; ///< base register, can be safely interpreted as
///< a value of type `sysz_reg`, but it is only
///< one byte wide
uint8_t index; ///< index register, same conditions apply here
uint64_t length; ///< BDLAddr operand
int64_t disp; ///< displacement/offset value
} sysz_op_mem;
/// Instruction operand
typedef struct cs_sysz_op {
sysz_op_type type; ///< operand type
union {
sysz_reg reg; ///< register value for REG operand
int64_t imm; ///< immediate value for IMM operand
sysz_op_mem mem; ///< base/disp value for MEM operand
};
} cs_sysz_op;
// Instruction structure
typedef struct cs_sysz {
sysz_cc cc; ///< Code condition
/// Number of operands of this instruction,
/// or 0 when instruction has no operand.
uint8_t op_count;
cs_sysz_op operands[6]; ///< operands for this instruction.
} cs_sysz;
/// SystemZ instruction
typedef enum sysz_insn {
SYSZ_INS_INVALID = 0,
SYSZ_INS_A,
SYSZ_INS_ADB,
SYSZ_INS_ADBR,
SYSZ_INS_AEB,
SYSZ_INS_AEBR,
SYSZ_INS_AFI,
SYSZ_INS_AG,
SYSZ_INS_AGF,
SYSZ_INS_AGFI,
SYSZ_INS_AGFR,
SYSZ_INS_AGHI,
SYSZ_INS_AGHIK,
SYSZ_INS_AGR,
SYSZ_INS_AGRK,
SYSZ_INS_AGSI,
SYSZ_INS_AH,
SYSZ_INS_AHI,
SYSZ_INS_AHIK,
SYSZ_INS_AHY,
SYSZ_INS_AIH,
SYSZ_INS_AL,
SYSZ_INS_ALC,
SYSZ_INS_ALCG,
SYSZ_INS_ALCGR,
SYSZ_INS_ALCR,
SYSZ_INS_ALFI,
SYSZ_INS_ALG,
SYSZ_INS_ALGF,
SYSZ_INS_ALGFI,
SYSZ_INS_ALGFR,
SYSZ_INS_ALGHSIK,
SYSZ_INS_ALGR,
SYSZ_INS_ALGRK,
SYSZ_INS_ALHSIK,
SYSZ_INS_ALR,
SYSZ_INS_ALRK,
SYSZ_INS_ALY,
SYSZ_INS_AR,
SYSZ_INS_ARK,
SYSZ_INS_ASI,
SYSZ_INS_AXBR,
SYSZ_INS_AY,
SYSZ_INS_BCR,
SYSZ_INS_BRC,
SYSZ_INS_BRCL,
SYSZ_INS_CGIJ,
SYSZ_INS_CGRJ,
SYSZ_INS_CIJ,
SYSZ_INS_CLGIJ,
SYSZ_INS_CLGRJ,
SYSZ_INS_CLIJ,
SYSZ_INS_CLRJ,
SYSZ_INS_CRJ,
SYSZ_INS_BER,
SYSZ_INS_JE,
SYSZ_INS_JGE,
SYSZ_INS_LOCE,
SYSZ_INS_LOCGE,
SYSZ_INS_LOCGRE,
SYSZ_INS_LOCRE,
SYSZ_INS_STOCE,
SYSZ_INS_STOCGE,
SYSZ_INS_BHR,
SYSZ_INS_BHER,
SYSZ_INS_JHE,
SYSZ_INS_JGHE,
SYSZ_INS_LOCHE,
SYSZ_INS_LOCGHE,
SYSZ_INS_LOCGRHE,
SYSZ_INS_LOCRHE,
SYSZ_INS_STOCHE,
SYSZ_INS_STOCGHE,
SYSZ_INS_JH,
SYSZ_INS_JGH,
SYSZ_INS_LOCH,
SYSZ_INS_LOCGH,
SYSZ_INS_LOCGRH,
SYSZ_INS_LOCRH,
SYSZ_INS_STOCH,
SYSZ_INS_STOCGH,
SYSZ_INS_CGIJNLH,
SYSZ_INS_CGRJNLH,
SYSZ_INS_CIJNLH,
SYSZ_INS_CLGIJNLH,
SYSZ_INS_CLGRJNLH,
SYSZ_INS_CLIJNLH,
SYSZ_INS_CLRJNLH,
SYSZ_INS_CRJNLH,
SYSZ_INS_CGIJE,
SYSZ_INS_CGRJE,
SYSZ_INS_CIJE,
SYSZ_INS_CLGIJE,
SYSZ_INS_CLGRJE,
SYSZ_INS_CLIJE,
SYSZ_INS_CLRJE,
SYSZ_INS_CRJE,
SYSZ_INS_CGIJNLE,
SYSZ_INS_CGRJNLE,
SYSZ_INS_CIJNLE,
SYSZ_INS_CLGIJNLE,
SYSZ_INS_CLGRJNLE,
SYSZ_INS_CLIJNLE,
SYSZ_INS_CLRJNLE,
SYSZ_INS_CRJNLE,
SYSZ_INS_CGIJH,
SYSZ_INS_CGRJH,
SYSZ_INS_CIJH,
SYSZ_INS_CLGIJH,
SYSZ_INS_CLGRJH,
SYSZ_INS_CLIJH,
SYSZ_INS_CLRJH,
SYSZ_INS_CRJH,
SYSZ_INS_CGIJNL,
SYSZ_INS_CGRJNL,
SYSZ_INS_CIJNL,
SYSZ_INS_CLGIJNL,
SYSZ_INS_CLGRJNL,
SYSZ_INS_CLIJNL,
SYSZ_INS_CLRJNL,
SYSZ_INS_CRJNL,
SYSZ_INS_CGIJHE,
SYSZ_INS_CGRJHE,
SYSZ_INS_CIJHE,
SYSZ_INS_CLGIJHE,
SYSZ_INS_CLGRJHE,
SYSZ_INS_CLIJHE,
SYSZ_INS_CLRJHE,
SYSZ_INS_CRJHE,
SYSZ_INS_CGIJNHE,
SYSZ_INS_CGRJNHE,
SYSZ_INS_CIJNHE,
SYSZ_INS_CLGIJNHE,
SYSZ_INS_CLGRJNHE,
SYSZ_INS_CLIJNHE,
SYSZ_INS_CLRJNHE,
SYSZ_INS_CRJNHE,
SYSZ_INS_CGIJL,
SYSZ_INS_CGRJL,
SYSZ_INS_CIJL,
SYSZ_INS_CLGIJL,
SYSZ_INS_CLGRJL,
SYSZ_INS_CLIJL,
SYSZ_INS_CLRJL,
SYSZ_INS_CRJL,
SYSZ_INS_CGIJNH,
SYSZ_INS_CGRJNH,
SYSZ_INS_CIJNH,
SYSZ_INS_CLGIJNH,
SYSZ_INS_CLGRJNH,
SYSZ_INS_CLIJNH,
SYSZ_INS_CLRJNH,
SYSZ_INS_CRJNH,
SYSZ_INS_CGIJLE,
SYSZ_INS_CGRJLE,
SYSZ_INS_CIJLE,
SYSZ_INS_CLGIJLE,
SYSZ_INS_CLGRJLE,
SYSZ_INS_CLIJLE,
SYSZ_INS_CLRJLE,
SYSZ_INS_CRJLE,
SYSZ_INS_CGIJNE,
SYSZ_INS_CGRJNE,
SYSZ_INS_CIJNE,
SYSZ_INS_CLGIJNE,
SYSZ_INS_CLGRJNE,
SYSZ_INS_CLIJNE,
SYSZ_INS_CLRJNE,
SYSZ_INS_CRJNE,
SYSZ_INS_CGIJLH,
SYSZ_INS_CGRJLH,
SYSZ_INS_CIJLH,
SYSZ_INS_CLGIJLH,
SYSZ_INS_CLGRJLH,
SYSZ_INS_CLIJLH,
SYSZ_INS_CLRJLH,
SYSZ_INS_CRJLH,
SYSZ_INS_BLR,
SYSZ_INS_BLER,
SYSZ_INS_JLE,
SYSZ_INS_JGLE,
SYSZ_INS_LOCLE,
SYSZ_INS_LOCGLE,
SYSZ_INS_LOCGRLE,
SYSZ_INS_LOCRLE,
SYSZ_INS_STOCLE,
SYSZ_INS_STOCGLE,
SYSZ_INS_BLHR,
SYSZ_INS_JLH,
SYSZ_INS_JGLH,
SYSZ_INS_LOCLH,
SYSZ_INS_LOCGLH,
SYSZ_INS_LOCGRLH,
SYSZ_INS_LOCRLH,
SYSZ_INS_STOCLH,
SYSZ_INS_STOCGLH,
SYSZ_INS_JL,
SYSZ_INS_JGL,
SYSZ_INS_LOCL,
SYSZ_INS_LOCGL,
SYSZ_INS_LOCGRL,
SYSZ_INS_LOCRL,
SYSZ_INS_LOC,
SYSZ_INS_LOCG,
SYSZ_INS_LOCGR,
SYSZ_INS_LOCR,
SYSZ_INS_STOCL,
SYSZ_INS_STOCGL,
SYSZ_INS_BNER,
SYSZ_INS_JNE,
SYSZ_INS_JGNE,
SYSZ_INS_LOCNE,
SYSZ_INS_LOCGNE,
SYSZ_INS_LOCGRNE,
SYSZ_INS_LOCRNE,
SYSZ_INS_STOCNE,
SYSZ_INS_STOCGNE,
SYSZ_INS_BNHR,
SYSZ_INS_BNHER,
SYSZ_INS_JNHE,
SYSZ_INS_JGNHE,
SYSZ_INS_LOCNHE,
SYSZ_INS_LOCGNHE,
SYSZ_INS_LOCGRNHE,
SYSZ_INS_LOCRNHE,
SYSZ_INS_STOCNHE,
SYSZ_INS_STOCGNHE,
SYSZ_INS_JNH,
SYSZ_INS_JGNH,
SYSZ_INS_LOCNH,
SYSZ_INS_LOCGNH,
SYSZ_INS_LOCGRNH,
SYSZ_INS_LOCRNH,
SYSZ_INS_STOCNH,
SYSZ_INS_STOCGNH,
SYSZ_INS_BNLR,
SYSZ_INS_BNLER,
SYSZ_INS_JNLE,
SYSZ_INS_JGNLE,
SYSZ_INS_LOCNLE,
SYSZ_INS_LOCGNLE,
SYSZ_INS_LOCGRNLE,
SYSZ_INS_LOCRNLE,
SYSZ_INS_STOCNLE,
SYSZ_INS_STOCGNLE,
SYSZ_INS_BNLHR,
SYSZ_INS_JNLH,
SYSZ_INS_JGNLH,
SYSZ_INS_LOCNLH,
SYSZ_INS_LOCGNLH,
SYSZ_INS_LOCGRNLH,
SYSZ_INS_LOCRNLH,
SYSZ_INS_STOCNLH,
SYSZ_INS_STOCGNLH,
SYSZ_INS_JNL,
SYSZ_INS_JGNL,
SYSZ_INS_LOCNL,
SYSZ_INS_LOCGNL,
SYSZ_INS_LOCGRNL,
SYSZ_INS_LOCRNL,
SYSZ_INS_STOCNL,
SYSZ_INS_STOCGNL,
SYSZ_INS_BNOR,
SYSZ_INS_JNO,
SYSZ_INS_JGNO,
SYSZ_INS_LOCNO,
SYSZ_INS_LOCGNO,
SYSZ_INS_LOCGRNO,
SYSZ_INS_LOCRNO,
SYSZ_INS_STOCNO,
SYSZ_INS_STOCGNO,
SYSZ_INS_BOR,
SYSZ_INS_JO,
SYSZ_INS_JGO,
SYSZ_INS_LOCO,
SYSZ_INS_LOCGO,
SYSZ_INS_LOCGRO,
SYSZ_INS_LOCRO,
SYSZ_INS_STOCO,
SYSZ_INS_STOCGO,
SYSZ_INS_STOC,
SYSZ_INS_STOCG,
SYSZ_INS_BASR,
SYSZ_INS_BR,
SYSZ_INS_BRAS,
SYSZ_INS_BRASL,
SYSZ_INS_J,
SYSZ_INS_JG,
SYSZ_INS_BRCT,
SYSZ_INS_BRCTG,
SYSZ_INS_C,
SYSZ_INS_CDB,
SYSZ_INS_CDBR,
SYSZ_INS_CDFBR,
SYSZ_INS_CDGBR,
SYSZ_INS_CDLFBR,
SYSZ_INS_CDLGBR,
SYSZ_INS_CEB,
SYSZ_INS_CEBR,
SYSZ_INS_CEFBR,
SYSZ_INS_CEGBR,
SYSZ_INS_CELFBR,
SYSZ_INS_CELGBR,
SYSZ_INS_CFDBR,
SYSZ_INS_CFEBR,
SYSZ_INS_CFI,
SYSZ_INS_CFXBR,
SYSZ_INS_CG,
SYSZ_INS_CGDBR,
SYSZ_INS_CGEBR,
SYSZ_INS_CGF,
SYSZ_INS_CGFI,
SYSZ_INS_CGFR,
SYSZ_INS_CGFRL,
SYSZ_INS_CGH,
SYSZ_INS_CGHI,
SYSZ_INS_CGHRL,
SYSZ_INS_CGHSI,
SYSZ_INS_CGR,
SYSZ_INS_CGRL,
SYSZ_INS_CGXBR,
SYSZ_INS_CH,
SYSZ_INS_CHF,
SYSZ_INS_CHHSI,
SYSZ_INS_CHI,
SYSZ_INS_CHRL,
SYSZ_INS_CHSI,
SYSZ_INS_CHY,
SYSZ_INS_CIH,
SYSZ_INS_CL,
SYSZ_INS_CLC,
SYSZ_INS_CLFDBR,
SYSZ_INS_CLFEBR,
SYSZ_INS_CLFHSI,
SYSZ_INS_CLFI,
SYSZ_INS_CLFXBR,
SYSZ_INS_CLG,
SYSZ_INS_CLGDBR,
SYSZ_INS_CLGEBR,
SYSZ_INS_CLGF,
SYSZ_INS_CLGFI,
SYSZ_INS_CLGFR,
SYSZ_INS_CLGFRL,
SYSZ_INS_CLGHRL,
SYSZ_INS_CLGHSI,
SYSZ_INS_CLGR,
SYSZ_INS_CLGRL,
SYSZ_INS_CLGXBR,
SYSZ_INS_CLHF,
SYSZ_INS_CLHHSI,
SYSZ_INS_CLHRL,
SYSZ_INS_CLI,
SYSZ_INS_CLIH,
SYSZ_INS_CLIY,
SYSZ_INS_CLR,
SYSZ_INS_CLRL,
SYSZ_INS_CLST,
SYSZ_INS_CLY,
SYSZ_INS_CPSDR,
SYSZ_INS_CR,
SYSZ_INS_CRL,
SYSZ_INS_CS,
SYSZ_INS_CSG,
SYSZ_INS_CSY,
SYSZ_INS_CXBR,
SYSZ_INS_CXFBR,
SYSZ_INS_CXGBR,
SYSZ_INS_CXLFBR,
SYSZ_INS_CXLGBR,
SYSZ_INS_CY,
SYSZ_INS_DDB,
SYSZ_INS_DDBR,
SYSZ_INS_DEB,
SYSZ_INS_DEBR,
SYSZ_INS_DL,
SYSZ_INS_DLG,
SYSZ_INS_DLGR,
SYSZ_INS_DLR,
SYSZ_INS_DSG,
SYSZ_INS_DSGF,
SYSZ_INS_DSGFR,
SYSZ_INS_DSGR,
SYSZ_INS_DXBR,
SYSZ_INS_EAR,
SYSZ_INS_FIDBR,
SYSZ_INS_FIDBRA,
SYSZ_INS_FIEBR,
SYSZ_INS_FIEBRA,
SYSZ_INS_FIXBR,
SYSZ_INS_FIXBRA,
SYSZ_INS_FLOGR,
SYSZ_INS_IC,
SYSZ_INS_ICY,
SYSZ_INS_IIHF,
SYSZ_INS_IIHH,
SYSZ_INS_IIHL,
SYSZ_INS_IILF,
SYSZ_INS_IILH,
SYSZ_INS_IILL,
SYSZ_INS_IPM,
SYSZ_INS_L,
SYSZ_INS_LA,
SYSZ_INS_LAA,
SYSZ_INS_LAAG,
SYSZ_INS_LAAL,
SYSZ_INS_LAALG,
SYSZ_INS_LAN,
SYSZ_INS_LANG,
SYSZ_INS_LAO,
SYSZ_INS_LAOG,
SYSZ_INS_LARL,
SYSZ_INS_LAX,
SYSZ_INS_LAXG,
SYSZ_INS_LAY,
SYSZ_INS_LB,
SYSZ_INS_LBH,
SYSZ_INS_LBR,
SYSZ_INS_LCDBR,
SYSZ_INS_LCEBR,
SYSZ_INS_LCGFR,
SYSZ_INS_LCGR,
SYSZ_INS_LCR,
SYSZ_INS_LCXBR,
SYSZ_INS_LD,
SYSZ_INS_LDEB,
SYSZ_INS_LDEBR,
SYSZ_INS_LDGR,
SYSZ_INS_LDR,
SYSZ_INS_LDXBR,
SYSZ_INS_LDXBRA,
SYSZ_INS_LDY,
SYSZ_INS_LE,
SYSZ_INS_LEDBR,
SYSZ_INS_LEDBRA,
SYSZ_INS_LER,
SYSZ_INS_LEXBR,
SYSZ_INS_LEXBRA,
SYSZ_INS_LEY,
SYSZ_INS_LFH,
SYSZ_INS_LG,
SYSZ_INS_LGB,
SYSZ_INS_LGBR,
SYSZ_INS_LGDR,
SYSZ_INS_LGF,
SYSZ_INS_LGFI,
SYSZ_INS_LGFR,
SYSZ_INS_LGFRL,
SYSZ_INS_LGH,
SYSZ_INS_LGHI,
SYSZ_INS_LGHR,
SYSZ_INS_LGHRL,
SYSZ_INS_LGR,
SYSZ_INS_LGRL,
SYSZ_INS_LH,
SYSZ_INS_LHH,
SYSZ_INS_LHI,
SYSZ_INS_LHR,
SYSZ_INS_LHRL,
SYSZ_INS_LHY,
SYSZ_INS_LLC,
SYSZ_INS_LLCH,
SYSZ_INS_LLCR,
SYSZ_INS_LLGC,
SYSZ_INS_LLGCR,
SYSZ_INS_LLGF,
SYSZ_INS_LLGFR,
SYSZ_INS_LLGFRL,
SYSZ_INS_LLGH,
SYSZ_INS_LLGHR,
SYSZ_INS_LLGHRL,
SYSZ_INS_LLH,
SYSZ_INS_LLHH,
SYSZ_INS_LLHR,
SYSZ_INS_LLHRL,
SYSZ_INS_LLIHF,
SYSZ_INS_LLIHH,
SYSZ_INS_LLIHL,
SYSZ_INS_LLILF,
SYSZ_INS_LLILH,
SYSZ_INS_LLILL,
SYSZ_INS_LMG,
SYSZ_INS_LNDBR,
SYSZ_INS_LNEBR,
SYSZ_INS_LNGFR,
SYSZ_INS_LNGR,
SYSZ_INS_LNR,
SYSZ_INS_LNXBR,
SYSZ_INS_LPDBR,
SYSZ_INS_LPEBR,
SYSZ_INS_LPGFR,
SYSZ_INS_LPGR,
SYSZ_INS_LPR,
SYSZ_INS_LPXBR,
SYSZ_INS_LR,
SYSZ_INS_LRL,
SYSZ_INS_LRV,
SYSZ_INS_LRVG,
SYSZ_INS_LRVGR,
SYSZ_INS_LRVR,
SYSZ_INS_LT,
SYSZ_INS_LTDBR,
SYSZ_INS_LTEBR,
SYSZ_INS_LTG,
SYSZ_INS_LTGF,
SYSZ_INS_LTGFR,
SYSZ_INS_LTGR,
SYSZ_INS_LTR,
SYSZ_INS_LTXBR,
SYSZ_INS_LXDB,
SYSZ_INS_LXDBR,
SYSZ_INS_LXEB,
SYSZ_INS_LXEBR,
SYSZ_INS_LXR,
SYSZ_INS_LY,
SYSZ_INS_LZDR,
SYSZ_INS_LZER,
SYSZ_INS_LZXR,
SYSZ_INS_MADB,
SYSZ_INS_MADBR,
SYSZ_INS_MAEB,
SYSZ_INS_MAEBR,
SYSZ_INS_MDB,
SYSZ_INS_MDBR,
SYSZ_INS_MDEB,
SYSZ_INS_MDEBR,
SYSZ_INS_MEEB,
SYSZ_INS_MEEBR,
SYSZ_INS_MGHI,
SYSZ_INS_MH,
SYSZ_INS_MHI,
SYSZ_INS_MHY,
SYSZ_INS_MLG,
SYSZ_INS_MLGR,
SYSZ_INS_MS,
SYSZ_INS_MSDB,
SYSZ_INS_MSDBR,
SYSZ_INS_MSEB,
SYSZ_INS_MSEBR,
SYSZ_INS_MSFI,
SYSZ_INS_MSG,
SYSZ_INS_MSGF,
SYSZ_INS_MSGFI,
SYSZ_INS_MSGFR,
SYSZ_INS_MSGR,
SYSZ_INS_MSR,
SYSZ_INS_MSY,
SYSZ_INS_MVC,
SYSZ_INS_MVGHI,
SYSZ_INS_MVHHI,
SYSZ_INS_MVHI,
SYSZ_INS_MVI,
SYSZ_INS_MVIY,
SYSZ_INS_MVST,
SYSZ_INS_MXBR,
SYSZ_INS_MXDB,
SYSZ_INS_MXDBR,
SYSZ_INS_N,
SYSZ_INS_NC,
SYSZ_INS_NG,
SYSZ_INS_NGR,
SYSZ_INS_NGRK,
SYSZ_INS_NI,
SYSZ_INS_NIHF,
SYSZ_INS_NIHH,
SYSZ_INS_NIHL,
SYSZ_INS_NILF,
SYSZ_INS_NILH,
SYSZ_INS_NILL,
SYSZ_INS_NIY,
SYSZ_INS_NR,
SYSZ_INS_NRK,
SYSZ_INS_NY,
SYSZ_INS_O,
SYSZ_INS_OC,
SYSZ_INS_OG,
SYSZ_INS_OGR,
SYSZ_INS_OGRK,
SYSZ_INS_OI,
SYSZ_INS_OIHF,
SYSZ_INS_OIHH,
SYSZ_INS_OIHL,
SYSZ_INS_OILF,
SYSZ_INS_OILH,
SYSZ_INS_OILL,
SYSZ_INS_OIY,
SYSZ_INS_OR,
SYSZ_INS_ORK,
SYSZ_INS_OY,
SYSZ_INS_PFD,
SYSZ_INS_PFDRL,
SYSZ_INS_RISBG,
SYSZ_INS_RISBHG,
SYSZ_INS_RISBLG,
SYSZ_INS_RLL,
SYSZ_INS_RLLG,
SYSZ_INS_RNSBG,
SYSZ_INS_ROSBG,
SYSZ_INS_RXSBG,
SYSZ_INS_S,
SYSZ_INS_SDB,
SYSZ_INS_SDBR,
SYSZ_INS_SEB,
SYSZ_INS_SEBR,
SYSZ_INS_SG,
SYSZ_INS_SGF,
SYSZ_INS_SGFR,
SYSZ_INS_SGR,
SYSZ_INS_SGRK,
SYSZ_INS_SH,
SYSZ_INS_SHY,
SYSZ_INS_SL,
SYSZ_INS_SLB,
SYSZ_INS_SLBG,
SYSZ_INS_SLBR,
SYSZ_INS_SLFI,
SYSZ_INS_SLG,
SYSZ_INS_SLBGR,
SYSZ_INS_SLGF,
SYSZ_INS_SLGFI,
SYSZ_INS_SLGFR,
SYSZ_INS_SLGR,
SYSZ_INS_SLGRK,
SYSZ_INS_SLL,
SYSZ_INS_SLLG,
SYSZ_INS_SLLK,
SYSZ_INS_SLR,
SYSZ_INS_SLRK,
SYSZ_INS_SLY,
SYSZ_INS_SQDB,
SYSZ_INS_SQDBR,
SYSZ_INS_SQEB,
SYSZ_INS_SQEBR,
SYSZ_INS_SQXBR,
SYSZ_INS_SR,
SYSZ_INS_SRA,
SYSZ_INS_SRAG,
SYSZ_INS_SRAK,
SYSZ_INS_SRK,
SYSZ_INS_SRL,
SYSZ_INS_SRLG,
SYSZ_INS_SRLK,
SYSZ_INS_SRST,
SYSZ_INS_ST,
SYSZ_INS_STC,
SYSZ_INS_STCH,
SYSZ_INS_STCY,
SYSZ_INS_STD,
SYSZ_INS_STDY,
SYSZ_INS_STE,
SYSZ_INS_STEY,
SYSZ_INS_STFH,
SYSZ_INS_STG,
SYSZ_INS_STGRL,
SYSZ_INS_STH,
SYSZ_INS_STHH,
SYSZ_INS_STHRL,
SYSZ_INS_STHY,
SYSZ_INS_STMG,
SYSZ_INS_STRL,
SYSZ_INS_STRV,
SYSZ_INS_STRVG,
SYSZ_INS_STY,
SYSZ_INS_SXBR,
SYSZ_INS_SY,
SYSZ_INS_TM,
SYSZ_INS_TMHH,
SYSZ_INS_TMHL,
SYSZ_INS_TMLH,
SYSZ_INS_TMLL,
SYSZ_INS_TMY,
SYSZ_INS_X,
SYSZ_INS_XC,
SYSZ_INS_XG,
SYSZ_INS_XGR,
SYSZ_INS_XGRK,
SYSZ_INS_XI,
SYSZ_INS_XIHF,
SYSZ_INS_XILF,
SYSZ_INS_XIY,
SYSZ_INS_XR,
SYSZ_INS_XRK,
SYSZ_INS_XY,
SYSZ_INS_ENDING, // <-- mark the end of the list of instructions
} sysz_insn;
/// Group of SystemZ instructions
typedef enum sysz_insn_group {
SYSZ_GRP_INVALID = 0, ///< = CS_GRP_INVALID
// Generic groups
// all jump instructions (conditional+direct+indirect jumps)
SYSZ_GRP_JUMP, ///< = CS_GRP_JUMP
// Architecture-specific groups
SYSZ_GRP_DISTINCTOPS = 128,
SYSZ_GRP_FPEXTENSION,
SYSZ_GRP_HIGHWORD,
SYSZ_GRP_INTERLOCKEDACCESS1,
SYSZ_GRP_LOADSTOREONCOND,
SYSZ_GRP_ENDING, // <-- mark the end of the list of groups
} sysz_insn_group;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,359 @@
/* Capstone Disassembly Engine */
/* TMS320C64x Backend by Fotis Loukos <me@fotisl.com> 2016 */
#ifndef CAPSTONE_TMS320C64X_H
#define CAPSTONE_TMS320C64X_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
typedef enum tms320c64x_op_type {
TMS320C64X_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
TMS320C64X_OP_REG, ///< = CS_OP_REG (Register operand).
TMS320C64X_OP_IMM, ///< = CS_OP_IMM (Immediate operand).
TMS320C64X_OP_MEM, ///< = CS_OP_MEM (Memory operand).
TMS320C64X_OP_REGPAIR = 64, ///< Register pair for double word ops
} tms320c64x_op_type;
typedef enum tms320c64x_mem_disp {
TMS320C64X_MEM_DISP_INVALID = 0,
TMS320C64X_MEM_DISP_CONSTANT,
TMS320C64X_MEM_DISP_REGISTER,
} tms320c64x_mem_disp;
typedef enum tms320c64x_mem_dir {
TMS320C64X_MEM_DIR_INVALID = 0,
TMS320C64X_MEM_DIR_FW,
TMS320C64X_MEM_DIR_BW,
} tms320c64x_mem_dir;
typedef enum tms320c64x_mem_mod {
TMS320C64X_MEM_MOD_INVALID = 0,
TMS320C64X_MEM_MOD_NO,
TMS320C64X_MEM_MOD_PRE,
TMS320C64X_MEM_MOD_POST,
} tms320c64x_mem_mod;
typedef struct tms320c64x_op_mem {
unsigned int base; ///< base register
unsigned int disp; ///< displacement/offset value
unsigned int unit; ///< unit of base and offset register
unsigned int scaled; ///< offset scaled
unsigned int disptype; ///< displacement type
unsigned int direction; ///< direction
unsigned int modify; ///< modification
} tms320c64x_op_mem;
typedef struct cs_tms320c64x_op {
tms320c64x_op_type type; ///< operand type
union {
unsigned int reg; ///< register value for REG operand or first register for REGPAIR operand
int32_t imm; ///< immediate value for IMM operand
tms320c64x_op_mem mem; ///< base/disp value for MEM operand
};
} cs_tms320c64x_op;
typedef struct cs_tms320c64x {
uint8_t op_count;
cs_tms320c64x_op operands[8]; ///< operands for this instruction.
struct {
unsigned int reg;
unsigned int zero;
} condition;
struct {
unsigned int unit;
unsigned int side;
unsigned int crosspath;
} funit;
unsigned int parallel;
} cs_tms320c64x;
typedef enum tms320c64x_reg {
TMS320C64X_REG_INVALID = 0,
TMS320C64X_REG_AMR,
TMS320C64X_REG_CSR,
TMS320C64X_REG_DIER,
TMS320C64X_REG_DNUM,
TMS320C64X_REG_ECR,
TMS320C64X_REG_GFPGFR,
TMS320C64X_REG_GPLYA,
TMS320C64X_REG_GPLYB,
TMS320C64X_REG_ICR,
TMS320C64X_REG_IER,
TMS320C64X_REG_IERR,
TMS320C64X_REG_ILC,
TMS320C64X_REG_IRP,
TMS320C64X_REG_ISR,
TMS320C64X_REG_ISTP,
TMS320C64X_REG_ITSR,
TMS320C64X_REG_NRP,
TMS320C64X_REG_NTSR,
TMS320C64X_REG_REP,
TMS320C64X_REG_RILC,
TMS320C64X_REG_SSR,
TMS320C64X_REG_TSCH,
TMS320C64X_REG_TSCL,
TMS320C64X_REG_TSR,
TMS320C64X_REG_A0,
TMS320C64X_REG_A1,
TMS320C64X_REG_A2,
TMS320C64X_REG_A3,
TMS320C64X_REG_A4,
TMS320C64X_REG_A5,
TMS320C64X_REG_A6,
TMS320C64X_REG_A7,
TMS320C64X_REG_A8,
TMS320C64X_REG_A9,
TMS320C64X_REG_A10,
TMS320C64X_REG_A11,
TMS320C64X_REG_A12,
TMS320C64X_REG_A13,
TMS320C64X_REG_A14,
TMS320C64X_REG_A15,
TMS320C64X_REG_A16,
TMS320C64X_REG_A17,
TMS320C64X_REG_A18,
TMS320C64X_REG_A19,
TMS320C64X_REG_A20,
TMS320C64X_REG_A21,
TMS320C64X_REG_A22,
TMS320C64X_REG_A23,
TMS320C64X_REG_A24,
TMS320C64X_REG_A25,
TMS320C64X_REG_A26,
TMS320C64X_REG_A27,
TMS320C64X_REG_A28,
TMS320C64X_REG_A29,
TMS320C64X_REG_A30,
TMS320C64X_REG_A31,
TMS320C64X_REG_B0,
TMS320C64X_REG_B1,
TMS320C64X_REG_B2,
TMS320C64X_REG_B3,
TMS320C64X_REG_B4,
TMS320C64X_REG_B5,
TMS320C64X_REG_B6,
TMS320C64X_REG_B7,
TMS320C64X_REG_B8,
TMS320C64X_REG_B9,
TMS320C64X_REG_B10,
TMS320C64X_REG_B11,
TMS320C64X_REG_B12,
TMS320C64X_REG_B13,
TMS320C64X_REG_B14,
TMS320C64X_REG_B15,
TMS320C64X_REG_B16,
TMS320C64X_REG_B17,
TMS320C64X_REG_B18,
TMS320C64X_REG_B19,
TMS320C64X_REG_B20,
TMS320C64X_REG_B21,
TMS320C64X_REG_B22,
TMS320C64X_REG_B23,
TMS320C64X_REG_B24,
TMS320C64X_REG_B25,
TMS320C64X_REG_B26,
TMS320C64X_REG_B27,
TMS320C64X_REG_B28,
TMS320C64X_REG_B29,
TMS320C64X_REG_B30,
TMS320C64X_REG_B31,
TMS320C64X_REG_PCE1,
TMS320C64X_REG_ENDING, // <-- mark the end of the list of registers
// Alias registers
TMS320C64X_REG_EFR = TMS320C64X_REG_ECR,
TMS320C64X_REG_IFR = TMS320C64X_REG_ISR,
} tms320c64x_reg;
typedef enum tms320c64x_insn {
TMS320C64X_INS_INVALID = 0,
TMS320C64X_INS_ABS,
TMS320C64X_INS_ABS2,
TMS320C64X_INS_ADD,
TMS320C64X_INS_ADD2,
TMS320C64X_INS_ADD4,
TMS320C64X_INS_ADDAB,
TMS320C64X_INS_ADDAD,
TMS320C64X_INS_ADDAH,
TMS320C64X_INS_ADDAW,
TMS320C64X_INS_ADDK,
TMS320C64X_INS_ADDKPC,
TMS320C64X_INS_ADDU,
TMS320C64X_INS_AND,
TMS320C64X_INS_ANDN,
TMS320C64X_INS_AVG2,
TMS320C64X_INS_AVGU4,
TMS320C64X_INS_B,
TMS320C64X_INS_BDEC,
TMS320C64X_INS_BITC4,
TMS320C64X_INS_BNOP,
TMS320C64X_INS_BPOS,
TMS320C64X_INS_CLR,
TMS320C64X_INS_CMPEQ,
TMS320C64X_INS_CMPEQ2,
TMS320C64X_INS_CMPEQ4,
TMS320C64X_INS_CMPGT,
TMS320C64X_INS_CMPGT2,
TMS320C64X_INS_CMPGTU4,
TMS320C64X_INS_CMPLT,
TMS320C64X_INS_CMPLTU,
TMS320C64X_INS_DEAL,
TMS320C64X_INS_DOTP2,
TMS320C64X_INS_DOTPN2,
TMS320C64X_INS_DOTPNRSU2,
TMS320C64X_INS_DOTPRSU2,
TMS320C64X_INS_DOTPSU4,
TMS320C64X_INS_DOTPU4,
TMS320C64X_INS_EXT,
TMS320C64X_INS_EXTU,
TMS320C64X_INS_GMPGTU,
TMS320C64X_INS_GMPY4,
TMS320C64X_INS_LDB,
TMS320C64X_INS_LDBU,
TMS320C64X_INS_LDDW,
TMS320C64X_INS_LDH,
TMS320C64X_INS_LDHU,
TMS320C64X_INS_LDNDW,
TMS320C64X_INS_LDNW,
TMS320C64X_INS_LDW,
TMS320C64X_INS_LMBD,
TMS320C64X_INS_MAX2,
TMS320C64X_INS_MAXU4,
TMS320C64X_INS_MIN2,
TMS320C64X_INS_MINU4,
TMS320C64X_INS_MPY,
TMS320C64X_INS_MPY2,
TMS320C64X_INS_MPYH,
TMS320C64X_INS_MPYHI,
TMS320C64X_INS_MPYHIR,
TMS320C64X_INS_MPYHL,
TMS320C64X_INS_MPYHLU,
TMS320C64X_INS_MPYHSLU,
TMS320C64X_INS_MPYHSU,
TMS320C64X_INS_MPYHU,
TMS320C64X_INS_MPYHULS,
TMS320C64X_INS_MPYHUS,
TMS320C64X_INS_MPYLH,
TMS320C64X_INS_MPYLHU,
TMS320C64X_INS_MPYLI,
TMS320C64X_INS_MPYLIR,
TMS320C64X_INS_MPYLSHU,
TMS320C64X_INS_MPYLUHS,
TMS320C64X_INS_MPYSU,
TMS320C64X_INS_MPYSU4,
TMS320C64X_INS_MPYU,
TMS320C64X_INS_MPYU4,
TMS320C64X_INS_MPYUS,
TMS320C64X_INS_MVC,
TMS320C64X_INS_MVD,
TMS320C64X_INS_MVK,
TMS320C64X_INS_MVKL,
TMS320C64X_INS_MVKLH,
TMS320C64X_INS_NOP,
TMS320C64X_INS_NORM,
TMS320C64X_INS_OR,
TMS320C64X_INS_PACK2,
TMS320C64X_INS_PACKH2,
TMS320C64X_INS_PACKH4,
TMS320C64X_INS_PACKHL2,
TMS320C64X_INS_PACKL4,
TMS320C64X_INS_PACKLH2,
TMS320C64X_INS_ROTL,
TMS320C64X_INS_SADD,
TMS320C64X_INS_SADD2,
TMS320C64X_INS_SADDU4,
TMS320C64X_INS_SADDUS2,
TMS320C64X_INS_SAT,
TMS320C64X_INS_SET,
TMS320C64X_INS_SHFL,
TMS320C64X_INS_SHL,
TMS320C64X_INS_SHLMB,
TMS320C64X_INS_SHR,
TMS320C64X_INS_SHR2,
TMS320C64X_INS_SHRMB,
TMS320C64X_INS_SHRU,
TMS320C64X_INS_SHRU2,
TMS320C64X_INS_SMPY,
TMS320C64X_INS_SMPY2,
TMS320C64X_INS_SMPYH,
TMS320C64X_INS_SMPYHL,
TMS320C64X_INS_SMPYLH,
TMS320C64X_INS_SPACK2,
TMS320C64X_INS_SPACKU4,
TMS320C64X_INS_SSHL,
TMS320C64X_INS_SSHVL,
TMS320C64X_INS_SSHVR,
TMS320C64X_INS_SSUB,
TMS320C64X_INS_STB,
TMS320C64X_INS_STDW,
TMS320C64X_INS_STH,
TMS320C64X_INS_STNDW,
TMS320C64X_INS_STNW,
TMS320C64X_INS_STW,
TMS320C64X_INS_SUB,
TMS320C64X_INS_SUB2,
TMS320C64X_INS_SUB4,
TMS320C64X_INS_SUBAB,
TMS320C64X_INS_SUBABS4,
TMS320C64X_INS_SUBAH,
TMS320C64X_INS_SUBAW,
TMS320C64X_INS_SUBC,
TMS320C64X_INS_SUBU,
TMS320C64X_INS_SWAP4,
TMS320C64X_INS_UNPKHU4,
TMS320C64X_INS_UNPKLU4,
TMS320C64X_INS_XOR,
TMS320C64X_INS_XPND2,
TMS320C64X_INS_XPND4,
// Aliases
TMS320C64X_INS_IDLE,
TMS320C64X_INS_MV,
TMS320C64X_INS_NEG,
TMS320C64X_INS_NOT,
TMS320C64X_INS_SWAP2,
TMS320C64X_INS_ZERO,
TMS320C64X_INS_ENDING, // <-- mark the end of the list of instructions
} tms320c64x_insn;
typedef enum tms320c64x_insn_group {
TMS320C64X_GRP_INVALID = 0, ///< = CS_GRP_INVALID
TMS320C64X_GRP_JUMP, ///< = CS_GRP_JUMP
TMS320C64X_GRP_FUNIT_D = 128,
TMS320C64X_GRP_FUNIT_L,
TMS320C64X_GRP_FUNIT_M,
TMS320C64X_GRP_FUNIT_S,
TMS320C64X_GRP_FUNIT_NO,
TMS320C64X_GRP_ENDING, // <-- mark the end of the list of groups
} tms320c64x_insn_group;
typedef enum tms320c64x_funit {
TMS320C64X_FUNIT_INVALID = 0,
TMS320C64X_FUNIT_D,
TMS320C64X_FUNIT_L,
TMS320C64X_FUNIT_M,
TMS320C64X_FUNIT_S,
TMS320C64X_FUNIT_NO
} tms320c64x_funit;
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
#ifndef CAPSTONE_XCORE_H
#define CAPSTONE_XCORE_H
/* Capstone Disassembly Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2015 */
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
/// Operand type for instruction's operands
typedef enum xcore_op_type {
XCORE_OP_INVALID = 0, ///< = CS_OP_INVALID (Uninitialized).
XCORE_OP_REG, ///< = CS_OP_REG (Register operand).
XCORE_OP_IMM, ///< = CS_OP_IMM (Immediate operand).
XCORE_OP_MEM, ///< = CS_OP_MEM (Memory operand).
} xcore_op_type;
/// XCore registers
typedef enum xcore_reg {
XCORE_REG_INVALID = 0,
XCORE_REG_CP,
XCORE_REG_DP,
XCORE_REG_LR,
XCORE_REG_SP,
XCORE_REG_R0,
XCORE_REG_R1,
XCORE_REG_R2,
XCORE_REG_R3,
XCORE_REG_R4,
XCORE_REG_R5,
XCORE_REG_R6,
XCORE_REG_R7,
XCORE_REG_R8,
XCORE_REG_R9,
XCORE_REG_R10,
XCORE_REG_R11,
// pseudo registers
XCORE_REG_PC, ///< pc
// internal thread registers
// see The-XMOS-XS1-Architecture(X7879A).pdf
XCORE_REG_SCP, ///< save pc
XCORE_REG_SSR, //< save status
XCORE_REG_ET, //< exception type
XCORE_REG_ED, //< exception data
XCORE_REG_SED, //< save exception data
XCORE_REG_KEP, //< kernel entry pointer
XCORE_REG_KSP, //< kernel stack pointer
XCORE_REG_ID, //< thread ID
XCORE_REG_ENDING, // <-- mark the end of the list of registers
} xcore_reg;
/// Instruction's operand referring to memory
/// This is associated with XCORE_OP_MEM operand type above
typedef struct xcore_op_mem {
uint8_t base; ///< base register, can be safely interpreted as
///< a value of type `xcore_reg`, but it is only
///< one byte wide
uint8_t index; ///< index register, same conditions apply here
int32_t disp; ///< displacement/offset value
int direct; ///< +1: forward, -1: backward
} xcore_op_mem;
/// Instruction operand
typedef struct cs_xcore_op {
xcore_op_type type; ///< operand type
union {
xcore_reg reg; ///< register value for REG operand
int32_t imm; ///< immediate value for IMM operand
xcore_op_mem mem; ///< base/disp value for MEM operand
};
} cs_xcore_op;
/// Instruction structure
typedef struct cs_xcore {
/// Number of operands of this instruction,
/// or 0 when instruction has no operand.
uint8_t op_count;
cs_xcore_op operands[8]; ///< operands for this instruction.
} cs_xcore;
/// XCore instruction
typedef enum xcore_insn {
XCORE_INS_INVALID = 0,
XCORE_INS_ADD,
XCORE_INS_ANDNOT,
XCORE_INS_AND,
XCORE_INS_ASHR,
XCORE_INS_BAU,
XCORE_INS_BITREV,
XCORE_INS_BLA,
XCORE_INS_BLAT,
XCORE_INS_BL,
XCORE_INS_BF,
XCORE_INS_BT,
XCORE_INS_BU,
XCORE_INS_BRU,
XCORE_INS_BYTEREV,
XCORE_INS_CHKCT,
XCORE_INS_CLRE,
XCORE_INS_CLRPT,
XCORE_INS_CLRSR,
XCORE_INS_CLZ,
XCORE_INS_CRC8,
XCORE_INS_CRC32,
XCORE_INS_DCALL,
XCORE_INS_DENTSP,
XCORE_INS_DGETREG,
XCORE_INS_DIVS,
XCORE_INS_DIVU,
XCORE_INS_DRESTSP,
XCORE_INS_DRET,
XCORE_INS_ECALLF,
XCORE_INS_ECALLT,
XCORE_INS_EDU,
XCORE_INS_EEF,
XCORE_INS_EET,
XCORE_INS_EEU,
XCORE_INS_ENDIN,
XCORE_INS_ENTSP,
XCORE_INS_EQ,
XCORE_INS_EXTDP,
XCORE_INS_EXTSP,
XCORE_INS_FREER,
XCORE_INS_FREET,
XCORE_INS_GETD,
XCORE_INS_GET,
XCORE_INS_GETN,
XCORE_INS_GETR,
XCORE_INS_GETSR,
XCORE_INS_GETST,
XCORE_INS_GETTS,
XCORE_INS_INCT,
XCORE_INS_INIT,
XCORE_INS_INPW,
XCORE_INS_INSHR,
XCORE_INS_INT,
XCORE_INS_IN,
XCORE_INS_KCALL,
XCORE_INS_KENTSP,
XCORE_INS_KRESTSP,
XCORE_INS_KRET,
XCORE_INS_LADD,
XCORE_INS_LD16S,
XCORE_INS_LD8U,
XCORE_INS_LDA16,
XCORE_INS_LDAP,
XCORE_INS_LDAW,
XCORE_INS_LDC,
XCORE_INS_LDW,
XCORE_INS_LDIVU,
XCORE_INS_LMUL,
XCORE_INS_LSS,
XCORE_INS_LSUB,
XCORE_INS_LSU,
XCORE_INS_MACCS,
XCORE_INS_MACCU,
XCORE_INS_MJOIN,
XCORE_INS_MKMSK,
XCORE_INS_MSYNC,
XCORE_INS_MUL,
XCORE_INS_NEG,
XCORE_INS_NOT,
XCORE_INS_OR,
XCORE_INS_OUTCT,
XCORE_INS_OUTPW,
XCORE_INS_OUTSHR,
XCORE_INS_OUTT,
XCORE_INS_OUT,
XCORE_INS_PEEK,
XCORE_INS_REMS,
XCORE_INS_REMU,
XCORE_INS_RETSP,
XCORE_INS_SETCLK,
XCORE_INS_SET,
XCORE_INS_SETC,
XCORE_INS_SETD,
XCORE_INS_SETEV,
XCORE_INS_SETN,
XCORE_INS_SETPSC,
XCORE_INS_SETPT,
XCORE_INS_SETRDY,
XCORE_INS_SETSR,
XCORE_INS_SETTW,
XCORE_INS_SETV,
XCORE_INS_SEXT,
XCORE_INS_SHL,
XCORE_INS_SHR,
XCORE_INS_SSYNC,
XCORE_INS_ST16,
XCORE_INS_ST8,
XCORE_INS_STW,
XCORE_INS_SUB,
XCORE_INS_SYNCR,
XCORE_INS_TESTCT,
XCORE_INS_TESTLCL,
XCORE_INS_TESTWCT,
XCORE_INS_TSETMR,
XCORE_INS_START,
XCORE_INS_WAITEF,
XCORE_INS_WAITET,
XCORE_INS_WAITEU,
XCORE_INS_XOR,
XCORE_INS_ZEXT,
XCORE_INS_ENDING, // <-- mark the end of the list of instructions
} xcore_insn;
/// Group of XCore instructions
typedef enum xcore_insn_group {
XCORE_GRP_INVALID = 0, ///< = CS_GRP_INVALID
// Generic groups
// all jump instructions (conditional+direct+indirect jumps)
XCORE_GRP_JUMP, ///< = CS_GRP_JUMP
XCORE_GRP_ENDING, // <-- mark the end of the list of groups
} xcore_insn_group;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,110 @@
/* Capstone Disassembly Engine */
/* By Axel Souchet & Nguyen Anh Quynh, 2014 */
#ifndef CAPSTONE_PLATFORM_H
#define CAPSTONE_PLATFORM_H
// handle C99 issue (for pre-2013 VisualStudio)
#if !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
// MSVC
// stdbool.h
#if (_MSC_VER < 1800) || defined(_KERNEL_MODE)
// this system does not have stdbool.h
#ifndef __cplusplus
typedef unsigned char bool;
#define false 0
#define true 1
#endif
#else
// VisualStudio 2013+ -> C99 is supported
#include <stdbool.h>
#endif
#else
// not MSVC -> C99 is supported
#include <stdbool.h>
#endif
// handle C99 issue (for pre-2013 VisualStudio)
#if defined(CAPSTONE_HAS_OSXKERNEL) || (defined(_MSC_VER) && (_MSC_VER <= 1700 || defined(_KERNEL_MODE)))
// this system does not have inttypes.h
#if defined(_MSC_VER) && (_MSC_VER < 1600 || defined(_KERNEL_MODE))
// this system does not have stdint.h
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#define INT8_MIN (-127i8 - 1)
#define INT16_MIN (-32767i16 - 1)
#define INT32_MIN (-2147483647i32 - 1)
#define INT64_MIN (-9223372036854775807i64 - 1)
#define INT8_MAX 127i8
#define INT16_MAX 32767i16
#define INT32_MAX 2147483647i32
#define INT64_MAX 9223372036854775807i64
#define UINT8_MAX 0xffui8
#define UINT16_MAX 0xffffui16
#define UINT32_MAX 0xffffffffui32
#define UINT64_MAX 0xffffffffffffffffui64
#endif
#define __PRI_8_LENGTH_MODIFIER__ "hh"
#define __PRI_64_LENGTH_MODIFIER__ "ll"
#define PRId8 __PRI_8_LENGTH_MODIFIER__ "d"
#define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i"
#define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o"
#define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u"
#define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x"
#define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X"
#define PRId16 "hd"
#define PRIi16 "hi"
#define PRIo16 "ho"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hX"
#if defined(_MSC_VER) && _MSC_VER <= 1700
#define PRId32 "ld"
#define PRIi32 "li"
#define PRIo32 "lo"
#define PRIu32 "lu"
#define PRIx32 "lx"
#define PRIX32 "lX"
#else // OSX
#define PRId32 "d"
#define PRIi32 "i"
#define PRIo32 "o"
#define PRIu32 "u"
#define PRIx32 "x"
#define PRIX32 "X"
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1700
// redefine functions from inttypes.h used in cstool
#define strtoull _strtoui64
#endif
#define PRId64 __PRI_64_LENGTH_MODIFIER__ "d"
#define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i"
#define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o"
#define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u"
#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x"
#define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X"
#else
// this system has inttypes.h by default
#include <inttypes.h>
#endif
#endif

View File

@@ -0,0 +1,12 @@
#if defined(_MSC_VER) && defined(_WIN32_WCE) && (_WIN32_WCE < 0x800) && !defined(__INTRIN_H_) && !defined(_INTRIN)
#define _STDINT
#ifdef _M_ARM
#include <armintr.h>
#if (_WIN32_WCE >= 0x700) && defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__)
#include <arm_neon.h>
#endif
#endif // _M_ARM
#endif

View File

@@ -0,0 +1,133 @@
#if defined(_MSC_VER) && defined(_WIN32_WCE) && (_WIN32_WCE < 0x800) && !defined(_STDINT_H_) && !defined(_STDINT)
#define _STDINT
typedef __int8
int8_t,
int_least8_t;
typedef __int16
int16_t,
int_least16_t;
typedef __int32
int32_t,
int_least32_t,
int_fast8_t,
int_fast16_t,
int_fast32_t;
typedef __int64
int64_t,
intmax_t,
int_least64_t,
int_fast64_t;
typedef unsigned __int8
uint8_t,
uint_least8_t;
typedef unsigned __int16
uint16_t,
uint_least16_t;
typedef unsigned __int32
uint32_t,
uint_least32_t,
uint_fast8_t,
uint_fast16_t,
uint_fast32_t;
typedef unsigned __int64
uint64_t,
uintmax_t,
uint_least64_t,
uint_fast64_t;
#ifndef _INTPTR_T_DEFINED
#define _INTPTR_T_DEFINED
typedef __int32 intptr_t;
#endif
#ifndef _UINTPTR_T_DEFINED
#define _UINTPTR_T_DEFINED
typedef unsigned __int32 uintptr_t;
#endif
#define INT8_MIN (-127i8 - 1)
#define INT16_MIN (-32767i16 - 1)
#define INT32_MIN (-2147483647i32 - 1)
#define INT64_MIN (-9223372036854775807i64 - 1)
#define INT8_MAX 127i8
#define INT16_MAX 32767i16
#define INT32_MAX 2147483647i32
#define INT64_MAX 9223372036854775807i64
#define UINT8_MAX 0xffui8
#define UINT16_MAX 0xffffui16
#define UINT32_MAX 0xffffffffui32
#define UINT64_MAX 0xffffffffffffffffui64
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST16_MIN INT32_MIN
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MAX INT32_MAX
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT32_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
#define INTPTR_MIN INT32_MIN
#define INTPTR_MAX INT32_MAX
#define UINTPTR_MAX UINT32_MAX
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
#define PTRDIFF_MIN INTPTR_MIN
#define PTRDIFF_MAX INTPTR_MAX
#ifndef SIZE_MAX
#define SIZE_MAX UINTPTR_MAX
#endif
#define SIG_ATOMIC_MIN INT32_MIN
#define SIG_ATOMIC_MAX INT32_MAX
#define WCHAR_MIN 0x0000
#define WCHAR_MAX 0xffff
#define WINT_MIN 0x0000
#define WINT_MAX 0xffff
#define INT8_C(x) (x)
#define INT16_C(x) (x)
#define INT32_C(x) (x)
#define INT64_C(x) (x ## LL)
#define UINT8_C(x) (x)
#define UINT16_C(x) (x)
#define UINT32_C(x) (x ## U)
#define UINT64_C(x) (x ## ULL)
#define INTMAX_C(x) INT64_C(x)
#define UINTMAX_C(x) UINT64_C(x)
#endif

31
ai_anti_malware/head.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <iostream>
#include <winternl.h>
#include <vector>
#include <map>
#include <unordered_map>
#include <ntstatus.h>
#include <ctime>
#include "unicorn/include/unicorn/unicorn.h"
#include "capstone/include/capstone/capstone.h"
#pragma comment(lib, "unicorn/unicorn.lib")
#pragma comment(lib, "capstone/capstone.lib")
#include "libpeconv/include/peconv.h"
#include "native_struct.h"
struct BasicPeInfo {
std::string inputFilePath;
bool isX64;
uint64_t RecImageBase;
uint64_t entryPoint;
uint64_t imageEnd;
bool isRelocated;
uint8_t* peBuffer;
size_t peSize;
PIMAGE_NT_HEADERS ntHead64;
PIMAGE_NT_HEADERS32 ntHead32;
};
#include "sandbox.h"

View File

@@ -0,0 +1,83 @@
cmake_minimum_required ( VERSION 2.8 )
project ( libpeconv )
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
include_directories (
include
)
set (srcs
src/pe_hdrs_helper.cpp
src/pe_mode_detector.cpp
src/pe_raw_to_virtual.cpp
src/pe_virtual_to_raw.cpp
src/relocate.cpp
src/buffer_util.cpp
src/remote_pe_reader.cpp
src/imports_loader.cpp
src/delayed_imports_loader.cpp
src/fix_imports.cpp
src/pe_loader.cpp
src/pe_dumper.cpp
src/exports_lookup.cpp
src/function_resolver.cpp
src/hooks.cpp
src/exported_func.cpp
src/exports_mapper.cpp
src/resource_parser.cpp
src/file_util.cpp
src/resource_util.cpp
src/imports_uneraser.cpp
src/load_config_util.cpp
src/caves.cpp
src/util.cpp
src/fix_dot_net_ep.cpp
src/find_base.cpp
src/peb_lookup.cpp
)
set (hdrs
include/peconv.h
include/peconv/pe_hdrs_helper.h
include/peconv/pe_mode_detector.h
include/peconv/pe_raw_to_virtual.h
include/peconv/pe_virtual_to_raw.h
include/peconv/relocate.h
include/peconv/util.h
include/peconv/buffer_util.h
include/peconv/remote_pe_reader.h
include/peconv/imports_loader.h
include/peconv/delayed_imports_loader.h
include/peconv/fix_imports.h
include/peconv/pe_loader.h
include/peconv/pe_dumper.h
include/peconv/exports_lookup.h
include/peconv/function_resolver.h
include/peconv/hooks.h
include/peconv/exported_func.h
include/peconv/exports_mapper.h
include/peconv/resource_parser.h
include/peconv/file_util.h
include/peconv/resource_util.h
include/peconv/imports_uneraser.h
include/peconv/load_config_util.h
include/peconv/load_config_defs.h
include/peconv/caves.h
include/peconv/find_base.h
include/peconv/peb_lookup.h
src/fix_dot_net_ep.h #not in API
)
add_library ( ${PROJECT_NAME} STATIC ${hdrs} ${srcs} )
if(PECONV_LIB_INSTALL)
include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY "include/" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
endif()

View File

@@ -0,0 +1,30 @@
/**
* @file
* @brief Master include file, including everything else.
*/
#pragma once
#include "peconv/buffer_util.h"
#include "peconv/util.h"
#include "peconv/pe_hdrs_helper.h"
#include "peconv/pe_mode_detector.h"
#include "peconv/pe_raw_to_virtual.h"
#include "peconv/pe_virtual_to_raw.h"
#include "peconv/relocate.h"
#include "peconv/remote_pe_reader.h"
#include "peconv/imports_loader.h"
#include "peconv/pe_loader.h"
#include "peconv/pe_dumper.h"
#include "peconv/exports_lookup.h"
#include "peconv/function_resolver.h"
#include "peconv/hooks.h"
#include "peconv/exports_mapper.h"
#include "peconv/caves.h"
#include "peconv/fix_imports.h"
#include "peconv/delayed_imports_loader.h"
#include "peconv/resource_parser.h"
#include "peconv/load_config_util.h"
#include "peconv/peb_lookup.h"
#include "peconv/find_base.h"

View File

@@ -0,0 +1,76 @@
/**
* @file
* @brief Definitions of the used buffer types. Functions for their allocation and deallocation.
*/
#pragma once
#include <windows.h>
namespace peconv {
/**
Validates pointers, checks if the particular field is inside the given buffer. Sizes must be given in bytes.
*/
bool validate_ptr(
IN const void* buffer_bgn,
IN SIZE_T buffer_size,
IN const void* field_bgn,
IN SIZE_T field_size
);
//-----------------------------------------------------------------------------------
//
// supported buffers:
//
/**
A buffer allocated on the heap of a process, not aligned to the beginning of a memory page.
*/
typedef PBYTE UNALIGNED_BUF;
/**
A buffer allocated in a virtual space of a process, aligned to the beginning of a memory page.
*/
typedef PBYTE ALIGNED_BUF;
//
// alloc/free unaligned buffers:
//
/**
Allocates a buffer on the heap. Can be used in the cases when the buffer does not have to start at the beginning of a page.
*/
UNALIGNED_BUF alloc_unaligned(size_t buf_size);
//
/**
Frees buffer allocated by alloc_unaligned.
*/
void free_unaligned(UNALIGNED_BUF section_buffer);
//
// alloc/free aligned buffers:
//
/**
Allocates a buffer of a virtual memory (using VirtualAlloc). Can be used in the cases when the buffer have to be aligned to the beginning of a page.
*/
ALIGNED_BUF alloc_aligned(size_t buffer_size, DWORD protect, ULONGLONG desired_base=NULL, bool is_x64 = false);
/**
Frees buffer allocated by alloc_aligned.
*/
bool free_aligned(ALIGNED_BUF buffer, size_t buffer_size=0);
//PE buffers (wrappers)
/**
Allocates an aligned buffer for a PE file.
*/
ALIGNED_BUF alloc_pe_buffer(size_t buffer_size, DWORD protect, ULONGLONG desired_base=NULL);
/**
Free the memory allocated with alloc_pe_buffer.
*/
bool free_pe_buffer(ALIGNED_BUF buffer, size_t buffer_size=0);
}; //namespace peconv

View File

@@ -0,0 +1,27 @@
/**
* @file
* @brief Functions related to finding caves in the loaded PE file.
*/
#pragma once
#include <windows.h>
namespace peconv {
/**
Finds cave at the end of the image (extend last section's raw size without extending the full image size)
*/
PBYTE find_ending_cave(BYTE* module_ptr, size_t module_size, const DWORD cave_size, const DWORD cave_charact=IMAGE_SCN_MEM_READ);
/**
Finds cave in the difference between the original raw size, and the raw size rounded to the aligmnent
*/
PBYTE find_alignment_cave(BYTE* modulePtr, size_t moduleSize, const DWORD cave_size, const DWORD req_charact = IMAGE_SCN_MEM_READ);
/**
Finds cave at the end of the section, that comes from a NULL padding or INT3 padding
*/
PBYTE find_padding_cave(BYTE* modulePtr, size_t moduleSize, const size_t minimal_size, const DWORD req_charact = IMAGE_SCN_MEM_READ);
};//namespace peconv

View File

@@ -0,0 +1,61 @@
/**
* @file
* @brief Parsing and filling the Delayload Import Table.
*/
#pragma once
#include <windows.h>
#include "pe_hdrs_helper.h"
#include "function_resolver.h"
#if (defined(_WIN32_WINNT) && _WIN32_WINNT > 0x0601) || __MINGW32__ //Windows SDK version 6.1 (Windows 7)
#define DELAYLOAD_IMPORTS_DEFINED
#endif
#ifndef DELAYLOAD_IMPORTS_DEFINED
#include "pshpack4.h"
typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR {
union {
DWORD AllAttributes;
struct {
DWORD RvaBased : 1; // Delay load version 2
DWORD ReservedAttributes : 31;
} DUMMYSTRUCTNAME;
} Attributes;
DWORD DllNameRVA; // RVA to the name of the target library (NULL-terminate ASCII string)
DWORD ModuleHandleRVA; // RVA to the HMODULE caching location (PHMODULE)
DWORD ImportAddressTableRVA; // RVA to the start of the IAT (PIMAGE_THUNK_DATA)
DWORD ImportNameTableRVA; // RVA to the start of the name table (PIMAGE_THUNK_DATA::AddressOfData)
DWORD BoundImportAddressTableRVA; // RVA to an optional bound IAT
DWORD UnloadInformationTableRVA; // RVA to an optional unload info table
DWORD TimeDateStamp; // 0 if not bound,
// Otherwise, date/time of the target DLL
} IMAGE_DELAYLOAD_DESCRIPTOR, *PIMAGE_DELAYLOAD_DESCRIPTOR;
typedef const IMAGE_DELAYLOAD_DESCRIPTOR *PCIMAGE_DELAYLOAD_DESCRIPTOR;
#include "poppack.h"
#endif
namespace peconv {
/**
Get the Delayload Imports directory. Returns the pointer to the first descriptor. The size of the directory is passed via variable dir_size.
*/
IMAGE_DELAYLOAD_DESCRIPTOR* get_delayed_imps(IN const BYTE* modulePtr, IN const size_t moduleSize, OUT size_t &dir_size);
/**
Fill the Delayload Imports in the given module.
\param modulePtr : the pointer to the module where the imports needs to be filled.
\param moduleBase : the base to which the module was relocated, it may (or not) be the same as modulePtr
\param func_resolver : the resolver that will be used for loading the imports
\return : true if resolving all succeeded, false otherwise
*/
bool load_delayed_imports(BYTE* modulePtr, const ULONGLONG moduleBase, t_function_resolver* func_resolver = nullptr);
}; // namespace peconv

View File

@@ -0,0 +1,123 @@
/**
* @file
* @brief A definition of ExportedFunc class - used for storing the details of the exported function. Helper functions related to the export parsing.
*/
#pragma once
#include <windows.h>
#include <string>
#include <algorithm>
#include <set>
namespace peconv {
/**
Check if the pointer redirects to a forwarder - if so, return the length, otherwise return 0.
*/
size_t forwarder_name_len(BYTE* fPtr);
/**
get the DLL name without the extension
*/
std::string get_dll_shortname(const std::string& str);
/**
Get the function name from the string in a format: DLL_name.function_name
*/
std::string get_func_name(const std::string& str);
/**
Convert ordinal value to the ordinal string (in a format #[ordinal])
*/
std::string ordinal_to_string(DWORD func_ordinal);
/**
Check if the given string is in a format typical for storing ordinals (#[ordinal])
*/
bool is_ordinal_string(const std::string& str);
/**
Get the ordinal value from the ordinal string (in a format #[ordinal])
*/
DWORD ordinal_string_to_val(const std::string& str);
/**
Convert the function in a format: DLL_name.function_name into a normalized form (DLL name in lowercase).
*/
std::string format_dll_func(const std::string& str);
/**
A class storing the information about the exported function.
*/
class ExportedFunc
{
public:
/**
Converts the name to the normalized format.
*/
static std::string formatName(std::string name);
std::string libName;
std::string funcName;
DWORD funcOrdinal;
bool isByOrdinal;
//default constructor:
ExportedFunc() : funcOrdinal(0), isByOrdinal(false) {}
ExportedFunc(const ExportedFunc& other);
ExportedFunc(std::string libName, std::string funcName, DWORD funcOrdinal);
ExportedFunc(std::string libName, DWORD funcOrdinal);
ExportedFunc(const std::string &forwarderName);
/**
Compare two functions with each other.
Gives the priority to the named functions: if one of the compared functions is unnamed, the named one is treated as smaller.
If both functions are unnamed, the function with the smaller ordinal is treated as smaller.
Otherwise, the function with the shorter name is treated as smaller.
*/
bool operator < (const ExportedFunc& other) const
{
//if only one function is named, give the preference to the named one:
const size_t thisNameLen = this->funcName.length();
const size_t otherNameLen = other.funcName.length();
if (thisNameLen == 0 && otherNameLen > 0) {
return false;
}
if (thisNameLen > 0 && otherNameLen == 0) {
return true;
}
//select by shorter lib name:
int cmp = libName.compare(other.libName);
if (cmp != 0) {
return cmp < 0;
}
if (thisNameLen == 0 || otherNameLen == 0) {
return this->funcOrdinal < other.funcOrdinal;
}
if (thisNameLen != otherNameLen) {
return thisNameLen < otherNameLen;
}
cmp = funcName.compare(other.funcName);
return cmp < 0;
}
/**
Gets a string representation of the variable. Full info about the function: library, name, ordinal.
*/
std::string toString() const;
/**
Gets a string representation of the variable. Short info about the function: only function name or ordinal (if the name is missing).
*/
std::string nameToString() const;
bool isValid() const
{
return (funcName != "" || funcOrdinal != -1);
}
};
}; //namespace peconv

View File

@@ -0,0 +1,50 @@
/**
* @file
* @brief Searching specific functions in PE's Exports Table.
*/
#pragma once
#include <windows.h>
#include "pe_hdrs_helper.h"
#include "function_resolver.h"
#include "exports_mapper.h"
#include <string>
#include <vector>
#include <map>
namespace peconv {
/**
Gets the function address by the name. Uses Export Table lookup.
WARNING: doesn't work for the forwarded functions.
*/
FARPROC get_exported_func(PVOID modulePtr, LPSTR wanted_name);
/**
Gets list of all the functions from a given module that are exported by names.
*/
size_t get_exported_names(PVOID modulePtr, std::vector<std::string> &names_list);
/**
Function resolver using Export Table lookup.
*/
class export_based_resolver : default_func_resolver {
public:
/**
Get the address (VA) of the function with the given name, from the given DLL.
Uses Export Table lookup as a primary method of finding the import. On failure it falls back to the default Functions Resolver.
\param func_name : the name of the function
\param lib_name : the name of the DLL
\return Virtual Address of the exported function
*/
virtual FARPROC resolve_func(LPSTR lib_name, LPSTR func_name);
};
/**
Read the DLL name from the Export Table.
*/
LPSTR read_dll_name(HMODULE modulePtr);
}; //namespace peconv

View File

@@ -0,0 +1,140 @@
/**
* @file
* @brief A definition of ExportsMapper class. Creates a lookup of all the exported functions from the supplied DLLs. Allows to associate an address with a corresponding function.
*/
#pragma once
#include <windows.h>
#include <string>
#include <map>
#include <set>
#include <sstream>
#include "pe_hdrs_helper.h"
#include "pe_raw_to_virtual.h"
#include "peconv/exported_func.h"
#include "peconv/file_util.h"
namespace peconv {
class ExportsMapper {
public:
/**
Appends the given DLL to the lookup table of exported functions. Returns the number of functions exported from this DLL (not forwarded).
\param moduleName : name of the DLL
\param modulePtr : buffer containing the DLL in a Virtual format
\param moduleBase : a base address to which the given DLL was relocated
*/
size_t add_to_lookup(std::string moduleName, HMODULE modulePtr, ULONGLONG moduleBase);
/**
Appends the given DLL to the lookup table of exported functions. Returns the number of functions exported from this DLL (not forwarded).
Assumes that the module was relocated to the same address as is the address of the given buffer (modulePtr).
(A wrapper for the case if we are adding a DLL that was loaded within the current process.)
\param moduleName : name of the DLL
\param modulePtr : buffer containing the DLL in a Virtual format.
*/
size_t add_to_lookup(std::string moduleName, HMODULE modulePtr)
{
return add_to_lookup(moduleName, modulePtr, reinterpret_cast<ULONGLONG>(modulePtr));
}
/**
Find the set of Exported Functions that can be mapped to the given VA. Includes forwarders, and function aliases.
*/
const std::set<ExportedFunc>* find_exports_by_va(ULONGLONG va) const
{
std::map<ULONGLONG, std::set<ExportedFunc>>::const_iterator itr = va_to_func.find(va);
if (itr != va_to_func.end()) {
const std::set<ExportedFunc> &fSet = itr->second;
return &fSet;
}
return NULL;
}
/**
Retrieve the full path of the DLL with the given short name.
*/
std::string get_dll_path(std::string short_name) const
{
std::map<std::string, std::string>::const_iterator found = this->dll_shortname_to_path.find(short_name);
if (found == dll_shortname_to_path.end()) {
return "";
}
return found->second;
}
/**
Retrieve the full name of the DLL (including the extension) using its short name (without the extension).
*/
std::string get_dll_fullname(std::string short_name) const
{
std::string dll_path = get_dll_path(short_name);
if (dll_path.length() == 0) return "";
return get_file_name(dll_path);
}
/**
Find an Exported Function that can be mapped to the given VA,
*/
const ExportedFunc* find_export_by_va(ULONGLONG va) const
{
const std::set<ExportedFunc>* exp_set = find_exports_by_va(va);
if (exp_set == NULL) return NULL;
std::set<ExportedFunc>::iterator fItr = exp_set->begin();
const ExportedFunc* func = &(*fItr);
return func;
}
void print_va_to_func(std::stringstream &stream) const;
void print_func_to_va(std::stringstream &stream) const;
private:
enum ADD_FUNC_RES { RES_INVALID = 0, RES_MAPPED = 1, RES_FORWARDED = 2 };
ADD_FUNC_RES add_function_to_lookup(HMODULE modulePtr, ULONGLONG moduleBase, size_t moduleSize, ExportedFunc &currFunc, DWORD callRVA);
bool add_forwarded(ExportedFunc &currFunc, DWORD callRVA, PBYTE modulePtr, size_t moduleSize);
bool add_to_maps(ULONGLONG va, ExportedFunc &currFunc);
size_t resolve_forwarders(const ULONGLONG va, ExportedFunc &currFunc);
size_t make_ord_lookup_tables(PVOID modulePtr, size_t moduleSize, std::map<PDWORD, DWORD> &va_to_ord);
protected:
/**
Add a function and a VA into a mutual mapping.
*/
void associateVaAndFunc(ULONGLONG va, const ExportedFunc& func)
{
va_to_func[va].insert(func);
func_to_va[func] = va;
}
/**
A map associating VA of the function with the related exports.
*/
std::map<ULONGLONG, std::set<ExportedFunc>> va_to_func;
/**
A map associating an exported functions with its forwarders.
*/
std::map<ExportedFunc, std::set<ExportedFunc>> forwarders_lookup;
/**
A map associating an exported functions with its VA.
*/
std::map<ExportedFunc, ULONGLONG> func_to_va;
/**
A map associating DLL shortname with the full path to the DLL.
*/
std::map<std::string, std::string> dll_shortname_to_path;
};
}; //namespace peconv

View File

@@ -0,0 +1,55 @@
/**
* @file
* @brief Functions related to operations on files. Wrappers for read/write.
*/
#pragma once
#include <windows.h>
#include <iostream>
#include "buffer_util.h"
namespace peconv {
/**
Maps a file with the given path and copies its raw content into the output buffer.
If read_size is not zero, it reads maximum read_size of bytes. If read_size is zero, it reads the full file.
The actual read size is returned back in read_size.
Automatically allocates a buffer of the required size.
*/
peconv::ALIGNED_BUF load_file(IN const char *filename, OUT size_t &r_size);
/**
Reads a raw content of the file with the given path.
If read_size is not zero, it reads maximum read_size of bytes. If read_size is zero, it reads the full file.
The actual read size is returned back in read_size.
Automatically allocates a buffer of the required size.
*/
peconv::ALIGNED_BUF read_from_file(IN const char *path, IN OUT size_t &read_size);
/**
Writes a buffer of bytes into a file of given path.
\param path : the path to the output file
\param dump_data : the buffer to be dumped
\param dump_size : the size of data to be dumped (in bytes)
\return true if succeeded, false if failed
*/
bool dump_to_file(IN const char *path, IN PBYTE dump_data, IN size_t dump_size);
/**
Free the buffer allocated by load_file/read_from_file
*/
void free_file(IN peconv::ALIGNED_BUF buffer);
/**
Get the file name from the given path.
*/
std::string get_file_name(IN const std::string full_path);
/**
Get the directory name from the given path. It assumes that a directory name always ends with a separator ("/" or "\")
*/
std::string get_directory_name(IN const std::string full_path);
}; //namespace peconv

View File

@@ -0,0 +1,20 @@
/**
* @file
* @brief Functions related to finding a base to which the module was relocated.
*/
#pragma once
#include <windows.h>
namespace peconv {
/**
Try to find a base to which the PE file was relocated, basing on the filled relocations.
WARNING: the found base is an estimate, and sometimes may not be fully accurate.
\param module_ptr : the module which's base is being searched
\param module_size : the size of the given module
\return the base to which the module was relocated
*/
ULONGLONG find_base_candidate(IN BYTE *module_ptr, IN size_t module_size);
};

View File

@@ -0,0 +1,119 @@
/**
* @file
* @brief Functions and classes responsible for fixing Import Table. A definition of ImportedDllCoverage class.
*/
#pragma once
#include <windows.h>
#include <string>
#include <set>
#include <map>
#include <iterator>
#include "pe_hdrs_helper.h"
#include "exports_lookup.h"
#include "exports_mapper.h"
#define MIN_DLL_LEN 5
namespace peconv {
/**
a helper class that allows to store information about functions that could not be covered by the given mapping
*/
class ImpsNotCovered
{
public:
ImpsNotCovered() {}
~ImpsNotCovered() {}
/*
Number of stored records
*/
size_t count() { return thunkToAddr.size(); }
void insert(ULONGLONG thunk, ULONGLONG searchedAddr);
std::map<ULONGLONG, ULONGLONG> thunkToAddr; //addresses of not recovered functions with their thunks (call_via)
};
/**
fix imports in the given module, using the given map of all available exports
*/
bool fix_imports(IN OUT PVOID modulePtr, IN size_t moduleSize, IN const peconv::ExportsMapper& exportsMap, OUT OPTIONAL peconv::ImpsNotCovered* notCovered);
/**
a helper class that allows to find out where the functions are imported from
*/
class ImportedDllCoverage
{
public:
/**
A constructor of an object of ImportedDllCoverage class.
\param _addresses : the list of filled imports (VAs): the addresses to be covered
\param _exportsMap : the map of the exports of all the loaded DLLs (the space in which we will be searching)
*/
ImportedDllCoverage(std::set<ULONGLONG>& _addresses, const peconv::ExportsMapper& _exportsMap)
: addresses(_addresses), exportsMap(_exportsMap)
{
}
/**
Checks if all the addresses can be covered by one DLL. If yes, this dll will be saved into: dllName.
\return true if the covering DLL for the addresses was found. false otherwise.
*/
bool findCoveringDll();
/**
Maps the addresses from the set to functions from the given DLL.
Results are saved into: addrToFunc.
Addresses that could not be covered by the given DLL are saved into notFound.
Before each execution, the content of involved variables is erased.
\param _mappedDllName : the name of the DLL that we will be used to mapping. This DLL is saved into mappedDllName.
\return a number of covered functions
*/
size_t mapAddressesToFunctions(const std::string &_mappedDllName);
/**
Check if the functions mapping is complete.
\return the status: true if all the addresses are mapped to specific exports, false if not
*/
bool isMappingComplete() { return (addresses.size() == addrToFunc.size()) ? true : false; }
/**
A mapping associating each of the covered function addresses with the set of exports (from mapped DLL) that cover this address
*/
std::map<ULONGLONG, std::set<ExportedFunc>> addrToFunc;
/**
Addresses of the functions not found in the mapped DLL
*/
std::set<ULONGLONG> notFound;
/**
Name of the covering DLL
*/
std::string dllName;
protected:
/**
A name of the DLL that was used for mapping. In a typical scenario it will be the same as covering DLL, but may be set different.
*/
std::string mappedDllName;
/**
A supplied set of the addresses of imported functions.
Those addressed will be covered (associated with the corresponding exports from available DLLs, defined by exportsMap).
*/
std::set<ULONGLONG> &addresses;
/**
A supplied exportsMap. Only used as a lookup, no changes applied.
*/
const peconv::ExportsMapper& exportsMap;
};
}

View File

@@ -0,0 +1,39 @@
/**
* @file
* @brief Definitions of basic Imports Resolver classes. They can be used for filling imports when the PE is loaded.
*/
#pragma once
#include <windows.h>
namespace peconv {
/**
A base class for functions resolver.
*/
class t_function_resolver {
public:
/**
Get the address (VA) of the function with the given name, from the given DLL.
\param func_name : the name of the function
\param lib_name : the name of the DLL
\return Virtual Address of the exported function
*/
virtual FARPROC resolve_func(LPSTR lib_name, LPSTR func_name) = 0;
};
/**
A default functions resolver, using LoadLibraryA and GetProcAddress.
*/
class default_func_resolver : t_function_resolver {
public:
/**
Get the address (VA) of the function with the given name, from the given DLL, using LoadLibraryA and GetProcAddress.
\param func_name : the name of the function
\param lib_name : the name of the DLL
\return Virtual Address of the exported function
*/
virtual FARPROC resolve_func(LPSTR lib_name, LPSTR func_name);
};
}; //namespace peconv

View File

@@ -0,0 +1,135 @@
/**
* @file
* @brief Functions related to hooking the loaded PE. Reditecting/replacing a functions with another.
*/
#pragma once
#include <windows.h>
#include "function_resolver.h"
#include <iostream>
#include <string>
#include <map>
#include "peconv/buffer_util.h"
namespace peconv {
/**
A buffer storing a binary patch, that can be applied on a module. Used as a restorable backup in case of function patching.
*/
class PatchBackup {
public:
/**
Creates an empty backup.
*/
PatchBackup()
: buffer(nullptr), bufferSize(0), sourcePtr(nullptr)
{
}
~PatchBackup() {
deleteBackup();
}
/**
Destroys the backup and resets internal fields.
*/
void deleteBackup()
{
if (buffer) {
delete[] buffer;
bufferSize = 0;
sourcePtr = nullptr;
}
}
/**
Reads bytes from the binary to the backup. The source buffer must be within the current process.
*/
bool makeBackup(BYTE *patch_ptr, size_t patch_size);
/**
Applies the backup back to the pointer from which it was read.
*/
bool applyBackup();
/**
Checks if the buffer was filled.
*/
bool isBackup()
{
return buffer != nullptr;
}
protected:
BYTE *buffer;
size_t bufferSize;
BYTE *sourcePtr;
};
/**
A functions resolver that can be used for hooking IAT. Allows for defining functions that are supposed to be replaced.
*/
class hooking_func_resolver : peconv::default_func_resolver {
public:
/**
Define a function that will be replaced.
\param name : a name of the function that will be replaced
\param function : an address of the replacement function
*/
void add_hook(std::string name, FARPROC function)
{
hooks_map[name] = function;
}
/**
Get the address (VA) of the function with the given name, from the given DLL. If the function was hooked, it retrieves the address of the replacement function instead.
\param func_name : the name of the function
\param lib_name : the name of the DLL
\return Virtual Address of the exported function, or the address of the replacement function.
*/
virtual FARPROC resolve_func(LPSTR lib_name, LPSTR func_name);
private:
std::map<std::string, FARPROC> hooks_map;
};
/**
Installs inline hook at the given ptr. Returns the number of bytes overwriten.
64 bit version.
\param ptr : pointer to the function to be replaced
\param new_offset : VA of the new function
\param backup : (optional) backup that can be used to reverse the changes
\return size of the applied patch
*/
size_t redirect_to_local64(void *ptr, ULONGLONG new_offset, PatchBackup* backup = nullptr);
/**
Installs inline hook at the given ptr. Returns the number of bytes overwriten.
32 bit version.
\param ptr : pointer to the function to be replaced
\param new_offset : VA of the new function
\param backup : (optional) backup that can be used to reverse the changes
\return size of the applied patch
*/
size_t redirect_to_local32(void *ptr, DWORD new_offset, PatchBackup* backup = nullptr);
/**
Installs inline hook at the given ptr. Returns the number of bytes overwriten.
Uses bitness of the current applications for the bitness of the intalled hook.
\param ptr : pointer to the function to be replaced
\param new_function_ptr : pointer to the new function
\param backup : (optional) backup that can be used to reverse the changes
\return size of the applied patch
*/
size_t redirect_to_local(void *ptr, void* new_function_ptr, PatchBackup* backup = nullptr);
/**
Replaces a target address of JMP [DWORD] or CALL [DWORD]
*/
bool replace_target(BYTE *ptr, ULONGLONG dest_addr);
};//namespace peconv

View File

@@ -0,0 +1,70 @@
/**
* @file
* @brief Parsing and filling the Import Table.
*/
#pragma once
#include <windows.h>
#include "pe_hdrs_helper.h"
#include "function_resolver.h"
namespace peconv {
/**
A class defining a callback that will be executed when the next imported function was found
*/
class ImportThunksCallback
{
public:
ImportThunksCallback(BYTE* _modulePtr, size_t _moduleSize)
: modulePtr(_modulePtr), moduleSize(_moduleSize)
{
this->is64b = is64bit((BYTE*)modulePtr);
}
/**
A callback that will be executed by process_import_table when the next imported function was found
\param libName : the pointer to the DLL name
\param origFirstThunkPtr : the pointer to the Original First Thunk
\param firstThunkPtr : the pointer to the First Thunk
\return : true if processing succeeded, false otherwise
*/
virtual bool processThunks(LPSTR libName, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr) = 0;
protected:
BYTE* modulePtr;
size_t moduleSize;
bool is64b;
};
/**
Process the given PE's import table and execute the callback each time when the new imported function was found
\param modulePtr : a pointer to the loded PE (in virtual format)
\param moduleSize : a size of the supplied PE
\param callback : a callback that will be executed to process each imported function
\return : true if processing succeeded, false otherwise
*/
bool process_import_table(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ImportThunksCallback *callback);
/**
Fills imports of the given PE with the help of the defined functions resolver.
\param modulePtr : a pointer to the loded PE (in virtual format)
\param func_resolver : a resolver that will be used to fill the thunk of the import
\return : true if loading all functions succeeded, false otherwise
*/
bool load_imports(BYTE* modulePtr, t_function_resolver* func_resolver=nullptr);
/**
Checks if the given PE has a valid import table.
*/
bool has_valid_import_table(const PBYTE modulePtr, size_t moduleSize);
/**
Checks if the given lib_name is a valid DLL name.
A valid name must contain printable characters. Empty name is also acceptable (may have been erased).
*/
bool is_valid_import_name(const PBYTE modulePtr, const size_t moduleSize, LPSTR lib_name);
}; // namespace peconv

View File

@@ -0,0 +1,94 @@
/**
* @file
* @brief A definition of ImportsUneraser class - for recovery of a partialy erased Import Table.
*/
#pragma once
#include <windows.h>
#include <string>
#include <set>
#include <map>
#include <iterator>
#include "fix_imports.h"
#include "caves.h"
namespace peconv {
/**
A class responsible for recovering the partially erased Import Table from the PE.
*/
class ImportsUneraser
{
public:
ImportsUneraser(PVOID _modulePtr, size_t _moduleSize)
: modulePtr((PBYTE)_modulePtr), moduleSize(_moduleSize)
{
is64 = peconv::is64bit((BYTE*)modulePtr);
}
/**
Fill the imported functions' names in the given Import Descriptor, using the given coverage.
Collect addressees of functions that couldn't be filled with the given mapping.
\param lib_desc : the IMAGE_IMPORT_DESCRIPTOR where the functions' names should be set
\param dllCoverage : a mapping associating addresses with the corresponding exports from available DLLs
\param not_covered : a set of addresses that could not be found in the supplied mapping
\return true if succeeded
*/
bool uneraseDllImports(IN OUT IMAGE_IMPORT_DESCRIPTOR* lib_desc, IN ImportedDllCoverage &dllCoverage, OUT OPTIONAL ImpsNotCovered* not_covered);
/**
Recover the imported DLL name in the given Import Descriptor, filling it with the given dll_name.
*/
bool uneraseDllName(IMAGE_IMPORT_DESCRIPTOR* lib_desc, const std::string &dll_name);
protected:
/**
Copy the given DLL name into the given IMAGE_IMPORT_DESCRIPTOR. Validates the data correctness before writing.
\param lib_desc : the IMAGE_IMPORT_DESCRIPTOR where the DLL name should be set
\param dll_name : the DLL name that needs to be written into the lib_desc
\return true if succeeded
*/
bool writeFoundDllName(IMAGE_IMPORT_DESCRIPTOR* lib_desc, const std::string &dll_name);
/**
Fill the names of imported functions with names of the prepared mapping.
Collect addressees of functions that couldn't be filled with the given mapping.
\param lib_desc : the IMAGE_IMPORT_DESCRIPTOR where the functions' names should be set
\param ordinal_flag : the flag that is used to recognize import by ordinal (32 or 64 bit)
\param addr_to_func : a mapping assigning functions' addresses to their definitions (names etc.)
\param not_covered : a set of addresses that could not be found in the supplied mapping
\return true if succeeded
*/
template <typename FIELD_T, typename IMAGE_THUNK_DATA_T>
bool fillImportNames(IN OUT IMAGE_IMPORT_DESCRIPTOR* lib_desc,
IN const FIELD_T ordinal_flag,
IN std::map<ULONGLONG, std::set<ExportedFunc>> &addr_to_func,
OUT OPTIONAL ImpsNotCovered* not_covered
);
template <typename FIELD_T>
bool findNameInBinaryAndFill(IMAGE_IMPORT_DESCRIPTOR* lib_desc,
LPVOID call_via_ptr,
LPVOID thunk_ptr,
const FIELD_T ordinal_flag,
std::map<ULONGLONG, std::set<ExportedFunc>> &addr_to_func
);
/**
Fill the function data into the given IMAGE_THUNK_DATA.
\param desc : the poiner to IMAGE_THUNK_DATA that will be filled
\param ordinal_flag : an ordinal flag: 32 or 64 bit
\param foundFunc : the ExportedFunc that will be used for filling the desc
*/
template <typename FIELD_T, typename IMAGE_THUNK_DATA_T>
bool writeFoundFunction(IMAGE_THUNK_DATA_T* desc, const FIELD_T ordinal_flag, const ExportedFunc &foundFunc);
PBYTE modulePtr;
size_t moduleSize;
bool is64;
};
}

View File

@@ -0,0 +1,228 @@
#pragma once
#include <windows.h>
#include <pshpack4.h>
namespace peconv {
/**
IMAGE_LOAD_CONFIG_CODE_INTEGRITY: a structure used by IMAGE_LOAD_CONFIG_DIR - the Windows 10 version.
*/
typedef struct _IMAGE_LOAD_CONFIG_CODE_INTEGRITY_W10 {
WORD Flags; // Flags to indicate if CI information is available, etc.
WORD Catalog; // 0xFFFF means not available
DWORD CatalogOffset;
DWORD Reserved; // Additional bitmask to be defined later
} IMAGE_LOAD_CONFIG_CODE_INTEGRITY_W10;
/**
IMAGE_LOAD_CONFIG_DIR32: the Windows 10 version.
*/
typedef struct _IMAGE_LOAD_CONFIG_DIR32_W10 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
DWORD DeCommitFreeBlockThreshold;
DWORD DeCommitTotalFreeThreshold;
DWORD LockPrefixTable; // VA
DWORD MaximumAllocationSize;
DWORD VirtualMemoryThreshold;
DWORD ProcessHeapFlags;
DWORD ProcessAffinityMask;
WORD CSDVersion;
WORD DependentLoadFlags;
DWORD EditList; // VA
DWORD SecurityCookie; // VA
DWORD SEHandlerTable; // VA
DWORD SEHandlerCount;
DWORD GuardCFCheckFunctionPointer; // VA
DWORD GuardCFDispatchFunctionPointer; // VA
DWORD GuardCFFunctionTable; // VA
DWORD GuardCFFunctionCount;
DWORD GuardFlags;
IMAGE_LOAD_CONFIG_CODE_INTEGRITY_W10 CodeIntegrity;
DWORD GuardAddressTakenIatEntryTable; // VA
DWORD GuardAddressTakenIatEntryCount;
DWORD GuardLongJumpTargetTable; // VA
DWORD GuardLongJumpTargetCount;
DWORD DynamicValueRelocTable; // VA
DWORD CHPEMetadataPointer;
DWORD GuardRFFailureRoutine; // VA
DWORD GuardRFFailureRoutineFunctionPointer; // VA
DWORD DynamicValueRelocTableOffset;
WORD DynamicValueRelocTableSection;
WORD Reserved2;
DWORD GuardRFVerifyStackPointerFunctionPointer; // VA
DWORD HotPatchTableOffset;
DWORD Reserved3;
DWORD EnclaveConfigurationPointer; // VA
} IMAGE_LOAD_CONFIG_DIR32_W10;
/**
IMAGE_LOAD_CONFIG_DIR64: the Windows 10 version.
*/
typedef struct _IMAGE_LOAD_CONFIG_DIR64_W10 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
ULONGLONG DeCommitFreeBlockThreshold;
ULONGLONG DeCommitTotalFreeThreshold;
ULONGLONG LockPrefixTable; // VA
ULONGLONG MaximumAllocationSize;
ULONGLONG VirtualMemoryThreshold;
ULONGLONG ProcessAffinityMask;
DWORD ProcessHeapFlags;
WORD CSDVersion;
WORD DependentLoadFlags;
ULONGLONG EditList; // VA
ULONGLONG SecurityCookie; // VA
ULONGLONG SEHandlerTable; // VA
ULONGLONG SEHandlerCount;
ULONGLONG GuardCFCheckFunctionPointer; // VA
ULONGLONG GuardCFDispatchFunctionPointer; // VA
ULONGLONG GuardCFFunctionTable; // VA
ULONGLONG GuardCFFunctionCount;
DWORD GuardFlags;
IMAGE_LOAD_CONFIG_CODE_INTEGRITY_W10 CodeIntegrity;
ULONGLONG GuardAddressTakenIatEntryTable; // VA
ULONGLONG GuardAddressTakenIatEntryCount;
ULONGLONG GuardLongJumpTargetTable; // VA
ULONGLONG GuardLongJumpTargetCount;
ULONGLONG DynamicValueRelocTable; // VA
ULONGLONG CHPEMetadataPointer; // VA
ULONGLONG GuardRFFailureRoutine; // VA
ULONGLONG GuardRFFailureRoutineFunctionPointer; // VA
DWORD DynamicValueRelocTableOffset;
WORD DynamicValueRelocTableSection;
WORD Reserved2;
ULONGLONG GuardRFVerifyStackPointerFunctionPointer; // VA
DWORD HotPatchTableOffset;
DWORD Reserved3;
ULONGLONG EnclaveConfigurationPointer; // VA
} IMAGE_LOAD_CONFIG_DIR64_W10;
/**
IMAGE_LOAD_CONFIG_DIR32: the Windows 8 version.
*/
typedef struct _IMAGE_LOAD_CONFIG_DIR32_W8 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
DWORD DeCommitFreeBlockThreshold;
DWORD DeCommitTotalFreeThreshold;
DWORD LockPrefixTable; // VA
DWORD MaximumAllocationSize;
DWORD VirtualMemoryThreshold;
DWORD ProcessHeapFlags;
DWORD ProcessAffinityMask;
WORD CSDVersion;
WORD DependentLoadFlags;
DWORD EditList; // VA
DWORD SecurityCookie; // VA
DWORD SEHandlerTable; // VA
DWORD SEHandlerCount;
DWORD GuardCFCheckFunctionPointer; // VA
DWORD GuardCFDispatchFunctionPointer; // VA
DWORD GuardCFFunctionTable; // VA
DWORD GuardCFFunctionCount;
DWORD GuardFlags;
} IMAGE_LOAD_CONFIG_DIR32_W8;
/**
IMAGE_LOAD_CONFIG_DIR64: the Windows 8 version.
*/
typedef struct _IMAGE_LOAD_CONFIG_DIR64_W8 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
ULONGLONG DeCommitFreeBlockThreshold;
ULONGLONG DeCommitTotalFreeThreshold;
ULONGLONG LockPrefixTable; // VA
ULONGLONG MaximumAllocationSize;
ULONGLONG VirtualMemoryThreshold;
ULONGLONG ProcessAffinityMask;
DWORD ProcessHeapFlags;
WORD CSDVersion;
WORD DependentLoadFlags;
ULONGLONG EditList; // VA
ULONGLONG SecurityCookie; // VA
ULONGLONG SEHandlerTable; // VA
ULONGLONG SEHandlerCount;
ULONGLONG GuardCFCheckFunctionPointer; // VA
ULONGLONG GuardCFDispatchFunctionPointer; // VA
ULONGLONG GuardCFFunctionTable; // VA
ULONGLONG GuardCFFunctionCount;
DWORD GuardFlags;
} IMAGE_LOAD_CONFIG_DIR64_W8;
/**
IMAGE_LOAD_CONFIG_DIR32: the Windows 7 version.
*/
typedef struct _IMAGE_LOAD_CONFIG_DIR32_W7 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
DWORD DeCommitFreeBlockThreshold;
DWORD DeCommitTotalFreeThreshold;
DWORD LockPrefixTable; // VA
DWORD MaximumAllocationSize;
DWORD VirtualMemoryThreshold;
DWORD ProcessHeapFlags;
DWORD ProcessAffinityMask;
WORD CSDVersion;
WORD DependentLoadFlags;
DWORD EditList; // VA
DWORD SecurityCookie; // VA
DWORD SEHandlerTable; // VA
DWORD SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIR32_W7;
/**
IMAGE_LOAD_CONFIG_DIR64: the Windows 7 version.
*/
typedef struct _IMAGE_LOAD_CONFIG_DIR64_W7 {
DWORD Size;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD GlobalFlagsClear;
DWORD GlobalFlagsSet;
DWORD CriticalSectionDefaultTimeout;
ULONGLONG DeCommitFreeBlockThreshold;
ULONGLONG DeCommitTotalFreeThreshold;
ULONGLONG LockPrefixTable; // VA
ULONGLONG MaximumAllocationSize;
ULONGLONG VirtualMemoryThreshold;
ULONGLONG ProcessAffinityMask;
DWORD ProcessHeapFlags;
WORD CSDVersion;
WORD DependentLoadFlags;
ULONGLONG EditList; // VA
ULONGLONG SecurityCookie; // VA
ULONGLONG SEHandlerTable; // VA
ULONGLONG SEHandlerCount;
} IMAGE_LOAD_CONFIG_DIR64_W7;
}; //namespace peconv
#include <poppack.h>

View File

@@ -0,0 +1,42 @@
/**
* @file
* @brief Fetching Load Config Directory and recognizing its version.
*/
#pragma once
#include <windows.h>
#include "buffer_util.h"
#include "load_config_defs.h"
namespace peconv {
/**
A version of Load Config Directory.
*/
typedef enum {
LOAD_CONFIG_NONE = 0, /**< Load Config Directory not found */
LOAD_CONFIG_W7_VER = 7, /**< Load Config Directory in the Windows 7 version */
LOAD_CONFIG_W8_VER = 8, /**< Load Config Directory in the Windows 8 version */
LOAD_CONFIG_W10_VER = 10, /**< Load Config Directory in the Windows 10 version */
LOAD_CONFIG_UNK_VER = -1 /**< Load Config Directory in an unknown version */
} t_load_config_ver;
/**
Get a pointer to the Load Config Directory within the given PE.
\param buffer : a buffer containing the PE file in a Virtual format
\param buf_size : size of the buffer
\return a pointer to the Load Config Directory, NULL if the given PE does not have this directory
*/
BYTE* get_load_config_ptr(BYTE* buffer, size_t buf_size);
/**
Detect which version of Load Config Directory was used in the given PE.
\param buffer : a buffer containing the PE file in a Virtual format
\param buf_size : size of the buffer
\param ld_config_ptr : pointer to the Load Config Directory within the given PE
\return detected version of Load Config Directory
*/
t_load_config_ver get_load_config_version(BYTE* buffer, size_t buf_size, BYTE* ld_config_ptr);
}; // namespace peconv

View File

@@ -0,0 +1,48 @@
/**
* @file
* @brief Dumping PE from the memory buffer into a file.
*/
#pragma once
#include <windows.h>
#include "exports_mapper.h"
namespace peconv {
/**
A mode in which the PE fille be dumped.
*/
typedef enum {
PE_DUMP_AUTO = 0, /**< autodetect which dump mode is the most suitable for the given input */
PE_DUMP_VIRTUAL,/**< dump as it is in the memory (virtual) */
PE_DUMP_UNMAP, /**< convert to the raw format: using raw sections' headers */
PE_DUMP_REALIGN, /**< convert to the raw format: by realigning raw sections' headers to be the same as virtual (useful if the PE was unpacked in memory) */
PE_DUMP_MODES_COUNT /**< total number of the dump modes */
} t_pe_dump_mode;
/**
Detect dump mode that is the most suitable for the given input.
\param buffer : the buffer containing the PE to be dumped.
\param buffer_size : the size of the given buffer
*/
t_pe_dump_mode detect_dump_mode(IN const BYTE* buffer, IN size_t buffer_size);
/**
Dumps PE from the fiven buffer into a file. It expects the module base and size to be given.
\param outputFilePath : name of the file where the dump should be saved
\param buffer : the buffer containing the PE to be dumped. WARNING: the buffer may be preprocessed before dumping.
\param buffer_size : the size of the given buffer
\param module_base : the base to which the PE buffer was relocated
\param dump_mode : specifies in which format the PE should be dumped. If the mode was set to PE_DUMP_AUTO, it autodetects mode and returns the detected one.
\param exportsMap : optional. If exportsMap is supplied, it will try to recover destroyed import table of the PE, basing on the supplied map of exported functions.
*/
bool dump_pe(IN const char *outputFilePath,
IN OUT BYTE* buffer,
IN size_t buffer_size,
IN const ULONGLONG module_base,
IN OUT t_pe_dump_mode &dump_mode,
IN OPTIONAL const peconv::ExportsMapper* exportsMap = nullptr
);
};// namespace peconv

View File

@@ -0,0 +1,232 @@
/**
* @file
* @brief Wrappers over various fields in the PE header. Read, write, parse PE headers.
*/
#pragma once
#include <windows.h>
#include "buffer_util.h"
#ifndef PAGE_SIZE
#define PAGE_SIZE 0x1000
#endif
#define MASK_TO_DWORD(val) (val & 0xffffffff)
#define MASK_TO_WORD(val) (val & 0xffff)
namespace peconv {
/**
Maximal size of the PE header.
*/
const ULONGLONG MAX_HEADER_SIZE = PAGE_SIZE;
/**
Fetch image size from headers.
*/
DWORD get_image_size(IN const BYTE *payload);
/**
Change the Image Size in Optional Header to the given one.
*/
bool update_image_size(IN OUT BYTE* payload, IN DWORD new_img_size);
/**
Fetch architecture from the NT headers. Checks for bad pointers.
*/
WORD get_nt_hdr_architecture(IN const BYTE *pe_buffer);
/**
Wrapper for get_nt_hdr_architecture. Returns true if the PE file is 64 bit.
*/
bool is64bit(IN const BYTE *pe_buffer);
/**
Fetch pointer to the NT headers of the PE file.
Checks for bad pointers. If buffer_size is set, validates pointers against the buffer size.
*/
BYTE* get_nt_hdrs(
IN const BYTE *pe_buffer,
IN OPTIONAL size_t buffer_size=0 //if buffer_size=0 means size unknown
);
/**
Wrapper for get_nt_headers. Automatically detects if the PE is 32 bit - if not, returns null pointer.
*/
IMAGE_NT_HEADERS32* get_nt_hdrs32(IN const BYTE *pe_buffer);
/**
Wrapper for get_nt_headers. Automatically detects if the PE is 64 bit - if not, returns null pointer.
*/
IMAGE_NT_HEADERS64* get_nt_hdrs64(IN const BYTE *pe_buffer);
/**
Fetches optional header of the PE. Validates pointers against buffer size.
*/
LPVOID get_optional_hdr(IN const BYTE* payload, IN const size_t buffer_size);
/**
Fetches file header of the PE. Validates pointers against buffer size.
*/
const IMAGE_FILE_HEADER* get_file_hdr(
IN const BYTE* payload,
IN const size_t buffer_size
);
/**
Fetch the size of headers (from Optional Header).
*/
DWORD get_hdrs_size(IN const BYTE *pe_buffer);
/**
get Data Directory entry of the given number. If the entry is not filled and allow_empty is not set, it returns null pointer.
*/
IMAGE_DATA_DIRECTORY* get_directory_entry(IN const BYTE* pe_buffer, IN DWORD dir_id, IN bool allow_empty = false);
/**
Get pointer to the Data Directory content of the given number. Automatically cast to the chosen type.
*/
template <typename IMAGE_TYPE_DIRECTORY>
IMAGE_TYPE_DIRECTORY* get_type_directory(IN HMODULE modulePtr, IN DWORD dir_id)
{
IMAGE_DATA_DIRECTORY *my_dir = peconv::get_directory_entry((const BYTE*)modulePtr, dir_id);
if (!my_dir) return nullptr;
DWORD dir_addr = my_dir->VirtualAddress;
if (dir_addr == 0) return nullptr;
return (IMAGE_TYPE_DIRECTORY*)(dir_addr + (ULONG_PTR)modulePtr);
}
/**
Get pointer to the Export Directory.
*/
IMAGE_EXPORT_DIRECTORY* get_export_directory(IN HMODULE modulePtr);
// Fetch Image Base from Optional Header.
ULONGLONG get_image_base(IN const BYTE *pe_buffer);
/**
Change the Image Base in Optional Header to the given one.
*/
bool update_image_base(IN OUT BYTE* payload, IN ULONGLONG destImageBase);
/**
Get RVA of the Entry Point from the Optional Header.
*/
DWORD get_entry_point_rva(IN const BYTE *pe_buffer);
/**
Change the Entry Point RVA in the Optional Header to the given one.
*/
bool update_entry_point_rva(IN OUT BYTE *pe_buffer, IN DWORD ep);
/**
Get number of sections from the File Header. It does not validate if this the actual number.
*/
size_t get_sections_count(
IN const BYTE* buffer,
IN const size_t buffer_size
);
/**
Checks if the section headers are reachable. It does not validate sections alignment.
*/
bool is_valid_sections_hdr_offset(IN const BYTE* buffer, IN const size_t buffer_size);
/**
Gets pointer to the section header of the given number.
*/
PIMAGE_SECTION_HEADER get_section_hdr(
IN const BYTE* pe_buffer,
IN const size_t buffer_size,
IN size_t section_num
);
/**
Fetch the PE Characteristics from the File Header.
*/
WORD get_file_characteristics(IN const BYTE* payload);
/**
Check if the module is a DLL (basing on the Characteristcs in the header).
*/
bool is_module_dll(IN const BYTE* payload);
/**
Fetch the DLL Characteristics from the Optional Header.
*/
WORD get_dll_characteristics(IN const BYTE* payload);
/**
Set the PE subsystem in the header.
*/
bool set_subsystem(IN OUT BYTE* payload, IN WORD subsystem);
/**
Get the PE subsystem from the header.
*/
WORD get_subsystem(IN const BYTE* payload);
/**
Check if the PE has relocations Data Directory.
*/
bool has_relocations(IN const BYTE *pe_buffer);
/**
Fetch the pointer to the .NET header (if exist).
*/
IMAGE_COR20_HEADER* get_dotnet_hdr(
IN const BYTE* pe_buffer,
IN size_t const buffer_size,
IN const IMAGE_DATA_DIRECTORY* dotNetDir
);
/**
Fetch section aligmenent from headers. Depending on the flag, it fetches either Raw Alignment or Virtual Alignment.
*/
DWORD get_sec_alignment(IN const BYTE* modulePtr, IN bool is_raw);
/**
Change section aligmenent in headers. Depending on the flag, it sets either Raw Alignment or Virtual Alignment.
*/
bool set_sec_alignment(IN OUT BYTE* pe_buffer, IN bool is_raw, IN DWORD new_alignment);
/**
Get size of virtual section from the headers (optionaly rounds it up to the Virtual Alignment)
*/
DWORD get_virtual_sec_size(
IN const BYTE* pe_hdr,
IN const PIMAGE_SECTION_HEADER sec_hdr,
IN bool rounded //if set, it rounds it up to the Virtual Alignment
);
/**
Get the last section (in a raw or virtual alignment)
\param pe_buffer : buffer with a PE
\param pe_size : size of the given PE
\param is_raw : If true, give the section with the highest Raw offset. If false, give the section with the highest Virtual offset.
*/
PIMAGE_SECTION_HEADER get_last_section(IN const PBYTE pe_buffer, IN size_t pe_size, IN bool is_raw);
/**
Calculate full PE size (raw or virtual) using information from sections' headers. WARNING: it drops an overlay.
\param pe_buffer : a buffer containing a PE
\param pe_size : the size of the given buffer
\param is_raw : If true, the Raw alignment is used. If false, the Virtual alignment is used.
*/
DWORD calc_pe_size(
IN const PBYTE pe_buffer,
IN size_t pe_size,
IN bool is_raw
);
/**
Walk through sections headers checking if the sections beginnings and sizes are fitting the alignment (Virtual or Raw)
\param buffer : a buffer containing a PE
\param buffer_size : the size of the given buffer
\param is_raw : If true, the Raw alignment is checked. If false, the Virtual alignment is checked.
*/
bool is_valid_sectons_alignment(IN const BYTE* buffer, IN const SIZE_T buffer_size, IN bool is_raw);
}; // namespace peconv

View File

@@ -0,0 +1,42 @@
/**
* @file
* @brief Loading PE from a file with the help of the custom loader.
*/
#pragma once
#include "pe_raw_to_virtual.h"
#include "function_resolver.h"
namespace peconv {
/**
Reads PE from the given buffer into memory and maps it into vitual format.
(Automatic raw to virtual conversion).
If the executable flag is true, the PE file is loaded into executable memory.
If the relocate flag is true, applies relocations. Does not load imports.
Automatically allocates buffer of the needed size (the size is returned in outputSize). The buffer can be freed by the function free_pe_buffer.
*/
BYTE* load_pe_module(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, bool executable, bool relocate);
/**
Reads PE from the given file into memory and maps it into vitual format.
(Automatic raw to virtual conversion).
If the executable flag is true, the PE file is loaded into executable memory.
If the relocate flag is true, applies relocations. Does not load imports.
Automatically allocates buffer of the needed size (the size is returned in outputSize). The buffer can be freed by the function free_pe_buffer.
*/
BYTE* load_pe_module(const char *filename, OUT size_t &v_size, bool executable, bool relocate);
/**
Loads full PE from the raw buffer in a way in which it can be directly executed: remaps to virual format, applies relocations, loads imports.
Allows for supplying custom function resolver.
*/
BYTE* load_pe_executable(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, t_function_resolver* import_resolver=NULL);
/**
Loads full PE from file in a way in which it can be directly executed: remaps to virual format, applies relocations, loads imports.
Allows for supplying custom function resolver.
*/
BYTE* load_pe_executable(const char *filename, OUT size_t &v_size, t_function_resolver* import_resolver=NULL);
};// namespace peconv

View File

@@ -0,0 +1,46 @@
/**
* @file
* @brief Detecting in which mode is the PE in the supplied buffer (i.e. raw, virtual). Analyzes PE features typical for particular modes.
*/
#pragma once
#include <windows.h>
#include "pe_hdrs_helper.h"
namespace peconv {
/**
check if the PE in the memory is in raw format
*/
bool is_pe_raw(
IN const BYTE* pe_buffer,
IN size_t pe_size
);
/**
check if Virtual section addresses are identical to Raw addresses (i.e. if the PE was realigned)
*/
bool is_pe_raw_eq_virtual(
IN const BYTE* pe_buffer,
IN size_t pe_size
);
/**
checks if the PE has sections that were unpacked/expanded in the memory
*/
bool is_pe_expanded(
IN const BYTE* pe_buffer,
IN size_t pe_size
);
/**
checks if the given section was unpacked in the memory
*/
bool is_section_expanded(IN const BYTE* pe_buffer,
IN size_t pe_size,
IN const PIMAGE_SECTION_HEADER sec
);
};// namespace peconv

View File

@@ -0,0 +1,30 @@
/**
* @file
* @brief Converting PE from raw to virtual format.
*/
#pragma once
#include <windows.h>
#include <stdio.h>
#include "buffer_util.h"
namespace peconv {
/**
Converts a raw PE supplied in a buffer to a virtual format.
If the executable flag is true (default), the PE file is loaded into executable memory.
Does not apply relocations. Does not load imports.
Automatically allocates buffer of the needed size (the size is returned in outputSize). The buffer can be freed by the function free_pe_module.
If the desired_base is defined (0 by default), it enforces allocation at the particular base.
*/
BYTE* pe_raw_to_virtual(
IN const BYTE* rawPeBuffer,
IN size_t rawPeSize,
OUT size_t &outputSize,
IN OPTIONAL bool executable = true,
IN OPTIONAL ULONGLONG desired_base = 0
);
}; // namespace peconv

View File

@@ -0,0 +1,47 @@
/**
* @file
* @brief Converting PE from virtual to raw format.
*/
#pragma once
#include <windows.h>
#include "buffer_util.h"
namespace peconv {
/**
Maps virtual image of PE to into raw. Automaticaly applies relocations.
Automatically allocates buffer of the needed size (the size is returned in outputSize).
\param payload : the PE in the Virtual format that needs to be converted into the Raw format
\param in_size : size of the input buffer (the PE in the Virtual format)
\param loadBase : the base to which the given PE was relocated
\param outputSize : the size of the output buffer (the PE in the Raw format)
\param rebuffer : if set (default), the input buffer is rebuffered and the original buffer is not modified.
\return a buffer of the outputSize, containing the Raw PE. The buffer can be freed by the function free_pe_module.
*/
BYTE* pe_virtual_to_raw(
IN BYTE* payload,
IN size_t in_size,
IN ULONGLONG loadBase,
OUT size_t &outputSize,
IN OPTIONAL bool rebuffer=true
);
/*
Modifies raw alignment of the PE to be the same as virtual alignment.
\param payload : the PE in the Virtual format that needs to be realigned
\param in_size : size of the input buffer
\param loadBase : the base to which the given PE was relocated
\param outputSize : the size of the output buffer (the PE in the Raw format)
\return a buffer of the outputSize, containing the realigned PE. The buffer can be freed by the function free_pe_module.
*/
BYTE* pe_realign_raw_to_virtual(
IN const BYTE* payload,
IN size_t in_size,
IN ULONGLONG loadBase,
OUT size_t &outputSize
);
};//namespace peconv

View File

@@ -0,0 +1,40 @@
/**
* @file
* @brief Functions for retrieving process information from PEB.
*/
#pragma once
#include <windows.h>
namespace peconv {
/**
Gets handle to the given module via PEB. A low-level equivalent of `GetModuleHandleW`.
\param module_name : (optional) the name of the DLL loaded within the current process. If not set, the main module of the current process is used.
\return the handle of the DLL with given name, or, if the name was not given, the handle of the main module of the current process.
*/
HMODULE get_module_via_peb(IN OPTIONAL LPWSTR module_name = nullptr);
/**
Gets size of the given module via PEB.
\param hModule : (optional) the base of the module which's size we want to retrieve. If not set, the main module of the current process is used.
\return the size of the given module.
*/
size_t get_module_size_via_peb(IN OPTIONAL HMODULE hModule = nullptr);
/**
Sets the given module as the main module in the current PEB.
\param hModule : the module to be connected to the current PEB.
\return true if succeeded, false if failed
*/
bool set_main_module_in_peb(HMODULE hModule);
/**
Gets the main module from the current PEB.
\return the main module connected to the current PEB.
*/
HMODULE get_main_module_via_peb();
};

View File

@@ -0,0 +1,51 @@
/**
* @file
* @brief Operating on PE file's relocations table.
*/
#pragma once
#include <windows.h>
namespace peconv {
typedef struct _BASE_RELOCATION_ENTRY {
WORD Offset : 12;
WORD Type : 4;
} BASE_RELOCATION_ENTRY;
class RelocBlockCallback
{
public:
RelocBlockCallback(bool _is64bit)
: is64bit(_is64bit)
{
}
virtual bool processRelocField(ULONG_PTR relocField) = 0;
protected:
bool is64bit;
};
// Processs the relocation table and make your own callback on each relocation field
bool process_relocation_table(IN PVOID modulePtr, IN SIZE_T moduleSize, IN RelocBlockCallback *callback);
/**
Applies relocations on the PE in virtual format. Relocates it from the old base given to the new base given.
If 0 was supplied as the old base, it assumes that the old base is the ImageBase given in the header.
\param modulePtr : a buffer containing the PE to be relocated
\param moduleSize : the size of the given PE buffer
\param newBase : a base to which the PE should be relocated
\param oldBase : a base to which the PE is currently relocated (if not set, the imageBase from the header will be used)
*/
bool relocate_module(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase = 0);
/**
Checks if the given PE has a valid relocations table.
\param modulePtr : a buffer containing the PE to be checked
\param moduleSize : the size of the given PE buffer
*/
bool has_valid_relocation_table(IN const PBYTE modulePtr, IN const size_t moduleSize);
};//namespace peconv

View File

@@ -0,0 +1,93 @@
/**
* @file
* @brief Reading from a PE module that is loaded within a remote process.
*/
#pragma once
#include <windows.h>
#include "pe_hdrs_helper.h"
#include "pe_virtual_to_raw.h"
#include "exports_mapper.h"
#include "pe_dumper.h"
namespace peconv {
bool fetch_region_info(HANDLE processHandle, BYTE* start_addr, MEMORY_BASIC_INFORMATION &page_info);
/**
Fetch size of the memory region starting from the given address.
*/
size_t fetch_region_size(HANDLE processHandle, BYTE* start_addr);
/**
Fetch the allocation base of the memory region with the supplied start address.
\param processHandle : handle of the process where the region of interest belongs
\param start_addr : the address inside the region of interest
\return the allocation base address of the memory region, or 0 if not found
*/
ULONGLONG fetch_alloc_base(HANDLE processHandle, BYTE* start_addr);
/**
Wrapper over ReadProcessMemory. Requires a handle with privilege PROCESS_VM_READ.
If reading full buffer_size was not possible, it will keep trying to read smaller chunk,
decreasing requested size by step_size in each iteration. Returns how many bytes were successfuly read.
It is a workaround for errors such as FAULTY_HARDWARE_CORRUPTED_PAGE.
*/
size_t read_remote_memory(HANDLE processHandle, BYTE *start_addr, OUT BYTE* buffer, const size_t buffer_size, const SIZE_T step_size = 0x100);
/**
Reads the full memory area of a given size within a given process, skipping inaccessible pages.
Requires a handle with privilege PROCESS_QUERY_INFORMATION.
step_size is passed to the underlying read_remote_memory.
*/
size_t read_remote_area(HANDLE processHandle, BYTE *start_addr, OUT BYTE* buffer, const size_t buffer_size, const SIZE_T step_size = 0x100);
/**
Reads a PE header of the remote module within the given process. Requires a valid output buffer to be supplied (buffer).
*/
bool read_remote_pe_header(HANDLE processHandle, BYTE *moduleBase, OUT BYTE* buffer, const size_t bufferSize);
/**
Reads a PE section with a given number (sectionNum) from the remote module within the given process.
The buffer of appropriate size is automatically allocated. After use, it should be freed by the function free_unaligned.
The size of the buffer is writen into sectionSize.
\param processHandle : the handle to the remote process
\param moduleBase : the base address of the module
\param sectionNum : number of the section to be read
\param sectionSize : the size of the read section (output)
\param roundup : if set, the section size is roundup to the alignment unit
\return a buffer containing a copy of the section.
*/
peconv::UNALIGNED_BUF get_remote_pe_section(HANDLE processHandle, BYTE *moduleBase, const size_t sectionNum, OUT size_t &sectionSize, bool roundup = false);
/**
Reads PE file from the remote process into the supplied buffer. It expects the module base and size to be given.
*/
size_t read_remote_pe(const HANDLE processHandle, BYTE *moduleBase, const size_t moduleSize, OUT BYTE* buffer, const size_t bufferSize);
/**
Dumps PE from the remote process into a file. It expects the module base and size to be given.
\param outputFilePath : the path where the dump will be saved
\param processHandle : the handle to the remote process
\param moduleBase : the base address of the module that needs to be dumped
\param dump_mode : specifies in which format the PE should be dumped. If the mode was set to PE_DUMP_AUTO, it autodetects mode and returns the detected one.
\param exportsMap : optional. If exportsMap is supplied, it will try to recover destroyed import table of the PE, basing on the supplied map of exported functions.
*/
bool dump_remote_pe(
IN const char *outputFilePath,
IN const HANDLE processHandle,
IN BYTE *moduleBase,
IN OUT t_pe_dump_mode &dump_mode,
IN OPTIONAL peconv::ExportsMapper* exportsMap = nullptr
);
/**
Retrieve the Image Size saved in the header of the remote PE.
\param processHandle : process from where we are reading
\param start_addr : a base address of the PE within the given process
*/
DWORD get_remote_image_size(IN const HANDLE processHandle, IN BYTE *start_addr);
}; //namespace peconv

View File

@@ -0,0 +1,25 @@
/**
* @file
* @brief Parsing PE's resource directory.
*/
#pragma once
#include <windows.h>
namespace peconv {
/**
A callback that will be executed by the function parse_resources when the Resource Entry was found.
*/
typedef bool(*t_on_res_entry_found) (
BYTE* modulePtr,
IMAGE_RESOURCE_DIRECTORY_ENTRY *root_dir,
IMAGE_RESOURCE_DATA_ENTRY *curr_entry
);
/**
A function walking through the Resource Tree of the given PE. On each Resource Entry found, the callback is executed.
\param modulePtr : pointer to the buffer with the PE in a Virtual format
\param on_entry : a callback function executed on each Resource Entry
*/
bool parse_resources(BYTE* modulePtr, t_on_res_entry_found on_entry);
};

View File

@@ -0,0 +1,34 @@
/**
* @file
* @brief Functions related to manual retrieving of PE resources.
*/
#pragma once
#include <windows.h>
#include "buffer_util.h"
namespace peconv {
const LPSTR RT_RCDATA_A = MAKEINTRESOURCEA(10);
/**
Maps a resource with the given id + type and copies its raw content into the output buffer.
If out_size is not zero, it reads maximum out_size of bytes. If out_size is zero, it reads the full resource.
The actual read size is returned back in out_size.
Automatically allocates a buffer of the required size.
If hInstance is NULL, it search the resource in the current module. Otherwise, it search in the given module.
*/
peconv::ALIGNED_BUF load_resource_data(OUT size_t &out_size, const int res_id, const LPSTR res_type = RT_RCDATA_A, HMODULE hInstance = nullptr);
/**
Free the buffer with PE Resources, mapped by the function load_resource_data.
*/
void free_resource_data(peconv::ALIGNED_BUF buffer);
/**
a helper function to get the module handle of the current DLL
*/
HMODULE get_current_module_handle();
}; //namespace peconv

View File

@@ -0,0 +1,25 @@
/**
* @file
* @brief Miscellaneous utility functions.
*/
#pragma once
#include "file_util.h"
#include "resource_util.h"
namespace peconv {
/**
Checks if the given buffer is fully filled with the specified character.
\param cave_ptr : pointer to the buffer to be checked
\param cave_size : size of the buffer to be checked
\param padding_char : the required character
*/
bool is_padding(const BYTE *cave_ptr, size_t cave_size, const BYTE padding_char);
/**
Wrapper for GetProcessId - for a backward compatibility with old versions of Windows
*/
DWORD get_process_id(HANDLE hProcess);
};

View File

@@ -0,0 +1,87 @@
#include "peconv/buffer_util.h"
#include <iostream>
//
// validate pointer:
//
bool peconv::validate_ptr(IN const void* buffer_bgn, IN SIZE_T buffer_size, IN const void* field_bgn, IN SIZE_T field_size)
{
if (buffer_bgn == nullptr || field_bgn == nullptr) {
return false;
}
BYTE* _start = (BYTE*)buffer_bgn;
BYTE* _end = _start + buffer_size;
BYTE* _field_start = (BYTE*)field_bgn;
BYTE* _field_end = (BYTE*)field_bgn + field_size;
if (_field_start < _start) {
return false;
}
if (_field_end > _end) {
return false;
}
return true;
}
//-----------------------------------------------------------------------------------
//
// alloc/free unaligned buffers:
//
//allocates a buffer that does not have to start from the beginning of the section
peconv::UNALIGNED_BUF peconv::alloc_unaligned(size_t buf_size)
{
if (!buf_size) return NULL;
UNALIGNED_BUF buf = (UNALIGNED_BUF) calloc(buf_size, sizeof(BYTE));
return buf;
}
void peconv::free_unaligned(peconv::UNALIGNED_BUF section_buffer)
{
free(section_buffer);
}
//
// alloc/free aligned buffers:
//
peconv::ALIGNED_BUF peconv::alloc_aligned(size_t buffer_size, DWORD protect, ULONGLONG desired_base, bool is_x64)
{
if (!buffer_size) return NULL;
ALIGNED_BUF buf = (ALIGNED_BUF)VirtualAlloc((LPVOID)desired_base, buffer_size, MEM_COMMIT | MEM_RESERVE, protect);
return buf;
}
bool peconv::free_aligned(peconv::ALIGNED_BUF buffer, size_t buffer_size)
{
if (buffer == nullptr) return true;
if (!VirtualFree(buffer, 0, MEM_RELEASE)) {
#ifdef _DEBUG
std::cerr << "Releasing failed" << std::endl;
#endif
return false;
}
return true;
}
//-----------------------------------------------------------------------------------
//
// wrappers using appropriate buffer type according to the purpose:
//
// allocate a buffer for PE module:
peconv::ALIGNED_BUF peconv::alloc_pe_buffer(size_t buffer_size, DWORD protect, ULONGLONG desired_base)
{
return alloc_aligned(buffer_size, protect, desired_base);
}
// Free loaded PE module
bool peconv::free_pe_buffer(peconv::ALIGNED_BUF buffer, size_t buffer_size)
{
return peconv::free_aligned(buffer, buffer_size);
}

View File

@@ -0,0 +1,139 @@
#include "peconv/caves.h"
#include "peconv/pe_hdrs_helper.h"
#include "peconv/util.h"
using namespace peconv;
#ifdef _DEBUG
#include <iostream>
#endif
PBYTE peconv::find_ending_cave(BYTE*modulePtr, size_t moduleSize, const DWORD minimal_size, const DWORD req_charact)
{
size_t sec_count = peconv::get_sections_count(modulePtr, moduleSize);
if (sec_count == 0) return nullptr;
size_t last_sec = sec_count - 1;
PIMAGE_SECTION_HEADER section_hdr = peconv::get_section_hdr(modulePtr, moduleSize, last_sec);
if (section_hdr == nullptr) return nullptr;
if (!(section_hdr->Characteristics & req_charact)) return nullptr;
DWORD raw_size = section_hdr->SizeOfRawData;
DWORD virtual_size = (DWORD)moduleSize - section_hdr->VirtualAddress;
if (raw_size >= virtual_size) {
#ifdef _DEBUG
std::cout << "Last section's raw_size: " << std::hex << raw_size << " >= virtual_size: " << virtual_size << std::endl;
#endif
return nullptr;
}
DWORD cave_size = virtual_size - raw_size;
if (cave_size < minimal_size) {
#ifdef _DEBUG
std::cout << "Cave is too small" << std::endl;
#endif
return nullptr;
}
PBYTE cave_ptr = modulePtr + section_hdr->VirtualAddress + section_hdr->SizeOfRawData;
if (!validate_ptr(modulePtr, moduleSize, cave_ptr, minimal_size)) {
#ifdef _DEBUG
std::cout << "Invalid cave pointer" << std::endl;
#endif
return nullptr;
}
section_hdr->SizeOfRawData += minimal_size; //book this cave
return cave_ptr;
}
PBYTE peconv::find_alignment_cave(BYTE* modulePtr, size_t moduleSize, const DWORD minimal_size, const DWORD req_charact)
{
DWORD alignment = peconv::get_sec_alignment(modulePtr, true);
if (alignment == 0) return nullptr;
size_t sec_count = peconv::get_sections_count(modulePtr, moduleSize);
for (size_t i = 0; i < sec_count; i++) {
PIMAGE_SECTION_HEADER section_hdr = peconv::get_section_hdr(modulePtr, moduleSize, i);
if (section_hdr == nullptr) continue;
if (!(section_hdr->Characteristics & req_charact)) continue;
DWORD rem = section_hdr->SizeOfRawData % alignment;
if (rem == 0) continue;
DWORD div = (section_hdr->SizeOfRawData / alignment) + 1;
DWORD new_size = div * alignment;
DWORD cave_size = new_size - section_hdr->SizeOfRawData;
if (cave_size < minimal_size) {
#ifdef __DEBUG
std::cout << "Cave is too small" << std::endl;
#endif
continue;
}
DWORD sec_start = section_hdr->PointerToRawData;
if (sec_start == 0) continue;
DWORD sec_end = sec_start + section_hdr->SizeOfRawData;
#ifdef _DEBUG
std::cout << "section: " << std::hex << sec_start << " : " << sec_end << std::endl;
#endif
PBYTE cave_ptr = modulePtr + sec_end;
if (!validate_ptr(modulePtr, moduleSize, cave_ptr, minimal_size)) {
#ifdef _DEBUG
std::cout << "Invalid cave pointer" << std::endl;
#endif
continue;
}
section_hdr->SizeOfRawData += minimal_size; //book this cave
return cave_ptr;
}
#ifdef _DEBUG
std::cout << "Cave not found" << std::endl;
#endif
return nullptr;
}
PBYTE peconv::find_padding_cave(BYTE* modulePtr, size_t moduleSize, const size_t minimal_size, const DWORD req_charact)
{
size_t sec_count = peconv::get_sections_count(modulePtr, moduleSize);
for (size_t i = 0; i < sec_count; i++) {
PIMAGE_SECTION_HEADER section_hdr = peconv::get_section_hdr(modulePtr, moduleSize, i);
if (section_hdr == nullptr) continue;
if (!(section_hdr->Characteristics & req_charact)) continue;
if (section_hdr->SizeOfRawData < minimal_size) continue;
// we will be searching in the loaded, virtual image:
DWORD sec_start = section_hdr->VirtualAddress;
if (sec_start == 0) continue;
DWORD sec_end = sec_start + section_hdr->SizeOfRawData;
#ifdef _DEBUG
std::cout << "section: " << std::hex << sec_start << " : " << sec_end << std::endl;
#endif
//offset from the end of the section:
size_t cave_offset = section_hdr->SizeOfRawData - minimal_size;
PBYTE cave_ptr = modulePtr + sec_start + cave_offset;
if (!validate_ptr(modulePtr, moduleSize, cave_ptr, minimal_size)) {
#ifdef _DEBUG
std::cout << "Invalid cave pointer" << std::endl;
#endif
continue;
}
bool found = false;
if (is_padding(cave_ptr, minimal_size, 0)) {
found = true;
}
//if the section is code, check also code padding:
if (section_hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
if (is_padding(cave_ptr, minimal_size, 0xCC)) {
found = true;
}
}
if (found) {
return cave_ptr;
}
}
#ifdef _DEBUG
std::cout << "Cave not found" << std::endl;
#endif
return nullptr;
}

View File

@@ -0,0 +1,200 @@
#include "peconv/delayed_imports_loader.h"
#include "peconv/imports_loader.h"
#include <iostream>
IMAGE_DELAYLOAD_DESCRIPTOR* peconv::get_delayed_imps(IN const BYTE* modulePtr, IN const size_t moduleSize, OUT size_t &dir_size)
{
dir_size = 0;
IMAGE_DATA_DIRECTORY *d_imps_dir = peconv::get_directory_entry(modulePtr, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
if (!d_imps_dir) {
return nullptr;
}
BYTE* dimps_table = (BYTE*)((ULONGLONG) modulePtr + d_imps_dir->VirtualAddress);
const size_t min_size = sizeof(IMAGE_DELAYLOAD_DESCRIPTOR);
if (d_imps_dir->Size < min_size) {
return nullptr;
}
if (!peconv::validate_ptr((LPVOID)modulePtr, moduleSize, dimps_table, min_size)) {
return nullptr;
}
dir_size = d_imps_dir->Size;
return reinterpret_cast<IMAGE_DELAYLOAD_DESCRIPTOR*> (dimps_table);
}
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
bool parse_delayed_desc(BYTE* modulePtr, const size_t moduleSize,
const ULONGLONG img_base,
LPSTR lib_name,
const T_FIELD ordinal_flag,
IMAGE_DELAYLOAD_DESCRIPTOR *desc,
peconv::t_function_resolver* func_resolver
)
{
ULONGLONG iat_addr = desc->ImportAddressTableRVA;
if (iat_addr > img_base) iat_addr -= img_base; // it may be either RVA or VA
ULONGLONG thunk_addr = desc->ImportNameTableRVA;
if (thunk_addr > img_base) thunk_addr -= img_base; // it may be either RVA or VA
T_FIELD* record_va = (T_FIELD*)((ULONGLONG)modulePtr + iat_addr);
T_IMAGE_THUNK_DATA* thunk_va = (T_IMAGE_THUNK_DATA*)((ULONGLONG)modulePtr + thunk_addr);
for (; *record_va != NULL && thunk_va != NULL; record_va++, thunk_va++) {
if (!peconv::validate_ptr(modulePtr, moduleSize, record_va, sizeof(T_FIELD))) {
return false;
}
if (!peconv::validate_ptr(modulePtr, moduleSize, thunk_va, sizeof(T_FIELD))) {
return false;
}
T_FIELD iat_va = *record_va;
ULONGLONG iat_rva = (ULONGLONG)iat_va;
if (iat_va > img_base) iat_rva -= img_base; // it may be either RVA or VA
#ifdef _DEBUG
std::cout << std::hex << iat_rva << " : ";
#endif
T_FIELD* iat_record_ptr = (T_FIELD*)((ULONGLONG)modulePtr + iat_rva);
if (!peconv::validate_ptr(modulePtr, moduleSize, iat_record_ptr, sizeof(T_FIELD))) {
return false;
}
FARPROC hProc = nullptr;
if (thunk_va->u1.Ordinal & ordinal_flag) {
T_FIELD raw_ordinal = thunk_va->u1.Ordinal & (~ordinal_flag);
#ifdef _DEBUG
std::cout << std::hex << "ord: " << raw_ordinal << " ";
#endif
hProc = func_resolver->resolve_func(lib_name, MAKEINTRESOURCEA(raw_ordinal));
}
else {
ULONGLONG name_rva = thunk_va->u1.AddressOfData;
if (name_rva > img_base) {
name_rva -= img_base;
}
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + name_rva);
LPSTR func_name = reinterpret_cast<LPSTR>(by_name->Name);
if (!peconv::is_valid_import_name(modulePtr, moduleSize, func_name)) {
continue;
}
#ifdef _DEBUG
std::cout << func_name << " ";
#endif
hProc = func_resolver->resolve_func(lib_name, func_name);
}
if (hProc) {
//rather than loading it via proxy function, we just overwrite the thunk like normal IAT:
*record_va = (T_FIELD) hProc;
#ifdef _DEBUG
std::cout << "[OK]\n";
#endif
}
else {
#ifdef _DEBUG
std::cout << "[NOPE]\n";
#endif
}
}
return true;
}
bool peconv::load_delayed_imports(BYTE* modulePtr, ULONGLONG moduleBase, t_function_resolver* func_resolver)
{
const bool is_64bit = peconv::is64bit(modulePtr);
const size_t module_size = peconv::get_image_size(modulePtr);
default_func_resolver default_res;
if (!func_resolver) {
func_resolver = (t_function_resolver*)&default_res;
}
size_t table_size = 0;
IMAGE_DELAYLOAD_DESCRIPTOR* first_desc = get_delayed_imps(modulePtr, module_size, table_size);
if (!first_desc) {
return false;
}
#ifdef _DEBUG
std::cout << "OK, table_size = " << table_size << std::endl;
#endif
size_t max_count = table_size / sizeof(IMAGE_DELAYLOAD_DESCRIPTOR);
for (size_t i = 0; i < max_count; i++) {
IMAGE_DELAYLOAD_DESCRIPTOR* desc = &first_desc[i];
if (!validate_ptr(modulePtr, module_size, desc, sizeof(IMAGE_DELAYLOAD_DESCRIPTOR))) break;
if (desc->DllNameRVA == NULL) {
break;
}
ULONGLONG dll_name_rva = desc->DllNameRVA;
if (dll_name_rva > moduleBase) {
dll_name_rva -= moduleBase;
}
char* dll_name = (char*)((ULONGLONG)modulePtr + dll_name_rva);
if (!validate_ptr(modulePtr, module_size, dll_name, sizeof(char))) continue;
#ifdef _DEBUG
std::cout << dll_name << std::endl;
#endif
if (is_64bit) {
return parse_delayed_desc<ULONGLONG, IMAGE_THUNK_DATA64>(modulePtr, module_size, moduleBase, dll_name, IMAGE_ORDINAL_FLAG64, desc, func_resolver);
}
else {
return parse_delayed_desc<DWORD, IMAGE_THUNK_DATA32>(modulePtr, module_size, moduleBase, dll_name, IMAGE_ORDINAL_FLAG32, desc, func_resolver);
}
}
return true;
}
/*
bool peconv::load_delayed_imports(BYTE* modulePtr, ULONGLONG moduleBase, t_function_resolver* func_resolver)
{
const bool is_64bit = peconv::is64bit(modulePtr);
bool is_loader64 = false;
#ifdef _WIN64
is_loader64 = true;
#endif
if (is_64bit != is_loader64) {
std::cerr << "[ERROR] Loader/Payload bitness mismatch.\n";
return false;
}
const size_t module_size = peconv::get_image_size(modulePtr);
default_func_resolver default_res;
if (!func_resolver) {
func_resolver = (t_function_resolver*)&default_res;
}
size_t table_size = 0;
IMAGE_DELAYLOAD_DESCRIPTOR *first_desc = get_delayed_imps(modulePtr, module_size, table_size);
if (!first_desc) {
return false;
}
#ifdef _DEBUG
std::cout << "OK, table_size = " << table_size << std::endl;
#endif
size_t max_count = table_size / sizeof(IMAGE_DELAYLOAD_DESCRIPTOR);
for (size_t i = 0; i < max_count; i++) {
IMAGE_DELAYLOAD_DESCRIPTOR *desc = &first_desc[i];
if (!validate_ptr(modulePtr, module_size, desc, sizeof(IMAGE_DELAYLOAD_DESCRIPTOR))) break;
if (desc->DllNameRVA == NULL) {
break;
}
ULONGLONG dll_name_rva = desc->DllNameRVA;
if (dll_name_rva > moduleBase) {
dll_name_rva -= moduleBase;
}
char* dll_name = (char*)((ULONGLONG) modulePtr + dll_name_rva);
if (!validate_ptr(modulePtr, module_size, dll_name, sizeof(char))) continue;
#ifdef _DEBUG
std::cout << dll_name << std::endl;
#endif
if (is_64bit) {
#ifdef _WIN64
parse_delayed_desc<ULONGLONG,IMAGE_THUNK_DATA64>(modulePtr, module_size, moduleBase, dll_name, IMAGE_ORDINAL_FLAG64, desc, func_resolver);
#else
return false;
#endif
}
else {
#ifndef _WIN64
parse_delayed_desc<DWORD, IMAGE_THUNK_DATA32>(modulePtr, module_size, moduleBase, dll_name, IMAGE_ORDINAL_FLAG32, desc, func_resolver);
#else
return false;
#endif
}
}
return true;
}
*/

View File

@@ -0,0 +1,176 @@
#include "peconv/exported_func.h"
#include <algorithm>
#include <sstream>
#include <iomanip>
#include <iostream>
using namespace peconv;
std::string peconv::get_dll_shortname(const std::string& str)
{
std::size_t len = str.length();
std::size_t found = str.find_last_of("/\\");
std::size_t ext = str.find_last_of('.');
if (ext >= len) return "";
std::string name = str.substr(found+1, ext - (found+1));
std::transform(name.begin(), name.end(), name.begin(), tolower);
return name;
}
size_t peconv::forwarder_name_len(BYTE* fPtr)
{
// names can be also mangled, i.e. MSVCRT.??0__non_rtti_object@std@@QAE@ABV01@@Z
bool has_dot = false;
size_t len = 0;
while ((*fPtr >= 'a' && *fPtr <= 'z')
|| (*fPtr >= 'A' && *fPtr <= 'Z')
|| (*fPtr >= '0' && *fPtr <= '9')
|| (*fPtr == '.')
|| (*fPtr == '_')
|| (*fPtr == '#')
|| (*fPtr == '@')
|| (*fPtr == '?')
|| (*fPtr == '-'))
{
if (*fPtr == '.') has_dot = true;
len++;
fPtr++;
}
if (*fPtr == '\0') {
if (!has_dot) {
return 0; //this is not a valid forwarder
}
return len;
}
return 0;
}
std::string peconv::get_func_name(const std::string& str)
{
std::size_t len = str.length();
std::size_t ext = str.find_last_of(".");
if (ext >= len) return "";
std::string name = str.substr(ext+1, len - (ext+1));
return name;
}
std::string peconv::ordinal_to_string(DWORD func_ordinal)
{
std::stringstream stream;
stream << "#";
stream << std::dec << func_ordinal;
return stream.str();
}
bool peconv::is_ordinal_string(const std::string& func_name_str)
{
if (func_name_str.length() < 2) return false;
return (func_name_str[0] == '#');
}
DWORD peconv::ordinal_string_to_val(const std::string& func_name_str)
{
if (!is_ordinal_string(func_name_str)) return 0;
const char* func_name = func_name_str.c_str();
return atoi(func_name + 1);
}
std::string peconv::format_dll_func(const std::string& str)
{
std::string dllName = get_dll_shortname(str);
std::string funcName = get_func_name(str);
if (dllName.length() == 0 || funcName.length() == 0) {
return "";
}
std::transform(dllName.begin(), dllName.end(), dllName.begin(), tolower);
return dllName + "." + funcName;
}
ExportedFunc::ExportedFunc(std::string libName, std::string funcName, DWORD funcOrdinal)
{
this->libName = ExportedFunc::formatName(libName);
this->funcName = funcName;
this->funcOrdinal = funcOrdinal;
this->isByOrdinal = false;
}
ExportedFunc::ExportedFunc(std::string libName, DWORD funcOrdinal)
{
this->libName = ExportedFunc::formatName(libName);
this->funcOrdinal = funcOrdinal;
this->isByOrdinal = true;
}
ExportedFunc::ExportedFunc(const ExportedFunc& other)
{
this->libName = other.libName;
this->funcName = other.funcName;
this->funcOrdinal = other.funcOrdinal;
this->isByOrdinal = other.isByOrdinal;
}
ExportedFunc::ExportedFunc(const std::string &forwarderName)
{
this->libName = get_dll_shortname(forwarderName);
std::string func_name_str = get_func_name(forwarderName);
if (func_name_str.length() < 2) {
this->funcOrdinal = -1;
this->funcName = "";
this->isByOrdinal = false;
#ifdef _DEBUG
std::cerr << "Invalid function data" << std::endl;
#endif
return;
}
if (is_ordinal_string(func_name_str)) {
// it is an ordinal in a string form, i.e.: "COMBASE.#110"
this->funcOrdinal = peconv::ordinal_string_to_val(func_name_str);
this->isByOrdinal = true;
this->funcName = "";
//std::cout << "[O] Adding forwarded func: " << forwarderName << " parsed: " << this->toString() << std::endl;
} else {
this->funcName = func_name_str;
this->isByOrdinal = false;
this->funcOrdinal = 0;
//std::cout << "[N] Adding forwarded func:" << this->toString() << std::endl;
}
}
std::string ExportedFunc::formatName(std::string name)
{
if (name.length() == 0 || name.length() == 0) {
return "";
}
std::transform(name.begin(), name.end(), name.begin(), tolower);
return name;
}
std::string ExportedFunc::toString() const
{
if (!isValid()) {
return "[Invalid func]";
}
std::stringstream stream;
stream << this->libName;
stream << ".";
if (!this->isByOrdinal) {
stream << this->funcName;
stream << " ";
}
stream << ordinal_to_string(this->funcOrdinal);
return stream.str();
}
std::string ExportedFunc::nameToString() const
{
if (!isValid()) {
return "";
}
if (this->isByOrdinal) {
return ordinal_to_string(this->funcOrdinal);
}
return this->funcName;
}

View File

@@ -0,0 +1,193 @@
#include "peconv/exports_lookup.h"
#include <iostream>
/*
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
*/
#ifndef TO_LOWERCASE
#define TO_LOWERCASE(c1) c1 = (c1 <= 'Z' && c1 >= 'A') ? c1 = (c1 - 'A') + 'a': c1;
#endif
bool is_wanted_func(LPSTR curr_name, LPSTR wanted_name)
{
if (curr_name == NULL || wanted_name == NULL) return false;
size_t wanted_name_len = strlen(wanted_name);
size_t curr_name_len = strlen(curr_name);
if (curr_name_len != wanted_name_len) return false;
for (size_t i = 0; i < wanted_name_len; i++) {
char c1 = curr_name[i];
char c2 = wanted_name[i];
TO_LOWERCASE(c1);
TO_LOWERCASE(c2);
if (c1 != c2) return false;
}
return true;
}
bool is_ordinal(IMAGE_EXPORT_DIRECTORY *exp, LPSTR func_name)
{
ULONGLONG base = exp->Base;
ULONGLONG max_ord = base + exp->NumberOfFunctions;
ULONGLONG name_ptr_val = (ULONGLONG)func_name;
if (name_ptr_val >= base && name_ptr_val < max_ord) {
return true;
}
return false;
}
FARPROC get_export_by_ord(PVOID modulePtr, IMAGE_EXPORT_DIRECTORY* exp, DWORD wanted_ordinal)
{
SIZE_T functCount = exp->NumberOfFunctions;
DWORD funcsListRVA = exp->AddressOfFunctions;
DWORD ordBase = exp->Base;
//go through names:
for (DWORD i = 0; i < functCount; i++) {
DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
BYTE* fPtr = (BYTE*) modulePtr + (*funcRVA); //pointer to the function
DWORD ordinal = ordBase + i;
if (ordinal == wanted_ordinal) {
if (peconv::forwarder_name_len(fPtr) > 1) {
std::cerr << "[!] Forwarded function: ["<< wanted_ordinal << " -> "<< fPtr << "] cannot be resolved!" << std::endl;
return NULL; // this function is forwarded, cannot be resolved
}
return (FARPROC) fPtr; //return the pointer to the found function
}
}
return NULL;
}
size_t peconv::get_exported_names(PVOID modulePtr, std::vector<std::string> &names_list)
{
IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
if (exp == 0) return 0;
SIZE_T namesCount = exp->NumberOfNames;
DWORD funcNamesListRVA = exp->AddressOfNames;
//go through names:
SIZE_T i = 0;
for (i = 0; i < namesCount; i++) {
DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
if (IsBadReadPtr(name, 1)) break; // this shoudld not happen. maybe the PE file is corrupt?
names_list.push_back(name);
}
return i;
}
//WARNING: doesn't work for the forwarded functions.
FARPROC peconv::get_exported_func(PVOID modulePtr, LPSTR wanted_name)
{
IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
if (exp == NULL) return NULL;
SIZE_T namesCount = exp->NumberOfNames;
DWORD funcsListRVA = exp->AddressOfFunctions;
DWORD funcNamesListRVA = exp->AddressOfNames;
DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;
if (is_ordinal(exp, wanted_name)) {
#ifdef _DEBUG
std::cerr << "[*] Getting function by ordinal" << std::endl;
#endif
const DWORD ordinal = MASK_TO_DWORD((ULONG_PTR)wanted_name);
return get_export_by_ord(modulePtr, exp, ordinal);
}
if (IsBadReadPtr(wanted_name, 1)) {
std::cerr << "[-] Invalid pointer to the name" << std::endl;
return NULL;
}
//go through names:
for (SIZE_T i = 0; i < namesCount; i++) {
DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*) modulePtr + i * sizeof(WORD));
DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + (*nameIndex) * sizeof(DWORD));
LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
BYTE* fPtr = (BYTE*) modulePtr + (*funcRVA); //pointer to the function
if (!is_wanted_func(name, wanted_name)) {
continue; //this is not the function we are looking for
}
if (forwarder_name_len(fPtr) > 1) {
std::cerr << "[!] Forwarded function: ["<< name << " -> "<< fPtr << "] cannot be resolved!" << std::endl;
return NULL; // this function is forwarded, cannot be resolved
}
return (FARPROC) fPtr; //return the pointer to the found function
}
//function not found
std::cerr << "Function not found!" << std::endl;
return NULL;
}
FARPROC peconv::export_based_resolver::resolve_func(LPSTR lib_name, LPSTR func_name)
{
HMODULE libBasePtr = LoadLibraryA(lib_name);
if (libBasePtr == NULL) {
std::cerr << "Could not load the library!" << std::endl;
return NULL;
}
FARPROC hProc = get_exported_func(libBasePtr, func_name);
if (hProc == NULL) {
#ifdef _DEBUG
if (!IsBadReadPtr(func_name, 1)) {
std::cerr << "[!] Cound not get the function: "<< func_name <<" from exports!" << std::endl;
} else {
std::cerr << "[!] Cound not get the function: "<< MASK_TO_DWORD((ULONG_PTR)func_name) <<" from exports!" << std::endl;
}
std::cerr << "[!] Falling back to the default resolver..." <<std::endl;
#endif
hProc = default_func_resolver::resolve_func(lib_name, func_name);
if (hProc == NULL) {
std::cerr << "[-] Loading function from " << lib_name << " failed!" << std::endl;
}
}
#ifdef _DEBUG
FARPROC defaultProc = default_func_resolver::resolve_func(lib_name, func_name);
if (hProc != defaultProc) {
std::cerr << "[-] Loaded proc is not matching the default one!" << std::endl;
}
#endif
return hProc;
}
LPSTR peconv::read_dll_name(HMODULE modulePtr)
{
IMAGE_EXPORT_DIRECTORY* exp = get_export_directory(modulePtr);
if (exp == NULL) {
return NULL;
}
LPSTR module_name = (char*)((ULONGLONG)modulePtr + exp->Name);
if (IsBadReadPtr(module_name, 1)) {
return NULL;
}
size_t len = peconv::forwarder_name_len((BYTE*) module_name);
if (len > 1) {
return module_name;
}
return NULL;
}

View File

@@ -0,0 +1,269 @@
#include "peconv/exports_mapper.h"
#include <algorithm>
#include <iostream>
using namespace peconv;
void ExportsMapper::print_va_to_func(std::stringstream &stream) const
{
std::map<ULONGLONG, std::set<ExportedFunc>>::const_iterator itr;
for (itr = va_to_func.begin(); itr != va_to_func.end(); ++itr) {
stream << std::hex << itr->first << " :\n";
std::set<ExportedFunc>::const_iterator itr2;
const std::set<ExportedFunc> &funcs = itr->second;
for (itr2 = funcs.begin(); itr2 != funcs.end(); ++itr2) {
stream << "\t" << itr2->toString() << "\n";
}
}
}
void ExportsMapper::print_func_to_va(std::stringstream &stream) const
{
std::map<ExportedFunc, ULONGLONG>::const_iterator itr;
for (itr = func_to_va.begin(); itr != func_to_va.end(); ++itr) {
stream << itr->first.toString() << " : "
<< std::hex << itr->second << "\n";
}
}
ULONGLONG rebase_va(ULONGLONG va, ULONGLONG currBase, ULONGLONG targetBase)
{
if (currBase == targetBase) {
return va;
}
ULONGLONG rva = va - (ULONGLONG) currBase;
return rva + targetBase;
}
size_t ExportsMapper::make_ord_lookup_tables(
PVOID modulePtr,
size_t moduleSize,
std::map<PDWORD, DWORD> &va_to_ord
)
{
IMAGE_EXPORT_DIRECTORY* exp = peconv::get_export_directory((HMODULE) modulePtr);
if (exp == NULL) return 0;
SIZE_T functCount = exp->NumberOfFunctions;
DWORD funcsListRVA = exp->AddressOfFunctions;
DWORD ordBase = exp->Base;
//go through names:
for (DWORD i = 0; i < functCount; i++) {
DWORD* recordRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
if (*recordRVA == 0) {
#ifdef _DEBUG
std::cout << ">>> Skipping 0 function address at RVA:" << std::hex << (BYTE*)recordRVA - (BYTE*)modulePtr<< "(ord)\n";
#endif
//skip if the function RVA is 0 (empty export)
continue;
}
if (!peconv::validate_ptr(modulePtr, moduleSize, recordRVA, sizeof(DWORD))) {
break;
}
DWORD ordinal = ordBase + i;
va_to_ord[recordRVA] = ordinal;
}
return functCount;
}
size_t ExportsMapper::resolve_forwarders(const ULONGLONG va, ExportedFunc &currFunc)
{
size_t resolved = 0;
//resolve forwarders of this function (if any):
std::map<ExportedFunc, std::set<ExportedFunc>>::iterator fItr = forwarders_lookup.find(currFunc);
if (fItr != forwarders_lookup.end()) {
//printf("[+] Forwarders (%d):\n", fItr->second.size());
std::set<ExportedFunc>::iterator sItr;
for (sItr = fItr->second.begin(); sItr != fItr->second.end(); ++sItr) {
//printf("-> %s\n", sItr->c_str());
associateVaAndFunc(va, *sItr);
resolved++;
}
}
return resolved;
}
bool ExportsMapper::add_forwarded(ExportedFunc &currFunc, DWORD callRVA, PBYTE modulePtr, size_t moduleSize)
{
PBYTE fPtr = modulePtr + callRVA;
if (!peconv::validate_ptr(modulePtr, moduleSize, fPtr, 1)) {
return false;
}
if (peconv::forwarder_name_len(fPtr) < 1) {
return false; //not forwarded
}
std::string forwardedFunc = format_dll_func((char*)fPtr);
if (forwardedFunc.length() == 0) {
return false; //not forwarded
}
ExportedFunc forwarder(forwardedFunc);
if (!forwarder.isValid()) {
#ifdef _DEBUG
std::cerr << "Skipped invalid forwarder" << std::endl;
#endif
return false;
}
forwarders_lookup[forwarder].insert(currFunc);
if (func_to_va[forwarder] != 0) {
ULONGLONG va = func_to_va[forwarder];
associateVaAndFunc(va, currFunc);
}
return true;
}
DWORD get_ordinal(PDWORD recordPtr, std::map<PDWORD, DWORD> &va_to_ord)
{
std::map<PDWORD, DWORD>::iterator ord_itr = va_to_ord.find(recordPtr);
if (ord_itr == va_to_ord.end()) {
//ordinal not found
return -1;
}
DWORD ordinal = ord_itr->second;
va_to_ord.erase(ord_itr);
return ordinal;
}
bool ExportsMapper::add_to_maps(ULONGLONG va, ExportedFunc &currFunc)
{
associateVaAndFunc(va, currFunc);
resolve_forwarders(va, currFunc);
return true;
}
bool is_valid_export_table(IMAGE_EXPORT_DIRECTORY* exp, HMODULE modulePtr, const size_t module_size)
{
if (exp == nullptr) return false;
const SIZE_T namesCount = exp->NumberOfNames;
const SIZE_T funcCount = exp->NumberOfFunctions;
const DWORD funcsListRVA = exp->AddressOfFunctions;
const DWORD funcNamesListRVA = exp->AddressOfNames;
const DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;
for (DWORD i = 0; i < funcCount; i++) {
DWORD* recordRVA = (DWORD*)(funcsListRVA + (BYTE*)modulePtr + i * sizeof(DWORD));
if (*recordRVA == 0) {
//skip if the function RVA is 0 (empty export)
continue;
}
if (!peconv::validate_ptr(modulePtr, module_size, recordRVA, sizeof(DWORD))) {
return false;
}
}
for (SIZE_T i = 0; i < namesCount; i++) {
DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*)modulePtr + i * sizeof(DWORD));
WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*)modulePtr + i * sizeof(WORD));
if ((!peconv::validate_ptr(modulePtr, module_size, nameRVA, sizeof(DWORD)))
|| (!peconv::validate_ptr(modulePtr, module_size, nameIndex, sizeof(WORD))))
{
return false;
}
DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*)modulePtr + (*nameIndex) * sizeof(DWORD));
if (!peconv::validate_ptr(modulePtr, module_size, funcRVA, sizeof(DWORD)))
{
return false;
}
}
return true;
}
ExportsMapper::ADD_FUNC_RES ExportsMapper::add_function_to_lookup(HMODULE modulePtr, ULONGLONG moduleBase, size_t moduleSize, ExportedFunc &currFunc, DWORD callRVA)
{
if (add_forwarded(currFunc, callRVA, (BYTE*)modulePtr, moduleSize)) {
#ifdef _DEBUG
char* fPtr = (char*)modulePtr + callRVA;
std::cout << "FWD " << currFunc.toString() << " -> " << fPtr << "\n";
#endif
return ExportsMapper::RES_FORWARDED;
}
ULONGLONG callVa = callRVA + moduleBase;
if (!peconv::validate_ptr((BYTE*)moduleBase, moduleSize, (BYTE*)callVa, sizeof(ULONGLONG))) {
// this may happen when the function was forwarded and it is already filled
#ifdef _DEBUG
std::cout << "Validation failed: " << currFunc.toString() << "\n";
#endif
return ExportsMapper::RES_INVALID;
}
//not forwarded, simple case:
add_to_maps(callVa, currFunc);
return ExportsMapper::RES_MAPPED;
}
size_t ExportsMapper::add_to_lookup(std::string moduleName, HMODULE modulePtr, ULONGLONG moduleBase)
{
IMAGE_EXPORT_DIRECTORY* exp = get_export_directory(modulePtr);
if (exp == NULL) {
return 0;
}
size_t module_size = peconv::get_image_size(reinterpret_cast<const PBYTE>(modulePtr));
if (!is_valid_export_table(exp, modulePtr, module_size)) {
return 0;
}
std::string dllName = get_dll_shortname(moduleName);
this->dll_shortname_to_path[dllName] = moduleName;
std::map<PDWORD, DWORD> va_to_ord;
size_t functCount = make_ord_lookup_tables(modulePtr, module_size, va_to_ord);
//go through names:
size_t forwarded_ctr = 0;
SIZE_T namesCount = exp->NumberOfNames;
DWORD funcsListRVA = exp->AddressOfFunctions;
DWORD funcNamesListRVA = exp->AddressOfNames;
DWORD namesOrdsListRVA = exp->AddressOfNameOrdinals;
size_t mapped_ctr = 0;
for (SIZE_T i = 0; i < namesCount; i++) {
DWORD* nameRVA = (DWORD*)(funcNamesListRVA + (BYTE*) modulePtr + i * sizeof(DWORD));
WORD* nameIndex = (WORD*)(namesOrdsListRVA + (BYTE*) modulePtr + i * sizeof(WORD));
DWORD* funcRVA = (DWORD*)(funcsListRVA + (BYTE*) modulePtr + (*nameIndex) * sizeof(DWORD));
if (*funcRVA == 0) {
#ifdef _DEBUG
std::cout << ">>> Skipping 0 function address at RVA:" << std::hex << (BYTE*)funcRVA - (BYTE*)modulePtr << "(name)\n";
#endif
//skip if the function RVA is 0 (empty export)
continue;
}
LPSTR name = (LPSTR)(*nameRVA + (BYTE*) modulePtr);
if (!peconv::validate_ptr(modulePtr, module_size, name, sizeof(char))) break;
DWORD funcOrd = get_ordinal(funcRVA, va_to_ord);
DWORD callRVA = *funcRVA;
ExportedFunc currFunc(dllName, name, funcOrd);
int res = add_function_to_lookup(modulePtr, moduleBase, module_size, currFunc, callRVA);
if (res == ExportsMapper::RES_FORWARDED) forwarded_ctr++;
if (res == ExportsMapper::RES_MAPPED) mapped_ctr++;
}
//go through unnamed functions exported by ordinals:
std::map<PDWORD, DWORD>::iterator ord_itr = va_to_ord.begin();
for (;ord_itr != va_to_ord.end(); ++ord_itr) {
DWORD* funcRVA = ord_itr->first;
DWORD callRVA = *funcRVA;
ExportedFunc currFunc(dllName, ord_itr->second);
int res = add_function_to_lookup(modulePtr, moduleBase, module_size, currFunc, callRVA);
if (res == ExportsMapper::RES_FORWARDED) forwarded_ctr++;
if (res == ExportsMapper::RES_MAPPED) mapped_ctr++;
}
#ifdef _DEBUG
std::cout << "Finished exports parsing, mapped: "<< mapped_ctr << " forwarded: " << forwarded_ctr << std::endl;
#endif
return mapped_ctr;
}

View File

@@ -0,0 +1,147 @@
#include "peconv/file_util.h"
#include "peconv/buffer_util.h"
#include <fstream>
#ifdef _DEBUG
#include <iostream>
#endif
//load file content using MapViewOfFile
peconv::ALIGNED_BUF peconv::load_file(IN const char *filename, OUT size_t &read_size)
{
HANDLE file = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if(file == INVALID_HANDLE_VALUE) {
#ifdef _DEBUG
std::cerr << "Could not open file!" << std::endl;
#endif
return nullptr;
}
HANDLE mapping = CreateFileMapping(file, 0, PAGE_READONLY, 0, 0, 0);
if (!mapping) {
#ifdef _DEBUG
std::cerr << "Could not create mapping!" << std::endl;
#endif
CloseHandle(file);
return nullptr;
}
BYTE *dllRawData = (BYTE*) MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
if (!dllRawData) {
#ifdef _DEBUG
std::cerr << "Could not map view of file" << std::endl;
#endif
CloseHandle(mapping);
CloseHandle(file);
return nullptr;
}
size_t r_size = GetFileSize(file, 0);
if (read_size != 0 && read_size <= r_size) {
r_size = read_size;
}
if (IsBadReadPtr(dllRawData, r_size)) {
std::cerr << "[-] Mapping of " << filename << " is invalid!" << std::endl;
UnmapViewOfFile(dllRawData);
CloseHandle(mapping);
CloseHandle(file);
return nullptr;
}
peconv::ALIGNED_BUF localCopyAddress = peconv::alloc_aligned(r_size, PAGE_READWRITE);
if (localCopyAddress != nullptr) {
memcpy(localCopyAddress, dllRawData, r_size);
read_size = r_size;
} else {
read_size = 0;
#ifdef _DEBUG
std::cerr << "Could not allocate memory in the current process" << std::endl;
#endif
}
UnmapViewOfFile(dllRawData);
CloseHandle(mapping);
CloseHandle(file);
return localCopyAddress;
}
//load file content using ReadFile
peconv::ALIGNED_BUF peconv::read_from_file(IN const char *in_path, IN OUT size_t &read_size)
{
HANDLE file = CreateFileA(in_path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (file == INVALID_HANDLE_VALUE) {
#ifdef _DEBUG
std::cerr << "Cannot open the file for reading!" << std::endl;
#endif
return nullptr;
}
size_t r_size = static_cast<size_t>(GetFileSize(file, 0));
if (read_size != 0 && read_size <= r_size) {
r_size = read_size;
}
PBYTE buffer = peconv::alloc_pe_buffer(r_size, PAGE_READWRITE);
if (buffer == nullptr) {
#ifdef _DEBUG
std::cerr << "Allocation has failed!" << std::endl;
#endif
return nullptr;
}
DWORD out_size = 0;
if (!ReadFile(file, buffer, r_size, &out_size, nullptr)) {
#ifdef _DEBUG
std::cerr << "Reading failed!" << std::endl;
#endif
peconv::free_pe_buffer(buffer, r_size);
buffer = nullptr;
read_size = 0;
} else {
read_size = r_size;
}
CloseHandle(file);
return buffer;
}
//save the given buffer into a file
bool peconv::dump_to_file(IN const char *out_path, IN PBYTE dump_data, IN size_t dump_size)
{
if (!out_path || !dump_data || !dump_size) return false;
HANDLE file = CreateFileA(out_path, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (file == INVALID_HANDLE_VALUE) {
#ifdef _DEBUG
std::cerr << "Cannot open the file for writing!" << std::endl;
#endif
return false;
}
DWORD written_size = 0;
bool is_dumped = false;
if (WriteFile(file, dump_data, (DWORD) dump_size, &written_size, nullptr)) {
is_dumped = true;
}
#ifdef _DEBUG
else {
std::cerr << "Failed to write to the file : " << out_path << std::endl;
}
#endif
CloseHandle(file);
return is_dumped;
}
//free the buffer allocated by load_file/read_from_file
void peconv::free_file(IN peconv::ALIGNED_BUF buffer)
{
peconv::free_aligned(buffer);
}
std::string peconv::get_file_name(IN const std::string str)
{
size_t found = str.find_last_of("/\\");
if (found == std::string::npos) {
return str;
}
return str.substr(found + 1);
}
std::string peconv::get_directory_name(IN const std::string str)
{
size_t found = str.find_last_of("/\\");
if (found == std::string::npos) {
return "";
}
return str.substr(0, found);
}

View File

@@ -0,0 +1,125 @@
#include <peconv/find_base.h>
#include <peconv/pe_hdrs_helper.h>
#include <peconv/relocate.h>
#include <set>
#include <map>
#include <iostream>
namespace peconv {
class CollectCodeRelocs : public RelocBlockCallback
{
public:
CollectCodeRelocs(BYTE *pe_buffer, size_t buffer_size, IN bool _is64bit, OUT std::set<ULONGLONG> &_relocs)
: RelocBlockCallback(_is64bit), relocs(_relocs),
peBuffer(pe_buffer), bufferSize(buffer_size)
{
codeSec = getCodeSection(peBuffer, bufferSize);
}
virtual bool processRelocField(ULONG_PTR relocField)
{
if (!codeSec) return false;
ULONGLONG reloc_addr = (relocField - (ULONGLONG)peBuffer);
const bool is_in_code = (reloc_addr >= codeSec->VirtualAddress) && (reloc_addr < codeSec->Misc.VirtualSize);
if (!is64bit && !is_in_code) {
// in case of 32 bit PEs process only the relocations form the code section
return true;
}
ULONGLONG rva = 0;
if (is64bit) {
ULONGLONG* relocateAddr = (ULONGLONG*)((ULONG_PTR)relocField);
rva = (*relocateAddr);
//std::cout << std::hex << (relocField - (ULONGLONG)peBuffer) << " : " << rva << std::endl;
}
else {
DWORD* relocateAddr = (DWORD*)((ULONG_PTR)relocField);
rva = ULONGLONG(*relocateAddr);
//std::cout << std::hex << (relocField - (ULONGLONG)peBuffer) << " : " << rva << std::endl;
}
relocs.insert(rva);
return true;
}
static PIMAGE_SECTION_HEADER getCodeSection(BYTE *peBuffer, size_t bufferSize)
{
size_t sec_count = peconv::get_sections_count(peBuffer, bufferSize);
for (size_t i = 0; i < sec_count; i++) {
PIMAGE_SECTION_HEADER hdr = peconv::get_section_hdr(peBuffer, bufferSize, i);
if (!hdr) break;
if (hdr->VirtualAddress == 0 || hdr->SizeOfRawData == 0) {
continue;
}
if (hdr->Characteristics & IMAGE_SCN_MEM_EXECUTE) {
return hdr;
}
}
return nullptr;
}
protected:
std::set<ULONGLONG> &relocs;
PIMAGE_SECTION_HEADER codeSec;
BYTE *peBuffer;
size_t bufferSize;
};
}
ULONGLONG peconv::find_base_candidate(IN BYTE* modulePtr, IN size_t moduleSize)
{
if (moduleSize == 0) {
moduleSize = peconv::get_image_size((const BYTE*)modulePtr);
}
if (moduleSize == 0) return 0;
bool is64 = peconv::is64bit(modulePtr);
std::set<ULONGLONG> relocs;
peconv::CollectCodeRelocs callback(modulePtr, moduleSize, is64, relocs);
if (!peconv::process_relocation_table(modulePtr, moduleSize, &callback)) {
return 0;
}
if (relocs.size() == 0) {
return 0;
}
PIMAGE_SECTION_HEADER hdr = peconv::CollectCodeRelocs::getCodeSection(modulePtr, moduleSize);
if (!hdr) {
return 0;
}
const ULONGLONG mask = ~ULONGLONG(0xFFFF);
std::map<ULONGLONG, size_t>base_candidates;
std::set<ULONGLONG>::iterator itr = relocs.begin();
for (itr = relocs.begin(); itr != relocs.end(); ++itr) {
const ULONGLONG guessed_base = (*itr) & mask;
std::map<ULONGLONG, size_t>::iterator found = base_candidates.find(guessed_base);
if (found == base_candidates.end()) {
base_candidates[guessed_base] = 0;
}
base_candidates[guessed_base]++;
}
ULONGLONG most_freqent = 0;
size_t max_freq = 0;
std::map<ULONGLONG, size_t>::iterator mapItr;
for (mapItr = base_candidates.begin(); mapItr != base_candidates.end(); ++mapItr) {
if (mapItr->second >= max_freq) {
most_freqent = mapItr->first;
max_freq = mapItr->second;
}
}
for (itr = relocs.begin(); itr != relocs.end(); ++itr) {
ULONGLONG first = *itr;
ULONGLONG first_base = first & mask;
if (first_base > most_freqent) {
break;
}
ULONGLONG delta = most_freqent - first_base;
if (delta < moduleSize) {
return first_base;
}
}
return 0;
}

View File

@@ -0,0 +1,144 @@
#include "fix_dot_net_ep.h"
#include <peconv.h>
#include <string>
#include <map>
class ListImportNames : public peconv::ImportThunksCallback
{
public:
ListImportNames(BYTE* _modulePtr, size_t _moduleSize, std::map<std::string, DWORD> &name_to_addr)
: ImportThunksCallback(_modulePtr, _moduleSize), nameToAddr(name_to_addr)
{
}
virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr)
{
if (this->is64b) {
IMAGE_THUNK_DATA64* desc = reinterpret_cast<IMAGE_THUNK_DATA64*>(origFirstThunkPtr);
ULONGLONG* call_via = reinterpret_cast<ULONGLONG*>(firstThunkPtr);
return processThunks_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG64);
}
IMAGE_THUNK_DATA32* desc = reinterpret_cast<IMAGE_THUNK_DATA32*>(origFirstThunkPtr);
DWORD* call_via = reinterpret_cast<DWORD*>(firstThunkPtr);
return processThunks_tpl<DWORD, IMAGE_THUNK_DATA32>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG32);
}
protected:
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA* desc, T_FIELD* call_via, T_FIELD ordinal_flag)
{
DWORD call_via_rva = static_cast<DWORD>((ULONG_PTR)call_via - (ULONG_PTR)this->modulePtr);
#ifdef _DEBUG
std::cout << "via RVA: " << std::hex << call_via_rva << " : ";
#endif
bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
if (!is_by_ord) {
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + desc->u1.AddressOfData);
LPSTR func_name = reinterpret_cast<LPSTR>(by_name->Name);
#ifdef _DEBUG
std::cout << "name: " << func_name << std::endl;
#endif
nameToAddr[func_name] = call_via_rva;
}
return true;
}
std::map<std::string, DWORD> &nameToAddr;
};
DWORD find_corexemain(BYTE *buf, size_t buf_size)
{
std::map<std::string, DWORD> name_to_addr;
ListImportNames callback(buf, buf_size, name_to_addr);
if (!peconv::process_import_table(buf, buf_size, &callback)) return 0;
std::map<std::string, DWORD>::iterator found = name_to_addr.find("_CorExeMain");
if (found != name_to_addr.end()) return found->second;
found = name_to_addr.find("_CorDllMain");
if (found != name_to_addr.end()) return found->second;
return 0;
}
BYTE* search_jump(BYTE *buf, size_t buf_size, const DWORD cor_exe_main_thunk, const ULONGLONG img_base)
{
// search the jump pattern, i.e.:
//JMP DWORD NEAR [0X402000] : FF 25 00204000
const size_t jmp_size = 2;
const BYTE jmp_pattern[jmp_size] = { 0xFF, 0x25 };
const size_t arg_size = sizeof(DWORD);
if ((jmp_size + arg_size) > buf_size) {
return nullptr;
}
const size_t end_offset = buf_size - (jmp_size + arg_size);
for (size_t i = end_offset; // search backwards
(i + 1) != 0; // this is unsigned comparison, so we cannot do: i >= 0
i--) // go back by one BYTE
{
if (buf[i] == jmp_pattern[0] && buf[i + 1] == jmp_pattern[1]) { // JMP
DWORD* addr = (DWORD*)(&buf[i + jmp_size]);
DWORD rva = static_cast<DWORD>((*addr) - img_base);
if (rva == cor_exe_main_thunk) {
#ifdef _DEBUG
std::cout << "Found call to _CorExeMain\n";
#endif
return buf + i;
}
else {
std::cout << "[!] Mismatch: " << std::hex << rva << " vs _CorExeMain: " << cor_exe_main_thunk << std::endl;
}
}
}
return nullptr;
}
bool fix_dot_net_ep(BYTE *pe_buffer, size_t pe_buffer_size)
{
if (!pe_buffer) return false;
if (peconv::is64bit(pe_buffer)) {
//64bit .NET files have EP=0
peconv::update_entry_point_rva(pe_buffer, 0);
return true;
}
DWORD ep_rva = peconv::get_entry_point_rva(pe_buffer);
std::cout << "[*] This is a .NET payload and may require Enty Point corection. Current EP: " << std::hex << ep_rva << "\n";
PIMAGE_SECTION_HEADER sec_hdr = peconv::get_section_hdr(pe_buffer, pe_buffer_size, 0);
if (!sec_hdr) return false;
BYTE *sec_ptr = pe_buffer + sec_hdr->VirtualAddress;
if (!peconv::validate_ptr(pe_buffer, pe_buffer_size, sec_ptr, sec_hdr->SizeOfRawData)) {
return false;
}
ULONGLONG img_base = peconv::get_image_base(pe_buffer);
DWORD cor_exe_main_thunk = find_corexemain(pe_buffer, pe_buffer_size);
if (!cor_exe_main_thunk) {
return false;
}
BYTE* jump_ptr = search_jump(sec_ptr, sec_hdr->SizeOfRawData, cor_exe_main_thunk, img_base);
if (jump_ptr == nullptr) return false;
size_t offset = jump_ptr - pe_buffer;
peconv::update_entry_point_rva(pe_buffer, static_cast<DWORD>(offset));
std::cout << "[*] Found possible Entry Point: " << std::hex << offset << std::endl;
return true;
}
bool is_dot_net(BYTE *pe_buffer, size_t pe_buffer_size)
{
if (!pe_buffer) return false;
IMAGE_DATA_DIRECTORY* dotnet_ptr = peconv::get_directory_entry(pe_buffer, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, false);
if (!dotnet_ptr) return false;
if (peconv::get_dotnet_hdr(pe_buffer, pe_buffer_size, dotnet_ptr)) {
return true;
}
return false;
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include <windows.h>
bool fix_dot_net_ep(BYTE *pe_buffer, size_t pe_buffer_size);
bool is_dot_net(BYTE *pe_buffer, size_t pe_buffer_size);
BYTE* search_jump(BYTE *buf, size_t buf_size, const DWORD cor_exe_main_thunk, const ULONGLONG img_base);

View File

@@ -0,0 +1,306 @@
#include "peconv/fix_imports.h"
#include "peconv/imports_uneraser.h"
#include "peconv/file_util.h"
#include <iostream>
#include <algorithm>
using namespace peconv;
template <typename FIELD_T>
size_t find_addresses_to_fill(FIELD_T call_via, FIELD_T thunk_addr, LPVOID modulePtr, size_t moduleSize, IN const peconv::ExportsMapper& exportsMap, OUT std::set<ULONGLONG> &addresses)
{
size_t addrCounter = 0;
do {
LPVOID call_via_ptr = (LPVOID)((ULONGLONG)modulePtr + call_via);
if (call_via_ptr == nullptr) break;
LPVOID thunk_ptr = (LPVOID)((ULONGLONG)modulePtr + thunk_addr);
if (thunk_ptr == nullptr) break;
if (!validate_ptr(modulePtr, moduleSize, thunk_ptr, sizeof(FIELD_T))) {
break;
}
if (!validate_ptr(modulePtr, moduleSize, call_via_ptr, sizeof(FIELD_T))) {
break;
}
FIELD_T *thunk_val = reinterpret_cast<FIELD_T*>(thunk_ptr);
FIELD_T *call_via_val = reinterpret_cast<FIELD_T*>(call_via_ptr);
if (*call_via_val == 0) {
//nothing to fill, probably the last record
break;
}
ULONGLONG searchedAddr = ULONGLONG(*call_via_val);
if (exportsMap.find_export_by_va(searchedAddr) != nullptr) {
addresses.insert(searchedAddr);
addrCounter++;
}
//---
call_via += sizeof(FIELD_T);
thunk_addr += sizeof(FIELD_T);
} while (true);
return addrCounter;
}
std::set<std::string> get_all_dlls_exporting_function(ULONGLONG func_addr, const peconv::ExportsMapper& exportsMap)
{
std::set<std::string> currDllNames;
//1. Get all the functions from all accessible DLLs that correspond to this address:
const std::set<ExportedFunc>* exports_for_va = exportsMap.find_exports_by_va(func_addr);
if (!exports_for_va) {
std::cerr << "Cannot find any DLL exporting: " << std::hex << func_addr << std::endl;
return currDllNames; //empty
}
//2. Iterate through their DLL names and add them to a set:
for (std::set<ExportedFunc>::iterator strItr = exports_for_va->begin();
strItr != exports_for_va->end();
++strItr)
{
currDllNames.insert(strItr->libName);
}
return currDllNames;
}
std::set<std::string> get_dlls_intersection(const std::set<std::string> &dllNames, const std::set<std::string> &currDllNames)
{
std::set<std::string> resultSet;
std::set_intersection(dllNames.begin(), dllNames.end(),
currDllNames.begin(), currDllNames.end(),
std::inserter(resultSet, resultSet.begin())
);
return resultSet;
}
//find the name of the DLL that can cover all the addresses of imported functions
std::string find_covering_dll(std::set<ULONGLONG> &addresses, const peconv::ExportsMapper& exportsMap)
{
std::set<std::string> mainDllsSet;
std::set<std::string> reserveDllSet;
bool isFresh = true;
// the earliest addresses are more significant for the final decision on what DLL to choose
// so, they should be processed at the end
std::set<ULONGLONG>::iterator addrItr;
for (addrItr = addresses.begin(); addrItr != addresses.end(); ++addrItr) {
ULONGLONG searchedAddr = *addrItr;
//---
// 1. Find all the DLLs exporting this particular function (can be forwarded etc)
std::set<std::string> currDllNames = get_all_dlls_exporting_function(searchedAddr, exportsMap);
//2. Which of those DLLs covers also previous functions from this series?
if (isFresh) {
//if no other function was processed before, set the current DLL set as the total set
mainDllsSet = currDllNames;
isFresh = false;
continue;
}
// find the intersection between the total set and the current set
std::set<std::string> resultSet = get_dlls_intersection(mainDllsSet, currDllNames);
if (resultSet.size() > 0) {
//found intersection, overwrite the main set
mainDllsSet = resultSet;
continue;
}
// if no intersection found in the main set, check if there is any in the reserved set:
resultSet = get_dlls_intersection(reserveDllSet, currDllNames);
if (resultSet.size() > 0) {
//found intersection, overwrite the main set
reserveDllSet = mainDllsSet; // move the current to the reserve
mainDllsSet = resultSet;
continue;
}
// no intersection found with any of the sets:
reserveDllSet = currDllNames; //set is as a reserved DLL: to be used if it will reoccur
}
if (mainDllsSet.size() > 0) {
const std::string main_dll = *(mainDllsSet.begin());
return main_dll;
}
return "";
}
bool ImportedDllCoverage::findCoveringDll()
{
std::string found_name = find_covering_dll(this->addresses, this->exportsMap);
if (found_name.length() == 0) {
#ifdef _DEBUG
std::cerr << "Cannot find a covering DLL" << std::endl;
#endif
return false;
}
this->dllName = found_name;
#ifdef _DEBUG
std::cout << "[+] Found DLL name: " << found_name << std::endl;
#endif
return true;
}
size_t map_addresses_to_functions(std::set<ULONGLONG> &addresses,
IN const std::string &chosenDll,
IN const peconv::ExportsMapper& exportsMap,
OUT std::map<ULONGLONG, std::set<ExportedFunc>> &addr_to_func,
OUT std::set<ULONGLONG> &not_found
)
{
std::set<ULONGLONG> coveredAddresses;
std::set<ULONGLONG>::iterator addrItr;
for (addrItr = addresses.begin(); addrItr != addresses.end(); ++addrItr) {
ULONGLONG searchedAddr = *addrItr;
const std::set<ExportedFunc>* exports_for_va = exportsMap.find_exports_by_va(searchedAddr);
if (exports_for_va == nullptr) {
not_found.insert(searchedAddr);
#ifdef _DEBUG
std::cerr << "Cannot find any DLL exporting: " << std::hex << searchedAddr << std::endl;
#endif
continue;
}
for (std::set<ExportedFunc>::iterator strItr = exports_for_va->begin();
strItr != exports_for_va->end();
++strItr)
{
std::string dll_name = strItr->libName;
if (dll_name != chosenDll) {
continue;
}
ExportedFunc func = *strItr;
addr_to_func[searchedAddr].insert(func);
coveredAddresses.insert(searchedAddr);
}
if (addr_to_func.find(searchedAddr) == addr_to_func.end()) {
const ExportedFunc* func = exportsMap.find_export_by_va(searchedAddr);
not_found.insert(searchedAddr);
#ifdef _DEBUG
std::cerr << "[WARNING] A function: " << func->toString() << " not found in the covering DLL: " << chosenDll << std::endl;
#endif
}
}
return coveredAddresses.size();
}
size_t ImportedDllCoverage::mapAddressesToFunctions(const std::string &dll)
{
//reset all stored info:
this->mappedDllName = dll;
if (this->addrToFunc.size() > 0) {
this->addrToFunc.clear();
}
this->notFound.clear();
const size_t coveredCount = map_addresses_to_functions(this->addresses, dll, this->exportsMap, this->addrToFunc, this->notFound);
#ifdef _DEBUG
if (notFound.size()) {
std::cout << "[-] Not all addresses are covered! Not found: " << std::dec << notFound.size() << std::endl;
} else {
std::cout << "All covered!" << std::endl;
}
#endif
return coveredCount;
}
void ImpsNotCovered::insert(ULONGLONG thunk, ULONGLONG searchedAddr)
{
#ifdef _DEBUG
std::cerr << "[-] Function not recovered: [" << std::hex << searchedAddr << "] " << std::endl;
#endif
thunkToAddr[thunk] = searchedAddr;
}
bool peconv::fix_imports(IN OUT PVOID modulePtr, IN size_t moduleSize, IN const peconv::ExportsMapper& exportsMap, OUT OPTIONAL peconv::ImpsNotCovered* notCovered)
{
bool skip_bound = false; // skip boud imports?
IMAGE_DATA_DIRECTORY *importsDir = peconv::get_directory_entry((const BYTE*) modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
if (importsDir == NULL) {
return true; // done! no imports -> nothing to fix
}
bool is64 = peconv::is64bit((BYTE*)modulePtr);
DWORD maxSize = importsDir->Size;
DWORD impAddr = importsDir->VirtualAddress;
IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL;
DWORD parsedSize = 0;
#ifdef _DEBUG
printf("---IMP---\n");
#endif
while (parsedSize < maxSize) {
lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR) modulePtr);
if (!validate_ptr(modulePtr, moduleSize, lib_desc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
printf("[-] Invalid descriptor pointer!\n");
return false;
}
parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR);
if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) {
break;
}
const bool is_bound = (lib_desc->TimeDateStamp == (-1));
if (is_bound && skip_bound) {
continue;
}
#ifdef _DEBUG
printf("Imported Lib: %x : %x : %x\n", lib_desc->FirstThunk, lib_desc->OriginalFirstThunk, lib_desc->Name);
#endif
std::string lib_name = "";
if (lib_desc->Name != 0) {
LPSTR name_ptr = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name);
if (validate_ptr(modulePtr, moduleSize, name_ptr, sizeof(char) * MIN_DLL_LEN)) {
lib_name = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name);
}
}
DWORD call_via = lib_desc->FirstThunk;
DWORD thunk_addr = lib_desc->OriginalFirstThunk; // warning: it can be NULL!
std::set<ULONGLONG> addresses;
if (!is64) {
find_addresses_to_fill<DWORD>(call_via, thunk_addr, modulePtr, moduleSize, exportsMap, addresses);
} else {
find_addresses_to_fill<ULONGLONG>(call_via, thunk_addr, modulePtr, moduleSize, exportsMap, addresses);
}
ImportedDllCoverage dllCoverage(addresses, exportsMap);
bool is_all_covered = dllCoverage.findCoveringDll();
bool is_lib_erased = false;
lib_name = get_dll_shortname(lib_name); //without extension
if (lib_name.length() == 0) {
is_lib_erased = true;
if (is_all_covered) {
// set a name of the covering DLL:
lib_name = dllCoverage.dllName;
}
}
if (lib_name.length() == 0) {
//could not find a relevant DLL
continue;
}
#ifdef _DEBUG
std::cout << lib_name << std::endl;
#endif
if (!dllCoverage.mapAddressesToFunctions(lib_name)) {
// cannot find any functions imported from this DLL
continue;
}
//everything mapped, now recover it:
ImportsUneraser impUneraser(modulePtr, moduleSize);
if (!impUneraser.uneraseDllImports(lib_desc, dllCoverage, notCovered)) {
return false;
}
if (is_lib_erased) {
const std::string dll_with_ext = exportsMap.get_dll_fullname(dllCoverage.dllName);
impUneraser.uneraseDllName(lib_desc, dll_with_ext);
}
}
#ifdef _DEBUG
std::cout << "---------" << std::endl;
#endif
return true;
}

View File

@@ -0,0 +1,18 @@
#include "peconv/function_resolver.h"
#include <iostream>
FARPROC peconv::default_func_resolver::resolve_func(LPSTR lib_name, LPSTR func_name)
{
HMODULE libBasePtr = LoadLibraryA(lib_name);
if (libBasePtr == NULL) {
std::cerr << "Could not load the library!" << std::endl;
return NULL;
}
FARPROC hProc = GetProcAddress(libBasePtr, func_name);
if (hProc == NULL) {
std::cerr << "Could not load the function!" << std::endl;
return NULL;
}
return hProc;
}

View File

@@ -0,0 +1,224 @@
#include "peconv/hooks.h"
#include "peconv.h"
#include "peconv/peb_lookup.h"
using namespace peconv;
namespace peconv {
bool is_pointer_in_ntdll(LPVOID lpAddress)
{
HMODULE mod = peconv::get_module_via_peb((LPWSTR)L"ntdll.dll");
size_t module_size = peconv::get_module_size_via_peb(mod);
if (peconv::validate_ptr(mod, module_size, lpAddress, sizeof(BYTE))) {
return true; //this address lies within NTDLL
}
return false;
}
BOOL nt_protect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
FARPROC proc = peconv::get_exported_func(
peconv::get_module_via_peb((LPWSTR)L"ntdll.dll"),
(LPSTR)"NtProtectVirtualMemory"
);
if (!proc) {
return FALSE;
}
NTSTATUS(NTAPI *_NtProtectVirtualMemory)(
IN HANDLE,
IN OUT PVOID*,
IN OUT PSIZE_T,
IN DWORD,
OUT PDWORD) =
(NTSTATUS(NTAPI *)(
IN HANDLE,
IN OUT PVOID*,
IN OUT PSIZE_T,
IN DWORD,
OUT PDWORD)) proc;
SIZE_T protect_size = dwSize;
NTSTATUS status = _NtProtectVirtualMemory(GetCurrentProcess(), &lpAddress, &protect_size, flNewProtect, lpflOldProtect);
if (status != S_OK) {
return FALSE;
}
return TRUE;
}
};
bool PatchBackup::makeBackup(BYTE *patch_ptr, size_t patch_size)
{
if (!patch_ptr) {
return false;
}
deleteBackup();
this->sourcePtr = patch_ptr;
this->buffer = new BYTE[patch_size];
this->bufferSize = patch_size;
memcpy(buffer, patch_ptr, patch_size);
return true;
}
bool PatchBackup::applyBackup()
{
if (!isBackup()) {
return false;
}
DWORD oldProtect = 0;
if (!nt_protect((LPVOID)sourcePtr, bufferSize, PAGE_EXECUTE_READWRITE, &oldProtect)) {
return false;
}
memcpy(sourcePtr, buffer, bufferSize);
nt_protect((LPVOID)sourcePtr, bufferSize, oldProtect, &oldProtect);
//flush cache:
FlushInstructionCache(GetCurrentProcess(), sourcePtr, bufferSize);
return true;
}
FARPROC peconv::hooking_func_resolver::resolve_func(LPSTR lib_name, LPSTR func_name)
{
//the name may be ordinal rather than string, so check if it is a valid pointer:
if (!IsBadReadPtr(func_name, 1)) {
std::map<std::string, FARPROC>::iterator itr = hooks_map.find(func_name);
if (itr != hooks_map.end()) {
FARPROC hook = itr->second;
#ifdef _DEBUG
std::cout << ">>>>>>Replacing: " << func_name << " by: " << hook << std::endl;
#endif
return hook;
}
}
return peconv::default_func_resolver::resolve_func(lib_name, func_name);
}
size_t peconv::redirect_to_local64(void *ptr, ULONGLONG new_offset, PatchBackup* backup)
{
if (!ptr) return 0;
BYTE hook_64[] = {
0x48, 0xB8, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xEE, 0xFF, //movabs rax,FFEE998877665544
0xFF, 0xE0 //jmp rax
};
const size_t hook64_size = sizeof(hook_64);
if (is_pointer_in_ntdll(ptr)) {
std::cout << "[WARNING] Patching NTDLL is not allowed because of possible stability issues!\n";
return 0;
}
DWORD oldProtect = 0;
if (!nt_protect((LPVOID)ptr,
hook64_size,
PAGE_EXECUTE_READWRITE, //this must be executable if we are hooking kernel32.dll, because we are using VirtualProtect from kernel32 at the same time
&oldProtect))
{
return 0;
}
if (backup != nullptr) {
backup->makeBackup((BYTE*)ptr, hook64_size);
}
memcpy(hook_64 + 2, &new_offset, sizeof(ULONGLONG));
memcpy(ptr, hook_64, hook64_size);
nt_protect((LPVOID)ptr, hook64_size, oldProtect, &oldProtect);
//flush cache:
FlushInstructionCache(GetCurrentProcess(), ptr, hook64_size);
return hook64_size;
}
size_t peconv::redirect_to_local32(void *ptr, DWORD new_offset, PatchBackup* backup)
{
if (!ptr) return 0;
BYTE hook_32[] = {
0xB8, 0xCC, 0xDD, 0xEE, 0xFF, // mov eax,FFEEDDCC
0xFF, 0xE0 //jmp eax
};
const size_t hook32_size = sizeof(hook_32);
if (is_pointer_in_ntdll(ptr)) {
std::cout << "[WARNING] Patching NTDLL is not allowed because of possible stability issues!\n";
return 0;
}
DWORD oldProtect = 0;
if (!nt_protect((LPVOID)ptr,
hook32_size,
PAGE_EXECUTE_READWRITE, //this must be executable if we are hooking kernel32.dll, because we are using VirtualProtect from kernel32 at the same time
&oldProtect))
{
return 0;
}
if (backup != nullptr) {
backup->makeBackup((BYTE*)ptr, hook32_size);
}
memcpy(hook_32 + 1, &new_offset, sizeof(DWORD));
memcpy(ptr, hook_32, hook32_size);
nt_protect((LPVOID)ptr, hook32_size, oldProtect, &oldProtect);
//flush cache:
FlushInstructionCache(GetCurrentProcess(), ptr, hook32_size);
return hook32_size;
}
size_t peconv::redirect_to_local(void *ptr, void* new_function_ptr, PatchBackup* backup)
{
#ifdef _WIN64
return peconv::redirect_to_local64(ptr, (ULONGLONG)new_function_ptr, backup);
#else
return peconv::redirect_to_local32(ptr, (DWORD)new_function_ptr, backup);
#endif
}
inline long long int get_jmp_delta(ULONGLONG currVA, int instrLen, ULONGLONG destVA)
{
long long int diff = destVA - (currVA + instrLen);
return diff;
}
inline bool is_valid_delta(long long int delta)
{
DWORD first_dw = delta >> sizeof(DWORD) * 8;
if (first_dw == 0) {
return true;
}
const DWORD max_dword = DWORD(-1);
if (first_dw != max_dword) {
return false;
}
DWORD delta_dw = DWORD(delta);
if (delta_dw & 0x80000000) {
return true;
}
//invalid, sign bit is missing
return false;
}
bool peconv::replace_target(BYTE *patch_ptr, ULONGLONG dest_addr)
{
typedef enum {
OP_JMP = 0xE9,
OP_CALL_DWORD = 0xE8
} t_opcode;
if (patch_ptr[0] == OP_JMP || patch_ptr[0] == OP_CALL_DWORD) {
ULONGLONG delta = get_jmp_delta(ULONGLONG(patch_ptr), 5, dest_addr);
if (!is_valid_delta(delta)) {
#ifdef _DEBUG
std::cout << "Cannot replace the target: too big delta: " << std::hex << delta << std::endl;
#endif
//too big delta, cannot be saved in a DWORD
return false;
}
DWORD delta_dw = DWORD(delta);
memcpy(patch_ptr + 1, &delta_dw, sizeof(DWORD));
//flush cache:
FlushInstructionCache(GetCurrentProcess(), patch_ptr + 1, sizeof(DWORD));
return true;
}
return false;
}

View File

@@ -0,0 +1,254 @@
#include "peconv/imports_loader.h"
#include <iostream>
using namespace peconv;
class FillImportThunks : public ImportThunksCallback
{
public:
FillImportThunks(BYTE* _modulePtr, size_t _moduleSize, t_function_resolver* func_resolver)
: ImportThunksCallback(_modulePtr, _moduleSize), funcResolver(func_resolver)
{
}
virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr, ULONG_PTR firstThunkPtr)
{
if (this->is64b) {
IMAGE_THUNK_DATA64* desc = reinterpret_cast<IMAGE_THUNK_DATA64*>(origFirstThunkPtr);
ULONGLONG* call_via = reinterpret_cast<ULONGLONG*>(firstThunkPtr);
return processThunks_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG64);
}
else {
IMAGE_THUNK_DATA32* desc = reinterpret_cast<IMAGE_THUNK_DATA32*>(origFirstThunkPtr);
DWORD* call_via = reinterpret_cast<DWORD*>(firstThunkPtr);
return processThunks_tpl<DWORD, IMAGE_THUNK_DATA32>(lib_name, desc, call_via, IMAGE_ORDINAL_FLAG32);
}
}
protected:
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA* desc, T_FIELD* call_via, T_FIELD ordinal_flag)
{
if (!this->funcResolver) {
return false;
}
bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
FARPROC hProc = nullptr;
if (is_by_ord) {
T_FIELD raw_ordinal = desc->u1.Ordinal & (~ordinal_flag);
#ifdef _DEBUG
std::cout << "raw ordinal: " << std::hex << raw_ordinal << std::endl;
#endif
//hProc = funcResolver->resolve_func(lib_name, MAKEINTRESOURCEA(raw_ordinal));
return true;
}
else {
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + desc->u1.AddressOfData);
LPSTR func_name = reinterpret_cast<LPSTR>(by_name->Name);
#ifdef _DEBUG
std::cout << "name: " << func_name << std::endl;
#endif
hProc = this->funcResolver->resolve_func(lib_name, func_name);
}
if (!hProc) {
#ifdef _DEBUG
std::cerr << "Could not resolve the function!" << std::endl;
#endif
return false;
}
(*call_via) = reinterpret_cast<T_FIELD>(hProc);
return true;
}
//fields:
t_function_resolver* funcResolver;
};
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
bool process_imp_functions_tpl(BYTE* modulePtr, size_t module_size, LPSTR lib_name, DWORD call_via, DWORD thunk_addr, IN ImportThunksCallback *callback)
{
bool is_ok = true;
T_FIELD *thunks = (T_FIELD*)((ULONGLONG)modulePtr + thunk_addr);
T_FIELD *callers = (T_FIELD*)((ULONGLONG)modulePtr + call_via);
for (size_t index = 0; true; index++) {
if (!validate_ptr(modulePtr, module_size, &callers[index], sizeof(T_FIELD))) {
break;
}
if (!validate_ptr(modulePtr, module_size, &thunks[index], sizeof(T_FIELD))) {
break;
}
if (callers[index] == 0) {
//nothing to fill, probably the last record
return true;
}
LPVOID thunk_ptr = &thunks[index];
T_IMAGE_THUNK_DATA* desc = reinterpret_cast<T_IMAGE_THUNK_DATA*>(thunk_ptr);
if (!validate_ptr(modulePtr, module_size, desc, sizeof(T_IMAGE_THUNK_DATA))) {
break;
}
if (desc->u1.Function == NULL) {
break;
}
T_FIELD ordinal_flag = (sizeof(T_FIELD) == sizeof(ULONGLONG)) ? IMAGE_ORDINAL_FLAG64 : IMAGE_ORDINAL_FLAG32;
bool is_by_ord = (desc->u1.Ordinal & ordinal_flag) != 0;
if (!is_by_ord) {
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr + desc->u1.AddressOfData);
if (!validate_ptr(modulePtr, module_size, by_name, sizeof(IMAGE_IMPORT_BY_NAME))) {
break;
}
}
//when the callback is called, all the pointers should be already verified
if (!callback->processThunks(lib_name, (ULONG_PTR)&thunks[index], (ULONG_PTR)&callers[index])) {
is_ok = false;
}
}
return is_ok;
}
//Walk through the table of imported DLLs (starting from the given descriptor) and execute the callback each time when the new record was found
bool process_dlls(BYTE* modulePtr, size_t module_size, IMAGE_IMPORT_DESCRIPTOR *first_desc, IN ImportThunksCallback *callback)
{
bool isAllFilled = true;
#ifdef _DEBUG
std::cout << "---IMP---" << std::endl;
#endif
const bool is64 = is64bit((BYTE*)modulePtr);
IMAGE_IMPORT_DESCRIPTOR* lib_desc = nullptr;
for (size_t i = 0; true; i++) {
lib_desc = &first_desc[i];
if (!validate_ptr(modulePtr, module_size, lib_desc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
break;
}
if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) {
break;
}
LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name);
if (!peconv::is_valid_import_name(modulePtr, module_size, lib_name)) {
//invalid name
return false;
}
DWORD call_via = lib_desc->FirstThunk;
DWORD thunk_addr = lib_desc->OriginalFirstThunk;
if (thunk_addr == NULL) {
thunk_addr = lib_desc->FirstThunk;
}
#ifdef _DEBUG
std::cout << "Imported Lib: " << std::hex << lib_desc->FirstThunk << " : " << std::hex << lib_desc->OriginalFirstThunk << " : " << lib_desc->Name << std::endl;
#endif
size_t all_solved = false;
if (is64) {
all_solved = process_imp_functions_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(modulePtr, module_size, lib_name, call_via, thunk_addr, callback);
}
else {
all_solved = process_imp_functions_tpl<DWORD, IMAGE_THUNK_DATA32>(modulePtr, module_size, lib_name, call_via, thunk_addr, callback);
}
if (!all_solved) {
isAllFilled = false;
}
}
#ifdef _DEBUG
printf("---------\n");
#endif
return isAllFilled;
}
bool peconv::process_import_table(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ImportThunksCallback *callback)
{
if (moduleSize == 0) { //if not given, try to fetch
moduleSize = peconv::get_image_size((const BYTE*)modulePtr);
}
if (moduleSize == 0) return false;
IMAGE_DATA_DIRECTORY *importsDir = get_directory_entry((BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
if (!importsDir) {
return true; //no import table
}
const DWORD impAddr = importsDir->VirtualAddress;
IMAGE_IMPORT_DESCRIPTOR *first_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + (ULONG_PTR)modulePtr);
if (!peconv::validate_ptr(modulePtr, moduleSize, first_desc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
return false;
}
return process_dlls(modulePtr, moduleSize, first_desc, callback);
}
bool peconv::load_imports(BYTE* modulePtr, t_function_resolver* func_resolver)
{
size_t moduleSize = peconv::get_image_size((const BYTE*)modulePtr);
if (moduleSize == 0) return false;
bool is64 = is64bit((BYTE*)modulePtr);
default_func_resolver default_res;
if (!func_resolver) {
func_resolver = (t_function_resolver*)&default_res;
}
FillImportThunks callback(modulePtr, moduleSize, func_resolver);
return peconv::process_import_table(modulePtr, moduleSize, &callback);
}
// A valid name must contain printable characters. Empty name is also acceptable (may have been erased)
bool peconv::is_valid_import_name(const PBYTE modulePtr, const size_t moduleSize, LPSTR lib_name)
{
while (true) {
if (!peconv::validate_ptr(modulePtr, moduleSize, lib_name, sizeof(char))) {
return false;
}
char next_char = *lib_name;
if (next_char == '\0') break;
if (next_char <= 0x20 || next_char >= 0x7E) {
return false;
}
lib_name++;
}
return true;
}
bool peconv::has_valid_import_table(const PBYTE modulePtr, size_t moduleSize)
{
IMAGE_DATA_DIRECTORY *importsDir = get_directory_entry((BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
if (importsDir == NULL) return false;
const DWORD impAddr = importsDir->VirtualAddress;
IMAGE_IMPORT_DESCRIPTOR* lib_desc = NULL;
DWORD parsedSize = 0;
size_t valid_records = 0;
while (true) { //size of the import table doesn't matter
lib_desc = (IMAGE_IMPORT_DESCRIPTOR*)(impAddr + parsedSize + (ULONG_PTR)modulePtr);
if (!peconv::validate_ptr(modulePtr, moduleSize, lib_desc, sizeof(IMAGE_IMPORT_DESCRIPTOR))) {
return false;
}
parsedSize += sizeof(IMAGE_IMPORT_DESCRIPTOR);
if (lib_desc->OriginalFirstThunk == NULL && lib_desc->FirstThunk == NULL) {
break;
}
LPSTR lib_name = (LPSTR)((ULONGLONG)modulePtr + lib_desc->Name);
if (!is_valid_import_name(modulePtr, moduleSize, lib_name)) return false;
DWORD call_via = lib_desc->FirstThunk;
DWORD thunk_addr = lib_desc->OriginalFirstThunk;
if (thunk_addr == NULL) thunk_addr = lib_desc->FirstThunk;
DWORD *thunks = (DWORD*)((ULONGLONG)modulePtr + thunk_addr);
if (!peconv::validate_ptr(modulePtr, moduleSize, thunks, sizeof(DWORD))) return false;
DWORD *callers = (DWORD*)((ULONGLONG)modulePtr + call_via);
if (!peconv::validate_ptr(modulePtr, moduleSize, callers, sizeof(DWORD))) return false;
valid_records++;
}
return (valid_records > 0);
}

View File

@@ -0,0 +1,243 @@
#include "peconv/imports_uneraser.h"
#include <iostream>
using namespace peconv;
LPVOID search_name(std::string name, const char* modulePtr, size_t moduleSize)
{
const char* namec = name.c_str();
const size_t searched_len = name.length() + 1; // with terminating NULL
const char* found_ptr = std::search(modulePtr, modulePtr + moduleSize, namec, namec + searched_len);
if (found_ptr == NULL) {
return NULL;
}
size_t o = found_ptr - modulePtr;
if (o < moduleSize) {
return (LPVOID)(found_ptr);
}
return NULL;
}
bool ImportsUneraser::writeFoundDllName(IMAGE_IMPORT_DESCRIPTOR* lib_desc, const std::string &found_name)
{
#ifdef _DEBUG
std::cout << "Found name:" << found_name << std::endl;
#endif
LPSTR name_ptr = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name);
size_t full_name_len = found_name.length() + 1; // with terminating zero
if (!validate_ptr(modulePtr, moduleSize, name_ptr, full_name_len)) {
//corner case: allow to save the name at the very end of the buffer, without the terminating zero
full_name_len--;
if (!validate_ptr(modulePtr, moduleSize, name_ptr, full_name_len)) {
return false; //invalid pointer, cannot save
}
}
memcpy(name_ptr, found_name.c_str(), full_name_len);
return true;
}
bool ImportsUneraser::uneraseDllName(IMAGE_IMPORT_DESCRIPTOR* lib_desc, const std::string &dll_name)
{
LPSTR name_ptr = nullptr;
if (lib_desc->Name != 0) {
name_ptr = (LPSTR)((ULONGLONG) modulePtr + lib_desc->Name);
}
if (name_ptr == nullptr || !validate_ptr(modulePtr, moduleSize, name_ptr, sizeof(char) * MIN_DLL_LEN)) {
//try to get the cave:
DWORD cave_size = DWORD(dll_name.length() + 1 + 5); //ending null + padding
PBYTE ptr = find_ending_cave(modulePtr, moduleSize, cave_size);
if (ptr == nullptr) {
std::cerr << "Cannot save the DLL name: " << dll_name << std::endl;
return false;
}
DWORD cave_rva = static_cast<DWORD>(ptr - modulePtr);
lib_desc->Name = cave_rva;
}
if (writeFoundDllName(lib_desc, dll_name)) {
return true; // written the found name
}
return false;
}
template <typename FIELD_T>
bool ImportsUneraser::findNameInBinaryAndFill(IMAGE_IMPORT_DESCRIPTOR* lib_desc,
LPVOID call_via_ptr,
LPVOID thunk_ptr,
const FIELD_T ordinal_flag,
std::map<ULONGLONG, std::set<ExportedFunc>> &addr_to_func
)
{
if (call_via_ptr == NULL || modulePtr == NULL || lib_desc == NULL) {
return false; //malformed input
}
IMAGE_DATA_DIRECTORY *importsDir = get_directory_entry((BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_IMPORT);
if (!importsDir) return false;
const DWORD impAddr = importsDir->VirtualAddress; //start of the import table
FIELD_T *call_via_val = (FIELD_T*)call_via_ptr;
if (*call_via_val == 0) {
//nothing to fill, probably the last record
return false;
}
ULONGLONG searchedAddr = ULONGLONG(*call_via_val);
bool is_name_saved = false;
FIELD_T lastOrdinal = 0; //store also ordinal of the matching function
std::set<ExportedFunc>::iterator funcname_itr = addr_to_func[searchedAddr].begin();
for (funcname_itr = addr_to_func[searchedAddr].begin();
funcname_itr != addr_to_func[searchedAddr].end();
++funcname_itr)
{
const ExportedFunc &found_func = *funcname_itr;
lastOrdinal = found_func.funcOrdinal;
const char* names_start = ((const char*) modulePtr + impAddr);
BYTE* found_ptr = (BYTE*) search_name(found_func.funcName, names_start, moduleSize - (names_start - (const char*)modulePtr));
if (!found_ptr) {
//name not found in the binary
//TODO: maybe it is imported by ordinal?
continue;
}
const ULONGLONG name_offset = (ULONGLONG)found_ptr - (ULONGLONG)modulePtr;
#ifdef _DEBUG
//if it is not the first name from the list, inform about it:
if (funcname_itr != addr_to_func[searchedAddr].begin()) {
std::cout << ">[*][" << std::hex << searchedAddr << "] " << found_func.toString() << std::endl;
}
std::cout <<"[+] Found the name at: " << std::hex << name_offset << std::endl;
#endif
PIMAGE_IMPORT_BY_NAME imp_field = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(name_offset - sizeof(WORD)); // substract the size of Hint
//TODO: validate more...
memcpy(thunk_ptr, &imp_field, sizeof(FIELD_T));
#ifdef _DEBUG
std::cout << "[+] Wrote found to offset: " << std::hex << call_via_ptr << std::endl;
#endif
is_name_saved = true;
break;
}
//name not found or could not be saved - fill the ordinal instead:
if (!is_name_saved && lastOrdinal != 0) {
#ifdef _DEBUG
std::cout << "[+] Filling ordinal: " << lastOrdinal << std::endl;
#endif
FIELD_T ord_thunk = lastOrdinal | ordinal_flag;
memcpy(thunk_ptr, &ord_thunk, sizeof(FIELD_T));
is_name_saved = true;
}
return is_name_saved;
}
template <typename FIELD_T, typename IMAGE_THUNK_DATA_T>
bool ImportsUneraser::writeFoundFunction(IMAGE_THUNK_DATA_T* desc, const FIELD_T ordinal_flag, const ExportedFunc &foundFunc)
{
if (foundFunc.isByOrdinal) {
FIELD_T ordinal = foundFunc.funcOrdinal | ordinal_flag;
FIELD_T* by_ord = (FIELD_T*) desc;
*by_ord = ordinal;
#ifdef _DEBUG
std::cout << "[+] Saved ordinal" << std::endl;
#endif
return true;
}
PIMAGE_IMPORT_BY_NAME by_name = (PIMAGE_IMPORT_BY_NAME) ((ULONGLONG) modulePtr + desc->u1.AddressOfData);
LPSTR func_name_ptr = reinterpret_cast<LPSTR>(by_name->Name);
std::string found_name = foundFunc.funcName;
bool is_nameptr_valid = validate_ptr(modulePtr, moduleSize, func_name_ptr, found_name.length());
// try to save the found name under the pointer:
if (is_nameptr_valid) {
by_name->Hint = MASK_TO_WORD(foundFunc.funcOrdinal);
memcpy(func_name_ptr, found_name.c_str(), found_name.length() + 1); // with the ending '\0'
#ifdef _DEBUG
std::cout << "[+] Saved name" << std::endl;
#endif
return true;
}
return false;
}
template <typename FIELD_T, typename IMAGE_THUNK_DATA_T>
bool ImportsUneraser::fillImportNames(
IN OUT IMAGE_IMPORT_DESCRIPTOR* lib_desc,
IN const FIELD_T ordinal_flag,
IN std::map<ULONGLONG, std::set<ExportedFunc>> &addr_to_func,
OUT OPTIONAL ImpsNotCovered* notCovered
)
{
if (lib_desc == NULL) return false;
FIELD_T call_via = lib_desc->FirstThunk;
if (call_via == NULL) return false;
size_t processed_imps = 0;
size_t recovered_imps = 0;
FIELD_T thunk_addr = lib_desc->OriginalFirstThunk;
if (thunk_addr == NULL) {
thunk_addr = call_via;
}
BYTE* call_via_ptr = (BYTE*)((ULONGLONG)modulePtr + call_via);
BYTE* thunk_ptr = (BYTE*)((ULONGLONG)modulePtr + thunk_addr);
for (;
call_via_ptr != NULL && thunk_ptr != NULL;
call_via_ptr += sizeof(FIELD_T), thunk_ptr += sizeof(FIELD_T)
)
{
FIELD_T *thunk_val = (FIELD_T*)thunk_ptr;
FIELD_T *call_via_val = (FIELD_T*)call_via_ptr;
if (*call_via_val == 0) {
//nothing to fill, probably the last record
break;
}
IMAGE_THUNK_DATA_T* desc = (IMAGE_THUNK_DATA_T*)thunk_ptr;
if (desc->u1.Function == NULL) {
break;
}
ULONGLONG searchedAddr = ULONGLONG(*call_via_val);
std::map<ULONGLONG,std::set<ExportedFunc>>::const_iterator found_itr = addr_to_func.find(searchedAddr);
if (found_itr == addr_to_func.end() || found_itr->second.size() == 0) {
//not found, move on
if (notCovered) {
notCovered->insert((call_via_ptr - modulePtr), searchedAddr);
}
continue;
}
std::set<ExportedFunc>::const_iterator funcname_itr = found_itr->second.begin();
const peconv::ExportedFunc &foundFunc = *funcname_itr;
#ifdef _DEBUG
std::cout << "[*][" << std::hex << searchedAddr << "] " << funcname_itr->toString() << std::endl;
#endif
bool is_name_saved = writeFoundFunction<FIELD_T, IMAGE_THUNK_DATA_T>(desc, ordinal_flag, *funcname_itr);
if (!is_name_saved) {
is_name_saved = findNameInBinaryAndFill<FIELD_T>(lib_desc, call_via_ptr, thunk_ptr, ordinal_flag, addr_to_func);
}
processed_imps++;
if (is_name_saved) recovered_imps++;
}
return (recovered_imps == processed_imps);
}
bool ImportsUneraser::uneraseDllImports(IN OUT IMAGE_IMPORT_DESCRIPTOR* lib_desc, IN ImportedDllCoverage &dllCoverage, OUT OPTIONAL ImpsNotCovered* notCovered)
{
//everything mapped, now recover it:
bool is_filled = false;
if (!is64) {
is_filled = fillImportNames<DWORD, IMAGE_THUNK_DATA32>(lib_desc, IMAGE_ORDINAL_FLAG32, dllCoverage.addrToFunc, notCovered);
} else {
is_filled = fillImportNames<ULONGLONG, IMAGE_THUNK_DATA64>(lib_desc, IMAGE_ORDINAL_FLAG64, dllCoverage.addrToFunc, notCovered);
}
if (!is_filled) {
std::cerr << "[-] Could not fill some import names!" << std::endl;
return false;
}
return is_filled;
}

View File

@@ -0,0 +1,57 @@
#include "peconv/load_config_util.h"
#include "peconv/pe_hdrs_helper.h"
BYTE* peconv::get_load_config_ptr(BYTE* buffer, size_t buf_size)
{
if (!buffer || !buf_size) return nullptr;
IMAGE_DATA_DIRECTORY* dir = peconv::get_directory_entry(buffer, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG);
if (!dir) {
return 0;
}
DWORD entry_rva = dir->VirtualAddress;
DWORD entry_size = dir->Size;
if (!peconv::validate_ptr(buffer, buf_size, buffer + entry_rva, entry_size)) {
return 0;
}
IMAGE_LOAD_CONFIG_DIRECTORY32* ldc = reinterpret_cast<IMAGE_LOAD_CONFIG_DIRECTORY32*>((ULONG_PTR)buffer + entry_rva);
return reinterpret_cast<BYTE*>(ldc);
}
peconv::t_load_config_ver peconv::get_load_config_version(BYTE* buffer, size_t buf_size, BYTE* ld_config_ptr)
{
if (!buffer || !buf_size || !ld_config_ptr) peconv::LOAD_CONFIG_NONE;
bool is64b = peconv::is64bit(buffer);
if (!peconv::validate_ptr(buffer, buf_size, ld_config_ptr, sizeof(peconv::IMAGE_LOAD_CONFIG_DIR32_W7))) {
return peconv::LOAD_CONFIG_NONE;
}
peconv::IMAGE_LOAD_CONFIG_DIR32_W7* smallest = (peconv::IMAGE_LOAD_CONFIG_DIR32_W7*)ld_config_ptr;
const size_t curr_size = smallest->Size;
if (is64b) {
switch (curr_size) {
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR64_W7) :
return peconv::LOAD_CONFIG_W7_VER;
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR64_W8) :
return peconv::LOAD_CONFIG_W8_VER;
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR64_W10) :
return peconv::LOAD_CONFIG_W10_VER;
default:
return LOAD_CONFIG_UNK_VER;
}
}
else {
switch (curr_size) {
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR32_W7) :
return peconv::LOAD_CONFIG_W7_VER;
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR32_W8) :
return peconv::LOAD_CONFIG_W8_VER;
case sizeof(peconv::IMAGE_LOAD_CONFIG_DIR32_W10) :
return peconv::LOAD_CONFIG_W10_VER;
default:
return LOAD_CONFIG_UNK_VER;
}
}
return LOAD_CONFIG_UNK_VER;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
#include "peconv/pe_dumper.h"
#include "peconv/pe_hdrs_helper.h"
#include "peconv/pe_virtual_to_raw.h"
#include "peconv/fix_imports.h"
#include "peconv/file_util.h"
#include "peconv/pe_mode_detector.h"
#include "fix_dot_net_ep.h"
#include <iostream>
using namespace peconv;
t_pe_dump_mode peconv::detect_dump_mode(IN const BYTE* buffer, IN size_t mod_size)
{
const t_pe_dump_mode default_mode = peconv::PE_DUMP_UNMAP;
if (peconv::is_pe_raw(buffer, mod_size)) {
return peconv::PE_DUMP_VIRTUAL;
}
if (peconv::is_pe_expanded(buffer, mod_size)) {
return peconv::PE_DUMP_REALIGN;
}
return default_mode;
}
bool peconv::dump_pe(IN const char *out_path,
IN OUT BYTE *buffer, IN size_t mod_size,
IN const ULONGLONG start_addr,
IN OUT t_pe_dump_mode &dump_mode,
IN OPTIONAL const peconv::ExportsMapper* exportsMap
)
{
// if the exportsMap is supplied, attempt to recover the (destroyed) import table:
if (exportsMap != nullptr) {
if (!peconv::fix_imports(buffer, mod_size, *exportsMap, NULL)) {
std::cerr << "[-] Unable to fix imports!" << std::endl;
}
}
if (dump_mode == PE_DUMP_AUTO || dump_mode >= PE_DUMP_MODES_COUNT) {
dump_mode = detect_dump_mode(buffer, mod_size);
}
BYTE* dump_data = buffer;
size_t dump_size = mod_size;
size_t out_size = 0;
BYTE* unmapped_module = nullptr;
if (dump_mode == peconv::PE_DUMP_UNMAP || dump_mode == peconv::PE_DUMP_REALIGN) {
//if the image base in headers is invalid, set the current base and prevent from relocating PE:
if (peconv::get_image_base(buffer) == 0) {
peconv::update_image_base(buffer, (ULONGLONG)start_addr);
}
if (is_dot_net(buffer, mod_size)) {
fix_dot_net_ep(buffer, mod_size);
}
if (dump_mode == peconv::PE_DUMP_UNMAP) {
unmapped_module = pe_virtual_to_raw(buffer, mod_size, (ULONGLONG)start_addr, out_size, false);
}
else if (dump_mode == peconv::PE_DUMP_REALIGN) {
unmapped_module = peconv::pe_realign_raw_to_virtual(buffer, mod_size, (ULONGLONG)start_addr, out_size);
}
// unmap the PE file (convert from the Virtual Format into Raw Format)
if (unmapped_module) {
dump_data = unmapped_module;
dump_size = out_size;
}
}
// save the read module into a file
const bool is_dumped = dump_to_file(out_path, dump_data, dump_size);
peconv::free_pe_buffer(unmapped_module, mod_size);
return is_dumped;
}

View File

@@ -0,0 +1,633 @@
#include "peconv/pe_hdrs_helper.h"
using namespace peconv;
#ifdef _DEBUG
#include <iostream>
#endif
BYTE* peconv::get_nt_hdrs(IN const BYTE *pe_buffer, IN OPTIONAL size_t buffer_size)
{
if (!pe_buffer) return nullptr;
IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer;
if (buffer_size != 0) {
if (!peconv::validate_ptr((LPVOID)pe_buffer, buffer_size, (LPVOID)idh, sizeof(IMAGE_DOS_HEADER))) {
return nullptr;
}
}
if (IsBadReadPtr(idh, sizeof(IMAGE_DOS_HEADER))) {
return nullptr;
}
if (idh->e_magic != IMAGE_DOS_SIGNATURE) {
return nullptr;
}
const LONG kMaxOffset = 1024;
LONG pe_offset = idh->e_lfanew;
if (pe_offset > kMaxOffset) return nullptr;
IMAGE_NT_HEADERS32 *inh = (IMAGE_NT_HEADERS32 *)(pe_buffer + pe_offset);
if (buffer_size != 0) {
if (!peconv::validate_ptr((LPVOID)pe_buffer, buffer_size, (LPVOID)inh, sizeof(IMAGE_NT_HEADERS32))) {
return nullptr;
}
}
if (IsBadReadPtr(inh, sizeof(IMAGE_NT_HEADERS32))) {
return nullptr;
}
if (inh->Signature != IMAGE_NT_SIGNATURE) {
return nullptr;
}
return (BYTE*)inh;
}
IMAGE_NT_HEADERS32* peconv::get_nt_hdrs32(IN const BYTE *payload)
{
if (!payload) return nullptr;
BYTE *ptr = get_nt_hdrs(payload);
if (!ptr) return nullptr;
if (!is64bit(payload)) {
return (IMAGE_NT_HEADERS32*)ptr;
}
return nullptr;
}
IMAGE_NT_HEADERS64* peconv::get_nt_hdrs64(IN const BYTE *payload)
{
if (payload == nullptr) return nullptr;
BYTE *ptr = get_nt_hdrs(payload);
if (!ptr) return nullptr;
if (is64bit(payload)) {
return (IMAGE_NT_HEADERS64*)ptr;
}
return nullptr;
}
DWORD peconv::get_image_size(IN const BYTE *payload)
{
if (!get_nt_hdrs(payload)) {
return 0;
}
DWORD image_size = 0;
if (is64bit(payload)) {
IMAGE_NT_HEADERS64* nt64 = get_nt_hdrs64(payload);
image_size = nt64->OptionalHeader.SizeOfImage;
} else {
IMAGE_NT_HEADERS32* nt32 = get_nt_hdrs32(payload);
image_size = nt32->OptionalHeader.SizeOfImage;
}
return image_size;
}
bool peconv::update_image_size(IN OUT BYTE* payload, IN DWORD image_size)
{
if (!get_nt_hdrs(payload)) {
return false;
}
if (is64bit(payload)) {
IMAGE_NT_HEADERS64* nt64 = get_nt_hdrs64(payload);
nt64->OptionalHeader.SizeOfImage = image_size;
}
else {
IMAGE_NT_HEADERS32* nt32 = get_nt_hdrs32(payload);
nt32->OptionalHeader.SizeOfImage = image_size;
}
return true;
}
WORD peconv::get_nt_hdr_architecture(IN const BYTE *pe_buffer)
{
void *ptr = get_nt_hdrs(pe_buffer);
if (!ptr) return 0;
IMAGE_NT_HEADERS32 *inh = static_cast<IMAGE_NT_HEADERS32*>(ptr);
if (IsBadReadPtr(inh, sizeof(IMAGE_NT_HEADERS32))) {
return 0;
}
return inh->OptionalHeader.Magic;
}
bool peconv::is64bit(IN const BYTE *pe_buffer)
{
WORD arch = get_nt_hdr_architecture(pe_buffer);
if (arch == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
return true;
}
return false;
}
IMAGE_DATA_DIRECTORY* peconv::get_directory_entry(IN const BYTE *pe_buffer, IN DWORD dir_id, IN bool allow_empty)
{
if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return nullptr;
BYTE* nt_headers = get_nt_hdrs((BYTE*)pe_buffer);
if (!nt_headers) return nullptr;
IMAGE_DATA_DIRECTORY* peDir = nullptr;
if (is64bit(pe_buffer)) {
IMAGE_NT_HEADERS64* nt_headers64 = (IMAGE_NT_HEADERS64*)nt_headers;
peDir = &(nt_headers64->OptionalHeader.DataDirectory[dir_id]);
}
else {
IMAGE_NT_HEADERS32* nt_headers64 = (IMAGE_NT_HEADERS32*)nt_headers;
peDir = &(nt_headers64->OptionalHeader.DataDirectory[dir_id]);
}
if (!allow_empty && peDir->VirtualAddress == NULL) {
return nullptr;
}
return peDir;
}
ULONGLONG peconv::get_image_base(IN const BYTE *pe_buffer)
{
bool is64b = is64bit(pe_buffer);
//update image base in the written content:
BYTE* payload_nt_hdr = get_nt_hdrs(pe_buffer);
if (!payload_nt_hdr) {
return 0;
}
ULONGLONG img_base = 0;
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
img_base = payload_nt_hdr64->OptionalHeader.ImageBase;
} else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
img_base = static_cast<ULONGLONG>(payload_nt_hdr32->OptionalHeader.ImageBase);
}
return img_base;
}
DWORD peconv::get_entry_point_rva(IN const BYTE *pe_buffer)
{
bool is64b = is64bit(pe_buffer);
//update image base in the written content:
BYTE* payload_nt_hdr = get_nt_hdrs(pe_buffer);
if (!payload_nt_hdr) {
return 0;
}
DWORD value = 0;
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
value = payload_nt_hdr64->OptionalHeader.AddressOfEntryPoint;
} else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
value = payload_nt_hdr32->OptionalHeader.AddressOfEntryPoint;
}
return value;
}
bool peconv::update_entry_point_rva(IN OUT BYTE *pe_buffer, IN DWORD value)
{
bool is64b = is64bit(pe_buffer);
//update image base in the written content:
BYTE* payload_nt_hdr = get_nt_hdrs(pe_buffer);
if (!payload_nt_hdr) {
return false;
}
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
payload_nt_hdr64->OptionalHeader.AddressOfEntryPoint = value;
} else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
payload_nt_hdr32->OptionalHeader.AddressOfEntryPoint = value;
}
return true;
}
DWORD peconv::get_hdrs_size(IN const BYTE *pe_buffer)
{
bool is64b = is64bit(pe_buffer);
BYTE* payload_nt_hdr = get_nt_hdrs(pe_buffer);
if (!payload_nt_hdr) {
return 0;
}
DWORD hdrs_size = 0;
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
hdrs_size = payload_nt_hdr64->OptionalHeader.SizeOfHeaders;
} else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
hdrs_size = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
}
return hdrs_size;
}
bool peconv::update_image_base(IN OUT BYTE* payload, IN ULONGLONG destImageBase)
{
bool is64b = is64bit(payload);
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
if (!payload_nt_hdr) {
return false;
}
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
payload_nt_hdr64->OptionalHeader.ImageBase = (ULONGLONG)destImageBase;
}
else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
payload_nt_hdr32->OptionalHeader.ImageBase = (DWORD)destImageBase;
}
return true;
}
template <typename IMAGE_NT_HEADERS_T>
inline const IMAGE_FILE_HEADER* fetch_file_hdr(IN const BYTE* payload, IN const size_t buffer_size, IN const IMAGE_NT_HEADERS_T *payload_nt_hdr)
{
if (!payload || !payload_nt_hdr) return nullptr;
const IMAGE_FILE_HEADER *fileHdr = &(payload_nt_hdr->FileHeader);
if (!validate_ptr((const LPVOID)payload, buffer_size, (const LPVOID)fileHdr, sizeof(IMAGE_FILE_HEADER))) {
return nullptr;
}
return fileHdr;
}
const IMAGE_FILE_HEADER* peconv::get_file_hdr(IN const BYTE* payload, IN const size_t buffer_size)
{
if (!payload) return nullptr;
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
if (!payload_nt_hdr) {
return nullptr;
}
if (is64bit(payload)) {
return fetch_file_hdr(payload, buffer_size, (IMAGE_NT_HEADERS64*)payload_nt_hdr);
}
return fetch_file_hdr(payload, buffer_size, (IMAGE_NT_HEADERS32*)payload_nt_hdr);
}
template <typename IMAGE_NT_HEADERS_T>
inline const LPVOID fetch_opt_hdr(IN const BYTE* payload, IN const size_t buffer_size, IN const IMAGE_NT_HEADERS_T *payload_nt_hdr)
{
if (!payload) return nullptr;
const IMAGE_FILE_HEADER *fileHdr = fetch_file_hdr<IMAGE_NT_HEADERS_T>(payload, buffer_size, payload_nt_hdr);
if (!fileHdr) {
return nullptr;
}
const LPVOID opt_hdr = (const LPVOID) &(payload_nt_hdr->OptionalHeader);
const size_t opt_size = fileHdr->SizeOfOptionalHeader;
if (!validate_ptr((const LPVOID)payload, buffer_size, opt_hdr, opt_size)) {
return nullptr;
}
return opt_hdr;
}
LPVOID peconv::get_optional_hdr(IN const BYTE* payload, IN const size_t buffer_size)
{
if (!payload) return nullptr;
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
const IMAGE_FILE_HEADER* fileHdr = get_file_hdr(payload, buffer_size);
if (!payload_nt_hdr || !fileHdr) {
return nullptr;
}
if (is64bit(payload)) {
return fetch_opt_hdr<IMAGE_NT_HEADERS64>(payload,buffer_size, (IMAGE_NT_HEADERS64*)payload_nt_hdr);
}
return fetch_opt_hdr<IMAGE_NT_HEADERS32>(payload, buffer_size, (IMAGE_NT_HEADERS32*)payload_nt_hdr);
}
template <typename IMAGE_NT_HEADERS_T>
inline LPVOID fetch_section_hdrs_ptr(IN const BYTE* payload, IN const size_t buffer_size, IN const IMAGE_NT_HEADERS_T *payload_nt_hdr)
{
const IMAGE_FILE_HEADER *fileHdr = fetch_file_hdr<IMAGE_NT_HEADERS_T>(payload, buffer_size, payload_nt_hdr);
if (!fileHdr) {
return nullptr;
}
const size_t opt_size = fileHdr->SizeOfOptionalHeader;
BYTE* opt_hdr = (BYTE*)fetch_opt_hdr(payload, buffer_size, payload_nt_hdr);
if (!validate_ptr((const LPVOID)payload, buffer_size, opt_hdr, opt_size)) {
return nullptr;
}
//sections headers starts right after the end of the optional header
return (LPVOID)(opt_hdr + opt_size);
}
size_t peconv::get_sections_count(IN const BYTE* payload, IN const size_t buffer_size)
{
const IMAGE_FILE_HEADER* fileHdr = get_file_hdr(payload, buffer_size);
if (!fileHdr) {
return 0;
}
return fileHdr->NumberOfSections;
}
bool peconv::is_valid_sections_hdr_offset(IN const BYTE* buffer, IN const size_t buffer_size)
{
size_t sec_count = peconv::get_sections_count(buffer, buffer_size);
if (sec_count == 0) {
//no sections found - a valid PE should have at least one section
return false;
}
PIMAGE_SECTION_HEADER last_hdr = get_section_hdr(buffer, buffer_size, sec_count - 1);
if (!last_hdr) {
//could not fetch the last section
return false;
}
return true;
}
PIMAGE_SECTION_HEADER peconv::get_section_hdr(IN const BYTE* payload, IN const size_t buffer_size, IN size_t section_num)
{
if (!payload) return nullptr;
const size_t sections_count = peconv::get_sections_count(payload, buffer_size);
if (section_num >= sections_count) {
return nullptr;
}
LPVOID nt_hdrs = peconv::get_nt_hdrs(payload);
if (!nt_hdrs) return nullptr; //this should never happened, because the get_sections_count did not fail
LPVOID secptr = nullptr;
//get the beginning of sections headers:
if (is64bit(payload)) {
secptr = fetch_section_hdrs_ptr<IMAGE_NT_HEADERS64>(payload, buffer_size, (IMAGE_NT_HEADERS64*)nt_hdrs);
}
else {
secptr = fetch_section_hdrs_ptr<IMAGE_NT_HEADERS32>(payload, buffer_size, (IMAGE_NT_HEADERS32*)nt_hdrs);
}
//get the section header of given number:
PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)(
(ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * section_num)
);
//validate pointer:
if (!validate_ptr((const LPVOID) payload, buffer_size, (const LPVOID) next_sec, sizeof(IMAGE_SECTION_HEADER))) {
return nullptr;
}
return next_sec;
}
WORD peconv::get_file_characteristics(IN const BYTE* payload)
{
if (!payload) return 0;
bool is64b = is64bit(payload);
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
if (!payload_nt_hdr) {
return 0;
}
IMAGE_FILE_HEADER *fileHdr = nullptr;
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
fileHdr = &(payload_nt_hdr64->FileHeader);
}
else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
fileHdr = &(payload_nt_hdr32->FileHeader);
}
return fileHdr->Characteristics;
}
bool peconv::is_module_dll(IN const BYTE* payload)
{
if (!payload) return false;
WORD charact = get_file_characteristics(payload);
return ((charact & IMAGE_FILE_DLL) != 0);
}
WORD peconv::get_dll_characteristics(IN const BYTE* payload)
{
if (!payload) return 0;
bool is64b = is64bit(payload);
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
if (!payload_nt_hdr) {
return 0;
}
WORD charact = 0;
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
charact = payload_nt_hdr64->OptionalHeader.DllCharacteristics;
}
else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
charact = payload_nt_hdr32->OptionalHeader.DllCharacteristics;
}
return charact;
}
bool peconv::set_subsystem(IN OUT BYTE* payload, IN WORD subsystem)
{
if (!payload) return false;
bool is64b = is64bit(payload);
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
if (!payload_nt_hdr) {
return false;
}
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
payload_nt_hdr64->OptionalHeader.Subsystem = subsystem;
} else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
payload_nt_hdr32->OptionalHeader.Subsystem = subsystem;
}
return true;
}
WORD peconv::get_subsystem(IN const BYTE* payload)
{
if (!payload) return 0;
bool is64b = is64bit(payload);
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
if (payload_nt_hdr == NULL) {
return 0;
}
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
return payload_nt_hdr64->OptionalHeader.Subsystem;
} else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
return payload_nt_hdr32->OptionalHeader.Subsystem;
}
}
bool peconv::has_relocations(IN const BYTE *pe_buffer)
{
IMAGE_DATA_DIRECTORY* relocDir = get_directory_entry(pe_buffer, IMAGE_DIRECTORY_ENTRY_BASERELOC);
if (!relocDir) {
return false;
}
return true;
}
IMAGE_EXPORT_DIRECTORY* peconv::get_export_directory(IN HMODULE modulePtr)
{
return get_type_directory<IMAGE_EXPORT_DIRECTORY>(modulePtr, IMAGE_DIRECTORY_ENTRY_EXPORT);
}
IMAGE_COR20_HEADER * peconv::get_dotnet_hdr(IN const BYTE* module, IN size_t const module_size, IN const IMAGE_DATA_DIRECTORY * dotNetDir)
{
DWORD rva = dotNetDir->VirtualAddress;
DWORD hdr_size = dotNetDir->Size;
if (!peconv::validate_ptr(module, module_size, module + rva, hdr_size)) {
return nullptr;
}
IMAGE_COR20_HEADER *dnet_hdr = (IMAGE_COR20_HEADER*)(module + rva);
if (!peconv::validate_ptr(module, module_size, module + dnet_hdr->MetaData.VirtualAddress, dnet_hdr->MetaData.Size)) {
return nullptr;
}
DWORD* signature_ptr = (DWORD*)(module + dnet_hdr->MetaData.VirtualAddress);
const DWORD dotNetSign = 0x424A5342;
if (*signature_ptr != dotNetSign) {
//invalid header
return nullptr;
}
return dnet_hdr;
}
template <typename IMAGE_NT_HEADERS_T>
DWORD* _get_sec_alignment_ptr(const BYTE* modulePtr, bool is_raw)
{
IMAGE_NT_HEADERS_T* hdrs = reinterpret_cast<IMAGE_NT_HEADERS_T*>(peconv::get_nt_hdrs(modulePtr));
if (!hdrs) return nullptr;
if (is_raw) {
return &hdrs->OptionalHeader.FileAlignment;
}
return &hdrs->OptionalHeader.SectionAlignment;
}
DWORD peconv::get_sec_alignment(IN const BYTE* modulePtr, IN bool is_raw)
{
DWORD* alignment = 0;
if (peconv::is64bit(modulePtr)) {
alignment = _get_sec_alignment_ptr<IMAGE_NT_HEADERS64>(modulePtr, is_raw);
} else {
alignment = _get_sec_alignment_ptr<IMAGE_NT_HEADERS32>(modulePtr, is_raw);
}
if (!alignment) return 0;
return *alignment;
}
bool peconv::set_sec_alignment(IN OUT BYTE* modulePtr, IN bool is_raw, IN DWORD new_alignment)
{
DWORD* alignment = 0;
if (peconv::is64bit(modulePtr)) {
alignment = _get_sec_alignment_ptr<IMAGE_NT_HEADERS64>(modulePtr, is_raw);
}
else {
alignment = _get_sec_alignment_ptr<IMAGE_NT_HEADERS32>(modulePtr, is_raw);
}
if (!alignment) return false;
*alignment = new_alignment;
return true;
}
DWORD peconv::get_virtual_sec_size(IN const BYTE* pe_hdr, IN const PIMAGE_SECTION_HEADER sec_hdr, IN bool rounded)
{
if (!pe_hdr || !sec_hdr) {
return 0;
}
if (!rounded) {
return sec_hdr->Misc.VirtualSize;;
}
//TODO: calculate real size, round up to Virtual Alignment
DWORD alignment = peconv::get_sec_alignment((const PBYTE)pe_hdr, false);
DWORD vsize = sec_hdr->Misc.VirtualSize;
DWORD units = vsize / alignment;
if ((vsize % alignment) > 0) units++;
vsize = units * alignment;
DWORD image_size = peconv::get_image_size(pe_hdr);
//if it is bigger than the image size, use the size from the headers
if ((sec_hdr->VirtualAddress + vsize) > image_size) {
vsize = sec_hdr->Misc.VirtualSize;
}
return vsize;
}
PIMAGE_SECTION_HEADER peconv::get_last_section(IN const PBYTE pe_buffer, IN size_t pe_size, IN bool is_raw)
{
SIZE_T module_end = peconv::get_hdrs_size(pe_buffer);
const size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
if (sections_count == 0) {
return nullptr;
}
PIMAGE_SECTION_HEADER last_sec = nullptr;
//walk through sections
for (size_t i = 0; i < sections_count; i++) {
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
if (!sec) break;
size_t new_end = is_raw ? (sec->PointerToRawData + sec->SizeOfRawData) : (sec->VirtualAddress + sec->Misc.VirtualSize);
if (new_end > module_end) {
module_end = new_end;
last_sec = sec;
}
}
return last_sec;
}
DWORD peconv::calc_pe_size(IN const PBYTE pe_buffer, IN size_t pe_size, IN bool is_raw)
{
DWORD module_end = peconv::get_hdrs_size(pe_buffer);
const size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
if (sections_count == 0) {
return module_end;
}
//walk through sections
for (size_t i = 0; i < sections_count; i++) {
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
if (!sec) break;
DWORD new_end = is_raw ? (sec->PointerToRawData + sec->SizeOfRawData) : (sec->VirtualAddress + sec->Misc.VirtualSize);
if (new_end > module_end) module_end = new_end;
}
return module_end;
}
bool peconv::is_valid_sectons_alignment(IN const BYTE* payload, IN const SIZE_T payload_size, IN bool is_raw)
{
if (payload == NULL) return false;
const DWORD my_align = peconv::get_sec_alignment(payload, is_raw);
if (my_align == 0) {
#ifdef _DEBUG
std::cout << "Section alignment cannot be 0\n";
#endif
return false;
}
const size_t sections_count = peconv::get_sections_count(payload, payload_size);
if (sections_count == 0) {
//no sections
return false;
}
for (size_t i = 0; i < sections_count; i++) {
PIMAGE_SECTION_HEADER next_sec = peconv::get_section_hdr(payload, payload_size, i);
if (!next_sec) return false; //the number of the sections in header is out of scope
const DWORD next_sec_addr = is_raw ? (next_sec->PointerToRawData) : (next_sec->VirtualAddress);
SIZE_T sec_size = is_raw ? next_sec->SizeOfRawData : next_sec->Misc.VirtualSize;
if (sec_size == 0) continue;
if (next_sec->Misc.VirtualSize == 0) {
continue; // if the VirtualSize == 0 the section will not be mapped anyways
}
if (next_sec_addr == 0) {
//if cannot be 0 if the size is not 0
return false;
}
//check only if raw_align is non-zero
if (my_align && next_sec_addr % my_align != 0) {
#ifdef _DEBUG
std::cout << "Section is misaligned\n";
#endif
return false; //misaligned
}
}
return true;
}

View File

@@ -0,0 +1,122 @@
#include "peconv/pe_loader.h"
#include "peconv/relocate.h"
#include "peconv/imports_loader.h"
#include "peconv/buffer_util.h"
#include "peconv/function_resolver.h"
#include "peconv/exports_lookup.h"
#include <iostream>
using namespace peconv;
namespace peconv {
BYTE* load_no_sec_pe(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, bool executable)
{
ULONGLONG desired_base = 0;
size_t out_size = (r_size < PAGE_SIZE) ? PAGE_SIZE : r_size;
if (executable) {
desired_base = get_image_base(dllRawData);
out_size = peconv::get_image_size(dllRawData);
}
DWORD protect = (executable) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
BYTE* mappedPE = peconv::alloc_pe_buffer(out_size, protect, desired_base);
if (!mappedPE) {
return NULL;
}
memcpy(mappedPE, dllRawData, r_size);
v_size = out_size;
return mappedPE;
}
};
BYTE* peconv::load_pe_module(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, bool executable, bool relocate)
{
if (!peconv::get_nt_hdrs(dllRawData)) {
return NULL;
}
if (peconv::get_sections_count(dllRawData, r_size) == 0) {
return load_no_sec_pe(dllRawData, r_size, v_size, executable);
}
// by default, allow to load the PE at any base:
ULONGLONG desired_base = NULL;
// if relocating is required, but the PE has no relocation table...
if (relocate && !has_relocations(dllRawData)) {
// ...enforce loading the PE image at its default base (so that it will need no relocations)
desired_base = get_image_base(dllRawData);
}
// load a virtual image of the PE file at the desired_base address (random if desired_base is NULL):
BYTE *mappedDLL = pe_raw_to_virtual(dllRawData, r_size, v_size, executable, desired_base);
if (mappedDLL) {
//if the image was loaded at its default base, relocate_module will return always true (because relocating is already done)
if (relocate && !relocate_module(mappedDLL, v_size, (ULONGLONG)mappedDLL)) {
// relocating was required, but it failed - thus, the full PE image is useless
printf("Could not relocate the module!");
free_pe_buffer(mappedDLL, v_size);
mappedDLL = NULL;
}
} else {
printf("Could not allocate memory at the desired base!\n");
}
return mappedDLL;
}
BYTE* peconv::load_pe_module(const char *filename, OUT size_t &v_size, bool executable, bool relocate)
{
size_t r_size = 0;
BYTE *dllRawData = load_file(filename, r_size);
if (!dllRawData) {
#ifdef _DEBUG
std::cerr << "Cannot load the file: " << filename << std::endl;
#endif
return NULL;
}
BYTE* mappedPE = load_pe_module(dllRawData, r_size, v_size, executable, relocate);
free_pe_buffer(dllRawData);
return mappedPE;
}
BYTE* peconv::load_pe_executable(BYTE* dllRawData, size_t r_size, OUT size_t &v_size, t_function_resolver* import_resolver)
{
BYTE* loaded_pe = load_pe_module(dllRawData, r_size, v_size, true, true);
if (!loaded_pe) {
printf("[-] Loading failed!\n");
return NULL;
}
#if _DEBUG
printf("Loaded at: %p\n", loaded_pe);
#endif
if (has_valid_import_table(loaded_pe, v_size)) {
if (!load_imports(loaded_pe, import_resolver)) {
printf("[-] Loading imports failed!");
free_pe_buffer(loaded_pe, v_size);
return NULL;
}
}
else {
printf("[-] PE doesn't have a valid Import Table!\n");
}
return loaded_pe;
}
BYTE* peconv::load_pe_executable(const char *my_path, OUT size_t &v_size, t_function_resolver* import_resolver)
{
#if _DEBUG
printf("Module: %s\n", my_path);
#endif
BYTE* loaded_pe = load_pe_module(my_path, v_size, true, true);
if (!loaded_pe) {
printf("Loading failed!\n");
return NULL;
}
#if _DEBUG
printf("Loaded at: %p\n", loaded_pe);
#endif
if (!load_imports(loaded_pe, import_resolver)) {
printf("[-] Loading imports failed!");
free_pe_buffer(loaded_pe, v_size);
return NULL;
}
return loaded_pe;
}

View File

@@ -0,0 +1,205 @@
#include "peconv/pe_mode_detector.h"
#include "peconv/util.h"
#include "peconv/imports_loader.h"
#include "peconv/relocate.h"
#ifdef _DEBUG
#include <iostream>
#endif
// Check if gaps between sections are typical for Virtual Alignment.
// Returns true if confirmed, false if not confirmed. False result can also mean that data was invalid/insufficient to decide.
bool is_virtual_padding(const BYTE* pe_buffer, size_t pe_size)
{
const size_t r_align = peconv::get_sec_alignment((PBYTE)pe_buffer, true);
size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
if (sections_count < 2) return false;
bool is_valid_padding = false;
for (size_t i = 1; i < sections_count; i += 2) {
PIMAGE_SECTION_HEADER sec1 = peconv::get_section_hdr(pe_buffer, pe_size, i-1);
PIMAGE_SECTION_HEADER sec2 = peconv::get_section_hdr(pe_buffer, pe_size, i);
if (!sec1 || !sec2) continue; //skip if fetching any of the sections failed
if (sec1->SizeOfRawData == 0) continue; //skip empty sections
const DWORD sec1_end_offset = sec1->VirtualAddress + sec1->SizeOfRawData;
if (sec2->VirtualAddress == sec1_end_offset) continue;
if (sec2->VirtualAddress < sec1_end_offset) {
//std::cout << "Invalid size of the section: " << std::hex << sec2->VirtualAddress << " vs "<< sec1_end_offset << std::endl;
return false;
}
const size_t diff = sec2->VirtualAddress - sec1_end_offset;
if (diff < r_align) continue; //to small to determine
BYTE* sec1_end_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec1_end_offset);
if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec1_end_ptr, diff)) {
//std::cout << "Invalid pointer to the section\n";
return false;
}
if (peconv::is_padding(sec1_end_ptr, diff, 0)) {
is_valid_padding = true;
}
else {
return false;
}
}
return is_valid_padding;
}
// Check if the gap between the end of headers and the first section is typical for Virtual Alignment.
// Returns true if confirmed, false if not confirmed. False result can also mean that data was invalid/insufficient to decide.
bool is_hdr_virtual_align(const BYTE* pe_buffer, size_t pe_size)
{
const size_t v_align = peconv::get_sec_alignment((PBYTE)pe_buffer, false);
if (peconv::get_hdrs_size(pe_buffer) >= v_align) {
//undetermined for such case
return false;
}
//walk through sections and check their sizes
size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
if (sections_count == 0) return false;
for (size_t i = 0; i < sections_count; i++) {
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
if (!sec || sec->PointerToRawData == 0 || sec->SizeOfRawData == 0) {
continue; // check next
}
if (sec->PointerToRawData >= v_align) continue;
size_t diff = v_align - sec->PointerToRawData;
BYTE* sec_raw_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec->PointerToRawData);
if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec_raw_ptr, diff)) {
return false;
}
if (peconv::is_padding(sec_raw_ptr, diff, 0)) {
return true;
}
}
return false;
}
bool sec_hdrs_erased(IN const BYTE* pe_buffer, IN size_t pe_size, bool is_raw)
{
const size_t count = peconv::get_sections_count(pe_buffer, pe_size);
for (size_t i = 0; i < count; i++) {
const IMAGE_SECTION_HEADER* hdr = peconv::get_section_hdr(pe_buffer, pe_size, i);
if (!hdr) continue;
if (is_raw) {
if (hdr->PointerToRawData != 0) return false;
}
else {
if (hdr->VirtualAddress != 0) return false;
}
}
return true;
}
bool peconv::is_pe_raw_eq_virtual(IN const BYTE* pe_buffer, IN size_t pe_size)
{
const size_t count = peconv::get_sections_count(pe_buffer, pe_size);
for (size_t i = 0; i < count; i++) {
const IMAGE_SECTION_HEADER* hdr = peconv::get_section_hdr(pe_buffer, pe_size, i);
if (!hdr) continue;
if (hdr->VirtualAddress != hdr->PointerToRawData) {
return false;
}
}
return true;
}
bool is_pe_mapped(IN const BYTE* pe_buffer, IN size_t pe_size)
{
size_t v_score = 0;
if (peconv::has_valid_import_table((const PBYTE)pe_buffer, pe_size)) {
#ifdef _DEBUG
std::cout << "Valid Import Table found" << std::endl;
#endif
v_score++;
}
if (peconv::has_valid_relocation_table((const PBYTE)pe_buffer, pe_size)) {
#ifdef _DEBUG
std::cout << "Valid Relocations Table found" << std::endl;
#endif
v_score++;
}
if (is_hdr_virtual_align(pe_buffer, pe_size)) {
#ifdef _DEBUG
std::cout << "Header virtual align OK" << std::endl;
#endif
v_score++;
}
if (is_virtual_padding(pe_buffer, pe_size)) {
#ifdef _DEBUG
std::cout << "Virtual Padding OK" << std::endl;
#endif
v_score++;
}
#ifdef _DEBUG
std::cout << "TOTAL v_score: " << std::dec << v_score << std::endl;
#endif
if (v_score > 0) {
return true;
}
return false;
}
bool peconv::is_pe_raw(IN const BYTE* pe_buffer, IN size_t pe_size)
{
if (peconv::get_sections_count(pe_buffer, pe_size) == 0) {
return true;
}
if (is_pe_mapped(pe_buffer, pe_size)) {
// it has artefacts typical for a PE in a virtual alignment
return false;
}
if (sec_hdrs_erased(pe_buffer, pe_size, true)) {
#ifdef _DEBUG
std::cout << "Raw alignment is erased\n";
#endif
// the raw alignment of the sections is erased
return false;
}
return true;
}
// checks if any of the executable sections has been expanded in the memory
bool peconv::is_pe_expanded(IN const BYTE* pe_buffer, IN size_t pe_size)
{
//walk through sections and check their sizes
size_t sections_count = peconv::get_sections_count(pe_buffer, pe_size);
for (size_t i = 0; i < sections_count; i++) {
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(pe_buffer, pe_size, i);
//scan only executable sections
if ((sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0) {
if (is_section_expanded(pe_buffer, pe_size, sec)) {
return true;
}
}
}
return false;
}
// checks if the section's content in memory is bigger than in the raw format
bool peconv::is_section_expanded(IN const BYTE* pe_buffer, IN size_t pe_size, IN const PIMAGE_SECTION_HEADER sec)
{
if (!sec) return false;
size_t sec_vsize = peconv::get_virtual_sec_size(pe_buffer, sec, true);
size_t sec_rsize = sec->SizeOfRawData;
if (sec_rsize >= sec_vsize) return false;
size_t diff = sec_vsize - sec_rsize;
BYTE* sec_raw_end_ptr = (BYTE*)((ULONGLONG)pe_buffer + sec->VirtualAddress + sec_rsize);
if (!peconv::validate_ptr((const LPVOID)pe_buffer, pe_size, sec_raw_end_ptr, diff)) {
return false;
}
if (!is_padding(sec_raw_end_ptr, diff, 0)) {
//this is not padding: non-zero content detected
return true;
}
return false;
}

View File

@@ -0,0 +1,140 @@
#include "peconv/pe_raw_to_virtual.h"
#include "peconv/util.h"
#include "peconv/pe_hdrs_helper.h"
#include <iostream>
using namespace peconv;
// Map raw PE into virtual memory of local process:
bool sections_raw_to_virtual(IN const BYTE* payload, IN SIZE_T payloadSize, OUT BYTE* destBuffer, IN SIZE_T destBufferSize)
{
if (!payload || !destBuffer) return false;
bool is64b = is64bit(payload);
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
if (payload_nt_hdr == NULL) {
std::cerr << "Invalid payload: " << std::hex << (ULONGLONG) payload << std::endl;
return false;
}
IMAGE_FILE_HEADER *fileHdr = NULL;
DWORD hdrsSize = 0;
LPVOID secptr = NULL;
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*)payload_nt_hdr;
fileHdr = &(payload_nt_hdr64->FileHeader);
hdrsSize = payload_nt_hdr64->OptionalHeader.SizeOfHeaders;
secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr64->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
}
else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*)payload_nt_hdr;
fileHdr = &(payload_nt_hdr32->FileHeader);
hdrsSize = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr32->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
}
DWORD first_raw = 0;
//copy all the sections, one by one:
SIZE_T raw_end = 0;
for (WORD i = 0; i < fileHdr->NumberOfSections; i++) {
PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i));
if (!validate_ptr((const LPVOID)payload, destBufferSize, next_sec, IMAGE_SIZEOF_SECTION_HEADER)) {
return false;
}
if (next_sec->PointerToRawData == 0 || next_sec->SizeOfRawData == 0) {
continue; //skipping empty
}
LPVOID section_mapped = destBuffer + next_sec->VirtualAddress;
LPVOID section_raw_ptr = (BYTE*)payload + next_sec->PointerToRawData;
SIZE_T sec_size = next_sec->SizeOfRawData;
raw_end = next_sec->SizeOfRawData + next_sec->PointerToRawData;
if ((next_sec->VirtualAddress + sec_size) > destBufferSize) {
std::cerr << "[!] Virtual section size is out ouf bounds: " << std::hex << sec_size << std::endl;
sec_size = (destBufferSize > next_sec->VirtualAddress) ? SIZE_T(destBufferSize - next_sec->VirtualAddress) : 0;
std::cerr << "[!] Truncated to maximal size: " << std::hex << sec_size << ", buffer size:" << destBufferSize << std::endl;
}
if (next_sec->VirtualAddress >= destBufferSize && sec_size != 0) {
std::cerr << "[-] VirtualAddress of section is out ouf bounds: " << std::hex << next_sec->VirtualAddress << std::endl;
return false;
}
if (next_sec->PointerToRawData + sec_size > destBufferSize) {
std::cerr << "[-] Raw section size is out ouf bounds: " << std::hex << sec_size << std::endl;
return false;
}
// validate source:
if (!validate_ptr((const LPVOID)payload, payloadSize, section_raw_ptr, sec_size)) {
std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
continue;
}
// validate destination:
if (!peconv::validate_ptr(destBuffer, destBufferSize, section_mapped, sec_size)) {
std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
continue;
}
memcpy(section_mapped, section_raw_ptr, sec_size);
if (first_raw == 0 || (next_sec->PointerToRawData < first_raw)) {
first_raw = next_sec->PointerToRawData;
}
}
//copy payload's headers:
if (hdrsSize == 0) {
hdrsSize= first_raw;
#ifdef _DEBUG
std::cout << "hdrsSize not filled, using calculated size: " << std::hex << hdrsSize << "\n";
#endif
}
if (!validate_ptr((const LPVOID)payload, destBufferSize, (const LPVOID)payload, hdrsSize)) {
return false;
}
memcpy(destBuffer, payload, hdrsSize);
return true;
}
BYTE* peconv::pe_raw_to_virtual(
IN const BYTE* payload,
IN size_t in_size,
OUT size_t &out_size,
IN OPTIONAL bool executable,
IN OPTIONAL ULONGLONG desired_base
)
{
//check payload:
BYTE* nt_hdr = get_nt_hdrs(payload);
if (nt_hdr == NULL) {
std::cerr << "Invalid payload: " << std::hex << (ULONGLONG) payload << std::endl;
return nullptr;
}
DWORD payloadImageSize = 0;
bool is64 = is64bit(payload);
if (is64) {
IMAGE_NT_HEADERS64* payload_nt_hdr = (IMAGE_NT_HEADERS64*)nt_hdr;
payloadImageSize = payload_nt_hdr->OptionalHeader.SizeOfImage;
}
else {
IMAGE_NT_HEADERS32* payload_nt_hdr = (IMAGE_NT_HEADERS32*)nt_hdr;
payloadImageSize = payload_nt_hdr->OptionalHeader.SizeOfImage;
}
DWORD protect = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
//first we will prepare the payload image in the local memory, so that it will be easier to edit it, apply relocations etc.
//when it will be ready, we will copy it into the space reserved in the target process
BYTE* localCopyAddress = alloc_pe_buffer(payloadImageSize, protect, desired_base);
if (localCopyAddress == NULL) {
std::cerr << "Could not allocate memory in the current process" << std::endl;
return NULL;
}
//printf("Allocated local memory: %p size: %x\n", localCopyAddress, payloadImageSize);
if (!sections_raw_to_virtual(payload, in_size, (BYTE*)localCopyAddress, payloadImageSize)) {
std::cerr << "Could not copy PE file" << std::endl;
return NULL;
}
out_size = payloadImageSize;
return localCopyAddress;
}

View File

@@ -0,0 +1,213 @@
#include "peconv/pe_virtual_to_raw.h"
#include "peconv/util.h"
#include "peconv/pe_hdrs_helper.h"
#include "peconv/relocate.h"
#include <iostream>
using namespace peconv;
bool sections_virtual_to_raw(BYTE* payload, SIZE_T payload_size, OUT BYTE* destAddress, OUT SIZE_T *raw_size_ptr)
{
if (!payload || !destAddress) return false;
bool is64b = is64bit(payload);
BYTE* payload_nt_hdr = get_nt_hdrs(payload);
if (payload_nt_hdr == NULL) {
std::cerr << "Invalid payload: " << std::hex << (ULONGLONG) payload << std::endl;
return false;
}
IMAGE_FILE_HEADER *fileHdr = NULL;
DWORD hdrsSize = 0;
LPVOID secptr = NULL;
if (is64b) {
IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*) payload_nt_hdr;
fileHdr = &(payload_nt_hdr64->FileHeader);
hdrsSize = payload_nt_hdr64->OptionalHeader.SizeOfHeaders;
secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr64->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
} else {
IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*) payload_nt_hdr;
fileHdr = &(payload_nt_hdr32->FileHeader);
hdrsSize = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr32->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
}
//copy all the sections, one by one:
#ifdef _DEBUG
std::cout << "Coping sections:" << std::endl;
#endif
DWORD first_raw = 0;
SIZE_T raw_end = hdrsSize;
for (WORD i = 0; i < fileHdr->NumberOfSections; i++) {
PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i));
if (!validate_ptr(payload, payload_size, next_sec, IMAGE_SIZEOF_SECTION_HEADER)) {
return false;
}
LPVOID section_mapped = (BYTE*) payload + next_sec->VirtualAddress;
LPVOID section_raw_ptr = destAddress + next_sec->PointerToRawData;
SIZE_T sec_size = next_sec->SizeOfRawData;
size_t new_end = sec_size + next_sec->PointerToRawData;
if (new_end > raw_end) raw_end = new_end;
if ((next_sec->VirtualAddress + sec_size) > payload_size) {
std::cerr << "[!] Virtual section size is out ouf bounds: " << std::hex << sec_size << std::endl;
sec_size = (payload_size > next_sec->VirtualAddress) ? SIZE_T(payload_size - next_sec->VirtualAddress) : 0;
std::cerr << "[!] Truncated to maximal size: " << std::hex << sec_size << ", buffer size: " << payload_size << std::endl;
}
if (next_sec->VirtualAddress > payload_size && sec_size != 0) {
std::cerr << "[-] VirtualAddress of section is out ouf bounds: " << std::hex << next_sec->VirtualAddress << std::endl;
return false;
}
if (next_sec->PointerToRawData + sec_size > payload_size) {
std::cerr << "[-] Raw section size is out ouf bounds: " << std::hex << sec_size << std::endl;
return false;
}
#ifdef _DEBUG
std::cout << "[+] " << next_sec->Name << " to: " << std::hex << section_raw_ptr << std::endl;
#endif
//validate source:
if (!peconv::validate_ptr(payload, payload_size, section_mapped, sec_size)) {
std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
continue;
}
//validate destination:
if (!peconv::validate_ptr(destAddress, payload_size, section_raw_ptr, sec_size)) {
std::cerr << "[-] Section " << i << ": out ouf bounds, skipping... " << std::endl;
continue;
}
memcpy(section_raw_ptr, section_mapped, sec_size);
if (first_raw == 0 || (next_sec->PointerToRawData < first_raw)) {
first_raw = next_sec->PointerToRawData;
}
}
if (raw_end > payload_size) raw_end = payload_size;
if (raw_size_ptr != NULL) {
(*raw_size_ptr) = raw_end;
}
//copy payload's headers:
if (hdrsSize == 0) {
hdrsSize = first_raw;
#ifdef _DEBUG
std::cout << "hdrsSize not filled, using calculated size: " << std::hex << hdrsSize << "\n";
#endif
}
if (!validate_ptr(payload, payload_size, payload, hdrsSize)) {
return false;
}
memcpy(destAddress, payload, hdrsSize);
return true;
}
BYTE* peconv::pe_virtual_to_raw(
IN BYTE* payload,
IN size_t in_size,
IN ULONGLONG loadBase,
OUT size_t &out_size,
IN OPTIONAL bool rebuffer
)
{
BYTE* out_buf = (BYTE*)alloc_pe_buffer(in_size, PAGE_READWRITE);
if (out_buf == NULL) return NULL; //could not allocate output buffer
BYTE* in_buf = payload;
if (rebuffer) {
in_buf = (BYTE*) alloc_pe_buffer(in_size, PAGE_READWRITE);
if (in_buf == NULL) {
free_pe_buffer(out_buf, in_size);
return NULL;
}
memcpy(in_buf, payload, in_size);
}
ULONGLONG oldBase = get_image_base(in_buf);
bool isOk = true;
// from the loadBase go back to the original base
if (!relocate_module(in_buf, in_size, oldBase, loadBase)) {
//Failed relocating the module! Changing image base instead...
if (!update_image_base(in_buf, (ULONGLONG)loadBase)) {
std::cerr << "[-] Failed relocating the module!" << std::endl;
isOk = false;
} else {
#ifdef _DEBUG
std::cerr << "[!] WARNING: The module could not be relocated, so the ImageBase has been changed instead!" << std::endl;
#endif
}
}
SIZE_T raw_size = 0;
if (isOk) {
if (!sections_virtual_to_raw(in_buf, in_size, out_buf, &raw_size)) {
isOk = false;
}
}
if (rebuffer && in_buf != NULL) {
free_pe_buffer(in_buf, in_size);
in_buf = NULL;
}
if (!isOk) {
free_pe_buffer(out_buf, in_size);
out_buf = NULL;
raw_size = 0;
}
out_size = raw_size;
return out_buf;
}
BYTE* peconv::pe_realign_raw_to_virtual(
IN const BYTE* payload,
IN size_t in_size,
IN ULONGLONG loadBase,
OUT size_t &out_size
)
{
out_size = in_size;
BYTE* out_buf = (BYTE*)alloc_pe_buffer(out_size, PAGE_READWRITE);
if (!out_buf) {
out_size = 0;
return nullptr;
}
memcpy(out_buf, payload, in_size);
ULONGLONG oldBase = get_image_base(out_buf);
bool isOk = true;
// from the loadBase go back to the original base
if (!relocate_module(out_buf, out_size, oldBase, loadBase)) {
//Failed relocating the module! Changing image base instead...
if (!update_image_base(out_buf, (ULONGLONG)loadBase)) {
std::cerr << "[-] Failed relocating the module!" << std::endl;
isOk = false;
} else {
#ifdef _DEBUG
std::cerr << "[!] WARNING: The module could not be relocated, so the ImageBase has been changed instead!" << std::endl;
#endif
}
}
//---
//set raw alignment the same as virtual
DWORD v_alignment = peconv::get_sec_alignment((const PBYTE)payload, false);
if (!peconv::set_sec_alignment(out_buf, true, v_alignment)) {
isOk = false;
}
//set Raw pointers and sizes of the sections same as Virtual
size_t sections_count = peconv::get_sections_count(out_buf, out_size);
for (size_t i = 0; i < sections_count; i++) {
PIMAGE_SECTION_HEADER sec = peconv::get_section_hdr(out_buf, out_size, i);
if (!sec) break;
sec->Misc.VirtualSize = peconv::get_virtual_sec_size(out_buf, sec, true);
sec->SizeOfRawData = sec->Misc.VirtualSize;
sec->PointerToRawData = sec->VirtualAddress;
}
//!---
if (!isOk) {
free_pe_buffer(out_buf);
out_buf = nullptr;
out_size = 0;
}
return out_buf;
}

View File

@@ -0,0 +1,178 @@
#include "ntddk.h"
#include <peconv/peb_lookup.h>
class SectionLocker {
public:
SectionLocker(RTL_CRITICAL_SECTION &_section)
: section(_section)
{
RtlEnterCriticalSection(&section);
}
~SectionLocker()
{
RtlLeaveCriticalSection(&section);
}
protected:
RTL_CRITICAL_SECTION &section;
};
//here we don't want to use any functions imported form extenal modules
typedef struct _LDR_MODULE {
LIST_ENTRY InLoadOrderModuleList;// +0x00
LIST_ENTRY InMemoryOrderModuleList;// +0x08
LIST_ENTRY InInitializationOrderModuleList;// +0x10
void* BaseAddress; // +0x18
void* EntryPoint; // +0x1c
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
HANDLE SectionHandle;
ULONG CheckSum;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
inline PPEB get_peb()
{
#if defined(_WIN64)
return (PPEB)__readgsqword(0x60);
#else
return (PPEB)__readfsdword(0x30);
/*
//alternative way to fetch it:
LPVOID PEB = NULL;
__asm {
mov eax, fs:[30h]
mov PEB, eax
};
return (PPEB)PEB;
or:
LPVOID PEB = RtlGetCurrentPeb();
*/
#endif
}
inline WCHAR to_lowercase(WCHAR c1)
{
if (c1 <= L'Z' && c1 >= L'A') {
c1 = (c1 - L'A') + L'a';
}
return c1;
}
bool is_wanted_module(LPWSTR curr_name, LPWSTR wanted_name)
{
if (wanted_name == NULL || curr_name == NULL) return false;
WCHAR *curr_end_ptr = curr_name;
while (*curr_end_ptr != L'\0') {
curr_end_ptr++;
}
if (curr_end_ptr == curr_name) return false;
WCHAR *wanted_end_ptr = wanted_name;
while (*wanted_end_ptr != L'\0') {
wanted_end_ptr++;
}
if (wanted_end_ptr == wanted_name) return false;
while ((curr_end_ptr != curr_name) && (wanted_end_ptr != wanted_name)) {
if (to_lowercase(*wanted_end_ptr) != to_lowercase(*curr_end_ptr)) {
return false;
}
wanted_end_ptr--;
curr_end_ptr--;
}
return true;
}
HMODULE peconv::get_module_via_peb(IN OPTIONAL LPWSTR module_name)
{
PPEB peb = get_peb();
if (!peb) {
return NULL;
}
SectionLocker locker(*peb->LoaderLock);
LIST_ENTRY head = peb->Ldr->InLoadOrderModuleList;
const PLDR_MODULE first_module = *((PLDR_MODULE *)(&head));
PLDR_MODULE curr_module = first_module;
if (!module_name) {
return (HMODULE)(curr_module->BaseAddress);
}
// it is a cyclic list, so if the next record links to the initial one, it means we went throught the full loop
do {
// this should also work as a terminator, because the BaseAddress of the last module in the cycle is NULL
if (curr_module == NULL || curr_module->BaseAddress == NULL) {
break;
}
if (is_wanted_module(curr_module->BaseDllName.Buffer, module_name)) {
return (HMODULE)(curr_module->BaseAddress);
}
curr_module = (PLDR_MODULE)curr_module->InLoadOrderModuleList.Flink;
} while (curr_module != first_module);
return NULL;
}
size_t peconv::get_module_size_via_peb(IN OPTIONAL HMODULE hModule)
{
PPEB peb = get_peb();
if (!peb) {
return 0;
}
SectionLocker locker(*peb->LoaderLock);
LIST_ENTRY head = peb->Ldr->InLoadOrderModuleList;
const PLDR_MODULE first_module = *((PLDR_MODULE *)(&head));
PLDR_MODULE curr_module = first_module;
if (!hModule) {
return (size_t)(curr_module->SizeOfImage);
}
// it is a cyclic list, so if the next record links to the initial one, it means we went throught the full loop
do {
// this should also work as a terminator, because the BaseAddress of the last module in the cycle is NULL
if (curr_module == NULL || curr_module->BaseAddress == NULL) {
break;
}
if (hModule == (HMODULE)(curr_module->BaseAddress)) {
return (size_t)(curr_module->SizeOfImage);
}
curr_module = (PLDR_MODULE)curr_module->InLoadOrderModuleList.Flink;
} while (curr_module != first_module);
return 0;
}
bool peconv::set_main_module_in_peb(HMODULE module_ptr)
{
PPEB peb = get_peb();
if (peb == NULL) {
return false;
}
SectionLocker locker(*peb->FastPebLock);
peb->ImageBaseAddress = module_ptr;
return true;
}
HMODULE peconv::get_main_module_via_peb()
{
PPEB peb = get_peb();
if (peb == NULL) {
return NULL;
}
SectionLocker locker(*peb->FastPebLock);
return (HMODULE) peb->ImageBaseAddress;
}

View File

@@ -0,0 +1,189 @@
#include "peconv/relocate.h"
#include "peconv/pe_hdrs_helper.h"
#include <stdio.h>
#include <iostream>
using namespace peconv;
#define RELOC_32BIT_FIELD 3
#define RELOC_64BIT_FIELD 0xA
class ApplyRelocCallback : public RelocBlockCallback
{
public:
ApplyRelocCallback(bool _is64bit, ULONGLONG _oldBase, ULONGLONG _newBase)
: RelocBlockCallback(_is64bit), oldBase(_oldBase), newBase(_newBase)
{
}
virtual bool processRelocField(ULONG_PTR relocField)
{
if (is64bit) {
ULONGLONG* relocateAddr = (ULONGLONG*)((ULONG_PTR)relocField);
ULONGLONG rva = (*relocateAddr) - oldBase;
(*relocateAddr) = rva + newBase;
}
else {
DWORD* relocateAddr = (DWORD*)((ULONG_PTR)relocField);
ULONGLONG rva = ULONGLONG(*relocateAddr) - oldBase;
(*relocateAddr) = static_cast<DWORD>(rva + newBase);
}
return true;
}
protected:
ULONGLONG oldBase;
ULONGLONG newBase;
};
bool is_empty_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize)
{
if (entriesNum == 0) {
return true; // nothing to process
}
BASE_RELOCATION_ENTRY* entry = block;
for (SIZE_T i = 0; i < entriesNum; i++) {
if (!validate_ptr(modulePtr, moduleSize, entry, sizeof(BASE_RELOCATION_ENTRY))) {
return false;
}
DWORD type = entry->Type;
if (type != 0) {
//non empty block found
return false;
}
entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)entry + sizeof(WORD));
}
return true;
}
bool process_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, PVOID modulePtr, SIZE_T moduleSize, bool is64bit, RelocBlockCallback *callback)
{
if (entriesNum == 0) {
return true; // nothing to process
}
BASE_RELOCATION_ENTRY* entry = block;
SIZE_T i = 0;
for (i = 0; i < entriesNum; i++) {
if (!validate_ptr(modulePtr, moduleSize, entry, sizeof(BASE_RELOCATION_ENTRY))) {
break;
}
DWORD offset = entry->Offset;
DWORD type = entry->Type;
if (type == 0) {
break;
}
if (type != RELOC_32BIT_FIELD && type != RELOC_64BIT_FIELD) {
if (callback) { //print debug messages only if the callback function was set
printf("[-] Not supported relocations format at %d: %d\n", (int)i, (int)type);
}
return false;
}
DWORD reloc_field = page + offset;
if (reloc_field >= moduleSize) {
if (callback) { //print debug messages only if the callback function was set
printf("[-] Malformed field: %lx\n", reloc_field);
}
return false;
}
if (callback) {
bool isOk = callback->processRelocField(((ULONG_PTR)modulePtr + reloc_field));
if (!isOk) {
std::cout << "[-] Failed processing reloc field at: " << std::hex << reloc_field << "\n";
return false;
}
}
entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)entry + sizeof(WORD));
}
return (i != 0);
}
bool peconv::process_relocation_table(IN PVOID modulePtr, IN SIZE_T moduleSize, IN RelocBlockCallback *callback)
{
IMAGE_DATA_DIRECTORY* relocDir = peconv::get_directory_entry((const BYTE*)modulePtr, IMAGE_DIRECTORY_ENTRY_BASERELOC);
if (relocDir == NULL) {
std::cout << "[!] WARNING: no relocation table found!\n";
return false;
}
if (!validate_ptr(modulePtr, moduleSize, relocDir, sizeof(IMAGE_DATA_DIRECTORY))) {
std::cerr << "[!] Invalid relocDir pointer\n";
return false;
}
DWORD maxSize = relocDir->Size;
DWORD relocAddr = relocDir->VirtualAddress;
bool is64b = is64bit((BYTE*)modulePtr);
IMAGE_BASE_RELOCATION* reloc = NULL;
DWORD parsedSize = 0;
DWORD validBlocks = 0;
while (parsedSize < maxSize) {
reloc = (IMAGE_BASE_RELOCATION*)(relocAddr + parsedSize + (ULONG_PTR)modulePtr);
if (!validate_ptr(modulePtr, moduleSize, reloc, sizeof(IMAGE_BASE_RELOCATION))) {
std::cerr << "[-] Invalid address of relocations\n";
return false;
}
if (reloc->SizeOfBlock == 0) {
break;
}
size_t entriesNum = (reloc->SizeOfBlock - 2 * sizeof(DWORD)) / sizeof(WORD);
DWORD page = reloc->VirtualAddress;
BASE_RELOCATION_ENTRY* block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR)reloc + sizeof(DWORD) + sizeof(DWORD));
if (!validate_ptr(modulePtr, moduleSize, block, sizeof(BASE_RELOCATION_ENTRY))) {
std::cerr << "[-] Invalid address of relocations block\n";
return false;
}
if (!is_empty_reloc_block(block, entriesNum, page, modulePtr, moduleSize)) {
if (process_reloc_block(block, entriesNum, page, modulePtr, moduleSize, is64b, callback)) {
validBlocks++;
}
else {
// the block was malformed
return false;
}
}
parsedSize += reloc->SizeOfBlock;
}
return (validBlocks != 0);
}
bool apply_relocations(PVOID modulePtr, SIZE_T moduleSize, ULONGLONG newBase, ULONGLONG oldBase)
{
const bool is64b = is64bit((BYTE*)modulePtr);
ApplyRelocCallback callback(is64b, oldBase, newBase);
return process_relocation_table(modulePtr, moduleSize, &callback);
}
bool peconv::relocate_module(IN BYTE* modulePtr, IN SIZE_T moduleSize, IN ULONGLONG newBase, IN ULONGLONG oldBase)
{
if (modulePtr == NULL) {
return false;
}
if (oldBase == 0) {
oldBase = get_image_base(modulePtr);
}
printf("<EFBFBD><EFBFBD>ʼ<EFBFBD>ض<EFBFBD>λ: %p -> %p \n", oldBase, newBase);
#ifdef _DEBUG
printf("New Base: %llx\n", newBase);
printf("Old Base: %llx\n", oldBase);
#endif
if (newBase == oldBase) {
printf("Nothing to relocate! oldBase is the same as the newBase!\n");
return true; //nothing to relocate
}
if (apply_relocations(modulePtr, moduleSize, newBase, oldBase)) {
return true;
}
#ifdef _DEBUG
printf("Could not relocate the module!\n");
#endif
return false;
}
bool peconv::has_valid_relocation_table(IN const PBYTE modulePtr, IN const size_t moduleSize)
{
return process_relocation_table(modulePtr, moduleSize, nullptr);
}

View File

@@ -0,0 +1,299 @@
#include "peconv/remote_pe_reader.h"
#include <iostream>
#include "peconv/util.h"
#include "peconv/fix_imports.h"
using namespace peconv;
bool peconv::fetch_region_info(HANDLE processHandle, BYTE* moduleBase, MEMORY_BASIC_INFORMATION &page_info)
{
memset(&page_info, 0, sizeof(MEMORY_BASIC_INFORMATION));
SIZE_T out = VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &page_info, sizeof(page_info));
if (out != sizeof(page_info)) {
return false;
}
return true;
}
size_t peconv::fetch_region_size(HANDLE processHandle, BYTE* moduleBase)
{
MEMORY_BASIC_INFORMATION page_info = { 0 };
if (!peconv::fetch_region_info(processHandle, moduleBase, page_info)) {
return 0;
}
if (page_info.Type == 0) {
return false; //invalid type, skip it
}
if ((BYTE*)page_info.BaseAddress > moduleBase) {
return 0; //should never happen
}
size_t offset = moduleBase - (BYTE*)page_info.BaseAddress;
size_t area_size = page_info.RegionSize - offset;
return area_size;
}
ULONGLONG peconv::fetch_alloc_base(HANDLE processHandle, BYTE* moduleBase)
{
MEMORY_BASIC_INFORMATION page_info = { 0 };
if (!peconv::fetch_region_info(processHandle, moduleBase, page_info)) {
return 0;
}
if (page_info.Type == 0) {
return 0; //invalid type, skip it
}
return (ULONGLONG) page_info.AllocationBase;
}
size_t peconv::read_remote_memory(HANDLE processHandle, BYTE *start_addr, OUT BYTE* buffer, const size_t buffer_size, const SIZE_T step_size)
{
if (!buffer) {
return 0;
}
memset(buffer, 0, buffer_size);
SIZE_T read_size = 0;
DWORD last_error = ERROR_SUCCESS;
for (SIZE_T to_read_size = buffer_size; to_read_size > 0; to_read_size -= step_size)
{
if (ReadProcessMemory(processHandle, start_addr, buffer, to_read_size, &read_size)) {
break;
}
// is it not the first attempt?
if (last_error != ERROR_SUCCESS) {
if (read_size == 0 && (last_error != ERROR_PARTIAL_COPY)) {
last_error = GetLastError();
break; // no progress, break
}
}
last_error = GetLastError();
if ((to_read_size < step_size) || step_size == 0) {
break;
}
//otherwise, decrease the to_read_size, and try again...
}
#ifdef _DEBUG
if (read_size == 0) {
std::cerr << "[WARNING] Cannot read memory. Last Error : " << last_error << std::endl;
}
else if (read_size < buffer_size) {
std::cerr << "[WARNING] Read size: " << std::hex << read_size
<< " is smaller than the requested size: " << std::hex << buffer_size
<< ". Last Error: " << last_error << std::endl;
}
#endif
return static_cast<size_t>(read_size);
}
size_t read_remote_region(HANDLE processHandle, BYTE *start_addr, OUT BYTE* buffer, const size_t buffer_size, const SIZE_T step_size)
{
if (buffer == nullptr) {
return 0;
}
size_t region_size = peconv::fetch_region_size(processHandle, start_addr);
if (region_size == 0) return false;
if (region_size >= buffer_size) {
return peconv::read_remote_memory(processHandle, start_addr, buffer, buffer_size, step_size);
}
return peconv::read_remote_memory(processHandle, start_addr, buffer, region_size, step_size);
}
size_t peconv::read_remote_area(HANDLE processHandle, BYTE *start_addr, OUT BYTE* buffer, const size_t buffer_size, const SIZE_T step_size)
{
if (!buffer || !start_addr) {
return 0;
}
memset(buffer, 0, buffer_size);
size_t read = 0;
for (read = 0; read < buffer_size; ) {
size_t read_chunk = read_remote_region(processHandle, start_addr + read, buffer + read, buffer_size - read, step_size);
if (read_chunk == 0) {
size_t region_size = peconv::fetch_region_size(processHandle, start_addr);
if (region_size == 0) break;
//skip the region that could not be read:
read += region_size;
continue;
}
read += read_chunk;
}
return read;
}
bool peconv::read_remote_pe_header(HANDLE processHandle, BYTE *start_addr, OUT BYTE* buffer, const size_t buffer_size)
{
if (buffer == nullptr) {
return false;
}
SIZE_T read_size = read_remote_memory(processHandle, start_addr, buffer, buffer_size);
if (read_size == 0) {
return false;
}
BYTE *nt_ptr = get_nt_hdrs(buffer);
if (nt_ptr == nullptr) {
return false;
}
const size_t nt_offset = nt_ptr - buffer;
const size_t nt_size = peconv::is64bit(buffer) ? sizeof(IMAGE_NT_HEADERS64) : sizeof(IMAGE_NT_HEADERS32);
const size_t min_size = nt_offset + nt_size;
if (read_size < min_size) {
std::cerr << "[-] [" << std::dec << get_process_id(processHandle)
<< " ][" << std::hex << (ULONGLONG) start_addr
<< "] Read size: " << std::hex << read_size
<< " is smaller that the minimal size:" << get_hdrs_size(buffer)
<< std::endl;
return false;
}
//reading succeeded and the header passed the checks:
return true;
}
namespace peconv {
inline size_t roundup_to_unit(size_t size, size_t unit)
{
if (unit == 0) {
return size;
}
size_t parts = size / unit;
if (size % unit) parts++;
return parts * unit;
}
};
peconv::UNALIGNED_BUF peconv::get_remote_pe_section(HANDLE processHandle, BYTE *start_addr, const size_t section_num, OUT size_t &section_size, bool roundup)
{
BYTE header_buffer[MAX_HEADER_SIZE] = { 0 };
if (!read_remote_pe_header(processHandle, start_addr, header_buffer, MAX_HEADER_SIZE)) {
return NULL;
}
PIMAGE_SECTION_HEADER section_hdr = get_section_hdr(header_buffer, MAX_HEADER_SIZE, section_num);
if (section_hdr == NULL || section_hdr->Misc.VirtualSize == 0) {
return NULL;
}
size_t buffer_size = section_hdr->Misc.VirtualSize;
if (roundup) {
DWORD va = peconv::get_sec_alignment(header_buffer, false);
if (va == 0) va = PAGE_SIZE;
buffer_size = roundup_to_unit(section_hdr->Misc.VirtualSize, va);
}
UNALIGNED_BUF module_code = peconv::alloc_unaligned(buffer_size);
if (module_code == NULL) {
return NULL;
}
size_t read_size = read_remote_memory(processHandle, start_addr + section_hdr->VirtualAddress, module_code, buffer_size);
if (read_size == 0) {
peconv::free_unaligned(module_code);
return NULL;
}
section_size = buffer_size;
return module_code;
}
size_t peconv::read_remote_pe(const HANDLE processHandle, BYTE *start_addr, const size_t mod_size, OUT BYTE* buffer, const size_t bufferSize)
{
if (buffer == nullptr) {
std::cerr << "[-] Invalid output buffer: NULL pointer" << std::endl;
return 0;
}
if (bufferSize < mod_size || bufferSize < MAX_HEADER_SIZE ) {
std::cerr << "[-] Invalid output buffer: too small size!" << std::endl;
return 0;
}
// read PE section by section
PBYTE hdr_buffer = buffer;
//try to read headers:
if (!read_remote_pe_header(processHandle, start_addr, hdr_buffer, MAX_HEADER_SIZE)) {
std::cerr << "[-] Failed to read the module header" << std::endl;
return 0;
}
if (!is_valid_sections_hdr_offset(hdr_buffer, MAX_HEADER_SIZE)) {
std::cerr << "[-] Sections headers are invalid or atypically aligned" << std::endl;
return 0;
}
size_t sections_count = get_sections_count(hdr_buffer, MAX_HEADER_SIZE);
#ifdef _DEBUG
std::cout << "Sections: " << sections_count << std::endl;
#endif
size_t read_size = MAX_HEADER_SIZE;
for (size_t i = 0; i < sections_count; i++) {
PIMAGE_SECTION_HEADER hdr = get_section_hdr(hdr_buffer, MAX_HEADER_SIZE, i);
if (!hdr) {
std::cerr << "[-] Failed to read the header of section: " << i << std::endl;
break;
}
const DWORD sec_va = hdr->VirtualAddress;
const DWORD sec_vsize = get_virtual_sec_size(hdr_buffer, hdr, true);
if (sec_va + sec_vsize > bufferSize) {
std::cerr << "[-] No more space in the buffer!" << std::endl;
break;
}
if (sec_vsize > 0 && !read_remote_memory(processHandle, start_addr + sec_va, buffer + sec_va, sec_vsize)) {
std::cerr << "[-] Failed to read the module section " << i <<" : at: " << std::hex << ULONG_PTR(start_addr + sec_va) << std::endl;
}
// update the end of the read area:
size_t new_end = sec_va + sec_vsize;
if (new_end > read_size) read_size = new_end;
}
#ifdef _DEBUG
std::cout << "Total read size: " << read_size << std::endl;
#endif
return read_size;
}
DWORD peconv::get_remote_image_size(IN const HANDLE processHandle, IN BYTE *start_addr)
{
BYTE hdr_buffer[MAX_HEADER_SIZE] = { 0 };
if (!read_remote_pe_header(processHandle, start_addr, hdr_buffer, MAX_HEADER_SIZE)) {
return 0;
}
return peconv::get_image_size(hdr_buffer);
}
bool peconv::dump_remote_pe(IN const char *out_path,
IN const HANDLE processHandle,
IN BYTE* start_addr,
IN OUT t_pe_dump_mode &dump_mode,
IN OPTIONAL peconv::ExportsMapper* exportsMap)
{
DWORD mod_size = get_remote_image_size(processHandle, start_addr);
#ifdef _DEBUG
std::cout << "Module Size: " << mod_size << std::endl;
#endif
if (mod_size == 0) {
return false;
}
BYTE* buffer = peconv::alloc_pe_buffer(mod_size, PAGE_READWRITE);
if (buffer == nullptr) {
std::cerr << "[-] Failed allocating buffer. Error: " << GetLastError() << std::endl;
return false;
}
//read the module that it mapped in the remote process:
const size_t read_size = read_remote_pe(processHandle, start_addr, mod_size, buffer, mod_size);
if (read_size == 0) {
std::cerr << "[-] Failed reading module. Error: " << GetLastError() << std::endl;
peconv::free_pe_buffer(buffer, mod_size);
buffer = nullptr;
return false;
}
const bool is_dumped = peconv::dump_pe(out_path,
buffer, mod_size,
reinterpret_cast<ULONGLONG>(start_addr),
dump_mode, exportsMap);
peconv::free_pe_buffer(buffer, mod_size);
buffer = nullptr;
return is_dumped;
}

View File

@@ -0,0 +1,90 @@
#include "peconv/resource_parser.h"
#include "peconv/pe_hdrs_helper.h"
#ifdef _DEBUG
#include <iostream>
#endif
bool parse_resource_dir(BYTE* modulePtr, const size_t moduleSize,
IMAGE_RESOURCE_DIRECTORY_ENTRY *root_dir,
const IMAGE_RESOURCE_DIRECTORY *upper_dir,
IMAGE_RESOURCE_DIRECTORY* curr_dir,
peconv::t_on_res_entry_found on_entry);
bool parse_resource_entry(BYTE* modulePtr, const size_t moduleSize,
IMAGE_RESOURCE_DIRECTORY_ENTRY *root_dir,
const IMAGE_RESOURCE_DIRECTORY *upper_dir,
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry,
peconv::t_on_res_entry_found on_entry)
{
if (!entry->DataIsDirectory) {
#ifdef _DEBUG
std::cout << "Entry is NOT a directory\n";
#endif
DWORD offset = entry->OffsetToData;
#ifdef _DEBUG
std::cout << "Offset: " << offset << std::endl;
#endif
IMAGE_RESOURCE_DATA_ENTRY *data_entry = (IMAGE_RESOURCE_DATA_ENTRY*)(offset + (ULONGLONG)upper_dir);
if (!peconv::validate_ptr(modulePtr, moduleSize, data_entry, sizeof(IMAGE_RESOURCE_DATA_ENTRY))) {
return false;
}
#ifdef _DEBUG
std::cout << "Data Offset: " << data_entry->OffsetToData << " : " << data_entry->Size << std::endl;
#endif
BYTE* data_ptr = (BYTE*)((ULONGLONG)modulePtr + data_entry->OffsetToData);
if (!peconv::validate_ptr(modulePtr, moduleSize, data_ptr, data_entry->Size)) {
return false;
}
on_entry(modulePtr, root_dir, data_entry);
return true;
}
#ifdef _DEBUG
std::cout << "Entry is a directory\n";
#endif
//else: it is a next level directory
DWORD offset = entry->OffsetToDirectory;
#ifdef _DEBUG
std::cout << "Offset: " << offset << std::endl;
#endif
IMAGE_RESOURCE_DIRECTORY *next_dir = (IMAGE_RESOURCE_DIRECTORY*)(offset + (ULONGLONG)upper_dir);
if (!peconv::validate_ptr(modulePtr, moduleSize, next_dir, sizeof(IMAGE_RESOURCE_DIRECTORY))) {
return false;
}
return parse_resource_dir(modulePtr, moduleSize, root_dir, upper_dir, next_dir, on_entry);
}
bool parse_resource_dir(BYTE* modulePtr, const size_t moduleSize,
IMAGE_RESOURCE_DIRECTORY_ENTRY *root_dir,
const IMAGE_RESOURCE_DIRECTORY *upper_dir,
IMAGE_RESOURCE_DIRECTORY* curr_dir,
peconv::t_on_res_entry_found on_entry)
{
size_t total_entries = curr_dir->NumberOfIdEntries + curr_dir->NumberOfNamedEntries;
IMAGE_RESOURCE_DIRECTORY_ENTRY* first_entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)((ULONGLONG)&curr_dir->NumberOfIdEntries + sizeof(WORD));
for (size_t i = 0; i < total_entries; i++) {
IMAGE_RESOURCE_DIRECTORY_ENTRY* entry = &first_entry[i];
#ifdef _DEBUG
std::cout << "Entry:" << std::hex << i << " ; " << "Id: " << entry->Id << " ; dataOffset:" << entry->OffsetToData << "\n";
#endif
if (root_dir == nullptr) {
root_dir = entry;
}
parse_resource_entry(modulePtr, moduleSize, root_dir, upper_dir, entry, on_entry);
}
return true;
}
bool peconv::parse_resources(BYTE* modulePtr, t_on_res_entry_found on_entry)
{
const size_t module_size = peconv::get_image_size(modulePtr);
IMAGE_DATA_DIRECTORY *dir = peconv::get_directory_entry(modulePtr, IMAGE_DIRECTORY_ENTRY_RESOURCE);
if (!dir || dir->VirtualAddress == 0 || dir->Size == 0) {
return false;
}
IMAGE_RESOURCE_DIRECTORY *res_dir = (IMAGE_RESOURCE_DIRECTORY*)(dir->VirtualAddress + (ULONGLONG)modulePtr);
if (!peconv::validate_ptr(modulePtr, module_size, res_dir, sizeof(IMAGE_DEBUG_DIRECTORY))) {
return false;
}
return parse_resource_dir(modulePtr, module_size, nullptr, res_dir, res_dir, on_entry);
}

View File

@@ -0,0 +1,56 @@
#include "peconv/resource_util.h"
#ifdef _DEBUG
#include <iostream>
#endif
HMODULE peconv::get_current_module_handle()
{
HMODULE hMod = NULL;
GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCWSTR>(&peconv::get_current_module_handle),
&hMod);
return hMod;
}
peconv::ALIGNED_BUF peconv::load_resource_data(OUT size_t &out_size, int res_id, const LPSTR res_type, HMODULE hInstance)
{
if (hInstance == nullptr) {
hInstance = GetModuleHandleA(NULL);
}
HRSRC res = FindResourceA(hInstance, MAKEINTRESOURCEA(res_id), res_type);
if (!res) {
#ifdef _DEBUG
std::cerr << "Cannot find resource" << std::endl;
#endif
return nullptr;
}
HGLOBAL res_handle = LoadResource(hInstance, res);
if (res_handle == nullptr) {
#ifdef _DEBUG
std::cerr << "Cannot get resource handle" << std::endl;
#endif
return nullptr;
}
BYTE* res_data = (BYTE*) LockResource(res_handle);
size_t r_size = static_cast<size_t>(SizeofResource(hInstance, res));
if (out_size != 0 && out_size <= r_size) {
r_size = out_size;
}
peconv::ALIGNED_BUF out_buf = peconv::alloc_aligned(r_size, PAGE_READWRITE);
if (out_buf != nullptr) {
memcpy(out_buf, res_data, r_size);
out_size = r_size;
} else {
out_size = 0;
}
FreeResource(res_handle);
return out_buf;
}
void peconv::free_resource_data(peconv::ALIGNED_BUF buffer)
{
peconv::free_aligned(buffer);
}

View File

@@ -0,0 +1,100 @@
#include "peconv/util.h"
namespace peconv {
DWORD(WINAPI *g_GetProcessId)(IN HANDLE Process) = nullptr;
HMODULE g_kernel32Hndl = nullptr;
HMODULE g_ntdllHndl = nullptr;
HMODULE get_kernel32_hndl()
{
if (g_kernel32Hndl == nullptr) {
g_kernel32Hndl = LoadLibraryA("kernel32.dll");
}
return g_kernel32Hndl;
}
HMODULE get_ntdll_hndl()
{
if (g_ntdllHndl == nullptr) {
g_ntdllHndl = LoadLibraryA("ntdll.dll");
}
return g_ntdllHndl;
}
};
DWORD ntdll_get_process_id(HANDLE hProcess)
{
#if !defined PROCESSINFOCLASS
typedef LONG PROCESSINFOCLASS;
#endif
NTSTATUS(WINAPI *_ZwQueryInformationProcess)(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength
) = NULL;
HINSTANCE hNtDll = peconv::get_ntdll_hndl();
if (!hNtDll) {
return 0;
}
FARPROC procPtr = GetProcAddress(hNtDll, "ZwQueryInformationProcess");
if (!procPtr) {
return 0;
}
_ZwQueryInformationProcess = (NTSTATUS(WINAPI *)(
HANDLE,
PROCESSINFOCLASS,
PVOID,
ULONG,
PULONG)
) procPtr;
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PVOID PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
PROCESS_BASIC_INFORMATION pbi = { 0 };
if (_ZwQueryInformationProcess(hProcess, 0, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL) == S_OK) {
const DWORD pid = static_cast<DWORD>(pbi.UniqueProcessId);
return pid;
}
return 0;
}
DWORD peconv::get_process_id(HANDLE hProcess)
{
if (!peconv::g_GetProcessId) {
HMODULE kernelLib = peconv::get_kernel32_hndl();
if (!kernelLib) return FALSE;
FARPROC procPtr = GetProcAddress(kernelLib, "GetProcessId");
if (!procPtr) return FALSE;
peconv::g_GetProcessId = (DWORD(WINAPI *) (IN HANDLE))procPtr;
}
if (peconv::g_GetProcessId) {
return peconv::g_GetProcessId(hProcess);
}
//could not retrieve Pid using GetProcessId, try using NTDLL:
return ntdll_get_process_id(hProcess);
}
bool peconv::is_padding(const BYTE *cave_ptr, size_t cave_size, const BYTE padding)
{
for (size_t i = 0; i < cave_size; i++) {
if (cave_ptr[i] != padding) {
return false;
}
}
return true;
}

File diff suppressed because it is too large Load Diff

575
ai_anti_malware/sandbox.cpp Normal file
View File

@@ -0,0 +1,575 @@
#include "sandbox.h"
#include "sandbox_callbacks.h"
std::string getDllNameFromApiSetMap(const std::string& apiSet) {
const std::wstring wApiSet(apiSet.begin(), apiSet.end());
// 获取系统版本信息
using RtlGetVersionFunc = LONG(__stdcall*)(PRTL_OSVERSIONINFOW);
const auto pRtlGetVersion = reinterpret_cast<RtlGetVersionFunc>(
GetProcAddress(LoadLibraryA("ntdll.dll"), "RtlGetVersion"));
RTL_OSVERSIONINFOEXW verInfo{};
verInfo.dwOSVersionInfoSize = sizeof(verInfo);
pRtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(&verInfo));
const ULONG verShort = (verInfo.dwMajorVersion << 8) |
(verInfo.dwMinorVersion << 4) |
verInfo.wServicePackMajor;
if (verShort >= static_cast<ULONG>(WinVer::kWin10)) {
const auto apiSetMap = reinterpret_cast<API_SET_NAMESPACE_ARRAY_10*>(
reinterpret_cast<X64PEB*>(__readgsqword(0x60))->ApiSetMap);
const auto apiSetMapAsNumber = reinterpret_cast<ULONG_PTR>(apiSetMap);
auto nsEntry = reinterpret_cast<PAPI_SET_NAMESPACE_ENTRY_10>(
apiSetMap->Start + apiSetMapAsNumber);
// 遍历API集合查找匹配项
for (ULONG i = 0; i < apiSetMap->Count; i++) {
UNICODE_STRING nameString{}, valueString{};
nameString.MaximumLength = static_cast<USHORT>(nsEntry->NameLength);
nameString.Length = static_cast<USHORT>(nsEntry->NameLength);
nameString.Buffer = reinterpret_cast<PWCHAR>(apiSetMapAsNumber +
nsEntry->NameOffset);
const std::wstring name(nameString.Buffer,
nameString.Length / sizeof(WCHAR));
const std::wstring fullName = name + L".dll";
if (_wcsicmp(wApiSet.c_str(), fullName.c_str()) == 0) {
if (nsEntry->ValueCount == 0) {
return "";
}
const auto valueEntry =
reinterpret_cast<PAPI_SET_VALUE_ENTRY_10>(
apiSetMapAsNumber + nsEntry->ValueOffset);
valueString.Buffer = reinterpret_cast<PWCHAR>(
apiSetMapAsNumber + valueEntry->ValueOffset);
valueString.MaximumLength =
static_cast<USHORT>(valueEntry->ValueLength);
valueString.Length =
static_cast<USHORT>(valueEntry->ValueLength);
const std::wstring value(valueString.Buffer,
valueString.Length / sizeof(WCHAR));
return {value.begin(), value.end()};
}
++nsEntry;
}
} else {
// 不支持Windows 10以下版本
throw std::runtime_error("Unsupported Windows version");
}
return "";
}
class ImportResolver : public peconv::t_function_resolver {
public:
explicit ImportResolver(std::map<std::string, uint64_t> context)
: _functionMap(std::move(context)) {}
FARPROC resolve_func(LPSTR libName, LPSTR funcName) override {
return reinterpret_cast<FARPROC>(_functionMap[std::string(funcName)]);
}
private:
std::map<std::string, uint64_t> _functionMap;
};
class cListImportNames : public peconv::ImportThunksCallback {
public:
cListImportNames(BYTE* _modulePtr, size_t _moduleSize,
std::vector<std::shared_ptr<moudle_import>>& name_to_addr)
: ImportThunksCallback(_modulePtr, _moduleSize),
nameToAddr(name_to_addr) {}
virtual bool processThunks(LPSTR lib_name, ULONG_PTR origFirstThunkPtr,
ULONG_PTR firstThunkPtr) {
if (this->is64b) {
IMAGE_THUNK_DATA64* desc =
reinterpret_cast<IMAGE_THUNK_DATA64*>(origFirstThunkPtr);
ULONGLONG* call_via = reinterpret_cast<ULONGLONG*>(firstThunkPtr);
return processThunks_tpl<ULONGLONG, IMAGE_THUNK_DATA64>(
lib_name, desc, call_via, IMAGE_ORDINAL_FLAG64);
}
IMAGE_THUNK_DATA32* desc =
reinterpret_cast<IMAGE_THUNK_DATA32*>(origFirstThunkPtr);
DWORD* call_via = reinterpret_cast<DWORD*>(firstThunkPtr);
return processThunks_tpl<DWORD, IMAGE_THUNK_DATA32>(
lib_name, desc, call_via, IMAGE_ORDINAL_FLAG32);
}
protected:
template <typename T_FIELD, typename T_IMAGE_THUNK_DATA>
bool processThunks_tpl(LPSTR lib_name, T_IMAGE_THUNK_DATA* desc,
T_FIELD* call_via, T_FIELD ordinal_flag) {
DWORD call_via_rva = static_cast<DWORD>((ULONG_PTR)call_via -
(ULONG_PTR)this->modulePtr);
LPSTR func_name = NULL;
if ((desc->u1.Ordinal & ordinal_flag) == 0) {
PIMAGE_IMPORT_BY_NAME by_name =
(PIMAGE_IMPORT_BY_NAME)((ULONGLONG)modulePtr +
desc->u1.AddressOfData);
func_name = reinterpret_cast<LPSTR>(by_name->Name);
std::string fuck_up_api_ms = lib_name;
if (fuck_up_api_ms.find("api-ms-") != std::string::npos) {
fuck_up_api_ms = getDllNameFromApiSetMap(fuck_up_api_ms);
if (fuck_up_api_ms.size() <= 1) __debugbreak();
}
auto import_data = std::make_shared<moudle_import>();
memcpy(import_data->name, func_name, strlen(func_name));
memcpy(import_data->dll_name, fuck_up_api_ms.c_str(),
fuck_up_api_ms.size());
import_data->function_address = call_via_rva;
import_data->is_delayed_import = false;
nameToAddr.push_back(import_data);
}
return true;
}
std::vector<std::shared_ptr<moudle_import>>& nameToAddr;
};
Sandbox::Sandbox() {}
Sandbox::~Sandbox() {}
auto Sandbox::PushModuleToVM(const char* dllName, uint64_t moduleBase,
uint32_t x32Base) -> void {
// 检查模块是否已加载
auto isModuleLoaded =
std::any_of(m_moduleList.begin(), m_moduleList.end(),
[moduleBase](std::shared_ptr<struct_moudle> module) {
return module->base == moduleBase;
});
if (isModuleLoaded) {
std::cout << "[PE] Skipping " << dllName << " (already loaded)\n";
return;
}
// 解析PE头
auto* dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(moduleBase);
auto* ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<LPBYTE>(moduleBase) + dosHeader->e_lfanew);
// 获取区段对齐值
DWORD sectionAlignment =
(ntHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64)
? reinterpret_cast<PIMAGE_NT_HEADERS64>(ntHeaders)
->OptionalHeader.SectionAlignment
: ntHeaders->OptionalHeader.SectionAlignment;
// 获取区段头
auto* sectionHeader = reinterpret_cast<PIMAGE_SECTION_HEADER>(
reinterpret_cast<PUCHAR>(ntHeaders) + sizeof(ntHeaders->Signature) +
sizeof(ntHeaders->FileHeader) +
ntHeaders->FileHeader.SizeOfOptionalHeader);
// 创建新模块
struct_moudle newModule{};
strncpy(newModule.name, dllName, strlen(dllName));
newModule.base = this->m_peInfo->isX64 ? moduleBase : x32Base;
newModule.entry = ntHeaders->OptionalHeader.AddressOfEntryPoint;
newModule.size = ntHeaders->OptionalHeader.SizeOfImage;
// 处理区段
for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) {
const auto& section = sectionHeader[i];
// if (!(section.Characteristics &
// (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))) {
// continue;
// }
// 设置区段保护属性
int protection = UC_PROT_READ;
if (section.Characteristics & IMAGE_SCN_MEM_EXECUTE)
protection |= UC_PROT_EXEC;
if (section.Characteristics & IMAGE_SCN_MEM_WRITE)
protection |= UC_PROT_WRITE;
// 计算区段大小
auto sectionSize =
AlignSize(max(section.Misc.VirtualSize, section.SizeOfRawData),
sectionAlignment);
// 创建区段信息
moudle_section newSection{};
strncpy(newSection.name, reinterpret_cast<const char*>(section.Name),
8);
newSection.base = section.VirtualAddress;
newSection.size = sectionSize;
newSection.protect_flag = protection;
newModule.sections.push_back(
std::make_shared<moudle_section>(newSection));
std::cout << "[PE] " << dllName << " Section found: " << newSection.name
<< '\n';
}
m_moduleList.push_back(std::make_shared<struct_moudle>(newModule));
uc_mem_map(m_ucEngine, moduleBase, newModule.size,
UC_PROT_READ | UC_PROT_EXEC);
uc_mem_write(m_ucEngine, moduleBase, (void*)moduleBase, newModule.size);
}
auto Sandbox::ResolveExport() -> void {
DWORD exportSize = 0;
static RtlImageDirectoryEntryToDataFn fnRtlImageDirectoryEntryToData;
if (fnRtlImageDirectoryEntryToData == nullptr) {
fnRtlImageDirectoryEntryToData =
reinterpret_cast<RtlImageDirectoryEntryToDataFn>(GetProcAddress(
GetModuleHandleA("ntdll.dll"), "RtlImageDirectoryEntryToData"));
}
// 获取导出表
PIMAGE_EXPORT_DIRECTORY exportDirectory =
static_cast<PIMAGE_EXPORT_DIRECTORY>(fnRtlImageDirectoryEntryToData(
m_peInfo->peBuffer, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT,
&exportSize));
if (exportDirectory) {
const DWORD numberOfNames = exportDirectory->NumberOfNames;
PDWORD addressOfFunctions =
reinterpret_cast<PDWORD>(static_cast<PUCHAR>(m_peInfo->peBuffer) +
exportDirectory->AddressOfFunctions);
PDWORD addressOfNames =
reinterpret_cast<PDWORD>(static_cast<PUCHAR>(m_peInfo->peBuffer) +
exportDirectory->AddressOfNames);
PWORD addressOfNameOrdinals =
reinterpret_cast<PWORD>(static_cast<PUCHAR>(m_peInfo->peBuffer) +
exportDirectory->AddressOfNameOrdinals);
// 遍历导出函数
for (size_t i = 0; i < numberOfNames; i++) {
PCHAR functionName = reinterpret_cast<PCHAR>(
static_cast<PUCHAR>(m_peInfo->peBuffer) + addressOfNames[i]);
// 获取函数RVA
const DWORD functionRva =
addressOfFunctions[addressOfNameOrdinals[i]];
// 创建导出数据结构
moudle_export exportData{};
memcpy(exportData.name, functionName, strlen(functionName));
exportData.function_address = functionRva;
m_exportFuncDict.push_back(
std::make_shared<moudle_export>(exportData));
}
}
}
auto Sandbox::processImportModule(const moudle_import* importModule) -> void {
// 构建模块路径
const std::string systemDir =
m_peInfo->isX64 ? "\\System32\\" : "\\SysWOW64\\";
char windowsPath[MAX_PATH];
if (!GetWindowsDirectoryA(windowsPath, sizeof(windowsPath))) {
throw std::runtime_error("Failed to get Windows directory");
}
const std::string modulePath =
std::string(windowsPath) + systemDir + importModule->dll_name;
// 加载PE模块
size_t mappedPeSize = 0;
const auto moduleBase = reinterpret_cast<uint64_t>(
peconv::load_pe_module(modulePath.c_str(), mappedPeSize, false, false));
if (!moduleBase) {
return;
}
// 添加到虚拟机
const auto moduleBase32 = static_cast<uint32_t>(moduleBase);
PushModuleToVM(importModule->dll_name, moduleBase, moduleBase32);
}
auto Sandbox::ResoveImport() -> void {
// 处理延迟导入
peconv::load_delayed_imports(static_cast<BYTE*>(m_peInfo->peBuffer), 0);
// 解析导入表
cListImportNames importCallback(static_cast<BYTE*>(m_peInfo->peBuffer),
m_peInfo->peSize, m_impFuncDict);
if (!peconv::process_import_table(static_cast<BYTE*>(m_peInfo->peBuffer),
m_peInfo->peSize, &importCallback)) {
throw std::runtime_error("Failed to process import table");
}
// 处理每个导入模块
for (const auto& importModule : m_impFuncDict) {
processImportModule(importModule.get());
}
}
auto Sandbox::SetupVirtualMachine() -> void {
SegmentSelector cs = {0};
cs.fields.index = 1;
uc_reg_write(m_ucEngine, UC_X86_REG_CS, &cs.all);
SegmentSelector ds = {0};
ds.fields.index = 2;
uc_reg_write(m_ucEngine, UC_X86_REG_DS, &ds.all);
SegmentSelector ss = {0};
ss.fields.index = 2;
uc_reg_write(m_ucEngine, UC_X86_REG_SS, &ss.all);
SegmentSelector es = {0};
es.fields.index = 2;
uc_reg_write(m_ucEngine, UC_X86_REG_ES, &es.all);
SegmentSelector gs = {0};
gs.fields.index = 2;
uc_reg_write(m_ucEngine, UC_X86_REG_GS, &gs.all);
FlagRegister eflags = {0};
eflags.fields.id = 1;
eflags.fields.intf = 1;
eflags.fields.reserved1 = 1;
uc_reg_write(m_ucEngine, UC_X86_REG_EFLAGS, &eflags.all);
uint64_t cr8 = 0;
uc_reg_write(m_ucEngine, UC_X86_REG_CR8, &cr8);
/*
映射 m_KSharedUserDataBase
*/
uint64_t m_KSharedUserDataBase = 0x7FFE0000;
uint64_t m_KSharedUserDataEnd = 0x7FFE0FFF; // 0x7FFE2000
uint64_t m_KSharedUserDataSize =
AlignSize(m_KSharedUserDataEnd - m_KSharedUserDataBase, PAGE_SIZE);
uc_mem_map(m_ucEngine, m_KSharedUserDataBase, m_KSharedUserDataSize,
UC_PROT_READ);
uc_mem_write(m_ucEngine, m_KSharedUserDataBase,
(void*)m_KSharedUserDataBase, m_KSharedUserDataSize);
m_tebBase = TEB_BASE; // 进程TEB地址
m_pebBase = PEB_BASE; // 进程PEB地址
// stack
m_stackBase = this->m_peInfo->isX64 ? STACK_BASE_64 : STACK_BASE_32;
m_stackSize = this->m_peInfo->isX64 ? STACK_SIZE_64 : STACK_SIZE_32;
m_stackEnd = m_stackBase + m_stackSize;
// heap
m_heapBase = this->m_peInfo->isX64 ? HEAP_ADDRESS_64 : HEAP_ADDRESS_32;
m_heapSize = this->m_peInfo->isX64 ? HEAP_SIZE_64 : HEAP_SIZE_32;
m_heapEnd = m_heapBase + m_heapSize;
// 根据PE文件类型设置PEB和TEB
if (this->m_peInfo->isX64) {
// 设置64位PEB
m_peb64.ImageBaseAddress = m_peInfo->RecImageBase;
m_pebEnd = m_pebBase + AlignSize(sizeof(X64PEB), PAGE_SIZE);
m_tebEnd = m_tebBase + AlignSize(sizeof(X64TEB), PAGE_SIZE);
// 设置64位TEB
m_teb64.ClientId.UniqueProcess = GetCurrentProcessId();
m_teb64.ClientId.UniqueThread = GetCurrentThreadId();
m_teb64.ProcessEnvironmentBlock = reinterpret_cast<X64PEB*>(m_pebBase);
m_teb64.NtTib.StackBase = (DWORD64)m_stackBase;
m_teb64.NtTib.StackLimit = (DWORD64)m_stackSize;
// 设置堆
m_peb64.ProcessHeap = m_heapBase;
// 设置GS基址结构
m_gsBaseStruct.teb = m_tebBase;
m_gsBaseStruct.peb = m_pebBase;
uint64_t gsAllocSize = AlignSize(sizeof(struct_gs_base), PAGE_SIZE);
// 映射PEB到虚拟内存
uc_mem_map(m_ucEngine, m_pebBase, m_pebEnd - m_pebBase,
UC_PROT_READ | UC_PROT_WRITE);
uc_mem_write(m_ucEngine, m_pebBase, &m_peb64, sizeof(X64PEB));
// 映射TEB到虚拟内存
uc_mem_map(m_ucEngine, m_tebBase, m_tebEnd - m_tebBase,
UC_PROT_READ | UC_PROT_WRITE);
uc_mem_write(m_ucEngine, m_tebBase, &m_teb64, sizeof(X64TEB));
// 映射GS基址结构到虚拟内存
uc_mem_map(m_ucEngine, m_gsBase, gsAllocSize, UC_PROT_READ);
uc_mem_write(m_ucEngine, m_gsBase, &m_gsBaseStruct,
sizeof(struct_gs_base));
// 设置GS基址MSR
uc_x86_msr msr;
msr.rid = static_cast<uint32_t>(Msr::kIa32GsBase);
msr.value = m_gsBase;
uc_reg_write(m_ucEngine, UC_X86_REG_MSR, &msr);
} else {
// 设置32位PEB
m_peb32.ImageBaseAddress = static_cast<ULONG>(m_peInfo->RecImageBase);
m_pebEnd = m_pebBase + AlignSize(sizeof(X32PEB), PAGE_SIZE);
m_tebEnd = m_tebBase + AlignSize(sizeof(X32TEB), PAGE_SIZE);
// 设置32位TEB
m_teb32.ClientId.UniqueProcess = GetCurrentProcessId();
m_teb32.ClientId.UniqueThread = GetCurrentThreadId();
m_teb32.ProcessEnvironmentBlock = static_cast<ULONG>(m_pebBase);
m_teb32.NtTib.StackBase = static_cast<ULONG>(m_stackBase);
m_teb32.NtTib.StackLimit = static_cast<ULONG>(m_stackSize);
// 设置堆
m_peb32.ProcessHeap = static_cast<ULONG>(m_heapBase);
// 映射PEB到虚拟内存
uc_mem_map(m_ucEngine, m_pebBase, m_pebEnd - m_pebBase,
UC_PROT_READ | UC_PROT_WRITE);
uc_mem_write(m_ucEngine, m_pebBase, &m_peb32, sizeof(X32PEB));
// 映射TEB到虚拟内存
uc_mem_map(m_ucEngine, m_tebBase, m_tebEnd - m_tebBase,
UC_PROT_READ | UC_PROT_WRITE);
uc_mem_write(m_ucEngine, m_tebBase, &m_teb32, sizeof(X32TEB));
// 对于32位我们需要设置FS段寄存器指向TEB
SegmentSelector fs = {0};
fs.fields.index = 3;
uc_reg_write(m_ucEngine, UC_X86_REG_FS, &fs.all);
// 设置FS基址MSR
uc_x86_msr msr;
msr.rid = static_cast<uint32_t>(Msr::kIa32FsBase);
msr.value = m_tebBase;
uc_reg_write(m_ucEngine, UC_X86_REG_MSR, &msr);
}
}
auto Sandbox::InitEnv(std::shared_ptr<BasicPeInfo> peInfo) -> void {
m_peInfo = peInfo;
if (cs_open(CS_ARCH_X86, peInfo->isX64 ? CS_MODE_64 : CS_MODE_32,
&m_csHandle) != CS_ERR_OK) {
throw std::runtime_error("Failed to initialize Capstone");
}
if (uc_open(UC_ARCH_X86, peInfo->isX64 ? UC_MODE_64 : UC_MODE_32,
&m_ucEngine) != UC_ERR_OK) {
cs_close(&m_csHandle); // 清理已分配的capstone资源
throw std::runtime_error("Failed to initialize Unicorn");
}
ResoveImport();
ResolveExport();
uc_err ucErr = uc_mem_map(m_ucEngine, m_peInfo->RecImageBase,
m_peInfo->peSize, UC_PROT_ALL);
if (ucErr != UC_ERR_OK) {
throw std::runtime_error("Failed to map memory");
}
uc_mem_write(m_ucEngine, m_peInfo->RecImageBase, m_peInfo->peBuffer,
m_peInfo->peSize);
printf("map file to vm file: %llx\n", m_peInfo->RecImageBase);
printf("map file to vm size: %llx\n", m_peInfo->peSize);
SetupVirtualMachine();
}
auto Sandbox::Run() -> void {
// 初始化堆栈
uc_err err = uc_mem_map(m_ucEngine, m_stackBase, m_stackSize,
UC_PROT_READ | UC_PROT_WRITE);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to map stack memory");
}
// 初始化堆
err = uc_mem_map(m_ucEngine, m_heapBase, m_heapSize,
UC_PROT_READ | UC_PROT_WRITE);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to map heap memory");
}
// 设置寄存器
uint64_t rsp = m_stackEnd - 128;
err = uc_reg_write(m_ucEngine,
m_peInfo->isX64 ? UC_X86_REG_RSP : UC_X86_REG_ESP, &rsp);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to write stack pointer");
}
// 设置入口点
uint64_t entryPoint = m_peInfo->RecImageBase + m_peInfo->entryPoint;
// 添加钩子
uc_hook hook_code, hook_mem, hook_mem_unmap, hook_mem_write, hook_syscall;
// 代码执行钩子
err = uc_hook_add(m_ucEngine, &hook_code, UC_HOOK_CODE,
reinterpret_cast<void*>(sandboxCallbacks::handleCodeRun),
this, 1, 0);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to add code hook");
}
// 内存读取钩子
err =
uc_hook_add(m_ucEngine, &hook_mem, UC_HOOK_MEM_READ | UC_HOOK_MEM_FETCH,
reinterpret_cast<void*>(sandboxCallbacks::handleMemoryRead),
this, 1, 0);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to add memory read hook");
}
// 未映射内存访问钩子
err = uc_hook_add(
m_ucEngine, &hook_mem_unmap,
UC_HOOK_MEM_FETCH_UNMAPPED | UC_HOOK_MEM_READ_UNMAPPED |
UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_PROT,
reinterpret_cast<void*>(sandboxCallbacks::handleMemoryUnmapRead), this,
1, 0);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to add unmapped memory hook");
}
// 内存写入钩子
err = uc_hook_add(
m_ucEngine, &hook_mem_write, UC_HOOK_MEM_WRITE | UC_HOOK_MEM_WRITE_PROT,
reinterpret_cast<void*>(sandboxCallbacks::handleMemoryWrite), this, 1,
0);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to add memory write hook");
}
// 系统调用钩子
err = uc_hook_add(m_ucEngine, &hook_syscall, UC_HOOK_INTR | UC_HOOK_INSN,
reinterpret_cast<void*>(sandboxCallbacks::handleSyscall),
this, 1, 0, UC_X86_INS_SYSCALL);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to add syscall hook");
}
// 设置EIP/RIP
err = uc_reg_write(m_ucEngine,
m_peInfo->isX64 ? UC_X86_REG_RIP : UC_X86_REG_EIP,
&entryPoint);
if (err != UC_ERR_OK) {
throw std::runtime_error("Failed to set entry point");
}
// 开始执行
std::cout << "Starting execution at " << std::hex << entryPoint
<< std::endl;
err = uc_emu_start(m_ucEngine, entryPoint, m_peInfo->imageEnd, 0, 0);
if (err != UC_ERR_OK) {
std::cerr << "Emulation error: " << uc_strerror(err) << std::endl;
// 32位环境下的错误处理
if (!m_peInfo->isX64) {
uint32_t eip;
uc_reg_read(m_ucEngine, UC_X86_REG_EIP, &eip);
std::cerr << "Error occurred at EIP: 0x" << std::hex << eip
<< std::endl;
// 尝试读取当前指令
uint8_t instruction[16];
if (uc_mem_read(m_ucEngine, eip, instruction,
sizeof(instruction)) == UC_ERR_OK) {
std::cerr << "Instruction bytes: ";
for (int i = 0; i < 16; i++) {
printf("%02X ", instruction[i]);
}
std::cerr << std::endl;
}
}
}
}

94
ai_anti_malware/sandbox.h Normal file
View File

@@ -0,0 +1,94 @@
#pragma once
#include "head.h"
#define PAGE_SIZE 0x1000
#define CF_MASK (1 << 0)
#define PF_MASK (1 << 2)
#define ZF_MASK (1 << 6)
#define SF_MASK (1 << 7)
#define OF_MASK (1 << 11)
#define ALL_MASK (OF_MASK | SF_MASK | ZF_MASK | PF_MASK | CF_MASK)
#define STACK_BASE_64 0x7ffffffde000
#define STACK_BASE_32 0xfffdd000
#define STACK_SIZE_64 0x40000
#define STACK_SIZE_32 0x21000
#define HEAP_ADDRESS_64 0x500000000
#define HEAP_SIZE_64 0x5000000
#define HEAP_ADDRESS_32 0x5000000
#define HEAP_SIZE_32 0x5000000
#define PEB_BASE 0x80000
#define TEB_BASE 0x90000
#define X86_GDT_ADDR 0x30000
#define X86_GDT_LIMIT 0x1000
#define X86_GDT_ENTRY_SIZE 0x8
#define API_FUNCTION_SIZE 8
#define PAGE_ALIGN(Va) (ULONG_PTR)(Va) & ~(PAGE_SIZE - 1)
#define PAGE_ALIGN_64(Va) (Va) & ~(0x1000ull - 1)
#define PAGE_ALIGN_64k(Va) ((Va)) & ~(0x10000ull - 1)
#define AlignSize(Size, Align) (Size + Align - 1) / Align* Align
enum class WinVer {
kWin7 = 0x0610,
kWin7SP1 = 0x0611,
kWin8 = 0x0620,
kWin81 = 0x0630,
kWin10 = 0x0A00,
kWin10RS1 = 0x0A01, // Anniversary update
kWin10RS2 = 0x0A02, // Creators update
kWin10RS3 = 0x0A03, // Fall creators update
kWin10RS4 = 0x0A04, // Spring creators update
kWin10RS5 = 0x0A05, // October 2018 update
kWin1019H1 = 0x0A06, // May 2019 update 19H1
kWin1019H2 = 0x0A07, // November 2019 update 19H2
kWin1020H1 = 0x0A08 // April 2020 update 20H1
};
class Sandbox {
public:
Sandbox();
~Sandbox();
// Public methods
auto InitEnv(std::shared_ptr<BasicPeInfo> peInfo) -> void;
auto Run() -> void;
auto GetCapstoneHandle() const -> csh { return m_csHandle; }
auto GetUnicornHandle() const -> uc_engine* { return m_ucEngine; }
auto GetPeInfo() const -> std::shared_ptr<BasicPeInfo> { return m_peInfo; }
private:
std::shared_ptr<BasicPeInfo> m_peInfo;
uint64_t m_gsBase;
uint64_t m_pebBase;
uint64_t m_pebEnd;
uint64_t m_tebBase;
uint64_t m_tebEnd;
PVOID m_stackBuffer; // 没有释放
uint64_t m_stackBase;
uint64_t m_stackSize;
uint64_t m_stackEnd;
uint64_t m_heapBase;
uint64_t m_heapSize;
uint64_t m_heapEnd;
uint64_t m_fakeBase;
struct_gs_base m_gsBaseStruct;
X64TEB m_teb64;
X64PEB m_peb64;
X32TEB m_teb32;
X32PEB m_peb32;
csh m_csHandle; // Capstone handle
uc_engine* m_ucEngine; // Unicorn engine handle
std::vector<std::shared_ptr<moudle_import>> m_impFuncDict;
std::vector<std::shared_ptr<moudle_export>> m_exportFuncDict;
std::vector<std::shared_ptr<struct_moudle>> m_moduleList;
auto ResoveImport() -> void;
auto SetupVirtualMachine() -> void;
auto ResolveExport() -> void;
auto PushModuleToVM(const char* dllName, uint64_t moduleBase,
uint32_t x32Base) -> void;
auto processImportModule(const moudle_import* importModule) -> void;
};

View File

@@ -0,0 +1 @@
#include "sandbox_callbacks.h"

View File

@@ -0,0 +1,70 @@
#pragma once
#include "sandbox.h"
namespace sandboxCallbacks {
static void handleCodeRun(uc_engine* uc, uint64_t address, uint32_t size,
void* userData) {
auto* sandbox = static_cast<Sandbox*>(userData);
if (!sandbox) return;
// 读取当前执行的代码
uint8_t* codeBuffer = new uint8_t[size];
if (uc_mem_read(uc, address, codeBuffer, size) != UC_ERR_OK) {
delete[] codeBuffer;
return;
}
// 使用Capstone反汇编
cs_insn* instruction;
size_t instructionCount =
cs_disasm(sandbox->GetCapstoneHandle(), codeBuffer, size, address, 0,
&instruction);
if (instructionCount > 0) {
// 打印地址和反汇编结果
printf("0x%016" PRIx64 " %-12s %s\n", instruction[0].address,
instruction[0].mnemonic, instruction[0].op_str);
cs_free(instruction, instructionCount);
}
delete[] codeBuffer;
}
static void handleMemoryRead(uc_engine* uc, uc_mem_type type, uint64_t address,
int size, int64_t value, void* userData) {
auto* sandbox = static_cast<Sandbox*>(userData);
if (!sandbox) return;
uint64_t regRax, regRip;
uc_reg_read(uc,
sandbox->GetPeInfo()->isX64 ? UC_X86_REG_RAX : UC_X86_REG_EAX,
&regRax);
uc_reg_read(uc,
sandbox->GetPeInfo()->isX64 ? UC_X86_REG_RIP : UC_X86_REG_EIP,
&regRip);
uint64_t readAddress;
auto readError =
uc_mem_read(sandbox->GetUnicornHandle(), address, &readAddress, size);
printf(
"[handleMemoryRead] Address: %p Size: %p Rax: %p Rip: %p Error: %d "
"ReadData: %p\n",
address, size, regRax, regRip, readError, readAddress);
}
static void handleMemoryUnmapRead(uc_engine* uc, uc_mem_type type,
uint64_t address, int size, int64_t value,
void* userData) {
// 待实现
}
static void handleMemoryWrite(uc_engine* uc, uc_mem_type type, uint64_t address,
int size, int64_t value, void* userData) {
// 待实现
}
static void handleSyscall(uc_engine* uc, void* userData) {
// 待实现
}
} // namespace sandboxCallbacks

View File

@@ -0,0 +1,157 @@
/* Unicorn Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */
/* This file is released under LGPL2.
See COPYING.LGPL2 in root directory for more details
*/
#ifndef UNICORN_ARM_H
#define UNICORN_ARM_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
//> ARM registers
typedef enum uc_arm_reg {
UC_ARM_REG_INVALID = 0,
UC_ARM_REG_APSR,
UC_ARM_REG_APSR_NZCV,
UC_ARM_REG_CPSR,
UC_ARM_REG_FPEXC,
UC_ARM_REG_FPINST,
UC_ARM_REG_FPSCR,
UC_ARM_REG_FPSCR_NZCV,
UC_ARM_REG_FPSID,
UC_ARM_REG_ITSTATE,
UC_ARM_REG_LR,
UC_ARM_REG_PC,
UC_ARM_REG_SP,
UC_ARM_REG_SPSR,
UC_ARM_REG_D0,
UC_ARM_REG_D1,
UC_ARM_REG_D2,
UC_ARM_REG_D3,
UC_ARM_REG_D4,
UC_ARM_REG_D5,
UC_ARM_REG_D6,
UC_ARM_REG_D7,
UC_ARM_REG_D8,
UC_ARM_REG_D9,
UC_ARM_REG_D10,
UC_ARM_REG_D11,
UC_ARM_REG_D12,
UC_ARM_REG_D13,
UC_ARM_REG_D14,
UC_ARM_REG_D15,
UC_ARM_REG_D16,
UC_ARM_REG_D17,
UC_ARM_REG_D18,
UC_ARM_REG_D19,
UC_ARM_REG_D20,
UC_ARM_REG_D21,
UC_ARM_REG_D22,
UC_ARM_REG_D23,
UC_ARM_REG_D24,
UC_ARM_REG_D25,
UC_ARM_REG_D26,
UC_ARM_REG_D27,
UC_ARM_REG_D28,
UC_ARM_REG_D29,
UC_ARM_REG_D30,
UC_ARM_REG_D31,
UC_ARM_REG_FPINST2,
UC_ARM_REG_MVFR0,
UC_ARM_REG_MVFR1,
UC_ARM_REG_MVFR2,
UC_ARM_REG_Q0,
UC_ARM_REG_Q1,
UC_ARM_REG_Q2,
UC_ARM_REG_Q3,
UC_ARM_REG_Q4,
UC_ARM_REG_Q5,
UC_ARM_REG_Q6,
UC_ARM_REG_Q7,
UC_ARM_REG_Q8,
UC_ARM_REG_Q9,
UC_ARM_REG_Q10,
UC_ARM_REG_Q11,
UC_ARM_REG_Q12,
UC_ARM_REG_Q13,
UC_ARM_REG_Q14,
UC_ARM_REG_Q15,
UC_ARM_REG_R0,
UC_ARM_REG_R1,
UC_ARM_REG_R2,
UC_ARM_REG_R3,
UC_ARM_REG_R4,
UC_ARM_REG_R5,
UC_ARM_REG_R6,
UC_ARM_REG_R7,
UC_ARM_REG_R8,
UC_ARM_REG_R9,
UC_ARM_REG_R10,
UC_ARM_REG_R11,
UC_ARM_REG_R12,
UC_ARM_REG_S0,
UC_ARM_REG_S1,
UC_ARM_REG_S2,
UC_ARM_REG_S3,
UC_ARM_REG_S4,
UC_ARM_REG_S5,
UC_ARM_REG_S6,
UC_ARM_REG_S7,
UC_ARM_REG_S8,
UC_ARM_REG_S9,
UC_ARM_REG_S10,
UC_ARM_REG_S11,
UC_ARM_REG_S12,
UC_ARM_REG_S13,
UC_ARM_REG_S14,
UC_ARM_REG_S15,
UC_ARM_REG_S16,
UC_ARM_REG_S17,
UC_ARM_REG_S18,
UC_ARM_REG_S19,
UC_ARM_REG_S20,
UC_ARM_REG_S21,
UC_ARM_REG_S22,
UC_ARM_REG_S23,
UC_ARM_REG_S24,
UC_ARM_REG_S25,
UC_ARM_REG_S26,
UC_ARM_REG_S27,
UC_ARM_REG_S28,
UC_ARM_REG_S29,
UC_ARM_REG_S30,
UC_ARM_REG_S31,
UC_ARM_REG_C1_C0_2,
UC_ARM_REG_C13_C0_2,
UC_ARM_REG_C13_C0_3,
UC_ARM_REG_IPSR,
UC_ARM_REG_MSP,
UC_ARM_REG_PSP,
UC_ARM_REG_CONTROL,
UC_ARM_REG_ENDING, // <-- mark the end of the list or registers
//> alias registers
UC_ARM_REG_R13 = UC_ARM_REG_SP,
UC_ARM_REG_R14 = UC_ARM_REG_LR,
UC_ARM_REG_R15 = UC_ARM_REG_PC,
UC_ARM_REG_SB = UC_ARM_REG_R9,
UC_ARM_REG_SL = UC_ARM_REG_R10,
UC_ARM_REG_FP = UC_ARM_REG_R11,
UC_ARM_REG_IP = UC_ARM_REG_R12,
} uc_arm_reg;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,344 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */
/* This file is released under LGPL2.
See COPYING.LGPL2 in root directory for more details
*/
#ifndef UNICORN_ARM64_H
#define UNICORN_ARM64_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
//> ARM64 registers
typedef enum uc_arm64_reg {
UC_ARM64_REG_INVALID = 0,
UC_ARM64_REG_X29,
UC_ARM64_REG_X30,
UC_ARM64_REG_NZCV,
UC_ARM64_REG_SP,
UC_ARM64_REG_WSP,
UC_ARM64_REG_WZR,
UC_ARM64_REG_XZR,
UC_ARM64_REG_B0,
UC_ARM64_REG_B1,
UC_ARM64_REG_B2,
UC_ARM64_REG_B3,
UC_ARM64_REG_B4,
UC_ARM64_REG_B5,
UC_ARM64_REG_B6,
UC_ARM64_REG_B7,
UC_ARM64_REG_B8,
UC_ARM64_REG_B9,
UC_ARM64_REG_B10,
UC_ARM64_REG_B11,
UC_ARM64_REG_B12,
UC_ARM64_REG_B13,
UC_ARM64_REG_B14,
UC_ARM64_REG_B15,
UC_ARM64_REG_B16,
UC_ARM64_REG_B17,
UC_ARM64_REG_B18,
UC_ARM64_REG_B19,
UC_ARM64_REG_B20,
UC_ARM64_REG_B21,
UC_ARM64_REG_B22,
UC_ARM64_REG_B23,
UC_ARM64_REG_B24,
UC_ARM64_REG_B25,
UC_ARM64_REG_B26,
UC_ARM64_REG_B27,
UC_ARM64_REG_B28,
UC_ARM64_REG_B29,
UC_ARM64_REG_B30,
UC_ARM64_REG_B31,
UC_ARM64_REG_D0,
UC_ARM64_REG_D1,
UC_ARM64_REG_D2,
UC_ARM64_REG_D3,
UC_ARM64_REG_D4,
UC_ARM64_REG_D5,
UC_ARM64_REG_D6,
UC_ARM64_REG_D7,
UC_ARM64_REG_D8,
UC_ARM64_REG_D9,
UC_ARM64_REG_D10,
UC_ARM64_REG_D11,
UC_ARM64_REG_D12,
UC_ARM64_REG_D13,
UC_ARM64_REG_D14,
UC_ARM64_REG_D15,
UC_ARM64_REG_D16,
UC_ARM64_REG_D17,
UC_ARM64_REG_D18,
UC_ARM64_REG_D19,
UC_ARM64_REG_D20,
UC_ARM64_REG_D21,
UC_ARM64_REG_D22,
UC_ARM64_REG_D23,
UC_ARM64_REG_D24,
UC_ARM64_REG_D25,
UC_ARM64_REG_D26,
UC_ARM64_REG_D27,
UC_ARM64_REG_D28,
UC_ARM64_REG_D29,
UC_ARM64_REG_D30,
UC_ARM64_REG_D31,
UC_ARM64_REG_H0,
UC_ARM64_REG_H1,
UC_ARM64_REG_H2,
UC_ARM64_REG_H3,
UC_ARM64_REG_H4,
UC_ARM64_REG_H5,
UC_ARM64_REG_H6,
UC_ARM64_REG_H7,
UC_ARM64_REG_H8,
UC_ARM64_REG_H9,
UC_ARM64_REG_H10,
UC_ARM64_REG_H11,
UC_ARM64_REG_H12,
UC_ARM64_REG_H13,
UC_ARM64_REG_H14,
UC_ARM64_REG_H15,
UC_ARM64_REG_H16,
UC_ARM64_REG_H17,
UC_ARM64_REG_H18,
UC_ARM64_REG_H19,
UC_ARM64_REG_H20,
UC_ARM64_REG_H21,
UC_ARM64_REG_H22,
UC_ARM64_REG_H23,
UC_ARM64_REG_H24,
UC_ARM64_REG_H25,
UC_ARM64_REG_H26,
UC_ARM64_REG_H27,
UC_ARM64_REG_H28,
UC_ARM64_REG_H29,
UC_ARM64_REG_H30,
UC_ARM64_REG_H31,
UC_ARM64_REG_Q0,
UC_ARM64_REG_Q1,
UC_ARM64_REG_Q2,
UC_ARM64_REG_Q3,
UC_ARM64_REG_Q4,
UC_ARM64_REG_Q5,
UC_ARM64_REG_Q6,
UC_ARM64_REG_Q7,
UC_ARM64_REG_Q8,
UC_ARM64_REG_Q9,
UC_ARM64_REG_Q10,
UC_ARM64_REG_Q11,
UC_ARM64_REG_Q12,
UC_ARM64_REG_Q13,
UC_ARM64_REG_Q14,
UC_ARM64_REG_Q15,
UC_ARM64_REG_Q16,
UC_ARM64_REG_Q17,
UC_ARM64_REG_Q18,
UC_ARM64_REG_Q19,
UC_ARM64_REG_Q20,
UC_ARM64_REG_Q21,
UC_ARM64_REG_Q22,
UC_ARM64_REG_Q23,
UC_ARM64_REG_Q24,
UC_ARM64_REG_Q25,
UC_ARM64_REG_Q26,
UC_ARM64_REG_Q27,
UC_ARM64_REG_Q28,
UC_ARM64_REG_Q29,
UC_ARM64_REG_Q30,
UC_ARM64_REG_Q31,
UC_ARM64_REG_S0,
UC_ARM64_REG_S1,
UC_ARM64_REG_S2,
UC_ARM64_REG_S3,
UC_ARM64_REG_S4,
UC_ARM64_REG_S5,
UC_ARM64_REG_S6,
UC_ARM64_REG_S7,
UC_ARM64_REG_S8,
UC_ARM64_REG_S9,
UC_ARM64_REG_S10,
UC_ARM64_REG_S11,
UC_ARM64_REG_S12,
UC_ARM64_REG_S13,
UC_ARM64_REG_S14,
UC_ARM64_REG_S15,
UC_ARM64_REG_S16,
UC_ARM64_REG_S17,
UC_ARM64_REG_S18,
UC_ARM64_REG_S19,
UC_ARM64_REG_S20,
UC_ARM64_REG_S21,
UC_ARM64_REG_S22,
UC_ARM64_REG_S23,
UC_ARM64_REG_S24,
UC_ARM64_REG_S25,
UC_ARM64_REG_S26,
UC_ARM64_REG_S27,
UC_ARM64_REG_S28,
UC_ARM64_REG_S29,
UC_ARM64_REG_S30,
UC_ARM64_REG_S31,
UC_ARM64_REG_W0,
UC_ARM64_REG_W1,
UC_ARM64_REG_W2,
UC_ARM64_REG_W3,
UC_ARM64_REG_W4,
UC_ARM64_REG_W5,
UC_ARM64_REG_W6,
UC_ARM64_REG_W7,
UC_ARM64_REG_W8,
UC_ARM64_REG_W9,
UC_ARM64_REG_W10,
UC_ARM64_REG_W11,
UC_ARM64_REG_W12,
UC_ARM64_REG_W13,
UC_ARM64_REG_W14,
UC_ARM64_REG_W15,
UC_ARM64_REG_W16,
UC_ARM64_REG_W17,
UC_ARM64_REG_W18,
UC_ARM64_REG_W19,
UC_ARM64_REG_W20,
UC_ARM64_REG_W21,
UC_ARM64_REG_W22,
UC_ARM64_REG_W23,
UC_ARM64_REG_W24,
UC_ARM64_REG_W25,
UC_ARM64_REG_W26,
UC_ARM64_REG_W27,
UC_ARM64_REG_W28,
UC_ARM64_REG_W29,
UC_ARM64_REG_W30,
UC_ARM64_REG_X0,
UC_ARM64_REG_X1,
UC_ARM64_REG_X2,
UC_ARM64_REG_X3,
UC_ARM64_REG_X4,
UC_ARM64_REG_X5,
UC_ARM64_REG_X6,
UC_ARM64_REG_X7,
UC_ARM64_REG_X8,
UC_ARM64_REG_X9,
UC_ARM64_REG_X10,
UC_ARM64_REG_X11,
UC_ARM64_REG_X12,
UC_ARM64_REG_X13,
UC_ARM64_REG_X14,
UC_ARM64_REG_X15,
UC_ARM64_REG_X16,
UC_ARM64_REG_X17,
UC_ARM64_REG_X18,
UC_ARM64_REG_X19,
UC_ARM64_REG_X20,
UC_ARM64_REG_X21,
UC_ARM64_REG_X22,
UC_ARM64_REG_X23,
UC_ARM64_REG_X24,
UC_ARM64_REG_X25,
UC_ARM64_REG_X26,
UC_ARM64_REG_X27,
UC_ARM64_REG_X28,
UC_ARM64_REG_V0,
UC_ARM64_REG_V1,
UC_ARM64_REG_V2,
UC_ARM64_REG_V3,
UC_ARM64_REG_V4,
UC_ARM64_REG_V5,
UC_ARM64_REG_V6,
UC_ARM64_REG_V7,
UC_ARM64_REG_V8,
UC_ARM64_REG_V9,
UC_ARM64_REG_V10,
UC_ARM64_REG_V11,
UC_ARM64_REG_V12,
UC_ARM64_REG_V13,
UC_ARM64_REG_V14,
UC_ARM64_REG_V15,
UC_ARM64_REG_V16,
UC_ARM64_REG_V17,
UC_ARM64_REG_V18,
UC_ARM64_REG_V19,
UC_ARM64_REG_V20,
UC_ARM64_REG_V21,
UC_ARM64_REG_V22,
UC_ARM64_REG_V23,
UC_ARM64_REG_V24,
UC_ARM64_REG_V25,
UC_ARM64_REG_V26,
UC_ARM64_REG_V27,
UC_ARM64_REG_V28,
UC_ARM64_REG_V29,
UC_ARM64_REG_V30,
UC_ARM64_REG_V31,
//> pseudo registers
UC_ARM64_REG_PC, // program counter register
UC_ARM64_REG_CPACR_EL1,
//> thread registers
UC_ARM64_REG_TPIDR_EL0,
UC_ARM64_REG_TPIDRRO_EL0,
UC_ARM64_REG_TPIDR_EL1,
UC_ARM64_REG_PSTATE,
//> exception link registers
UC_ARM64_REG_ELR_EL0,
UC_ARM64_REG_ELR_EL1,
UC_ARM64_REG_ELR_EL2,
UC_ARM64_REG_ELR_EL3,
//> stack pointers registers
UC_ARM64_REG_SP_EL0,
UC_ARM64_REG_SP_EL1,
UC_ARM64_REG_SP_EL2,
UC_ARM64_REG_SP_EL3,
//> other CP15 registers
UC_ARM64_REG_TTBR0_EL1,
UC_ARM64_REG_TTBR1_EL1,
UC_ARM64_REG_ESR_EL0,
UC_ARM64_REG_ESR_EL1,
UC_ARM64_REG_ESR_EL2,
UC_ARM64_REG_ESR_EL3,
UC_ARM64_REG_FAR_EL0,
UC_ARM64_REG_FAR_EL1,
UC_ARM64_REG_FAR_EL2,
UC_ARM64_REG_FAR_EL3,
UC_ARM64_REG_PAR_EL1,
UC_ARM64_REG_MAIR_EL1,
UC_ARM64_REG_VBAR_EL0,
UC_ARM64_REG_VBAR_EL1,
UC_ARM64_REG_VBAR_EL2,
UC_ARM64_REG_VBAR_EL3,
UC_ARM64_REG_ENDING, // <-- mark the end of the list of registers
//> alias registers
UC_ARM64_REG_IP0 = UC_ARM64_REG_X16,
UC_ARM64_REG_IP1 = UC_ARM64_REG_X17,
UC_ARM64_REG_FP = UC_ARM64_REG_X29,
UC_ARM64_REG_LR = UC_ARM64_REG_X30,
} uc_arm64_reg;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,50 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2017 */
/* This file is released under LGPL2.
See COPYING.LGPL2 in root directory for more details
*/
#ifndef UNICORN_M68K_H
#define UNICORN_M68K_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
//> M68K registers
typedef enum uc_m68k_reg {
UC_M68K_REG_INVALID = 0,
UC_M68K_REG_A0,
UC_M68K_REG_A1,
UC_M68K_REG_A2,
UC_M68K_REG_A3,
UC_M68K_REG_A4,
UC_M68K_REG_A5,
UC_M68K_REG_A6,
UC_M68K_REG_A7,
UC_M68K_REG_D0,
UC_M68K_REG_D1,
UC_M68K_REG_D2,
UC_M68K_REG_D3,
UC_M68K_REG_D4,
UC_M68K_REG_D5,
UC_M68K_REG_D6,
UC_M68K_REG_D7,
UC_M68K_REG_SR,
UC_M68K_REG_PC,
UC_M68K_REG_ENDING, // <-- mark the end of the list of registers
} uc_m68k_reg;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,232 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */
/* This file is released under LGPL2.
See COPYING.LGPL2 in root directory for more details
*/
#ifndef UNICORN_MIPS_H
#define UNICORN_MIPS_H
#ifdef __cplusplus
extern "C" {
#endif
// GCC MIPS toolchain has a default macro called "mips" which breaks
// compilation
#undef mips
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
//> MIPS registers
typedef enum UC_MIPS_REG {
UC_MIPS_REG_INVALID = 0,
//> General purpose registers
UC_MIPS_REG_PC,
UC_MIPS_REG_0,
UC_MIPS_REG_1,
UC_MIPS_REG_2,
UC_MIPS_REG_3,
UC_MIPS_REG_4,
UC_MIPS_REG_5,
UC_MIPS_REG_6,
UC_MIPS_REG_7,
UC_MIPS_REG_8,
UC_MIPS_REG_9,
UC_MIPS_REG_10,
UC_MIPS_REG_11,
UC_MIPS_REG_12,
UC_MIPS_REG_13,
UC_MIPS_REG_14,
UC_MIPS_REG_15,
UC_MIPS_REG_16,
UC_MIPS_REG_17,
UC_MIPS_REG_18,
UC_MIPS_REG_19,
UC_MIPS_REG_20,
UC_MIPS_REG_21,
UC_MIPS_REG_22,
UC_MIPS_REG_23,
UC_MIPS_REG_24,
UC_MIPS_REG_25,
UC_MIPS_REG_26,
UC_MIPS_REG_27,
UC_MIPS_REG_28,
UC_MIPS_REG_29,
UC_MIPS_REG_30,
UC_MIPS_REG_31,
//> DSP registers
UC_MIPS_REG_DSPCCOND,
UC_MIPS_REG_DSPCARRY,
UC_MIPS_REG_DSPEFI,
UC_MIPS_REG_DSPOUTFLAG,
UC_MIPS_REG_DSPOUTFLAG16_19,
UC_MIPS_REG_DSPOUTFLAG20,
UC_MIPS_REG_DSPOUTFLAG21,
UC_MIPS_REG_DSPOUTFLAG22,
UC_MIPS_REG_DSPOUTFLAG23,
UC_MIPS_REG_DSPPOS,
UC_MIPS_REG_DSPSCOUNT,
//> ACC registers
UC_MIPS_REG_AC0,
UC_MIPS_REG_AC1,
UC_MIPS_REG_AC2,
UC_MIPS_REG_AC3,
//> COP registers
UC_MIPS_REG_CC0,
UC_MIPS_REG_CC1,
UC_MIPS_REG_CC2,
UC_MIPS_REG_CC3,
UC_MIPS_REG_CC4,
UC_MIPS_REG_CC5,
UC_MIPS_REG_CC6,
UC_MIPS_REG_CC7,
//> FPU registers
UC_MIPS_REG_F0,
UC_MIPS_REG_F1,
UC_MIPS_REG_F2,
UC_MIPS_REG_F3,
UC_MIPS_REG_F4,
UC_MIPS_REG_F5,
UC_MIPS_REG_F6,
UC_MIPS_REG_F7,
UC_MIPS_REG_F8,
UC_MIPS_REG_F9,
UC_MIPS_REG_F10,
UC_MIPS_REG_F11,
UC_MIPS_REG_F12,
UC_MIPS_REG_F13,
UC_MIPS_REG_F14,
UC_MIPS_REG_F15,
UC_MIPS_REG_F16,
UC_MIPS_REG_F17,
UC_MIPS_REG_F18,
UC_MIPS_REG_F19,
UC_MIPS_REG_F20,
UC_MIPS_REG_F21,
UC_MIPS_REG_F22,
UC_MIPS_REG_F23,
UC_MIPS_REG_F24,
UC_MIPS_REG_F25,
UC_MIPS_REG_F26,
UC_MIPS_REG_F27,
UC_MIPS_REG_F28,
UC_MIPS_REG_F29,
UC_MIPS_REG_F30,
UC_MIPS_REG_F31,
UC_MIPS_REG_FCC0,
UC_MIPS_REG_FCC1,
UC_MIPS_REG_FCC2,
UC_MIPS_REG_FCC3,
UC_MIPS_REG_FCC4,
UC_MIPS_REG_FCC5,
UC_MIPS_REG_FCC6,
UC_MIPS_REG_FCC7,
//> AFPR128
UC_MIPS_REG_W0,
UC_MIPS_REG_W1,
UC_MIPS_REG_W2,
UC_MIPS_REG_W3,
UC_MIPS_REG_W4,
UC_MIPS_REG_W5,
UC_MIPS_REG_W6,
UC_MIPS_REG_W7,
UC_MIPS_REG_W8,
UC_MIPS_REG_W9,
UC_MIPS_REG_W10,
UC_MIPS_REG_W11,
UC_MIPS_REG_W12,
UC_MIPS_REG_W13,
UC_MIPS_REG_W14,
UC_MIPS_REG_W15,
UC_MIPS_REG_W16,
UC_MIPS_REG_W17,
UC_MIPS_REG_W18,
UC_MIPS_REG_W19,
UC_MIPS_REG_W20,
UC_MIPS_REG_W21,
UC_MIPS_REG_W22,
UC_MIPS_REG_W23,
UC_MIPS_REG_W24,
UC_MIPS_REG_W25,
UC_MIPS_REG_W26,
UC_MIPS_REG_W27,
UC_MIPS_REG_W28,
UC_MIPS_REG_W29,
UC_MIPS_REG_W30,
UC_MIPS_REG_W31,
UC_MIPS_REG_HI,
UC_MIPS_REG_LO,
UC_MIPS_REG_P0,
UC_MIPS_REG_P1,
UC_MIPS_REG_P2,
UC_MIPS_REG_MPL0,
UC_MIPS_REG_MPL1,
UC_MIPS_REG_MPL2,
UC_MIPS_REG_CP0_CONFIG3,
UC_MIPS_REG_CP0_USERLOCAL,
UC_MIPS_REG_ENDING, // <-- mark the end of the list or registers
// alias registers
UC_MIPS_REG_ZERO = UC_MIPS_REG_0,
UC_MIPS_REG_AT = UC_MIPS_REG_1,
UC_MIPS_REG_V0 = UC_MIPS_REG_2,
UC_MIPS_REG_V1 = UC_MIPS_REG_3,
UC_MIPS_REG_A0 = UC_MIPS_REG_4,
UC_MIPS_REG_A1 = UC_MIPS_REG_5,
UC_MIPS_REG_A2 = UC_MIPS_REG_6,
UC_MIPS_REG_A3 = UC_MIPS_REG_7,
UC_MIPS_REG_T0 = UC_MIPS_REG_8,
UC_MIPS_REG_T1 = UC_MIPS_REG_9,
UC_MIPS_REG_T2 = UC_MIPS_REG_10,
UC_MIPS_REG_T3 = UC_MIPS_REG_11,
UC_MIPS_REG_T4 = UC_MIPS_REG_12,
UC_MIPS_REG_T5 = UC_MIPS_REG_13,
UC_MIPS_REG_T6 = UC_MIPS_REG_14,
UC_MIPS_REG_T7 = UC_MIPS_REG_15,
UC_MIPS_REG_S0 = UC_MIPS_REG_16,
UC_MIPS_REG_S1 = UC_MIPS_REG_17,
UC_MIPS_REG_S2 = UC_MIPS_REG_18,
UC_MIPS_REG_S3 = UC_MIPS_REG_19,
UC_MIPS_REG_S4 = UC_MIPS_REG_20,
UC_MIPS_REG_S5 = UC_MIPS_REG_21,
UC_MIPS_REG_S6 = UC_MIPS_REG_22,
UC_MIPS_REG_S7 = UC_MIPS_REG_23,
UC_MIPS_REG_T8 = UC_MIPS_REG_24,
UC_MIPS_REG_T9 = UC_MIPS_REG_25,
UC_MIPS_REG_K0 = UC_MIPS_REG_26,
UC_MIPS_REG_K1 = UC_MIPS_REG_27,
UC_MIPS_REG_GP = UC_MIPS_REG_28,
UC_MIPS_REG_SP = UC_MIPS_REG_29,
UC_MIPS_REG_FP = UC_MIPS_REG_30, UC_MIPS_REG_S8 = UC_MIPS_REG_30,
UC_MIPS_REG_RA = UC_MIPS_REG_31,
UC_MIPS_REG_HI0 = UC_MIPS_REG_AC0,
UC_MIPS_REG_HI1 = UC_MIPS_REG_AC1,
UC_MIPS_REG_HI2 = UC_MIPS_REG_AC2,
UC_MIPS_REG_HI3 = UC_MIPS_REG_AC3,
UC_MIPS_REG_LO0 = UC_MIPS_REG_HI0,
UC_MIPS_REG_LO1 = UC_MIPS_REG_HI1,
UC_MIPS_REG_LO2 = UC_MIPS_REG_HI2,
UC_MIPS_REG_LO3 = UC_MIPS_REG_HI3,
} UC_MIPS_REG;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,221 @@
/* This file is released under LGPL2.
See COPYING.LGPL2 in root directory for more details
*/
/*
This file is to support header files that are missing in MSVC and
other non-standard compilers.
*/
#ifndef UNICORN_PLATFORM_H
#define UNICORN_PLATFORM_H
/*
These are the various MSVC versions as given by _MSC_VER:
MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003)
MSVC++ 7.0 _MSC_VER == 1300
MSVC++ 6.0 _MSC_VER == 1200
MSVC++ 5.0 _MSC_VER == 1100
*/
#define MSC_VER_VS2003 1310
#define MSC_VER_VS2005 1400
#define MSC_VER_VS2008 1500
#define MSC_VER_VS2010 1600
#define MSC_VER_VS2012 1700
#define MSC_VER_VS2013 1800
#define MSC_VER_VS2015 1900
// handle stdbool.h compatibility
#if !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
// MSVC
// stdbool.h
#if (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE)
// this system does not have stdbool.h
#ifndef __cplusplus
typedef unsigned char bool;
#define false 0
#define true 1
#endif // __cplusplus
#else
// VisualStudio 2013+ -> C99 is supported
#include <stdbool.h>
#endif // (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE)
#else
// not MSVC -> C99 is supported
#include <stdbool.h>
#endif // !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE)
// this system does not have stdint.h
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef signed long long int64_t;
typedef unsigned long long uint64_t;
#ifndef _INTPTR_T_DEFINED
#define _INTPTR_T_DEFINED
#ifdef _WIN64
typedef long long intptr_t;
#else /* _WIN64 */
typedef _W64 int intptr_t;
#endif /* _WIN64 */
#endif /* _INTPTR_T_DEFINED */
#ifndef _UINTPTR_T_DEFINED
#define _UINTPTR_T_DEFINED
#ifdef _WIN64
typedef unsigned long long uintptr_t;
#else /* _WIN64 */
typedef _W64 unsigned int uintptr_t;
#endif /* _WIN64 */
#endif /* _UINTPTR_T_DEFINED */
#define INT8_MIN (-127i8 - 1)
#define INT16_MIN (-32767i16 - 1)
#define INT32_MIN (-2147483647i32 - 1)
#define INT64_MIN (-9223372036854775807i64 - 1)
#define INT8_MAX 127i8
#define INT16_MAX 32767i16
#define INT32_MAX 2147483647i32
#define INT64_MAX 9223372036854775807i64
#define UINT8_MAX 0xffui8
#define UINT16_MAX 0xffffui16
#define UINT32_MAX 0xffffffffui32
#define UINT64_MAX 0xffffffffffffffffui64
#else // this system has stdint.h
#include <stdint.h>
#endif // (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE)
// handle inttypes.h compatibility
#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013)) || defined(_KERNEL_MODE)
// this system does not have inttypes.h
#define __PRI_8_LENGTH_MODIFIER__ "hh"
#define __PRI_64_LENGTH_MODIFIER__ "ll"
#define PRId8 __PRI_8_LENGTH_MODIFIER__ "d"
#define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i"
#define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o"
#define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u"
#define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x"
#define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X"
#define PRId16 "hd"
#define PRIi16 "hi"
#define PRIo16 "ho"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hX"
#if defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012)
#define PRId32 "ld"
#define PRIi32 "li"
#define PRIo32 "lo"
#define PRIu32 "lu"
#define PRIx32 "lx"
#define PRIX32 "lX"
#else // OSX
#define PRId32 "d"
#define PRIi32 "i"
#define PRIo32 "o"
#define PRIu32 "u"
#define PRIx32 "x"
#define PRIX32 "X"
#endif // defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012)
#if defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012)
// redefine functions from inttypes.h used in cstool
#define strtoull _strtoui64
#endif
#define PRId64 __PRI_64_LENGTH_MODIFIER__ "d"
#define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i"
#define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o"
#define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u"
#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x"
#define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X"
#else
// this system has inttypes.h by default
#include <inttypes.h>
#endif // #if defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE)
// sys/time.h compatibility
#if defined(_MSC_VER)
#include <sys/timeb.h>
#include <winsock2.h>
#include <windows.h>
static int gettimeofday(struct timeval* t, void* timezone)
{
struct _timeb timebuffer;
_ftime( &timebuffer );
t->tv_sec = (long)timebuffer.time;
t->tv_usec = 1000*timebuffer.millitm;
return 0;
}
#else
#include <sys/time.h>
#endif
// unistd.h compatibility
#if defined(_MSC_VER)
static int usleep(uint32_t usec)
{
HANDLE timer;
LARGE_INTEGER due;
timer = CreateWaitableTimer(NULL, TRUE, NULL);
if (!timer)
return -1;
due.QuadPart = (-((int64_t) usec)) * 10LL;
if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0)) {
CloseHandle(timer);
return -1;
}
WaitForSingleObject(timer, INFINITE);
CloseHandle(timer);
return 0;
}
#else
#include <unistd.h>
#endif
// misc support
#if defined(_MSC_VER)
#ifdef _WIN64
typedef signed __int64 ssize_t;
#else
typedef _W64 signed int ssize_t;
#endif
#ifndef va_copy
#define va_copy(d,s) ((d) = (s))
#endif
#define strcasecmp _stricmp
#if (_MSC_VER < MSC_VER_VS2015)
#define snprintf _snprintf
#endif
#if (_MSC_VER <= MSC_VER_VS2013)
#define strtoll _strtoi64
#endif
#endif
#endif // UNICORN_PLATFORM_H

View File

@@ -0,0 +1,130 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2017 */
/* This file is released under LGPL2.
See COPYING.LGPL2 in root directory for more details
*/
#ifndef UNICORN_SPARC_H
#define UNICORN_SPARC_H
#ifdef __cplusplus
extern "C" {
#endif
// GCC SPARC toolchain has a default macro called "sparc" which breaks
// compilation
#undef sparc
#ifdef _MSC_VER
#pragma warning(disable:4201)
#endif
//> SPARC registers
typedef enum uc_sparc_reg {
UC_SPARC_REG_INVALID = 0,
UC_SPARC_REG_F0,
UC_SPARC_REG_F1,
UC_SPARC_REG_F2,
UC_SPARC_REG_F3,
UC_SPARC_REG_F4,
UC_SPARC_REG_F5,
UC_SPARC_REG_F6,
UC_SPARC_REG_F7,
UC_SPARC_REG_F8,
UC_SPARC_REG_F9,
UC_SPARC_REG_F10,
UC_SPARC_REG_F11,
UC_SPARC_REG_F12,
UC_SPARC_REG_F13,
UC_SPARC_REG_F14,
UC_SPARC_REG_F15,
UC_SPARC_REG_F16,
UC_SPARC_REG_F17,
UC_SPARC_REG_F18,
UC_SPARC_REG_F19,
UC_SPARC_REG_F20,
UC_SPARC_REG_F21,
UC_SPARC_REG_F22,
UC_SPARC_REG_F23,
UC_SPARC_REG_F24,
UC_SPARC_REG_F25,
UC_SPARC_REG_F26,
UC_SPARC_REG_F27,
UC_SPARC_REG_F28,
UC_SPARC_REG_F29,
UC_SPARC_REG_F30,
UC_SPARC_REG_F31,
UC_SPARC_REG_F32,
UC_SPARC_REG_F34,
UC_SPARC_REG_F36,
UC_SPARC_REG_F38,
UC_SPARC_REG_F40,
UC_SPARC_REG_F42,
UC_SPARC_REG_F44,
UC_SPARC_REG_F46,
UC_SPARC_REG_F48,
UC_SPARC_REG_F50,
UC_SPARC_REG_F52,
UC_SPARC_REG_F54,
UC_SPARC_REG_F56,
UC_SPARC_REG_F58,
UC_SPARC_REG_F60,
UC_SPARC_REG_F62,
UC_SPARC_REG_FCC0, // Floating condition codes
UC_SPARC_REG_FCC1,
UC_SPARC_REG_FCC2,
UC_SPARC_REG_FCC3,
UC_SPARC_REG_G0,
UC_SPARC_REG_G1,
UC_SPARC_REG_G2,
UC_SPARC_REG_G3,
UC_SPARC_REG_G4,
UC_SPARC_REG_G5,
UC_SPARC_REG_G6,
UC_SPARC_REG_G7,
UC_SPARC_REG_I0,
UC_SPARC_REG_I1,
UC_SPARC_REG_I2,
UC_SPARC_REG_I3,
UC_SPARC_REG_I4,
UC_SPARC_REG_I5,
UC_SPARC_REG_FP,
UC_SPARC_REG_I7,
UC_SPARC_REG_ICC, // Integer condition codes
UC_SPARC_REG_L0,
UC_SPARC_REG_L1,
UC_SPARC_REG_L2,
UC_SPARC_REG_L3,
UC_SPARC_REG_L4,
UC_SPARC_REG_L5,
UC_SPARC_REG_L6,
UC_SPARC_REG_L7,
UC_SPARC_REG_O0,
UC_SPARC_REG_O1,
UC_SPARC_REG_O2,
UC_SPARC_REG_O3,
UC_SPARC_REG_O4,
UC_SPARC_REG_O5,
UC_SPARC_REG_SP,
UC_SPARC_REG_O7,
UC_SPARC_REG_Y,
// special register
UC_SPARC_REG_XCC,
// pseudo register
UC_SPARC_REG_PC, // program counter register
UC_SPARC_REG_ENDING, // <-- mark the end of the list of registers
// extras
UC_SPARC_REG_O6 = UC_SPARC_REG_SP,
UC_SPARC_REG_I6 = UC_SPARC_REG_FP,
} uc_sparc_reg;
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,779 @@
/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */
/* This file is released under LGPL2.
See COPYING.LGPL2 in root directory for more details
*/
#ifndef UNICORN_ENGINE_H
#define UNICORN_ENGINE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
#include <stdarg.h>
#if defined(UNICORN_HAS_OSXKERNEL)
#include <libkern/libkern.h>
#else
#include <stdlib.h>
#include <stdio.h>
#endif
struct uc_struct;
typedef struct uc_struct uc_engine;
typedef size_t uc_hook;
#include "m68k.h"
#include "x86.h"
#include "arm.h"
#include "arm64.h"
#include "mips.h"
#include "sparc.h"
#ifdef __GNUC__
#define DEFAULT_VISIBILITY __attribute__((visibility("default")))
#else
#define DEFAULT_VISIBILITY
#endif
#ifdef _MSC_VER
#pragma warning(disable:4201)
#pragma warning(disable:4100)
#ifdef UNICORN_SHARED
#define UNICORN_EXPORT __declspec(dllexport)
#else // defined(UNICORN_STATIC)
#define UNICORN_EXPORT
#endif
#else
#ifdef __GNUC__
#define UNICORN_EXPORT __attribute__((visibility("default")))
#else
#define UNICORN_EXPORT
#endif
#endif
#ifdef __GNUC__
#define UNICORN_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define UNICORN_DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement UNICORN_DEPRECATED for this compiler")
#define UNICORN_DEPRECATED
#endif
// Unicorn API version
#define UC_API_MAJOR 1
#define UC_API_MINOR 0
// Unicorn package version
#define UC_VERSION_MAJOR UC_API_MAJOR
#define UC_VERSION_MINOR UC_API_MINOR
#define UC_VERSION_EXTRA 2
/*
Macro to create combined version which can be compared to
result of uc_version() API.
*/
#define UC_MAKE_VERSION(major, minor) ((major << 8) + minor)
// Scales to calculate timeout on microsecond unit
// 1 second = 1000,000 microseconds
#define UC_SECOND_SCALE 1000000
// 1 milisecond = 1000 nanoseconds
#define UC_MILISECOND_SCALE 1000
// Architecture type
typedef enum uc_arch {
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
UC_ARCH_ARM64, // ARM-64, also called AArch64
UC_ARCH_MIPS, // Mips architecture
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
UC_ARCH_PPC, // PowerPC architecture (currently unsupported)
UC_ARCH_SPARC, // Sparc architecture
UC_ARCH_M68K, // M68K architecture
UC_ARCH_MAX,
} uc_arch;
// Mode type
typedef enum uc_mode {
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
// arm / arm64
UC_MODE_ARM = 0, // ARM mode
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported)
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
// arm (32bit) cpu types
UC_MODE_ARM926 = 1 << 7, // ARM926 CPU type
UC_MODE_ARM946 = 1 << 8, // ARM946 CPU type
UC_MODE_ARM1176 = 1 << 9, // ARM1176 CPU type
// mips
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
// x86 / x64
UC_MODE_16 = 1 << 1, // 16-bit mode
UC_MODE_32 = 1 << 2, // 32-bit mode
UC_MODE_64 = 1 << 3, // 64-bit mode
// ppc
UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported)
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
// sparc
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
// m68k
} uc_mode;
// All type of errors encountered by Unicorn API.
// These are values returned by uc_errno()
typedef enum uc_err {
UC_ERR_OK = 0, // No error: everything was fine
UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate()
UC_ERR_ARCH, // Unsupported architecture: uc_open()
UC_ERR_HANDLE, // Invalid handle
UC_ERR_MODE, // Invalid/unsupported mode: uc_open()
UC_ERR_VERSION, // Unsupported version (bindings)
UC_ERR_READ_UNMAPPED, // Quit emulation due to READ on unmapped memory: uc_emu_start()
UC_ERR_WRITE_UNMAPPED, // Quit emulation due to WRITE on unmapped memory: uc_emu_start()
UC_ERR_FETCH_UNMAPPED, // Quit emulation due to FETCH on unmapped memory: uc_emu_start()
UC_ERR_HOOK, // Invalid hook type: uc_hook_add()
UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start()
UC_ERR_MAP, // Invalid memory mapping: uc_mem_map()
UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start()
UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start()
UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start()
UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API)
UC_ERR_READ_UNALIGNED, // Unaligned read
UC_ERR_WRITE_UNALIGNED, // Unaligned write
UC_ERR_FETCH_UNALIGNED, // Unaligned fetch
UC_ERR_HOOK_EXIST, // hook for this event already existed
UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start()
UC_ERR_EXCEPTION, // Unhandled CPU exception
} uc_err;
/*
Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK)
@address: address where the code is being executed
@size: size of machine instruction(s) being executed, or 0 when size is unknown
@user_data: user data passed to tracing APIs.
*/
typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
/*
Callback function for tracing interrupts (for uc_hook_intr())
@intno: interrupt number
@user_data: user data passed to tracing APIs.
*/
typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
/*
Callback function for tracing invalid instructions
@user_data: user data passed to tracing APIs.
@return: return true to continue, or false to stop program (due to invalid instruction).
*/
typedef bool (*uc_cb_hookinsn_invalid_t)(uc_engine *uc, void *user_data);
/*
Callback function for tracing IN instruction of X86
@port: port number
@size: data size (1/2/4) to be read from this port
@user_data: user data passed to tracing APIs.
*/
typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void *user_data);
/*
Callback function for OUT instruction of X86
@port: port number
@size: data size (1/2/4) to be written to this port
@value: data value to be written to this port
*/
typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data);
// All type of memory accesses for UC_HOOK_MEM_*
typedef enum uc_mem_type {
UC_MEM_READ = 16, // Memory is read from
UC_MEM_WRITE, // Memory is written to
UC_MEM_FETCH, // Memory is fetched
UC_MEM_READ_UNMAPPED, // Unmapped memory is read from
UC_MEM_WRITE_UNMAPPED, // Unmapped memory is written to
UC_MEM_FETCH_UNMAPPED, // Unmapped memory is fetched
UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory
UC_MEM_READ_PROT, // Read from read protected, but mapped, memory
UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory
UC_MEM_READ_AFTER, // Memory is read from (successful access)
} uc_mem_type;
// All type of hooks for uc_hook_add() API.
typedef enum uc_hook_type {
// Hook all interrupt/syscall events
UC_HOOK_INTR = 1 << 0,
// Hook a particular instruction - only a very small subset of instructions supported here
UC_HOOK_INSN = 1 << 1,
// Hook a range of code
UC_HOOK_CODE = 1 << 2,
// Hook basic blocks
UC_HOOK_BLOCK = 1 << 3,
// Hook for memory read on unmapped memory
UC_HOOK_MEM_READ_UNMAPPED = 1 << 4,
// Hook for invalid memory write events
UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5,
// Hook for invalid memory fetch for execution events
UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6,
// Hook for memory read on read-protected memory
UC_HOOK_MEM_READ_PROT = 1 << 7,
// Hook for memory write on write-protected memory
UC_HOOK_MEM_WRITE_PROT = 1 << 8,
// Hook for memory fetch on non-executable memory
UC_HOOK_MEM_FETCH_PROT = 1 << 9,
// Hook memory read events.
UC_HOOK_MEM_READ = 1 << 10,
// Hook memory write events.
UC_HOOK_MEM_WRITE = 1 << 11,
// Hook memory fetch for execution events
UC_HOOK_MEM_FETCH = 1 << 12,
// Hook memory read events, but only successful access.
// The callback will be triggered after successful read.
UC_HOOK_MEM_READ_AFTER = 1 << 13,
// Hook invalid instructions exceptions.
UC_HOOK_INSN_INVALID = 1 << 14,
} uc_hook_type;
// Hook type for all events of unmapped memory access
#define UC_HOOK_MEM_UNMAPPED (UC_HOOK_MEM_READ_UNMAPPED + UC_HOOK_MEM_WRITE_UNMAPPED + UC_HOOK_MEM_FETCH_UNMAPPED)
// Hook type for all events of illegal protected memory access
#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT)
// Hook type for all events of illegal read memory access
#define UC_HOOK_MEM_READ_INVALID (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_UNMAPPED)
// Hook type for all events of illegal write memory access
#define UC_HOOK_MEM_WRITE_INVALID (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_UNMAPPED)
// Hook type for all events of illegal fetch memory access
#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED)
// Hook type for all events of illegal memory access
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT)
// Hook type for all events of valid memory access
// NOTE: UC_HOOK_MEM_READ is triggered before UC_HOOK_MEM_READ_PROT and UC_HOOK_MEM_READ_UNMAPPED, so
// this hook may technically trigger on some invalid reads.
#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH)
/*
Callback function for hooking memory (READ, WRITE & FETCH)
@type: this memory is being READ, or WRITE
@address: address where the code is being executed
@size: size of data being read or written
@value: value of data being written to memory, or irrelevant if type = READ.
@user_data: user data passed to tracing APIs
*/
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data);
/*
Callback function for handling invalid memory access events (UNMAPPED and
PROT events)
@type: this memory is being READ, or WRITE
@address: address where the code is being executed
@size: size of data being read or written
@value: value of data being written to memory, or irrelevant if type = READ.
@user_data: user data passed to tracing APIs
@return: return true to continue, or false to stop program (due to invalid memory).
NOTE: returning true to continue execution will only work if if the accessed
memory is made accessible with the correct permissions during the hook.
In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback,
the memory should be uc_mem_map()-ed with the correct permissions, and the
instruction will then read or write to the address as it was supposed to.
In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be mapped
in as executable, in which case execution will resume from the fetched address.
The instruction pointer may be written to in order to change where execution resumes,
but the fetch must succeed if execution is to resume.
*/
typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data);
/*
Memory region mapped by uc_mem_map() and uc_mem_map_ptr()
Retrieve the list of memory regions with uc_mem_regions()
*/
typedef struct uc_mem_region {
uint64_t begin; // begin address of the region (inclusive)
uint64_t end; // end address of the region (inclusive)
uint32_t perms; // memory permissions of the region
} uc_mem_region;
// All type of queries for uc_query() API.
typedef enum uc_query_type {
// Dynamically query current hardware mode.
UC_QUERY_MODE = 1,
UC_QUERY_PAGE_SIZE, // query pagesize of engine
UC_QUERY_ARCH, // query architecture of engine (for ARM to query Thumb mode)
UC_QUERY_TIMEOUT, // query if emulation stops due to timeout (indicated if result = True)
} uc_query_type;
// Opaque storage for CPU context, used with uc_context_*()
struct uc_context;
typedef struct uc_context uc_context;
/*
Return combined API version & major and minor version numbers.
@major: major number of API version
@minor: minor number of API version
@return hexical number as (major << 8 | minor), which encodes both
major & minor versions.
NOTE: This returned value can be compared with version number made
with macro UC_MAKE_VERSION
For example, second API version would return 1 in @major, and 1 in @minor
The return value would be 0x0101
NOTE: if you only care about returned value, but not major and minor values,
set both @major & @minor arguments to NULL.
*/
UNICORN_EXPORT
unsigned int uc_version(unsigned int *major, unsigned int *minor);
/*
Determine if the given architecture is supported by this library.
@arch: architecture type (UC_ARCH_*)
@return True if this library supports the given arch.
*/
UNICORN_EXPORT
bool uc_arch_supported(uc_arch arch);
/*
Create new instance of unicorn engine.
@arch: architecture type (UC_ARCH_*)
@mode: hardware mode. This is combined of UC_MODE_*
@uc: pointer to uc_engine, which will be updated at return time
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc);
/*
Close a Unicorn engine instance.
NOTE: this must be called only when there is no longer any
usage of @uc. This API releases some of @uc's cached memory, thus
any use of the Unicorn API with @uc after it has been closed may
crash your application. After this, @uc is invalid, and is no
longer usable.
@uc: pointer to a handle returned by uc_open()
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_close(uc_engine *uc);
/*
Query internal status of engine.
@uc: handle returned by uc_open()
@type: query type. See uc_query_type
@result: save the internal status queried
@return: error code of uc_err enum type (UC_ERR_*, see above)
*/
UNICORN_EXPORT
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result);
/*
Report the last error number when some API function fail.
Like glibc's errno, uc_errno might not retain its old value once accessed.
@uc: handle returned by uc_open()
@return: error code of uc_err enum type (UC_ERR_*, see above)
*/
UNICORN_EXPORT
uc_err uc_errno(uc_engine *uc);
/*
Return a string describing given error code.
@code: error code (see UC_ERR_* above)
@return: returns a pointer to a string that describes the error code
passed in the argument @code
*/
UNICORN_EXPORT
const char *uc_strerror(uc_err code);
/*
Write to register.
@uc: handle returned by uc_open()
@regid: register ID that is to be modified.
@value: pointer to the value that will set to register @regid
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_reg_write(uc_engine *uc, int regid, const void *value);
/*
Read register value.
@uc: handle returned by uc_open()
@regid: register ID that is to be retrieved.
@value: pointer to a variable storing the register value.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value);
/*
Write multiple register values.
@uc: handle returned by uc_open()
@rges: array of register IDs to store
@value: pointer to array of register values
@count: length of both *regs and *vals
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count);
/*
Read multiple register values.
@uc: handle returned by uc_open()
@rges: array of register IDs to retrieve
@value: pointer to array of values to hold registers
@count: length of both *regs and *vals
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count);
/*
Write to a range of bytes in memory.
@uc: handle returned by uc_open()
@address: starting memory address of bytes to set.
@bytes: pointer to a variable containing data to be written to memory.
@size: size of memory to write to.
NOTE: @bytes must be big enough to contain @size bytes.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size);
/*
Read a range of bytes in memory.
@uc: handle returned by uc_open()
@address: starting memory address of bytes to get.
@bytes: pointer to a variable containing data copied from memory.
@size: size of memory to read.
NOTE: @bytes must be big enough to contain @size bytes.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size);
/*
Emulate machine code in a specific duration of time.
@uc: handle returned by uc_open()
@begin: address where emulation starts
@until: address where emulation stops (i.e when this address is hit)
@timeout: duration to emulate the code (in microseconds). When this value is 0,
we will emulate the code in infinite time, until the code is finished.
@count: the number of instructions to be emulated. When this value is 0,
we will emulate all the code available, until the code is finished.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);
/*
Stop emulation (which was started by uc_emu_start() API.
This is typically called from callback functions registered via tracing APIs.
@uc: handle returned by uc_open()
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_emu_stop(uc_engine *uc);
/*
Register callback for a hook event.
The callback will be run when the hook event is hit.
@uc: handle returned by uc_open()
@hh: hook handle returned from this registration. To be used in uc_hook_del() API
@type: hook type
@callback: callback to be run when instruction is hit
@user_data: user-defined data. This will be passed to callback function in its
last argument @user_data
@begin: start address of the area where the callback is effect (inclusive)
@end: end address of the area where the callback is effect (inclusive)
NOTE 1: the callback is called only if related address is in range [@begin, @end]
NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered
@...: variable arguments (depending on @type)
NOTE: if @type = UC_HOOK_INSN, this is the instruction ID (ex: UC_X86_INS_OUT)
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
void *user_data, uint64_t begin, uint64_t end, ...);
/*
Unregister (remove) a hook callback.
This API removes the hook callback registered by uc_hook_add().
NOTE: this should be called only when you no longer want to trace.
After this, @hh is invalid, and nolonger usable.
@uc: handle returned by uc_open()
@hh: handle returned by uc_hook_add()
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_hook_del(uc_engine *uc, uc_hook hh);
typedef enum uc_prot {
UC_PROT_NONE = 0,
UC_PROT_READ = 1,
UC_PROT_WRITE = 2,
UC_PROT_EXEC = 4,
UC_PROT_ALL = 7,
} uc_prot;
/*
Map memory in for emulation.
This API adds a memory region that can be used by emulation.
@uc: handle returned by uc_open()
@address: starting address of the new memory region to be mapped in.
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
@size: size of the new memory region to be mapped in.
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
@perms: Permissions for the newly mapped region.
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC,
or this will return with UC_ERR_ARG error.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
/*
Map existing host memory in for emulation.
This API adds a memory region that can be used by emulation.
@uc: handle returned by uc_open()
@address: starting address of the new memory region to be mapped in.
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
@size: size of the new memory region to be mapped in.
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
@perms: Permissions for the newly mapped region.
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC,
or this will return with UC_ERR_ARG error.
@ptr: pointer to host memory backing the newly mapped memory. This host memory is
expected to be an equal or larger size than provided, and be mapped with at
least PROT_READ | PROT_WRITE. If it is not, the resulting behavior is undefined.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr);
/*
Unmap a region of emulation memory.
This API deletes a memory mapping from the emulation memory space.
@uc: handle returned by uc_open()
@address: starting address of the memory region to be unmapped.
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
@size: size of the memory region to be modified.
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size);
/*
Set memory permissions for emulation memory.
This API changes permissions on an existing memory region.
@uc: handle returned by uc_open()
@address: starting address of the memory region to be modified.
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
@size: size of the memory region to be modified.
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
@perms: New permissions for the mapped region.
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC,
or this will return with UC_ERR_ARG error.
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
/*
Retrieve all memory regions mapped by uc_mem_map() and uc_mem_map_ptr()
This API allocates memory for @regions, and user must free this memory later
by free() to avoid leaking memory.
NOTE: memory regions may be splitted by uc_mem_unmap()
@uc: handle returned by uc_open()
@regions: pointer to an array of uc_mem_region struct. This is allocated by
Unicorn, and must be freed by user later with uc_free()
@count: pointer to number of struct uc_mem_region contained in @regions
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count);
/*
Allocate a region that can be used with uc_context_{save,restore} to perform
quick save/rollback of the CPU context, which includes registers and some
internal metadata. Contexts may not be shared across engine instances with
differing arches or modes.
@uc: handle returned by uc_open()
@context: pointer to a uc_engine*. This will be updated with the pointer to
the new context on successful return of this function.
Later, this allocated memory must be freed with uc_free().
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_context_alloc(uc_engine *uc, uc_context **context);
/*
Free the memory allocated by uc_mem_regions.
WARNING: After Unicorn 1.0.1rc5, the memory allocated by uc_context_alloc should
be free-ed by uc_context_free(). Calling uc_free() may still work, but the result
is **undefined**.
@mem: memory allocated by uc_mem_regions (returned in *regions).
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_free(void *mem);
/*
Save a copy of the internal CPU context.
This API should be used to efficiently make or update a saved copy of the
internal CPU state.
@uc: handle returned by uc_open()
@context: handle returned by uc_context_alloc()
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_context_save(uc_engine *uc, uc_context *context);
/*
Restore the current CPU context from a saved copy.
This API should be used to roll the CPU context back to a previous
state saved by uc_context_save().
@uc: handle returned by uc_open()
@context: handle returned by uc_context_alloc that has been used with uc_context_save
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_context_restore(uc_engine *uc, uc_context *context);
/*
Return the size needed to store the cpu context. Can be used to allocate a buffer
to contain the cpu context and directly call uc_context_save.
@uc: handle returned by uc_open()
@return the size for needed to store the cpu context as as size_t.
*/
UNICORN_EXPORT
size_t uc_context_size(uc_engine *uc);
/*
Free the context allocated by uc_context_alloc().
@context: handle returned by uc_context_alloc()
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
for detailed error).
*/
UNICORN_EXPORT
uc_err uc_context_free(uc_context *context);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'unicorn'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'unicorn'
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure()
with:
name: artifacts
path: ./out/artifacts

View File

@@ -0,0 +1,67 @@
name: PyPI 📦 Distribution
on: [push]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
platform: [x32, x64]
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set up MSVC
if: matrix.os == 'windows-latest'
uses: microsoft/setup-msbuild@v1
- name: Install dependencies
run: |
pip install setuptools wheel
- name: Build distribution 📦
shell: bash
run: |
if [ ${{ matrix.platform }} == 'x32' ] && [ ${{ matrix.os }} == 'windows-latest' ]; then
cd bindings/python && python setup.py build -p win32 sdist bdist_wheel -p win32
rm dist/*.tar.gz
elif [ ${{ matrix.platform }} == 'x32' ] && [ ${{ matrix.os }} == 'ubuntu-latest' ]; then
docker run --rm -v `pwd`/:/work dockcross/manylinux1-x86 > ./dockcross
chmod +x ./dockcross
./dockcross bindings/python/build_wheel.sh
elif [ ${{ matrix.platform }} == 'x64' ] && [ ${{ matrix.os }} == 'ubuntu-latest' ]; then
docker run --rm -v `pwd`/:/work dockcross/manylinux1-x64 > ./dockcross
chmod +x ./dockcross
./dockcross bindings/python/build_wheel.sh
elif [ ${{ matrix.platform }} == 'x32' ] && [ ${{ matrix.os }} == 'macos-latest' ]; then
cd bindings/python && python setup.py sdist
else
cd bindings/python && python setup.py bdist_wheel
fi
- uses: actions/upload-artifact@v2
with:
path: ${{ github.workspace }}/bindings/python/dist/*
publish:
needs: [build]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags')
steps:
- uses: actions/download-artifact@v2
with:
name: artifact
path: dist
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.pypi_pass }}

View File

@@ -0,0 +1,101 @@
.DS_Store
*.swp
*.d
*.o
*.a
*.dSYM
*.so
*.so.*
*.exe
*.dll
*.class
*.jar
*~
qemu/config-all-devices.mak
qemu/aarch64-softmmu/
qemu/aarch64eb-softmmu/
qemu/arm-softmmu/
qemu/armeb-softmmu/
qemu/m68k-softmmu/
qemu/mips64el-softmmu/
qemu/mips64-softmmu/
qemu/mipsel-softmmu/
qemu/mips-softmmu/
qemu/sparc64-softmmu/
qemu/sparc-softmmu/
qemu/i386-softmmu/
qemu/x86_64-softmmu/
qemu/ppc-softmmu/
qemu/ppc64-softmmu/
tags
qemu/config-host.ld
qemu/config.log
qemu/config.status
qemu/config-host.h
qemu/config-host.h-timestamp
qemu/config-host.mak
libunicorn*.dll
libunicorn*.so
libunicorn*.dylib
unicorn.pc
unicorn.lib
unicorn.dll
unicorn.exp
unicorn.def
unicorn_*.lib
unicorn_*.exp
unicorn_*.dll
*.tgz
*.zip
*.pyc
_*.txt
_*.diff
tmp/
bindings/python/build/
bindings/python/dist/
bindings/python/src/
bindings/python/unicorn.egg-info/
bindings/python/unicorn/lib/
bindings/python/unicorn/include/
bindings/python/MANIFEST
config.log
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# vscode
.vscode
.vscode/
# User-specific files
*.opensdf
*.sdf
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
Win32/
build/
[Bb]in/
[Oo]bj/
packages/
cmocka/

View File

@@ -0,0 +1,353 @@
language: c
env:
- PATH=$PATH:/usr/local/opt/binutils/bin
script:
- |
if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then
if [[ "$TRAVIS_COMPILER" == "clang" ]]; then
choco install cygwin cyg-get && \
cyg-get.bat default autoconf automake make gcc-core clang pkg-config libpcre-devel cmake python27-setuptools ruby wget && \
export SHELLOPTS && set -o igncr && \
cmd.exe //C "C:\\tools\\cygwin\\bin\\bash.exe -lc 'cd /cygdrive/$TRAVIS_BUILD_DIR; make header; make'"
else
choco install cygwin cyg-get && \
cyg-get.bat default autoconf automake make gcc-core clang pkg-config libpcre-devel cmake python27-setuptools ruby wget && \
export SHELLOPTS && set -o igncr && \
cmd.exe //C "C:\\tools\\cygwin\\bin\\bash.exe -lc 'cd /cygdrive/$TRAVIS_BUILD_DIR; make header; make; ./install-cmocka-linux.sh; export PATH="$PATH":/cygdrive/$TRAVIS_BUILD_DIR:/cygdrive/$TRAVIS_BUILD_DIR/cmocka/src; make test'"
fi
elif [[ "$TRAVIS_CPU_ARCH" == "arm64" ]]; then
make header && make && make -C tests/unit test && make -C tests/regress test
else
make header && make && make -C bindings/go && make -C bindings/go test && make test
fi
compiler:
- clang
- gcc
os:
- linux
- windows
arch:
- amd64
- arm64
matrix:
fast_finish: true
exclude:
- os: windows
arch: arm64
include:
- name: "Compiler: clang C"
os: osx
osx_image: xcode10.1
python: 3.7
compiler: clang
before_cache:
- brew cleanup
- find /usr/local/Homebrew \! -regex ".+\.git.+" -delete;
cache:
directories:
- $HOME/Library/Caches/Homebrew
- /usr/local/Homebrew
before_install:
- cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core && git stash && git clean -d -f
script:
- cd $TRAVIS_BUILD_DIR
- make header && make && make -C bindings/go && make -C bindings/go test && make test
- name: "Compiler: gcc C"
os: osx
osx_image: xcode10.1
python: 3.7
compiler: gcc
before_cache:
- brew cleanup
- find /usr/local/Homebrew \! -regex ".+\.git.+" -delete;
cache:
directories:
- $HOME/Library/Caches/Homebrew
- /usr/local/Homebrew
before_install:
- cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core && git stash && git clean -d -f
script:
- cd $TRAVIS_BUILD_DIR
- make header && make && make -C bindings/go && make -C bindings/go test && make test
- name: "Linux clang ASAN"
os: linux
compiler: clang
env:
- PATH=$PATH:/usr/local/opt/binutils/bin
- ASAN_OPTIONS=detect_leaks=0
- CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link"
- CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link"
- LDFLAGS="-fsanitize=address"
script:
- make header && make
- make -C tests/fuzz && sh tests/fuzz/dlcorpus.sh
- name: "Linux clang MSAN"
os: linux
compiler: clang
env:
- PATH=$PATH:/usr/local/opt/binutils/bin
- ASAN_OPTIONS=detect_leaks=0
- CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory -fsanitize=fuzzer-no-link"
- CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory -fsanitize=fuzzer-no-link"
- LDFLAGS="-fsanitize=memory"
script:
- make header && make
- make -C tests/fuzz && sh tests/fuzz/dlcorpus.sh
- name: "Linux clang USAN"
os: linux
compiler: clang
env:
- PATH=$PATH:/usr/local/opt/binutils/bin
- ASAN_OPTIONS=detect_leaks=0
- CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fsanitize=fuzzer-no-link"
- CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fsanitize=fuzzer-no-link"
- LDFLAGS="-fsanitize=undefined"
script:
- make header && make
- make -C tests/fuzz && sh tests/fuzz/dlcorpus.sh
- name: "Linux 32bit"
os: linux
compiler: gcc
env:
- CFLAGS="-m32" LDFLAGS="-m32" LDFLAGS_STATIC="-m32" UNICORN_QEMU_FLAGS="--cpu=i386"
- PATH=$PATH:/usr/local/opt/binutils/bin
script: make header && make && make -C tests/unit test && make -C tests/regress test
addons:
apt:
packages:
- lib32ncurses5-dev
- lib32z1-dev
- libpthread-stubs0-dev
- lib32gcc-4.8-dev
- libc6-dev-i386
- gcc-multilib
- libcmocka-dev:i386
- name: "Linux Cmake 32bit"
os: linux
compiler: gcc
env:
- CFLAGS="-m32" LDFLAGS="-m32" LDFLAGS_STATIC="-m32" UNICORN_QEMU_FLAGS="--cpu=i386"
- PATH=$PATH:/usr/local/opt/binutils/bin
script:
- mkdir build
- cd build
- ../cmake.sh x86
- cp libunicorn.* ../
- make -C ../tests/unit test && make -C ../tests/regress test
addons:
apt:
packages:
- lib32ncurses5-dev
- lib32z1-dev
- libpthread-stubs0-dev
- lib32gcc-4.8-dev
- libc6-dev-i386
- gcc-multilib
- libcmocka-dev:i386
- name: "Linux Cmake 64bit"
os: linux
compiler: gcc
env:
- PATH=$PATH:/usr/local/opt/binutils/bin
script:
- mkdir build
- cd build
- ../cmake.sh
- cp libunicorn.* ../
- make -C ../tests/unit test && make -C ../tests/regress test
- name: "Linux Cmake Static 32bit"
os: linux
compiler: gcc
env:
- CFLAGS="-m32" LDFLAGS="-m32" LDFLAGS_STATIC="-m32" UNICORN_QEMU_FLAGS="--cpu=i386"
- PATH=$PATH:/usr/local/opt/binutils/bin
script:
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DUNICORN_ARCH=x86 -DUNICORN_BUILD_SHARED=OFF .. && make -j8
# temporarily disable test for static build
# - cp libunicorn.* ../
# - make -C ../tests/unit test && make -C ../tests/regress test
addons:
apt:
packages:
- lib32ncurses5-dev
- lib32z1-dev
- libpthread-stubs0-dev
- lib32gcc-4.8-dev
- libc6-dev-i386
- gcc-multilib
- libcmocka-dev:i386
- name: "Linux Cmake Static 64bit"
os: linux
compiler: gcc
env:
- PATH=$PATH:/usr/local/opt/binutils/bin
script:
- mkdir build
- cd build
- cmake -DCMAKE_BUILD_TYPE=Release -DUNICORN_BUILD_SHARED=OFF .. && make -j8
# - cp libunicorn.* ../
# - make -C ../tests/unit test && make -C ../tests/regress test
- name: "MacOSX brew"
os: osx
osx_image: xcode10.1
python: 3.7
before_cache:
- brew cleanup
- find /usr/local/Homebrew \! -regex ".+\.git.+" -delete;
cache:
directories:
- $HOME/Library/Caches/Homebrew
- /usr/local/Homebrew
before_install:
- cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core && git stash && git clean -d -f
script:
- brew install --HEAD unicorn
- brew test unicorn
- name: "Windows nmake 32bit"
os: windows
language: shell
script:
- mkdir build
- cd build
- cmd.exe //C 'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat' x86 '&' cmd.exe //C '..\nmake.bat' x86
- name: "Windows nmake 64bit"
os: windows
language: shell
script:
- mkdir build
- cd build
- cmd.exe //C 'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat' amd64 '&' cmd.exe //C '..\nmake.bat'
- name: "Windows MSVC 32bit"
os: windows
language: shell
env:
- MSBUILD_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin"
script:
- PATH=$MSBUILD_PATH:$PATH
- cmd.exe //C 'msbuild.exe msvc/unicorn.sln /m:2 /nologo /p:Configuration=Release /p:Platform=Win32'
- name: "Windows MSVC 64bit"
os: windows
language: shell
env:
- MSBUILD_PATH="C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin"
script:
- PATH=$MSBUILD_PATH:$PATH
- cmd.exe //C 'msbuild.exe msvc/unicorn.sln /m:2 /nologo /p:Configuration=Release /p:Platform=x64'
- name: "Windows MSYS2/MinGW32"
os: windows
language: shell
env:
- PATH=/C/tools/msys64/mingw32/bin:$PATH
before_install:
- |
if [[ ! -f /C/tools/msys64/msys2_shell.cmd ]]; then
rm -rf /C/tools/msys64
fi
- choco uninstall -y mingw
- choco upgrade --no-progress -y msys2
- export msys2='cmd //C RefreshEnv.cmd '
- export msys2+='& set MSYS=winsymlinks:nativestrict '
- export msys2+='& C:\\tools\\msys64\\msys2_shell.cmd -defterm -no-start'
- export shell="$msys2 -mingw32 -full-path -here -c \$\* --"
- export msys2+=" -msys2 -c \$\* --"
- $msys2 pacman --sync --noconfirm --needed \
autoconf \
automake \
make \
perl \
python \
mingw-w64-i686-libtool \
mingw-w64-i686-toolchain \
mingw-w64-i686-gcc \
mingw-w64-i686-cmake \
mingw-w64-i686-cmocka \
mingw-w64-i686-python3-setuptools \
unzip
- export CPPFLAGS=-D__USE_MINGW_ANSI_STDIO=1
- export CC=i686-w64-mingw32-gcc
- export AR=gcc-ar
- export RANLIB=gcc-ranlib
- export CFLAGS="-m32"
- export LDFLAGS="-m32"
- export LDFLAGS_STATIC="-m32"
- export UNICORN_QEMU_FLAGS="--cpu=i386"
# before_cache:
# - $msys2 pacman --sync --clean --noconfirm
# cache:
# timeout:
# 1000
# directories:
# - $HOME/AppData/Local/Temp/chocolatey
# - /C/tools/msys64
script:
- $shell make header; $shell make; cp unicorn.dll /C/Windows/SysWOW64/; $shell make test
- name: "Windows MSYS2/MinGW64"
os: windows
language: shell
env:
- PATH=/C/tools/msys64/mingw64/bin:$PATH
before_install:
- |
if [[ ! -f /C/tools/msys64/msys2_shell.cmd ]]; then
rm -rf /C/tools/msys64
fi
- choco uninstall -y mingw
- choco upgrade --no-progress -y msys2
- export msys2='cmd //C RefreshEnv.cmd '
- export msys2+='& set MSYS=winsymlinks:nativestrict '
- export msys2+='& C:\\tools\\msys64\\msys2_shell.cmd -defterm -no-start'
- export shell="$msys2 -mingw64 -full-path -here -c \$\* --"
- export msys2+=" -msys2 -c \$\* --"
- $msys2 pacman --sync --noconfirm --needed \
autoconf \
automake \
make \
perl \
python \
mingw-w64-x86_64-libtool \
mingw-w64-x86_64-toolchain \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-cmocka \
mingw-w64-x86_64-python3-setuptools
unzip
- export CPPFLAGS=-D__USE_MINGW_ANSI_STDIO=1
- export CC=x86_64-w64-mingw32-gcc
- export AR=gcc-ar
- export RANLIB=gcc-ranlib
# before_cache:
# - $msys2 pacman --sync --clean --noconfirm
# cache:
# timeout:
# 1000
# directories:
# - $HOME/AppData/Local/Temp/chocolatey
# - /C/tools/msys64
script:
- $shell make header; $shell make; cp unicorn.dll /C/Windows/System32/; $shell make test
addons:
apt:
packages:
- libpthread-stubs0-dev
- libcmocka-dev
homebrew:
update: true
brewfile: true

View File

@@ -0,0 +1,2 @@
Nguyen Anh Quynh <aquynh -at- gmail.com>
Dang Hoang Vu <dang.hvu -at- gmail.com>

Some files were not shown because too many files have changed in this diff Show More