[add] mm injector,[add] latest schema dump

This commit is contained in:
_or_75
2026-01-22 10:09:24 +03:00
parent 13e0db809f
commit 6fd1d8899f
149 changed files with 86877 additions and 3 deletions
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{cccb11fe-9b54-44bf-8c77-29dbb3b83b74}</ProjectGuid>
<RootNamespace>AndromedaInjector</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</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)'=='Release|x64'">
<IncludePath>$(MSBuildProjectDirectory)\Andromeda-Injector\Common\Include\;$(IncludePath)</IncludePath>
<TargetName>Andromeda-CS2-Base</TargetName>
</PropertyGroup>
<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>
<LanguageStandard>stdcpplatest</LanguageStandard>
<LanguageStandard_C>stdclatest</LanguageStandard_C>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<UACExecutionLevel>RequireAdministrator</UACExecutionLevel>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Andromeda-Injector\CInjector.cpp" />
<ClCompile Include="Andromeda-Injector\Main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Andromeda-Injector\CInjector.h" />
<ClInclude Include="Andromeda-Injector\Common\Common.h" />
<ClInclude Include="Andromeda-Injector\Common\Singleton.h" />
<ClInclude Include="Andromeda-Injector\Main.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\.gitattributes" />
<None Include="..\.gitignore" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Andromeda-Injector">
<UniqueIdentifier>{9c07d84f-e39a-4705-8217-1dbb5ae8bdb2}</UniqueIdentifier>
</Filter>
<Filter Include="Andromeda-Injector\Common">
<UniqueIdentifier>{59b7c3b3-cff8-4adf-854f-183274448de6}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Andromeda-Injector\CInjector.cpp">
<Filter>Andromeda-Injector</Filter>
</ClCompile>
<ClCompile Include="Andromeda-Injector\Main.cpp">
<Filter>Andromeda-Injector</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Andromeda-Injector\CInjector.h">
<Filter>Andromeda-Injector</Filter>
</ClInclude>
<ClInclude Include="Andromeda-Injector\Main.h">
<Filter>Andromeda-Injector</Filter>
</ClInclude>
<ClInclude Include="Andromeda-Injector\Common\Common.h">
<Filter>Andromeda-Injector\Common</Filter>
</ClInclude>
<ClInclude Include="Andromeda-Injector\Common\Singleton.h">
<Filter>Andromeda-Injector\Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\.gitattributes" />
<None Include="..\.gitignore" />
</ItemGroup>
</Project>
@@ -0,0 +1,188 @@
#include "CInjector.h"
#include <BlackBone/Process/Process.h>
auto CInjector::Init() -> bool
{
GetModuleFileNameA( 0 , szDllFilePath , MAX_PATH );
GetCurrentDirectoryA( MAX_PATH , szCurrentDir );
int len = lstrlenA( szDllFilePath );
szDllFilePath[len - 1] = 'l';
szDllFilePath[len - 2] = 'l';
szDllFilePath[len - 3] = 'd';
if ( GetPrivileges() && FileExist( szDllFilePath ) )
return true;
return false;
}
auto CInjector::GetPrivileges() -> bool
{
HANDLE hToken = NULL;
LUID luid;
TOKEN_PRIVILEGES tp;
OpenProcessToken( GetCurrentProcess() , TOKEN_ALL_ACCESS , &hToken );
LookupPrivilegeValue( NULL , SE_DEBUG_NAME , &luid );
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if ( AdjustTokenPrivileges( hToken , FALSE , &tp , sizeof( TOKEN_PRIVILEGES ) , NULL , NULL ) )
{
CloseHandle( hToken );
return true;
}
return false;
}
auto CInjector::GetProcessIdByName( const char* szProcName )->DWORD
{
HANDLE hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS , 0 );
DWORD dwGetProcessID = 0;
if ( hSnapshot != INVALID_HANDLE_VALUE )
{
PROCESSENTRY32 ProcEntry32 = { 0 };
ProcEntry32.dwSize = sizeof( MODULEENTRY32 );
if ( Process32First( hSnapshot , &ProcEntry32 ) )
{
do
{
if ( _stricmp( ProcEntry32.szExeFile , szProcName ) == 0 )
{
dwGetProcessID = (DWORD)ProcEntry32.th32ProcessID;
break;
}
} while ( Process32Next( hSnapshot , &ProcEntry32 ) );
}
CloseHandle( hSnapshot );
}
return dwGetProcessID;
}
auto CInjector::InjectManualMap( const char* szProcessName ) -> bool
{
bool Result = false;
DWORD PID = 0;
DEV_LOG( "[info] Wait for start %s\n" , szProcessName );
while ( !PID )
{
PID = GetProcessIdByName( szProcessName );
Sleep( 100 );
}
m_hProcess = OpenProcess( PROCESS_ALL_ACCESS , FALSE , PID );
if ( !m_hProcess )
{
DEV_LOG( "[-] inject code: #1\n" );
return false;
}
// Read Dll File
{
auto hFile = CreateFileA( szDllFilePath , GENERIC_READ , 0 , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL );
if ( !hFile )
{
DEV_LOG( "[-] inject code: #2\n" );
CloseHandle( m_hProcess );
return false;
}
auto dwLength = GetFileSize( hFile , NULL );
if ( dwLength == INVALID_FILE_SIZE || dwLength == 0 )
{
DEV_LOG( "[-] inject code: #3\n" );
CloseHandle( hFile );
CloseHandle( m_hProcess );
return false;
}
m_pDllFile = (PBYTE)HeapAlloc( GetProcessHeap() , 0 , dwLength );
if ( !m_pDllFile )
{
DEV_LOG( "[-] inject code: #4\n" );
CloseHandle( hFile );
CloseHandle( m_hProcess );
return false;
}
if ( ReadFile( hFile , m_pDllFile , dwLength , &m_DllFileSize , NULL ) == FALSE )
{
DEV_LOG( "[-] inject code: #5\n" );
CloseHandle( hFile );
CloseHandle( m_hProcess );
return false;
}
if ( dwLength != m_DllFileSize )
{
DEV_LOG( "[-] inject code: #6\n" );
CloseHandle( hFile );
CloseHandle( m_hProcess );
return false;
}
CloseHandle( hFile );
}
DllLoaderData_t LoaderData = { 0 };
// Loader Data
memcpy( LoaderData.DllPath , szCurrentDir , MAX_PATH );
// Inject To Process
{
blackbone::Process CS2Process;
CS2Process.Attach( m_hProcess );
blackbone::CustomArgs_t Args;
Args.push_back( &LoaderData , sizeof( DllLoaderData_t ) );
auto pImage = CS2Process.mmap().MapImage( m_DllFileSize , m_pDllFile , false , blackbone::WipeHeader , nullptr , nullptr , &Args );
if ( pImage )
Result = true;
else
DEV_LOG( "[-] inject: %ws\n" , blackbone::Utils::GetErrorDescription( pImage.status ).c_str() );
}
// Free And Close
{
if ( m_pDllFile )
HeapFree( GetProcessHeap() , 0 , m_pDllFile );
CloseHandle( m_hProcess );
}
return Result;
}
auto GetInjector() -> CInjector*
{
return CInjector::Instance();
}
@@ -0,0 +1,41 @@
#pragma once
#include "Main.h"
struct DllLoaderData_t
{
char DllPath[MAX_PATH] = { 0 };
};
class CInjector : Singleton<CInjector>
{
public:
auto Init() -> bool;
public:
auto InjectManualMap( const char* szProcessName ) -> bool;
private:
auto GetPrivileges() -> bool;
auto GetProcessIdByName( const char* szName ) -> DWORD;
private:
bool __forceinline FileExist( const char* szFileName )
{
return GetFileAttributesA( szFileName ) != INVALID_FILE_ATTRIBUTES;
}
public:
char szCurrentDir[MAX_PATH] = { 0 };
char szDllFilePath[MAX_PATH] = { 0 };
private:
HANDLE m_hProcess;
PBYTE m_pDllFile = nullptr;
DWORD m_DllFileSize = 0;
private:
friend auto GetInjector() -> CInjector*;
};
auto GetInjector() -> CInjector*;
@@ -0,0 +1,12 @@
#pragma once
#include <Windows.h>
#include <iostream>
#include <fstream>
#include <TlHelp32.h>
#include <stdio.h>
#include <string>
#include "Singleton.h"
#pragma warning( disable : 26812 )
@@ -0,0 +1,49 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
#if !defined(_ASMJIT_BUILD_H)
#include "build.h"
#endif // !_ASMJIT_BUILD_H
// ============================================================================
// [MSVC]
// ============================================================================
#if defined(_MSC_VER)
// Disable some warnings we know about
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4201) // nameless struct/union
# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible
// loss of data
# pragma warning(disable: 4251) // struct needs to have dll-interface to be used
// by clients of struct ...
# pragma warning(disable: 4275) // non dll-interface struct ... used as base for
// dll-interface struct
# pragma warning(disable: 4355) // this used in base member initializer list
# pragma warning(disable: 4480) // specifying underlying type for enum
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
// Rename symbols.
# if !defined(vsnprintf)
# define ASMJIT_DEFINED_VSNPRINTF
# define vsnprintf _vsnprintf
# endif // !vsnprintf
# if !defined(snprintf)
# define ASMJIT_DEFINED_SNPRINTF
# define snprintf _snprintf
# endif // !snprintf
#endif // _MSC_VER
// ============================================================================
// [GNUC]
// ============================================================================
#if defined(__GNUC__) && !defined(__clang__)
# if __GNUC__ >= 4 && !defined(__MINGW32__)
# pragma GCC visibility push(hidden)
# endif // __GNUC__ >= 4
#endif // __GNUC__
@@ -0,0 +1,33 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// ============================================================================
// [MSVC]
// ============================================================================
#if defined(_MSC_VER)
// Pop disabled warnings by ApiBegin.h
# pragma warning(pop)
// Rename symbols back.
# if defined(ASMJIT_DEFINED_VSNPRINTF)
# undef ASMJIT_DEFINED_VSNPRINTF
# undef vsnprintf
# endif // ASMJIT_DEFINED_VSNPRINTF
# if defined(ASMJIT_DEFINED_SNPRINTF)
# undef ASMJIT_DEFINED_SNPRINTF
# undef snprintf
# endif // ASMJIT_DEFINED_SNPRINTF
#endif // _MSC_VER
// ============================================================================
// [GNUC]
// ============================================================================
#if defined(__GNUC__) && !defined(__clang__)
# if __GNUC__ >= 4 && !defined(__MINGW32__)
# pragma GCC visibility pop
# endif // __GNUC__ >= 4
#endif // __GNUC__
@@ -0,0 +1,379 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_ASMJIT_H
#define _ASMJIT_ASMJIT_H
// ============================================================================
// [asmjit_mainpage]
// ============================================================================
//! @mainpage
//!
//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
//!
//! AsmJit is a complete JIT and remote assembler for C++ language. It can
//! generate native code for x86 and x64 architectures having support for
//! a full instruction set, from legacy MMX to the newest AVX2. It has a
//! type-safe API that allows C++ compiler to do a semantic checks at
//! compile-time even before the assembled code is generated or run.
//!
//! AsmJit is not a virtual machine (VM). It doesn't have functionality to
//! implement VM out of the box; however, it can be be used as a JIT backend
//! for your own VM. The usage of AsmJit is not limited at all; it's suitable
//! for multimedia, VM backends or remote code generation.
//!
//! @section AsmJit_Concepts Code Generation Concepts
//!
//! AsmJit has two completely different code generation concepts. The difference
//! is in how the code is generated. The first concept, also referred as the low
//! level concept, is called 'Assembler' and it's the same as writing RAW
//! assembly by using physical registers directly. In this case AsmJit does only
//! instruction encoding, verification and relocation.
//!
//! The second concept, also referred as the high level concept, is called
//! 'Compiler'. Compiler lets you use virtually unlimited number of registers
//! (called variables) significantly simplifying the code generation process.
//! Compiler allocates these virtual registers to physical registers after the
//! code generation is done. This requires some extra effort - Compiler has to
//! generate information for each node (instruction, function declaration,
//! function call) in the code, perform a variable liveness analysis and
//! translate the code having variables into code having only registers.
//!
//! In addition, Compiler understands functions and function calling conventions.
//! It has been designed in a way that the code generated is always a function
//! having prototype like in a programming language. By having a function
//! prototype the Compiler is able to insert prolog and epilog to a function
//! being generated and it is able to call a function inside a generated one.
//!
//! There is no conclusion on which concept is better. Assembler brings full
//! control on how the code is generated, while Compiler makes the generation
//! more portable.
//!
//! @section AsmJit_Main_CodeGeneration Code Generation
//!
//! - \ref asmjit_base_general "Assembler core" - Operands, intrinsics and low-level assembler.
//! - \ref asmjit_compiler "Compiler" - High level code generation.
//! - \ref asmjit_cpuinfo "Cpu Information" - Get information about host processor.
//! - \ref asmjit_logging "Logging" - Logging and error handling.
//! - \ref AsmJit_MemoryManagement "Memory Management" - Virtual memory management.
//!
//! @section AsmJit_Main_HomePage AsmJit Homepage
//!
//! - https://github.com/kobalicek/asmjit
// ============================================================================
// [asmjit_base]
// ============================================================================
//! \defgroup asmjit_base AsmJit
//!
//! \brief AsmJit.
// ============================================================================
// [asmjit_base_general]
// ============================================================================
//! \defgroup asmjit_base_general AsmJit General API
//! \ingroup asmjit_base
//!
//! \brief AsmJit general API.
//!
//! Contains all `asmjit` classes and helper functions that are architecture
//! independent or abstract. Abstract classes are implemented by the backend,
//! for example `Assembler` is implemented by `X86Assembler`.
//!
//! - See `Assembler` for low level code generation documentation.
//! - See `Compiler` for high level code generation documentation.
//! - See `Operand` for operand's overview.
//!
//! Logging and Error Handling
//! --------------------------
//!
//! AsmJit contains robust interface that can be used to log the generated code
//! and to handle possible errors. Base logging interface is defined in `Logger`
//! class that is abstract and can be overridden. AsmJit contains two loggers
//! that can be used out of the box - `FileLogger` that logs into a pure C
//! `FILE*` stream and `StringLogger` that just concatenates all log messages
//! by using a `StringBuilder` class.
//!
//! The following snippet shows how to setup a logger that logs to `stderr`:
//!
//! ~~~
//! // `FileLogger` instance.
//! FileLogger logger(stderr);
//!
//! // `Compiler` or any other `CodeGen` interface.
//! host::Compiler c;
//!
//! // use `setLogger` to replace the `CodeGen` logger.
//! c.setLogger(&logger);
//! ~~~
//!
//! \sa \ref Logger, \ref FileLogger, \ref StringLogger.
// ============================================================================
// [asmjit_base_compiler]
// ============================================================================
//! \defgroup asmjit_base_compiler AsmJit Compiler
//! \ingroup asmjit_base
//!
//! \brief AsmJit code-tree used by Compiler.
//!
//! AsmJit intermediate code-tree is a double-linked list that is made of nodes
//! that represent assembler instructions, directives, labels and high-level
//! constructs compiler is using to represent functions and function calls. The
//! node list can only be used together with \ref Compiler.
//!
//! TODO
// ============================================================================
// [asmjit_base_util]
// ============================================================================
//! \defgroup asmjit_base_util AsmJit Utilities
//! \ingroup asmjit_base
//!
//! \brief AsmJit utility classes.
//!
//! AsmJit contains numerous utility classes that are needed by the library
//! itself. The most useful ones have been made public and are now exported.
//!
//! POD Containers
//! --------------
//!
//! POD containers are used by AsmJit to manage its own data structures. The
//! following classes can be used by AsmJit consumers:
//!
//! - \ref PodVector - Simple growing array-like container for POD data.
//! - \ref StringBuilder - Simple string builder that can append string
//! and integers.
//!
//! Zone Memory Allocator
//! ---------------------
//!
//! Zone memory allocator is an incremental memory allocator that can be used
//! to allocate data of short life-time. It has much better performance
//! characteristics than all other allocators, because the only thing it can do
//! is to increment a pointer and return its previous address. See \ref Zone
//! for more details.
//!
//! CPU Ticks
//! ---------
//!
//! CPU Ticks is a simple helper that can be used to do basic benchmarks. See
//! \ref CpuTicks class for more details.
//!
//! Integer Utilities
//! -----------------
//!
//! Integer utilities are all implemented by a static class \ref IntUtil.
//! There are utilities for bit manipulation and bit counting, utilities to get
//! an integer minimum / maximum and various other helpers required to perform
//! alignment checks and binary casting from float to integer and vica versa.
//!
//! Vector Utilities
//! ----------------
//!
//! SIMD code generation often requires to embed constants after each function
//! or a block of functions generated. AsmJit contains classes `Vec64`,
//! `Vec128` and `Vec256` that can be used to prepare data useful when
//! generating SIMD code.
//!
//! X86/X64 code generator contains member functions `dmm`, `dxmm` and `dymm`
//! which can be used to embed 64-bit, 128-bit and 256-bit data structures into
//! machine code (both assembler and compiler are supported).
//!
//! \note Compiler contains a constant pool, which should be used instead of
//! embedding constants manually after the function body.
// ============================================================================
// [asmjit_x86]
// ============================================================================
//! \defgroup asmjit_x86 X86/X64
//!
//! \brief X86/X64 module
// ============================================================================
// [asmjit_x86_general]
// ============================================================================
//! \defgroup asmjit_x86_general X86/X64 General API
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 general API.
//!
//! X86/X64 Registers
//! -----------------
//!
//! There are static objects that represents X86 and X64 registers. They can
//! be used directly (like `eax`, `mm`, `xmm`, ...) or created through
//! these functions:
//!
//! - `asmjit::gpb_lo()` - Get Gpb-lo register.
//! - `asmjit::gpb_hi()` - Get Gpb-hi register.
//! - `asmjit::gpw()` - Get Gpw register.
//! - `asmjit::gpd()` - Get Gpd register.
//! - `asmjit::gpq()` - Get Gpq Gp register.
//! - `asmjit::gpz()` - Get Gpd/Gpq register.
//! - `asmjit::fp()` - Get Fp register.
//! - `asmjit::mm()` - Get Mm register.
//! - `asmjit::xmm()` - Get Xmm register.
//! - `asmjit::ymm()` - Get Ymm register.
//!
//! X86/X64 Addressing
//! ------------------
//!
//! X86 and x64 architectures contains several addressing modes and most ones
//! are possible with AsmJit library. Memory represents are represented by
//! `BaseMem` class. These functions are used to make operands that represents
//! memory addresses:
//!
//! - `asmjit::ptr()` - Address size not specified.
//! - `asmjit::byte_ptr()` - 1 byte.
//! - `asmjit::word_ptr()` - 2 bytes (Gpw size).
//! - `asmjit::dword_ptr()` - 4 bytes (Gpd size).
//! - `asmjit::qword_ptr()` - 8 bytes (Gpq/Mm size).
//! - `asmjit::tword_ptr()` - 10 bytes (FPU).
//! - `asmjit::oword_ptr()` - 16 bytes (Xmm size).
//! - `asmjit::yword_ptr()` - 32 bytes (Ymm size).
//! - `asmjit::zword_ptr()` - 64 bytes (Zmm size).
//!
//! Most useful function to make pointer should be `asmjit::ptr()`. It creates
//! pointer to the target with unspecified size. Unspecified size works in all
//! intrinsics where are used registers (this means that size is specified by
//! register operand or by instruction itself). For example `asmjit::ptr()`
//! can't be used with `Assembler::inc()` instruction. In this case size must
//! be specified and it's also reason to make difference between pointer sizes.
//!
//! Supported are simple address forms `[base + displacement]` and complex
//! address forms `[base + index * scale + displacement]`.
//!
//! X86/X64 Immediates
//! ------------------
//!
//! Immediate values are constants thats passed directly after instruction
//! opcode. To create such value use `imm()` or `imm_u()` methods to create
//! signed or unsigned immediate value.
//!
//! X86/X64 CPU Information
//! -----------------------
//!
//! The CPUID instruction can be used to get an exhaustive information about
//! the host X86/X64 processor. AsmJit contains utilities that can get the most
//! important information related to the features supported by the CPU and the
//! host operating system, in addition to host processor name and number of
//! cores. Class `X86CpuInfo` extends `CpuInfo` and provides functionality
//! specific to X86 and X64.
//!
//! By default AsmJit queries the CPU information after the library is loaded
//! and the queried information is reused by all instances of `JitRuntime`.
//! The global instance of `X86CpuInfo` can't be changed, because it will affect
//! the code generation of all `Runtime`s. If there is a need to have a
//! specific CPU information which contains modified features or processor
//! vendor it's possible by creating a new instance of `X86CpuInfo` and setting
//! up its members. `X86CpuUtil::detect` can be used to detect CPU features into
//! an existing `X86CpuInfo` instance - it may become handly if only one property
//! has to be turned on/off.
//!
//! If the high-level interface `X86CpuInfo` offers is not enough there is also
//! `X86CpuUtil::callCpuId` helper that can be used to call CPUID instruction
//! with a given parameters and to consume the output.
//!
//! Cpu detection is important when generating a JIT code that may or may not
//! use certain CPU features. For example there used to be a SSE/SSE2 detection
//! in the past and today there is often AVX/AVX2 detection.
//!
//! The example below shows how to detect SSE2:
//!
//! ~~~
//! using namespace asmjit;
//!
//! // Get `X86CpuInfo` global instance.
//! const X86CpuInfo* cpuInfo = X86CpuInfo::getHost();
//!
//! if (cpuInfo->hasFeature(kX86CpuFeatureSSE2)) {
//! // Processor has SSE2.
//! }
//! else if (cpuInfo->hasFeature(kX86CpuFeatureMMX)) {
//! // Processor doesn't have SSE2, but has MMX.
//! }
//! else {
//! // Processor is archaic; it's a wonder AsmJit works here!
//! }
//! ~~~
//!
//! The next example shows how to call `CPUID` directly:
//!
//! ~~~
//! using namespace asmjit;
//!
//! // Call cpuid, first two arguments are passed in Eax/Ecx.
//! X86CpuId out;
//! X86CpuUtil::callCpuId(0, 0, &out);
//!
//! // If Eax argument is 0, Ebx, Ecx and Edx registers are filled with a cpu vendor.
//! char cpuVendor[13];
//! ::memcpy(cpuVendor, &out.ebx, 4);
//! ::memcpy(cpuVendor + 4, &out.edx, 4);
//! ::memcpy(cpuVendor + 8, &out.ecx, 4);
//! vendor[12] = '\0';
//!
//! // Print a CPU vendor retrieved from CPUID.
//! ::printf("%s", cpuVendor);
//! ~~~
// ============================================================================
// [asmjit_x86_compiler]
// ============================================================================
//! \defgroup asmjit_x86_compiler X86/X64 Code-Tree
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 code-tree and helpers.
// ============================================================================
// [asmjit_x86_inst]
// ============================================================================
//! \defgroup asmjit_x86_inst X86/X64 Instructions
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 low-level instruction definitions.
// ============================================================================
// [asmjit_x86_util]
// ============================================================================
//! \defgroup asmjit_x86_util X86/X64 Utilities
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 utility classes.
// ============================================================================
// [asmjit_contrib]
// ============================================================================
//! \defgroup asmjit_contrib Contributions
//!
//! \brief Contributions.
// [Dependencies - Base]
#include "base.h"
// [Dependencies - X86/X64]
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
#include "x86.h"
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
// [Dependencies - Host]
#include "host.h"
// [Guard]
#endif // _ASMJIT_ASMJIT_H
@@ -0,0 +1,385 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BUILD_H
#define _ASMJIT_BUILD_H
// [Include]
#if defined(ASMJIT_CONFIG_FILE)
# include ASMJIT_CONFIG_FILE
#else
# include "./config.h"
#endif // ASMJIT_CONFIG_FILE
// Turn off deprecation warnings when compiling AsmJit.
#if defined(ASMJIT_EXPORTS) && defined(_MSC_VER)
# if !defined(_CRT_SECURE_NO_DEPRECATE)
# define _CRT_SECURE_NO_DEPRECATE
# endif // !_CRT_SECURE_NO_DEPRECATE
# if !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
# endif // !_CRT_SECURE_NO_WARNINGS
#endif // ASMJIT_EXPORTS
// [Dependencies - C]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// [Dependencies - C++]
#include <new>
// ============================================================================
// [asmjit::build - Sanity]
// ============================================================================
#if defined(ASMJIT_DISABLE_NAMES) && !defined(ASMJIT_DISABLE_LOGGER)
# error "ASMJIT_DISABLE_NAMES requires ASMJIT_DISABLE_LOGGER to be defined."
#endif // ASMJIT_DISABLE_NAMES && !ASMJIT_DISABLE_LOGGER
// ============================================================================
// [asmjit::build - OS]
// ============================================================================
#if defined(_WINDOWS) || defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64)
# define ASMJIT_OS_WINDOWS
#elif defined(__linux) || defined(__linux__)
# define ASMJIT_OS_POSIX
# define ASMJIT_OS_LINUX
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# define ASMJIT_OS_POSIX
# define ASMJIT_OS_BSD
#elif defined(__APPLE__)
# define ASMJIT_OS_POSIX
# define ASMJIT_OS_MAC
#else
# warning "AsmJit - Unable to detect host operating system, using ASMJIT_OS_POSIX"
# define ASMJIT_OS_POSIX
#endif
// ============================================================================
// [asmjit::build - Arch]
// ============================================================================
#if defined(_M_X64 ) || \
defined(_M_AMD64 ) || \
defined(_WIN64 ) || \
defined(__amd64__ ) || \
defined(__LP64 ) || \
defined(__x86_64__)
# define ASMJIT_HOST_X64
# define ASMJIT_HOST_LE
# define ASMJIT_HOST_UNALIGNED_16
# define ASMJIT_HOST_UNALIGNED_32
# define ASMJIT_HOST_UNALIGNED_64
#elif \
defined(_M_IX86 ) || \
defined(__INTEL__) || \
defined(__i386__ )
# define ASMJIT_HOST_X86
# define ASMJIT_HOST_LE
# define ASMJIT_HOST_UNALIGNED_16
# define ASMJIT_HOST_UNALIGNED_32
# define ASMJIT_HOST_UNALIGNED_64
#elif \
defined(_ARM ) || \
defined(_M_ARM_FP ) || \
defined(__ARM_NEON__ ) || \
defined(__arm ) || \
defined(__arm__ ) || \
defined(__TARGET_ARCH_ARM ) || \
defined(__TARGET_ARCH_THUMB) || \
defined(__thumb__ )
# define ASMJIT_HOST_ARM
# define ASMJIT_HOST_LE
#else
# warning "AsmJit - Unable to detect host architecture"
#endif
// ============================================================================
// [asmjit::build - Build]
// ============================================================================
// Build host architecture if no architecture is selected.
#if !defined(ASMJIT_BUILD_HOST) && \
!defined(ASMJIT_BUILD_X86) && \
!defined(ASMJIT_BUILD_X64)
# define ASMJIT_BUILD_HOST
#endif
// Autodetect host architecture if enabled.
#if defined(ASMJIT_BUILD_HOST)
# if defined(ASMJIT_HOST_X86) && !defined(ASMJIT_BUILD_X86)
# define ASMJIT_BUILD_X86
# endif // ASMJIT_HOST_X86 && !ASMJIT_BUILD_X86
# if defined(ASMJIT_HOST_X64) && !defined(ASMJIT_BUILD_X64)
# define ASMJIT_BUILD_X64
# endif // ASMJIT_HOST_X64 && !ASMJIT_BUILD_X64
#endif // ASMJIT_BUILD_HOST
// ============================================================================
// [asmjit::build - Decorators]
// ============================================================================
#if defined(ASMJIT_EMBED) && !defined(ASMJIT_STATIC)
# define ASMJIT_STATIC
#endif // ASMJIT_EMBED && !ASMJIT_STATIC
#if defined(ASMJIT_STATIC)
# define ASMJIT_API
#elif defined(ASMJIT_OS_WINDOWS)
# if (defined(__GNUC__) || defined(__clang__)) && !defined(__MINGW32__)
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __attribute__((dllexport))
# else
# define ASMJIT_API __attribute__((dllimport))
# endif // ASMJIT_EXPORTS
# else
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __declspec(dllexport)
# else
# define ASMJIT_API __declspec(dllimport)
# endif
# endif
#elif defined(__GNUC__) && (__GNUC__ >= 4)
# define ASMJIT_API __attribute__((visibility("default")))
#endif
#if !defined(ASMJIT_API)
# define ASMJIT_API
#endif // ASMJIT_API
// This is basically a workaround. When using MSVC and marking class as DLL
// export everything is exported, which is unwanted since there are many
// inlines which mimic instructions. MSVC automatically exports typeinfo and
// vtable if at least one symbol of that class is exported. However, GCC has
// some strange behavior that even if one or more symbol is exported it doesn't
// export `typeinfo` unless the class itself is marked as "visibility(default)".
#if !defined(ASMJIT_OS_WINDOWS) && (defined(__GNUC__) || defined (__clang__))
# define ASMJIT_VCLASS ASMJIT_API
#else
# define ASMJIT_VCLASS
#endif
#if !defined(ASMJIT_VAR)
# define ASMJIT_VAR extern ASMJIT_API
#endif // !ASMJIT_VAR
#if defined(_MSC_VER)
# define ASMJIT_INLINE __forceinline
#elif defined(__clang__)
# define ASMJIT_INLINE inline __attribute__((always_inline)) __attribute__((visibility("hidden")))
#elif defined(__GNUC__)
# define ASMJIT_INLINE inline __attribute__((always_inline))
#else
# define ASMJIT_INLINE inline
#endif
#if defined(ASMJIT_HOST_X86)
# if defined(__GNUC__) || defined(__clang__)
# define ASMJIT_REGPARM_1 __attribute__((regparm(1)))
# define ASMJIT_REGPARM_2 __attribute__((regparm(2)))
# define ASMJIT_REGPARM_3 __attribute__((regparm(3)))
# define ASMJIT_FASTCALL __attribute__((fastcall))
# define ASMJIT_STDCALL __attribute__((stdcall))
# define ASMJIT_CDECL __attribute__((cdecl))
# else
# define ASMJIT_FASTCALL __fastcall
# define ASMJIT_STDCALL __stdcall
# define ASMJIT_CDECL __cdecl
# endif
#else
# define ASMJIT_FASTCALL
# define ASMJIT_STDCALL
# define ASMJIT_CDECL
#endif // ASMJIT_HOST_X86
// ============================================================================
// [asmjit::build - Enum]
// ============================================================================
#if defined(_MSC_VER)
# define ASMJIT_ENUM(_Name_) enum _Name_ : uint32_t
#else
# define ASMJIT_ENUM(_Name_) enum _Name_
#endif
// ============================================================================
// [asmjit::build - Memory Management]
// ============================================================================
#if !defined(ASMJIT_ALLOC) && !defined(ASMJIT_REALLOC) && !defined(ASMJIT_FREE)
# define ASMJIT_ALLOC(_Size_) ::malloc(_Size_)
# define ASMJIT_REALLOC(_Ptr_, _Size_) ::realloc(_Ptr_, _Size_)
# define ASMJIT_FREE(_Ptr_) ::free(_Ptr_)
#else
# if !defined(ASMJIT_ALLOC) || !defined(ASMJIT_REALLOC) || !defined(ASMJIT_FREE)
# error "AsmJit - You must redefine ASMJIT_ALLOC, ASMJIT_REALLOC and ASMJIT_FREE."
# endif
#endif // !ASMJIT_ALLOC && !ASMJIT_REALLOC && !ASMJIT_FREE
// ============================================================================
// [asmjit::build - _ASMJIT_HOST_INDEX]
// ============================================================================
#if defined(ASMJIT_HOST_LE)
# define _ASMJIT_HOST_INDEX(_Total_, _Index_) (_Index_)
#else
# define _ASMJIT_HOST_INDEX(_Total_, _Index_) ((_Total_) - 1 - (_Index_))
#endif
// ============================================================================
// [asmjit::build - BLEND_OFFSET_OF]
// ============================================================================
//! Cross-platform solution to get offset of `_Field_` in `_Struct_`.
#define ASMJIT_OFFSET_OF(_Struct_, _Field_) \
static_cast<int>((intptr_t) ((const uint8_t*) &((const _Struct_*)0x1)->_Field_) - 1)
// ============================================================================
// [asmjit::build - ASMJIT_ARRAY_SIZE]
// ============================================================================
#define ASMJIT_ARRAY_SIZE(_Array_) \
(sizeof(_Array_) / sizeof(*_Array_))
// ============================================================================
// [asmjit::build - ASMJIT_DEBUG / ASMJIT_TRACE]
// ============================================================================
// If ASMJIT_DEBUG and ASMJIT_RELEASE is not defined ASMJIT_DEBUG will be
// detected using the compiler specific macros. This enables to set the build
// type using IDE.
#if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE)
# if defined(_DEBUG)
# define ASMJIT_DEBUG
# endif // _DEBUG
#endif // !ASMJIT_DEBUG && !ASMJIT_RELEASE
// ASMJIT_TRACE is only used by sources and private headers. It's safe to make
// it unavailable outside of AsmJit.
#if defined(ASMJIT_EXPORTS)
namespace asmjit { static inline int disabledTrace(...) { return 0; } }
# if defined(ASMJIT_TRACE)
# define ASMJIT_TSEC(_Section_) _Section_
# define ASMJIT_TLOG ::printf(__VA_ARGS__)
# else
# define ASMJIT_TSEC(_Section_) do {} while(0)
# define ASMJIT_TLOG 0 && ::asmjit::disabledTrace
# endif // ASMJIT_TRACE
#endif // ASMJIT_EXPORTS
// ============================================================================
// [asmjit::build - ASMJIT_UNUSED]
// ============================================================================
#if !defined(ASMJIT_UNUSED)
# define ASMJIT_UNUSED(_Var_) ((void)_Var_)
#endif // ASMJIT_UNUSED
// ============================================================================
// [asmjit::build - ASMJIT_NOP]
// ============================================================================
#if !defined(ASMJIT_NOP)
# define ASMJIT_NOP() ((void)0)
#endif // ASMJIT_NOP
// ============================================================================
// [asmjit::build - ASMJIT_NO_COPY]
// ============================================================================
#define ASMJIT_NO_COPY(_Type_) \
private: \
ASMJIT_INLINE _Type_(const _Type_& other); \
ASMJIT_INLINE _Type_& operator=(const _Type_& other); \
public:
// ============================================================================
// [asmjit::build - StdInt]
// ============================================================================
#if defined(__MINGW32__)
# include <sys/types.h>
#endif // __MINGW32__
#if defined(_MSC_VER) && (_MSC_VER < 1600)
# if !defined(ASMJIT_SUPRESS_STD_TYPES)
# if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed __int64 int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
# else
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef signed __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
# endif // _MSC_VER
# endif // ASMJIT_SUPRESS_STD_TYPES
#else
# include <stdint.h>
# include <limits.h>
#endif
#if defined(_MSC_VER)
# define ASMJIT_INT64_C(_Num_) _Num_##i64
# define ASMJIT_UINT64_C(_Num_) _Num_##ui64
#else
# define ASMJIT_INT64_C(_Num_) _Num_##LL
# define ASMJIT_UINT64_C(_Num_) _Num_##ULL
#endif
// ============================================================================
// [asmjit::build - Windows]
// ============================================================================
#if defined(ASMJIT_OS_WINDOWS) && !defined(ASMJIT_SUPRESS_WINDOWS_H)
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# define ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
# endif // !WIN32_LEAN_AND_MEAN
# if !defined(NOMINMAX)
# define NOMINMAX
# define ASMJIT_UNDEF_NOMINMAX
# endif // !NOMINMAX
# include <windows.h>
# if defined(ASMJIT_UNDEF_NOMINMAX)
# undef NOMINMAX
# undef ASMJIT_UNDEF_NOMINMAX
# endif
# if defined(ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN)
# undef WIN32_LEAN_AND_MEAN
# undef ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
# endif
#endif // ASMJIT_OS_WINDOWS && !ASMJIT_SUPRESS_WINDOWS_H
// ============================================================================
// [asmjit::build - Test]
// ============================================================================
// Include a unit testing package if this is a `asmjit_test` build.
#if defined(ASMJIT_TEST)
#include "./test/broken.h"
#endif // ASMJIT_TEST
// [Guard]
#endif // _ASMJIT_BUILD_H
@@ -0,0 +1,65 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_CONFIG_H
#define _ASMJIT_CONFIG_H
// This file can be used to modify built-in features of AsmJit. AsmJit is by
// default compiled only for host processor to enable JIT compilation. Both
// Assembler and Compiler code generators are compiled by default.
//
// ASMJIT_BUILD_... flags can be defined to build additional backends that can
// be used for remote code generation.
//
// ASMJIT_DISABLE_... flags can be defined to disable standard features. These
// are handy especially when building asmjit statically and some features are
// not needed or unwanted (like Compiler).
#ifdef _DEBUG
#define ASMJIT_DEBUG // Define to enable debug-mode.
#else
#define ASMJIT_RELEASE // Define to enable release-mode.
#endif
// ============================================================================
// [AsmJit - Build-Type]
// ============================================================================
#ifdef BLACKBONE_STATIC
#define ASMJIT_STATIC
#elif BLACKBONE_EXPORTS
#define ASMJIT_EXPORTS
#endif
// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC).
// #define ASMJIT_STATIC // Define to enable static-library build.
// ============================================================================
// [AsmJit - Build-Mode]
// ============================================================================
// #define ASMJIT_DEBUG // Define to enable debug-mode.
// #define ASMJIT_RELEASE // Define to enable release-mode.
// #define ASMJIT_TRACE // Define to enable tracing.
// ============================================================================
// [AsmJit - Features]
// ============================================================================
// If none of these is defined AsmJit will select host architecture by default.
#define ASMJIT_BUILD_X86 // Define to enable x86 instruction set (32-bit).
#define ASMJIT_BUILD_X64 // Define to enable x64 instruction set (64-bit).
// #define ASMJIT_BUILD_HOST // Define to enable host instruction set.
// AsmJit features are enabled by default.
#define ASMJIT_DISABLE_COMPILER // Disable Compiler (completely).
#define ASMJIT_DISABLE_LOGGER // Disable Logger (completely).
#define ASMJIT_DISABLE_NAMES // Disable everything that uses strings
// (instruction names, error names, ...).
// [Guard]
#endif // _ASMJIT_CONFIG_H
@@ -0,0 +1,34 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_H
#define _ASMJIT_BASE_H
// [Dependencies - AsmJit]
#include "build.h"
#include "base/assembler.h"
#include "base/codegen.h"
#include "base/compiler.h"
#include "base/constpool.h"
#include "base/containers.h"
#include "base/cpuinfo.h"
#include "base/cputicks.h"
#include "base/error.h"
#include "base/globals.h"
#include "base/intutil.h"
#include "base/lock.h"
#include "base/logger.h"
#include "base/operand.h"
#include "base/runtime.h"
#include "base/string.h"
#include "base/vectypes.h"
#include "base/vmem.h"
#include "base/zone.h"
// [Guard]
#endif // _ASMJIT_BASE_H
@@ -0,0 +1,542 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_ASSEMBLER_H
#define _ASMJIT_BASE_ASSEMBLER_H
// [Dependencies - AsmJit]
#include "../base/codegen.h"
#include "../base/containers.h"
#include "../base/error.h"
#include "../base/logger.h"
#include "../base/operand.h"
#include "../base/runtime.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kInstId]
// ============================================================================
//! Instruction codes (stub).
ASMJIT_ENUM(kInstId) {
//! No instruction.
kInstIdNone = 0
};
// ============================================================================
// [asmjit::kInstOptions]
// ============================================================================
//! Instruction options (stub).
ASMJIT_ENUM(kInstOptions) {
//! No instruction options.
kInstOptionNone = 0x00000000,
//! Emit short form of the instruction.
//!
//! X86/X64:
//!
//! Short form is mostly related to jmp and jcc instructions, but can be used
//! by other instructions supporting 8-bit or 32-bit immediates. This option
//! can be dangerous if the short jmp/jcc is required, but not encodable due
//! to large displacement, in such case an error happens and the whole
//! assembler/compiler stream is unusable.
kInstOptionShortForm = 0x00000001,
//! Emit long form of the instruction.
//!
//! X86/X64:
//!
//! Long form is mosrlt related to jmp and jcc instructions, but like the
//! `kInstOptionShortForm` option it can be used by other instructions
//! supporting both 8-bit and 32-bit immediates.
kInstOptionLongForm = 0x00000002,
//! Condition is likely to be taken.
kInstOptionTaken = 0x00000004,
//! Condition is unlikely to be taken.
kInstOptionNotTaken = 0x00000008
};
// ============================================================================
// [asmjit::LabelLink]
// ============================================================================
//! \internal
//!
//! Data structure used to link linked-labels.
struct LabelLink {
//! Previous link.
LabelLink* prev;
//! Offset.
intptr_t offset;
//! Inlined displacement.
intptr_t displacement;
//! RelocId if link must be absolute when relocated.
intptr_t relocId;
};
// ============================================================================
// [asmjit::LabelData]
// ============================================================================
//! \internal
//!
//! Label data.
struct LabelData {
//! Label offset.
intptr_t offset;
//! Label links chain.
LabelLink* links;
};
// ============================================================================
// [asmjit::RelocData]
// ============================================================================
//! \internal
//!
//! Code relocation data (relative vs absolute addresses).
//!
//! X86/X64:
//!
//! X86 architecture uses 32-bit absolute addressing model by memory operands,
//! but 64-bit mode uses relative addressing model (RIP + displacement). In
//! code we are always using relative addressing model for referencing labels
//! and embedded data. In 32-bit mode we must patch all references to absolute
//! address before we can call generated function.
struct RelocData {
//! Type of relocation.
uint32_t type;
//! Size of relocation (4 or 8 bytes).
uint32_t size;
//! Offset from code begin address.
Ptr from;
//! Relative displacement from code begin address (not to `offset`) or
//! absolute address.
Ptr data;
};
// ============================================================================
// [asmjit::Assembler]
// ============================================================================
//! Base assembler.
//!
//! This class implements the base interface to an assembler. The architecture
//! specific API is implemented by backends.
//!
//! \sa Compiler.
struct ASMJIT_VCLASS Assembler : public CodeGen {
ASMJIT_NO_COPY(Assembler)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `Assembler` instance.
ASMJIT_API Assembler(Runtime* runtime);
//! Destroy the `Assembler` instance.
ASMJIT_API virtual ~Assembler();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the assembler.
//!
//! If `releaseMemory` is true all buffers will be released to the system.
ASMJIT_API void reset(bool releaseMemory = false);
// --------------------------------------------------------------------------
// [Buffer]
// --------------------------------------------------------------------------
//! Get capacity of the code buffer.
ASMJIT_INLINE size_t getCapacity() const {
return (size_t)(_end - _buffer);
}
//! Get the number of remaining bytes (space between cursor and the end of
//! the buffer).
ASMJIT_INLINE size_t getRemainingSpace() const {
return (size_t)(_end - _cursor);
}
//! Get buffer.
ASMJIT_INLINE uint8_t* getBuffer() const {
return _buffer;
}
//! Get the end of the buffer (points to the first byte that is outside).
ASMJIT_INLINE uint8_t* getEnd() const {
return _end;
}
//! Get the current position in the buffer.
ASMJIT_INLINE uint8_t* getCursor() const {
return _cursor;
}
//! Set the current position in the buffer.
ASMJIT_INLINE void setCursor(uint8_t* cursor) {
ASMJIT_ASSERT(cursor >= _buffer && cursor <= _end);
_cursor = cursor;
}
//! Get the current offset in the buffer.
ASMJIT_INLINE size_t getOffset() const {
return (size_t)(_cursor - _buffer);
}
//! Set the current offset in the buffer to `offset` and get the previous
//! offset value.
ASMJIT_INLINE size_t setOffset(size_t offset) {
ASMJIT_ASSERT(offset < getCapacity());
size_t oldOffset = (size_t)(_cursor - _buffer);
_cursor = _buffer + offset;
return oldOffset;
}
//! Grow the internal buffer.
//!
//! The internal buffer will grow at least by `n` bytes so `n` bytes can be
//! added to it. If `n` is zero or `getOffset() + n` is not greater than the
//! current capacity of the buffer this function does nothing.
ASMJIT_API Error _grow(size_t n);
//! Reserve the internal buffer to at least `n` bytes.
ASMJIT_API Error _reserve(size_t n);
//! Get BYTE at position `pos`.
ASMJIT_INLINE uint8_t getByteAt(size_t pos) const {
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint8_t*>(_buffer + pos);
}
//! Get WORD at position `pos`.
ASMJIT_INLINE uint16_t getWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint16_t*>(_buffer + pos);
}
//! Get DWORD at position `pos`.
ASMJIT_INLINE uint32_t getDWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint32_t*>(_buffer + pos);
}
//! Get QWORD at position `pos`.
ASMJIT_INLINE uint64_t getQWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint64_t*>(_buffer + pos);
}
//! Get int32_t at position `pos`.
ASMJIT_INLINE int32_t getInt32At(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const int32_t*>(_buffer + pos);
}
//! Get uint32_t at position `pos`.
ASMJIT_INLINE uint32_t getUInt32At(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint32_t*>(_buffer + pos);
}
//! Set BYTE at position `pos`.
ASMJIT_INLINE void setByteAt(size_t pos, uint8_t x) {
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint8_t*>(_buffer + pos) = x;
}
//! Set WORD at position `pos`.
ASMJIT_INLINE void setWordAt(size_t pos, uint16_t x) {
ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint16_t*>(_buffer + pos) = x;
}
//! Set DWORD at position `pos`.
ASMJIT_INLINE void setDWordAt(size_t pos, uint32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint32_t*>(_buffer + pos) = x;
}
//! Set QWORD at position `pos`.
ASMJIT_INLINE void setQWordAt(size_t pos, uint64_t x) {
ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint64_t*>(_buffer + pos) = x;
}
//! Set int32_t at position `pos`.
ASMJIT_INLINE void setInt32At(size_t pos, int32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<int32_t*>(_buffer + pos) = x;
}
//! Set uint32_t at position `pos`.
ASMJIT_INLINE void setUInt32At(size_t pos, uint32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint32_t*>(_buffer + pos) = x;
}
// --------------------------------------------------------------------------
// [GetCodeSize]
// --------------------------------------------------------------------------
//! Get current offset in buffer, same as `getOffset() + getTramplineSize()`.
ASMJIT_INLINE size_t getCodeSize() const {
return getOffset() + getTrampolineSize();
}
// --------------------------------------------------------------------------
// [GetTrampolineSize]
// --------------------------------------------------------------------------
//! Get size of all possible trampolines.
//!
//! Trampolines are needed to successfuly generate relative jumps to absolute
//! addresses. This value is only non-zero if jmp of call instructions were
//! used with immediate operand (this means jumping or calling an absolute
//! address directly).
ASMJIT_INLINE size_t getTrampolineSize() const {
return _trampolineSize;
}
// --------------------------------------------------------------------------
// [Label]
// --------------------------------------------------------------------------
//! Get number of labels created.
ASMJIT_INLINE size_t getLabelsCount() const {
return _labelList.getLength();
}
//! Get whether the `label` is valid (created by the assembler).
ASMJIT_INLINE bool isLabelValid(const Label& label) const {
return isLabelValid(label.getId());
}
//! \overload
ASMJIT_INLINE bool isLabelValid(uint32_t id) const {
return static_cast<size_t>(id) < _labelList.getLength();
}
//! Get whether the `label` is bound.
//!
//! \note It's an error to pass label that is not valid. Check the validity
//! of the label by using `isLabelValid()` method before the bound check if
//! you are not sure about its validity, otherwise you may hit an assertion
//! failure in debug mode, and undefined behavior in release mode.
ASMJIT_INLINE bool isLabelBound(const Label& label) const {
return isLabelBound(label.getId());
}
//! \overload
ASMJIT_INLINE bool isLabelBound(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return _labelList[id].offset != -1;
}
//! Get `label` offset or -1 if the label is not yet bound.
ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const {
return getLabelOffset(label.getId());
}
//! \overload
ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return _labelList[id].offset;
}
//! Get `LabelData` by `label`.
ASMJIT_INLINE LabelData* getLabelData(const Label& label) const {
return getLabelData(label.getId());
}
//! \overload
ASMJIT_INLINE LabelData* getLabelData(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return const_cast<LabelData*>(&_labelList[id]);
}
//! \internal
//!
//! Register labels for other code generator, i.e. `Compiler`.
ASMJIT_API Error _registerIndexedLabels(size_t index);
//! \internal
//!
//! Create and initialize a new `Label`.
ASMJIT_API Error _newLabel(Label* dst);
//! \internal
//!
//! New LabelLink instance.
ASMJIT_API LabelLink* _newLabelLink();
//! Create and return a new `Label`.
ASMJIT_INLINE Label newLabel() {
Label result(NoInit);
_newLabel(&result);
return result;
}
//! Bind label to the current offset.
//!
//! \note Label can be bound only once!
ASMJIT_API virtual Error bind(const Label& label);
// --------------------------------------------------------------------------
// [Embed]
// --------------------------------------------------------------------------
//! Embed data into the code buffer.
ASMJIT_API virtual Error embed(const void* data, uint32_t size);
// --------------------------------------------------------------------------
// [Align]
// --------------------------------------------------------------------------
//! Align target buffer to `m` bytes.
//!
//! Typical usage of this is to align labels at start of the inner loops.
//!
//! Inserts `nop()` instructions or CPU optimized NOPs.
virtual Error align(uint32_t mode, uint32_t offset) = 0;
// --------------------------------------------------------------------------
// [Reloc]
// --------------------------------------------------------------------------
//! Relocate the code to `baseAddress` and copy to `dst`.
//!
//! \param dst Contains the location where the relocated code should be
//! copied. The pointer can be address returned by virtual memory allocator
//! or any other address that has sufficient space.
//!
//! \param base Base address used for relocation. The `JitRuntime` always
//! sets the `base` address to be the same as `dst`, but other runtimes, for
//! example `StaticRuntime`, do not have to follow this rule.
//!
//! \retval The number bytes actually used. If the code generator reserved
//! space for possible trampolines, but didn't use it, the number of bytes
//! used can actually be less than the expected worst case. Virtual memory
//! allocator can shrink the memory allocated first time.
//!
//! A given buffer will be overwritten, to get the number of bytes required,
//! use `getCodeSize()`.
ASMJIT_API size_t relocCode(void* dst, Ptr baseAddress = kNoBaseAddress) const;
//! \internal
//!
//! Reloc code.
virtual size_t _relocCode(void* dst, Ptr baseAddress) const = 0;
// --------------------------------------------------------------------------
// [Make]
// --------------------------------------------------------------------------
ASMJIT_API virtual void* make();
// --------------------------------------------------------------------------
// [Emit]
// --------------------------------------------------------------------------
//! Emit an instruction.
ASMJIT_API Error emit(uint32_t code);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2);
//! \overload
ASMJIT_INLINE Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) {
return _emit(code, o0, o1, o2, o3);
}
//! Emit an instruction with integer immediate operand.
ASMJIT_API Error emit(uint32_t code, int o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, uint64_t o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, int o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, uint64_t o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, int o2);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, uint64_t o2);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, uint64_t o3);
//! Emit an instruction (virtual).
virtual Error _emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Buffer where the code is emitted (either live or temporary).
//!
//! This is actually the base pointer of the buffer, to get the current
//! position (cursor) look at the `_cursor` member.
uint8_t* _buffer;
//! The end of the buffer (points to the first invalid byte).
//!
//! The end of the buffer is calculated as <code>_buffer + size</code>.
uint8_t* _end;
//! The current position in code `_buffer`.
uint8_t* _cursor;
//! Size of possible trampolines.
uint32_t _trampolineSize;
//! Inline comment that will be logged by the next instruction and set to NULL.
const char* _comment;
//! Unused `LabelLink` structures pool.
LabelLink* _unusedLinks;
//! LabelData list.
PodVector<LabelData> _labelList;
//! RelocData list.
PodVector<RelocData> _relocList;
};
//! \}
// ============================================================================
// [Defined-Later]
// ============================================================================
ASMJIT_INLINE Label::Label(Assembler& a) : Operand(NoInit) {
a._newLabel(this);
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ASSEMBLER_H
@@ -0,0 +1,337 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODEGEN_H
#define _ASMJIT_BASE_CODEGEN_H
// [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/logger.h"
#include "../base/runtime.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kCodeGen]
// ============================================================================
//! Features of \ref CodeGen.
ASMJIT_ENUM(kCodeGen) {
//! Emit optimized code-alignment sequences (`Assembler` and `Compiler`).
//!
//! Default `true`.
//!
//! X86/X64
//! -------
//!
//! Default align sequence used by X86/X64 architecture is one-byte 0x90
//! opcode that is mostly shown by disassemblers as nop. However there are
//! more optimized align sequences for 2-11 bytes that may execute faster.
//! If this feature is enabled asmjit will generate specialized sequences
//! for alignment between 1 to 11 bytes. Also when `X86Compiler` is used,
//! it can add REX prefixes into the code to make some instructions greater
//! so no alignment sequence is needed.
kCodeGenOptimizedAlign = 0,
//! Emit jump-prediction hints (`Assembler` and `Compiler`).
//!
//! Default `false`.
//!
//! X86/X64
//! -------
//!
//! Jump prediction is usually based on the direction of the jump. If the
//! jump is backward it is usually predicted as taken; and if the jump is
//! forward it is usually predicted as not-taken. The reason is that loops
//! generally use backward jumps and conditions usually use forward jumps.
//! However this behavior can be overridden by using instruction prefixes.
//! If this option is enabled these hints will be emitted.
//!
//! This feature is disabled by default, because the only processor that
//! used to take into consideration prediction hints was P4. Newer processors
//! implement heuristics for branch prediction that ignores any static hints.
kCodeGenPredictedJumps = 1,
//! Schedule instructions so they can be executed faster (`Compiler` only).
//!
//! Default `false` - has to be explicitly enabled as the scheduler needs
//! some time to run.
//!
//! X86/X64
//! -------
//!
//! If scheduling is enabled AsmJit will try to reorder instructions to
//! minimize dependency chain. Scheduler always runs after the registers are
//! allocated so it doesn't change count of register allocs/spills.
//!
//! This feature is highly experimental and untested.
kCodeGenEnableScheduler = 2
};
// ============================================================================
// [asmjit::kAlignMode]
// ============================================================================
//! Code aligning mode.
ASMJIT_ENUM(kAlignMode) {
//! Align by emitting a sequence that can be executed (code).
kAlignCode = 0,
//! Align by emitting sequence that shouldn't be executed (data).
kAlignData = 1
};
// ============================================================================
// [asmjit::kRelocMode]
// ============================================================================
//! Relocation mode.
ASMJIT_ENUM(kRelocMode) {
//! Relocate an absolute address to an absolute address.
kRelocAbsToAbs = 0,
//! Relocate a relative address to an absolute address.
kRelocRelToAbs = 1,
//! Relocate an absolute address to a relative address.
kRelocAbsToRel = 2,
//! Relocate an absolute address to a relative address or use trampoline.
kRelocTrampoline = 3
};
// ============================================================================
// [asmjit::CodeGen]
// ============================================================================
//! Abstract class defining basics of \ref Assembler and \ref Compiler.
struct ASMJIT_VCLASS CodeGen {
ASMJIT_NO_COPY(CodeGen)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CodeGen` instance.
ASMJIT_API CodeGen(Runtime* runtime);
//! Destroy the `CodeGen` instance.
ASMJIT_API virtual ~CodeGen();
// --------------------------------------------------------------------------
// [Runtime]
// --------------------------------------------------------------------------
//! Get runtime.
ASMJIT_INLINE Runtime* getRuntime() const {
return _runtime;
}
// --------------------------------------------------------------------------
// [Logger]
// --------------------------------------------------------------------------
#if !defined(ASMJIT_DISABLE_LOGGER)
//! Get whether the code generator has a logger.
ASMJIT_INLINE bool hasLogger() const {
return _logger != NULL;
}
//! Get logger.
ASMJIT_INLINE Logger* getLogger() const {
return _logger;
}
//! Set logger to `logger`.
ASMJIT_API Error setLogger(Logger* logger);
#endif // !ASMJIT_DISABLE_LOGGER
// --------------------------------------------------------------------------
// [Arch]
// --------------------------------------------------------------------------
//! Get target architecture.
ASMJIT_INLINE uint32_t getArch() const {
return _arch;
}
//! Get default register size (4 or 8 bytes).
ASMJIT_INLINE uint32_t getRegSize() const {
return _regSize;
}
// --------------------------------------------------------------------------
// [BaseAddress]
// --------------------------------------------------------------------------
//! Get whether the code-generator has a base address.
//!
//! \sa \ref getBaseAddress()
ASMJIT_INLINE bool hasBaseAddress() const {
return _baseAddress != kNoBaseAddress;
}
//! Get the base address.
ASMJIT_INLINE Ptr getBaseAddress() const {
return _baseAddress;
}
//! Set the base address to `baseAddress`.
ASMJIT_INLINE void setBaseAddress(Ptr baseAddress) {
_baseAddress = baseAddress;
}
//! Reset the base address.
ASMJIT_INLINE void resetBaseAddress() {
setBaseAddress(kNoBaseAddress);
}
// --------------------------------------------------------------------------
// [LastError / ErrorHandler]
// --------------------------------------------------------------------------
//! Get last error code.
ASMJIT_INLINE Error getError() const {
return _error;
}
//! Set last error code and propagate it through the error handler.
ASMJIT_API Error setError(Error error, const char* message = NULL);
//! Clear the last error code.
ASMJIT_INLINE void resetError() {
_error = kErrorOk;
}
//! Get error handler.
ASMJIT_INLINE ErrorHandler* getErrorHandler() const {
return _errorHandler;
}
//! Set error handler.
ASMJIT_API Error setErrorHandler(ErrorHandler* handler);
//! Clear error handler.
ASMJIT_INLINE Error resetErrorHandler() {
return setErrorHandler(NULL);
}
// --------------------------------------------------------------------------
// [Code-Generation Features]
// --------------------------------------------------------------------------
//! Get code-generator `feature`.
ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
ASMJIT_ASSERT(feature < 32);
return (_features & (1 << feature)) != 0;
}
//! Set code-generator `feature` to `value`.
ASMJIT_INLINE void setFeature(uint32_t feature, bool value) {
ASMJIT_ASSERT(feature < 32);
feature = static_cast<uint32_t>(value) << feature;
_features = (_features & ~feature) | feature;
}
//! Get code-generator features.
ASMJIT_INLINE uint32_t getFeatures() const {
return _features;
}
//! Set code-generator features.
ASMJIT_INLINE void setFeatures(uint32_t features) {
_features = features;
}
// --------------------------------------------------------------------------
// [Instruction Options]
// --------------------------------------------------------------------------
//! Get options of the next instruction.
ASMJIT_INLINE uint32_t getInstOptions() const {
return _instOptions;
}
//! Get options of the next instruction and reset them.
ASMJIT_INLINE uint32_t getInstOptionsAndReset() {
uint32_t instOptions = _instOptions;
_instOptions = 0;
return instOptions;
};
//! Set options of the next instruction.
ASMJIT_INLINE void setInstOptions(uint32_t instOptions) {
_instOptions = instOptions;
}
// --------------------------------------------------------------------------
// [Make]
// --------------------------------------------------------------------------
//! Make is a convenience method to make and relocate the current code and
//! add it to the associated `Runtime`.
//!
//! What is needed is only to cast the returned pointer to your function type
//! and then use it. If there was an error during `make()` `NULL` is returned
//! and the last error code can be obtained by calling `getError()`.
virtual void* make() = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Target runtime.
Runtime* _runtime;
#if !defined(ASMJIT_DISABLE_LOGGER)
//! Logger.
Logger* _logger;
#else
//! \internal
//!
//! Makes libraries built with or without logging support binary compatible.
void* _logger;
#endif // ASMJIT_DISABLE_LOGGER
//! Error handler, called by \ref setError().
ErrorHandler* _errorHandler;
//! Base address (-1 if unknown/not used).
Ptr _baseAddress;
//! Target architecture ID.
uint8_t _arch;
//! Target architecture GP register size in bytes (4 or 8).
uint8_t _regSize;
//! \internal
uint16_t _reserved;
//! Code-Generation features, used by \ref hasFeature() and \ref setFeature().
uint32_t _features;
//! Options affecting the next instruction.
uint32_t _instOptions;
//! Last error code.
uint32_t _error;
//! Base zone.
Zone _baseZone;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CODEGEN_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,303 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CONSTPOOL_H
#define _ASMJIT_BASE_CONSTPOOL_H
// [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::ConstPoolNode]
// ============================================================================
//! \internal
//!
//! Zone-allocated constant-pool node.
struct ConstPoolNode {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE void* getData() const {
return static_cast<void*>(const_cast<ConstPoolNode*>(this) + 1);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Left/Right nodes.
ConstPoolNode* _link[2];
//! Horizontal level for balance.
uint32_t _level : 31;
//! Whether this constant is shared with another.
uint32_t _shared : 1;
//! Data offset from the beginning of the pool.
uint32_t _offset;
};
// ============================================================================
// [asmjit::ConstPoolTree]
// ============================================================================
//! \internal
//!
//! Zone-allocated constant-pool tree.
struct ConstPoolTree {
enum {
//! Maximum tree height == log2(1 << 64).
kHeightLimit = 64
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE ConstPoolTree(size_t dataSize = 0) :
_root(NULL),
_length(0),
_dataSize(dataSize) {}
ASMJIT_INLINE ~ConstPoolTree() {}
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
_root = NULL;
_length = 0;
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const {
return _length == 0;
}
ASMJIT_INLINE size_t getLength() const {
return _length;
}
ASMJIT_INLINE void setDataSize(size_t dataSize) {
ASMJIT_ASSERT(isEmpty());
_dataSize = dataSize;
}
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
ASMJIT_API ConstPoolNode* get(const void* data);
ASMJIT_API void put(ConstPoolNode* node);
// --------------------------------------------------------------------------
// [Iterate]
// --------------------------------------------------------------------------
template<typename Visitor>
ASMJIT_INLINE void iterate(Visitor& visitor) const {
ConstPoolNode* node = const_cast<ConstPoolNode*>(_root);
ConstPoolNode* link;
ConstPoolNode* stack[kHeightLimit];
if (node == NULL)
return;
size_t top = 0;
for (;;) {
link = node->_link[0];
if (link != NULL) {
ASMJIT_ASSERT(top != kHeightLimit);
stack[top++] = node;
node = link;
continue;
}
_Visit:
visitor.visit(node);
link = node->_link[1];
if (link != NULL) {
node = link;
continue;
}
if (top == 0)
break;
node = stack[--top];
goto _Visit;
}
}
// --------------------------------------------------------------------------
// [Helpers]
// --------------------------------------------------------------------------
static ASMJIT_INLINE ConstPoolNode* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) {
ConstPoolNode* node = zone->allocT<ConstPoolNode>(sizeof(ConstPoolNode) + size);
if (node == NULL)
return NULL;
node->_link[0] = NULL;
node->_link[1] = NULL;
node->_level = 1;
node->_shared = shared;
node->_offset = static_cast<uint32_t>(offset);
::memcpy(node->getData(), data, size);
return node;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Root of the tree
ConstPoolNode* _root;
//! Length of the tree (count of nodes).
size_t _length;
//! Size of the data.
size_t _dataSize;
};
// ============================================================================
// [asmjit::ConstPoolGap]
// ============================================================================
//! \internal
//!
//! Zone-allocated constant-pool gap.
struct ConstPoolGap {
//! Link to the next gap
ConstPoolGap* _next;
//! Offset of the gap.
size_t _offset;
//! Remaining bytes of the gap (basically a gap size).
size_t _length;
};
// ============================================================================
// [asmjit::ConstPool]
// ============================================================================
//! Constant pool.
struct ConstPool {
ASMJIT_NO_COPY(ConstPool)
enum {
kIndex1 = 0,
kIndex2 = 1,
kIndex4 = 2,
kIndex8 = 3,
kIndex16 = 4,
kIndex32 = 5,
kIndexCount = 6
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API ConstPool(Zone* zone);
ASMJIT_API ~ConstPool();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_API void reset();
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
//! Get whether the constant-pool is empty.
ASMJIT_INLINE bool isEmpty() const {
return _size == 0;
}
//! Get the size of the constant-pool in bytes.
ASMJIT_INLINE size_t getSize() const {
return _size;
}
//! Get minimum alignment.
ASMJIT_INLINE size_t getAlignment() const {
return _alignment;
}
//! Add a constant to the constant pool.
//!
//! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes.
//! The constant is added to the pool only if it doesn't not exist, otherwise
//! cached value is returned.
//!
//! AsmJit is able to subdivide added constants, so for example if you add
//! 8-byte constant 0x1122334455667788 it will create the following slots:
//!
//! 8-byte: 0x1122334455667788
//! 4-byte: 0x11223344, 0x55667788
//!
//! The reason is that when combining MMX/SSE/AVX code some patterns are used
//! frequently. However, AsmJit is not able to reallocate a constant that has
//! been already added. For example if you try to add 4-byte constant and then
//! 8-byte constant having the same 4-byte pattern as the previous one, two
//! independent slots will be generated by the pool.
ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset);
// --------------------------------------------------------------------------
// [Fill]
// --------------------------------------------------------------------------
//! Fill the destination with the constants from the pool.
ASMJIT_API void fill(void* dst);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Zone allocator.
Zone* _zone;
//! Tree per size.
ConstPoolTree _tree[kIndexCount];
//! Gaps per size.
ConstPoolGap* _gaps[kIndexCount];
//! Gaps pool
ConstPoolGap* _gapPool;
//! Size of the pool (in bytes).
size_t _size;
//! Alignemnt.
size_t _alignment;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CONSTPOOL_H
@@ -0,0 +1,350 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CONTAINERS_H
#define _ASMJIT_BASE_CONTAINERS_H
// [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::PodVectorData]
// ============================================================================
//! \internal
struct PodVectorData {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get data.
ASMJIT_INLINE void* getData() const {
return (void*)(this + 1);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Capacity of the vector.
size_t capacity;
//! Length of the vector.
size_t length;
};
// ============================================================================
// [asmjit::PodVectorBase]
// ============================================================================
//! \internal
struct PodVectorBase {
static ASMJIT_API const PodVectorData _nullData;
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new instance of `PodVectorBase`.
ASMJIT_INLINE PodVectorBase() :
_d(const_cast<PodVectorData*>(&_nullData)) {}
//! Destroy the `PodVectorBase` and data.
ASMJIT_INLINE ~PodVectorBase() {
reset(true);
}
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the vector data and set its `length` to zero.
//!
//! If `releaseMemory` is true the vector buffer will be released to the
//! system.
ASMJIT_API void reset(bool releaseMemory = false);
// --------------------------------------------------------------------------
// [Grow / Reserve]
// --------------------------------------------------------------------------
protected:
ASMJIT_API Error _grow(size_t n, size_t sizeOfT);
ASMJIT_API Error _reserve(size_t n, size_t sizeOfT);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
public:
PodVectorData* _d;
};
// ============================================================================
// [asmjit::PodVector<T>]
// ============================================================================
//! Template used to store and manage array of POD data.
//!
//! This template has these adventages over other vector<> templates:
//! - Non-copyable (designed to be non-copyable, we want it)
//! - No copy-on-write (some implementations of stl can use it)
//! - Optimized for working only with POD types
//! - Uses ASMJIT_... memory management macros
template <typename T>
struct PodVector : PodVectorBase {
ASMJIT_NO_COPY(PodVector<T>)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new instance of `PodVector<T>`.
ASMJIT_INLINE PodVector() {}
//! Destroy the `PodVector<>` and data.
ASMJIT_INLINE ~PodVector() {}
// --------------------------------------------------------------------------
// [Data]
// --------------------------------------------------------------------------
//! Get whether the vector is empty.
ASMJIT_INLINE bool isEmpty() const {
return _d->length == 0;
}
//! Get length.
ASMJIT_INLINE size_t getLength() const {
return _d->length;
}
//! Get capacity.
ASMJIT_INLINE size_t getCapacity() const {
return _d->capacity;
}
//! Get data.
ASMJIT_INLINE T* getData() {
return static_cast<T*>(_d->getData());
}
//! \overload
ASMJIT_INLINE const T* getData() const {
return static_cast<const T*>(_d->getData());
}
// --------------------------------------------------------------------------
// [Grow / Reserve]
// --------------------------------------------------------------------------
//! Called to grow the buffer to fit at least `n` elements more.
ASMJIT_INLINE Error _grow(size_t n) {
return PodVectorBase::_grow(n, sizeof(T));
}
//! Realloc internal array to fit at least `n` items.
ASMJIT_INLINE Error _reserve(size_t n) {
return PodVectorBase::_reserve(n, sizeof(T));
}
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
//! Prepend `item` to vector.
Error prepend(const T& item) {
PodVectorData* d = _d;
if (d->length == d->capacity) {
ASMJIT_PROPAGATE_ERROR(_grow(1));
_d = d;
}
::memmove(static_cast<T*>(d->getData()) + 1, d->getData(), d->length * sizeof(T));
::memcpy(d->getData(), &item, sizeof(T));
d->length++;
return kErrorOk;
}
//! Insert an `item` at the `index`.
Error insert(size_t index, const T& item) {
PodVectorData* d = _d;
ASMJIT_ASSERT(index <= d->length);
if (d->length == d->capacity) {
ASMJIT_PROPAGATE_ERROR(_grow(1));
d = _d;
}
T* dst = static_cast<T*>(d->getData()) + index;
::memmove(dst + 1, dst, d->length - index);
::memcpy(dst, &item, sizeof(T));
d->length++;
return kErrorOk;
}
//! Append `item` to vector.
Error append(const T& item) {
PodVectorData* d = _d;
if (d->length == d->capacity) {
ASMJIT_PROPAGATE_ERROR(_grow(1));
d = _d;
}
::memcpy(static_cast<T*>(d->getData()) + d->length, &item, sizeof(T));
d->length++;
return kErrorOk;
}
//! Get index of `val` or `kInvalidIndex` if not found.
size_t indexOf(const T& val) const {
PodVectorData* d = _d;
const T* data = static_cast<const T*>(d->getData());
size_t len = d->length;
for (size_t i = 0; i < len; i++)
if (data[i] == val)
return i;
return kInvalidIndex;
}
//! Remove item at index `i`.
void removeAt(size_t i) {
PodVectorData* d = _d;
ASMJIT_ASSERT(i < d->length);
T* data = static_cast<T*>(d->getData()) + i;
d->length--;
::memmove(data, data + 1, d->length - i);
}
//! Swap this pod-vector with `other`.
void swap(PodVector<T>& other) {
T* otherData = other._d;
other._d = _d;
_d = otherData;
}
//! Get item at index `i`.
ASMJIT_INLINE T& operator[](size_t i) {
ASMJIT_ASSERT(i < getLength());
return getData()[i];
}
//! Get item at index `i`.
ASMJIT_INLINE const T& operator[](size_t i) const {
ASMJIT_ASSERT(i < getLength());
return getData()[i];
}
};
// ============================================================================
// [asmjit::PodList<T>]
// ============================================================================
//! \internal
template <typename T>
struct PodList {
ASMJIT_NO_COPY(PodList<T>)
// --------------------------------------------------------------------------
// [Link]
// --------------------------------------------------------------------------
struct Link {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get next node.
ASMJIT_INLINE Link* getNext() const { return _next; }
//! Get value.
ASMJIT_INLINE T getValue() const { return _value; }
//! Set value to `value`.
ASMJIT_INLINE void setValue(const T& value) { _value = value; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Link* _next;
T _value;
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE PodList() : _first(NULL), _last(NULL) {}
ASMJIT_INLINE ~PodList() {}
// --------------------------------------------------------------------------
// [Data]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const { return _first != NULL; }
ASMJIT_INLINE Link* getFirst() const { return _first; }
ASMJIT_INLINE Link* getLast() const { return _last; }
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
_first = NULL;
_last = NULL;
}
ASMJIT_INLINE void prepend(Link* link) {
link->_next = _first;
if (_first == NULL)
_last = link;
_first = link;
}
ASMJIT_INLINE void append(Link* link) {
link->_next = NULL;
if (_first == NULL)
_first = link;
else
_last->_next = link;
_last = link;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Link* _first;
Link* _last;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CONTAINERS_H
@@ -0,0 +1,307 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CONTEXT_P_H
#define _ASMJIT_BASE_CONTEXT_P_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../base/compiler.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_compiler
//! \{
// ============================================================================
// [asmjit::Context]
// ============================================================================
//! \internal
//!
//! Code generation context is the logic behind `Compiler`. The context is
//! used to compile the code stored in `Compiler`.
struct Context {
ASMJIT_NO_COPY(Context)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
Context(Compiler* compiler);
virtual ~Context();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the whole context.
virtual void reset(bool releaseMemory = false);
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get compiler.
ASMJIT_INLINE Compiler* getCompiler() const { return _compiler; }
//! Get function.
ASMJIT_INLINE FuncNode* getFunc() const { return _func; }
//! Get stop node.
ASMJIT_INLINE Node* getStop() const { return _stop; }
//! Get start of the current scope.
ASMJIT_INLINE Node* getStart() const { return _start; }
//! Get end of the current scope.
ASMJIT_INLINE Node* getEnd() const { return _end; }
//! Get extra block.
ASMJIT_INLINE Node* getExtraBlock() const { return _extraBlock; }
//! Set extra block.
ASMJIT_INLINE void setExtraBlock(Node* node) { _extraBlock = node; }
// --------------------------------------------------------------------------
// [Error]
// --------------------------------------------------------------------------
//! Get the last error code.
ASMJIT_INLINE Error getError() const {
return getCompiler()->getError();
}
//! Set the last error code and propagate it through the error handler.
ASMJIT_INLINE Error setError(Error error, const char* message = NULL) {
return getCompiler()->setError(error, message);
}
// --------------------------------------------------------------------------
// [State]
// --------------------------------------------------------------------------
//! Get current state.
ASMJIT_INLINE VarState* getState() const {
return _state;
}
//! Load current state from `target` state.
virtual void loadState(VarState* src) = 0;
//! Save current state, returning new `VarState` instance.
virtual VarState* saveState() = 0;
//! Change the current state to `target` state.
virtual void switchState(VarState* src) = 0;
//! Change the current state to the intersection of two states `a` and `b`.
virtual void intersectStates(VarState* a, VarState* b) = 0;
// --------------------------------------------------------------------------
// [Context]
// --------------------------------------------------------------------------
ASMJIT_INLINE Error _registerContextVar(VarData* vd) {
if (vd->hasContextId())
return kErrorOk;
uint32_t cid = static_cast<uint32_t>(_contextVd.getLength());
ASMJIT_PROPAGATE_ERROR(_contextVd.append(vd));
vd->setContextId(cid);
return kErrorOk;
}
// --------------------------------------------------------------------------
// [Mem]
// --------------------------------------------------------------------------
MemCell* _newVarCell(VarData* vd);
MemCell* _newStackCell(uint32_t size, uint32_t alignment);
ASMJIT_INLINE MemCell* getVarCell(VarData* vd) {
MemCell* cell = vd->getMemCell();
return cell ? cell : _newVarCell(vd);
}
virtual Error resolveCellOffsets();
// --------------------------------------------------------------------------
// [Bits]
// --------------------------------------------------------------------------
ASMJIT_INLINE VarBits* newBits(uint32_t len) {
return static_cast<VarBits*>(
_baseZone.allocZeroed(static_cast<size_t>(len) * VarBits::kEntitySize));
}
ASMJIT_INLINE VarBits* copyBits(const VarBits* src, uint32_t len) {
return static_cast<VarBits*>(
_baseZone.dup(src, static_cast<size_t>(len) * VarBits::kEntitySize));
}
// --------------------------------------------------------------------------
// [Fetch]
// --------------------------------------------------------------------------
//! Fetch.
//!
//! Fetch iterates over all nodes and gathers information about all variables
//! used. The process generates information required by register allocator,
//! variable liveness analysis and translator.
virtual Error fetch() = 0;
// --------------------------------------------------------------------------
// [RemoveUnreachableCode]
// --------------------------------------------------------------------------
//! Remove unreachable code.
virtual Error removeUnreachableCode();
// --------------------------------------------------------------------------
// [Analyze]
// --------------------------------------------------------------------------
//! Perform variable liveness analysis.
//!
//! Analysis phase iterates over nodes in reverse order and generates a bit
//! array describing variables that are alive at every node in the function.
//! When the analysis start all variables are assumed dead. When a read or
//! read/write operations of a variable is detected the variable becomes
//! alive; when only write operation is detected the variable becomes dead.
//!
//! When a label is found all jumps to that label are followed and analysis
//! repeats until all variables are resolved.
virtual Error livenessAnalysis();
// --------------------------------------------------------------------------
// [Annotate]
// --------------------------------------------------------------------------
virtual Error annotate() = 0;
// --------------------------------------------------------------------------
// [Translate]
// --------------------------------------------------------------------------
//! Translate code by allocating registers and handling state changes.
virtual Error translate() = 0;
// --------------------------------------------------------------------------
// [Schedule]
// --------------------------------------------------------------------------
virtual Error schedule();
// --------------------------------------------------------------------------
// [Cleanup]
// --------------------------------------------------------------------------
virtual void cleanup();
// --------------------------------------------------------------------------
// [Compile]
// --------------------------------------------------------------------------
virtual Error compile(FuncNode* func);
// --------------------------------------------------------------------------
// [Serialize]
// --------------------------------------------------------------------------
virtual Error serialize(Assembler* assembler, Node* start, Node* stop) = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Compiler.
Compiler* _compiler;
//! Function.
FuncNode* _func;
//! Zone allocator.
Zone _baseZone;
//! \internal
//!
//! Offset (how many bytes to add) to `VarMap` to get `VarAttr` array. Used
//! by liveness analysis shared across all backends. This is needed because
//! `VarMap` is a base class for a specialized version that liveness analysis
//! doesn't use, it just needs `VarAttr` array.
uint32_t _varMapToVaListOffset;
//! Start of the current active scope.
Node* _start;
//! End of the current active scope.
Node* _end;
//! Node that is used to insert extra code after the function body.
Node* _extraBlock;
//! Stop node.
Node* _stop;
//! Unreachable nodes.
PodList<Node*> _unreachableList;
//! Jump nodes.
PodList<Node*> _jccList;
//! All variables used by the current function.
PodVector<VarData*> _contextVd;
//! Memory used to spill variables.
MemCell* _memVarCells;
//! Memory used to alloc memory on the stack.
MemCell* _memStackCells;
//! Count of 1-byte cells.
uint32_t _mem1ByteVarsUsed;
//! Count of 2-byte cells.
uint32_t _mem2ByteVarsUsed;
//! Count of 4-byte cells.
uint32_t _mem4ByteVarsUsed;
//! Count of 8-byte cells.
uint32_t _mem8ByteVarsUsed;
//! Count of 16-byte cells.
uint32_t _mem16ByteVarsUsed;
//! Count of 32-byte cells.
uint32_t _mem32ByteVarsUsed;
//! Count of 64-byte cells.
uint32_t _mem64ByteVarsUsed;
//! Count of stack memory cells.
uint32_t _memStackCellsUsed;
//! Maximum memory alignment used by the function.
uint32_t _memMaxAlign;
//! Count of bytes used by variables.
uint32_t _memVarTotal;
//! Count of bytes used by stack.
uint32_t _memStackTotal;
//! Count of bytes used by variables and stack after alignment.
uint32_t _memAllTotal;
//! Default lenght of annotated instruction.
uint32_t _annotationLength;
//! Current state (used by register allocator).
VarState* _state;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_BASE_CONTEXT_P_H
@@ -0,0 +1,147 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CPUINFO_H
#define _ASMJIT_BASE_CPUINFO_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kCpuVendor]
// ============================================================================
//! Cpu vendor ID.
//!
//! Vendor IDs are specific to AsmJit library. During the library initialization
//! AsmJit checks host CPU and tries to identify the vendor based on the CPUID
//! calls. Some manufacturers changed their vendor strings and AsmJit is aware
//! of that - it checks multiple combinations and decides which vendor ID should
//! be used.
ASMJIT_ENUM(kCpuVendor) {
//! No/Unknown vendor.
kCpuVendorNone = 0,
//! Intel vendor.
kCpuVendorIntel = 1,
//! AMD vendor.
kCpuVendorAmd = 2,
//! VIA vendor.
kCpuVendorVia = 3
};
// ============================================================================
// [asmjit::CpuInfo]
// ============================================================================
//! Base cpu information.
struct CpuInfo {
ASMJIT_NO_COPY(CpuInfo)
//! \internal
enum {
kFeaturesPerUInt32 = static_cast<int>(sizeof(uint32_t)) * 8
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE CpuInfo(uint32_t size = sizeof(CpuInfo)) : _size(size) {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get CPU vendor string.
ASMJIT_INLINE const char* getVendorString() const { return _vendorString; }
//! Get CPU brand string.
ASMJIT_INLINE const char* getBrandString() const { return _brandString; }
//! Get CPU vendor ID.
ASMJIT_INLINE uint32_t getVendorId() const { return _vendorId; }
//! Get CPU family ID.
ASMJIT_INLINE uint32_t getFamily() const { return _family; }
//! Get CPU model ID.
ASMJIT_INLINE uint32_t getModel() const { return _model; }
//! Get CPU stepping.
ASMJIT_INLINE uint32_t getStepping() const { return _stepping; }
//! Get number of hardware threads available.
ASMJIT_INLINE uint32_t getHwThreadsCount() const { return _hwThreadsCount; }
//! Get whether CPU has a `feature`.
ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
ASMJIT_ASSERT(feature < sizeof(_features) * 8);
return static_cast<bool>(
(_features[feature / kFeaturesPerUInt32] >> (feature % kFeaturesPerUInt32)) & 0x1);
}
//! Add a CPU `feature`.
ASMJIT_INLINE CpuInfo& addFeature(uint32_t feature) {
ASMJIT_ASSERT(feature < sizeof(_features) * 8);
_features[feature / kFeaturesPerUInt32] |= (1U << (feature % kFeaturesPerUInt32));
return *this;
}
// --------------------------------------------------------------------------
// [Statics]
// --------------------------------------------------------------------------
//! Detect the number of hardware threads.
static ASMJIT_API uint32_t detectHwThreadsCount();
//! Get host cpu.
static ASMJIT_API const CpuInfo* getHost();
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Size of the structure in bytes.
uint32_t _size;
//! Cpu short vendor string.
char _vendorString[16];
//! Cpu long vendor string (brand).
char _brandString[64];
//! Cpu vendor id, see `asmjit::kCpuVendor`.
uint32_t _vendorId;
//! Cpu family ID.
uint32_t _family;
//! Cpu model ID.
uint32_t _model;
//! Cpu stepping.
uint32_t _stepping;
//! Number of hardware threads.
uint32_t _hwThreadsCount;
//! Cpu features bitfield.
uint32_t _features[4];
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CPUINFO_H
@@ -0,0 +1,40 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CPUTICKS_H
#define _ASMJIT_BASE_CPUTICKS_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::CpuTicks]
// ============================================================================
//! CPU ticks utilities.
struct CpuTicks {
//! Get the current CPU ticks for benchmarking (1ms resolution).
static ASMJIT_API uint32_t now();
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CPUTICKS_H
@@ -0,0 +1,218 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_ERROR_H
#define _ASMJIT_BASE_ERROR_H
// [Api-Begin]
#include "../apibegin.h"
// [Dependencies - AsmJit]
#include "../base/globals.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kError]
// ============================================================================
//! AsmJit error codes.
ASMJIT_ENUM(kError) {
//! No error (success).
//!
//! This is default state and state you want.
kErrorOk = 0,
//! Heap memory allocation failed.
kErrorNoHeapMemory = 1,
//! Virtual memory allocation failed.
kErrorNoVirtualMemory = 2,
//! Invalid argument.
kErrorInvalidArgument = 3,
//! Invalid state.
kErrorInvalidState = 4,
//! No code generated.
//!
//! Returned by runtime if the code-generator contains no code.
kErrorNoCodeGenerated = 5,
//! Code generated is too large to fit in memory reserved.
//!
//! Returned by `StaticRuntime` in case that the code generated is too large
//! to fit in the memory already reserved for it.
kErrorCodeTooLarge = 6,
//! Label is already bound.
kErrorLabelAlreadyBound = 7,
//! Unknown instruction (an instruction ID is out of bounds or instruction
//! name is invalid).
kErrorUnknownInst = 8,
//! Illegal instruction.
//!
//! This status code can also be returned in X64 mode if AH, BH, CH or DH
//! registers have been used together with a REX prefix. The instruction
//! is not encodable in such case.
//!
//! Example of raising `kErrorIllegalInst` error.
//!
//! ~~~
//! // Invalid address size.
//! a.mov(dword_ptr(eax), al);
//!
//! // Undecodable instruction - AH used with R10, however R10 can only be
//! // encoded by using REX prefix, which conflicts with AH.
//! a.mov(byte_ptr(r10), ah);
//! ~~~
//!
//! \note In debug mode assertion is raised instead of returning an error.
kErrorIllegalInst = 9,
//! Illegal (unencodable) addressing used.
kErrorIllegalAddresing = 10,
//! Illegal (unencodable) displacement used.
//!
//! X86/X64
//! -------
//!
//! Short form of jump instruction has been used, but the displacement is out
//! of bounds.
kErrorIllegalDisplacement = 11,
//! A variable has been assigned more than once to a function argument (Compiler).
kErrorOverlappedArgs = 12,
//! Count of AsmJit error codes.
kErrorCount = 13
};
// ============================================================================
// [asmjit::Error]
// ============================================================================
//! AsmJit error type (unsigned integer).
typedef uint32_t Error;
// ============================================================================
// [asmjit::ErrorHandler]
// ============================================================================
//! Error handler.
//!
//! Error handler can be used to override the default behavior of `CodeGen`
//! error handling and propagation. See `handleError` on how to override it.
//!
//! Please note that `addRef` and `release` functions are used, but there is
//! no reference counting implemented by default, reimplement to change the
//! default behavior.
struct ASMJIT_VCLASS ErrorHandler {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `ErrorHandler` instance.
ASMJIT_API ErrorHandler();
//! Destroy the `ErrorHandler` instance.
ASMJIT_API virtual ~ErrorHandler();
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Reference this error handler.
//!
//! \note This member function is provided for convenience. The default
//! implementation does nothing. If you are working in environment where
//! multiple `ErrorHandler` instances are used by a different code generators
//! you may provide your own functionality for reference counting. In that
//! case `addRef()` and `release()` functions should be overridden.
ASMJIT_API virtual ErrorHandler* addRef() const;
//! Release this error handler.
//!
//! \note This member function is provided for convenience. See `addRef()`
//! for more detailed information related to reference counting.
ASMJIT_API virtual void release();
//! Error handler (pure).
//!
//! Error handler is called when an error happened. An error can happen in
//! many places, but error handler is mostly used by `Assembler` and
//! `Compiler` classes to report anything that may cause incorrect code
//! generation. There are multiple ways how the error handler can be used
//! and each has it's pros/cons.
//!
//! AsmJit library doesn't use exceptions and can be compiled with or without
//! exception handling support. Even if the AsmJit library is compiled without
//! exceptions it is exception-safe and handleError() can report an incoming
//! error by throwing an exception of any type. It's guaranteed that the
//! exception won't be catched by AsmJit and will be propagated to the code
//! calling AsmJit `Assembler` or `Compiler` methods. Alternative to
//! throwing an exception is using `setjmp()` and `longjmp()` pair available
//! in the standard C library.
//!
//! If the exception or setjmp() / longjmp() mechanism is used, the state of
//! the `BaseAssember` or `Compiler` is unchanged and if it's possible the
//! execution (instruction serialization) can continue. However if the error
//! happened during any phase that translates or modifies the stored code
//! (for example relocation done by `Assembler` or analysis/translation
//! done by `Compiler`) the execution can't continue and the error will
//! be also stored in `Assembler` or `Compiler`.
//!
//! Finally, if no exceptions nor setjmp() / longjmp() mechanisms were used,
//! you can still implement a compatible handling by returning from your
//! error handler. Returning `true` means that error was reported and AsmJit
//! should continue execution, but `false` sets the rror immediately to the
//! `Assembler` or `Compiler` and execution shouldn't continue (this
//! is the default behavior in case no error handler is used).
virtual bool handleError(Error code, const char* message) = 0;
};
// ============================================================================
// [asmjit::ErrorUtil]
// ============================================================================
//! Error utilities.
struct ErrorUtil {
#if !defined(ASMJIT_DISABLE_NAMES)
//! Get printable version of AsmJit `kError` code.
static ASMJIT_API const char* asString(Error code);
#endif // ASMJIT_DISABLE_NAMES
};
//! \}
// ============================================================================
// [ASMJIT_PROPAGATE_ERROR]
// ============================================================================
//! \internal
//!
//! Used by AsmJit to return the `_Exp_` result if it's an error.
#define ASMJIT_PROPAGATE_ERROR(_Exp_) \
do { \
::asmjit::Error errval_ = (_Exp_); \
if (errval_ != ::asmjit::kErrorOk) \
return errval_; \
} while (0)
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ERROR_H
@@ -0,0 +1,177 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_GLOBALS_H
#define _ASMJIT_BASE_GLOBALS_H
// [Dependencies - AsmJit]
#include "../build.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::Ptr / SignedPtr]
// ============================================================================
//! 64-bit unsigned pointer, compatible with JIT and non-JIT generators.
//!
//! This is the preferred pointer type to use with AsmJit library. It has a
//! capability to hold any pointer for any architecture making it an ideal
//! candidate for cross-platform code generation.
typedef uint64_t Ptr;
//! 64-bit signed pointer, like \ref Ptr, but made signed.
typedef int64_t SignedPtr;
// ============================================================================
// [asmjit::kGlobals]
// ============================================================================
//! Invalid index
//!
//! Invalid index is the last possible index that is never used in practice. In
//! AsmJit it is used exclusively with strings to indicate the the length of the
//! string is not known and has to be determined.
static const size_t kInvalidIndex = ~static_cast<size_t>(0);
//! Invalid base address.
static const Ptr kNoBaseAddress = static_cast<Ptr>(static_cast<SignedPtr>(-1));
//! Global constants.
ASMJIT_ENUM(kGlobals) {
//! Invalid value or operand id.
kInvalidValue = 0xFFFFFFFF,
//! Invalid register index.
kInvalidReg = 0xFF,
//! Invalid variable type.
kInvalidVar = 0xFF,
//! Host memory allocator overhead.
//!
//! The overhead is decremented from all zone allocators so the operating
//! system doesn't have allocate extra virtual page to keep tract of the
//! requested memory block.
//!
//! The number is actually a guess.
kMemAllocOverhead = sizeof(intptr_t) * 4,
//! Memory grow threshold.
//!
//! After the grow threshold is reached the capacity won't be doubled
//! anymore.
kMemAllocGrowMax = 8192 * 1024
};
// ============================================================================
// [asmjit::kArch]
// ============================================================================
//! Architecture.
ASMJIT_ENUM(kArch) {
//! No/Unknown architecture.
kArchNone = 0,
//! X86 architecture.
kArchX86 = 1,
//! X64 architecture, also called AMD64.
kArchX64 = 2,
//! Arm architecture.
kArchArm = 4,
#if defined(ASMJIT_HOST_X86)
kArchHost = kArchX86,
#endif // ASMJIT_HOST_X86
#if defined(ASMJIT_HOST_X64)
kArchHost = kArchX64,
#endif // ASMJIT_HOST_X64
#if defined(ASMJIT_HOST_ARM)
kArchHost = kArchArm,
#endif // ASMJIT_HOST_ARM
//! Whether the host is 64-bit.
kArchHost64Bit = sizeof(intptr_t) >= 8
};
//! \}
// ============================================================================
// [asmjit::Init / NoInit]
// ============================================================================
#if !defined(ASMJIT_DOCGEN)
struct _Init {};
static const _Init Init = {};
struct _NoInit {};
static const _NoInit NoInit = {};
#endif // !ASMJIT_DOCGEN
// ============================================================================
// [asmjit::Assert]
// ============================================================================
//! \addtogroup asmjit_base_general
//! \{
//! Called in debug build on assertion failure.
//!
//! \param exp Expression that failed.
//! \param file Source file name where it happened.
//! \param line Line in the source file.
//!
//! If you have problems with assertions put a breakpoint at assertionFailed()
//! function (asmjit/base/globals.cpp) and check the call stack to locate the
//! failing code.
ASMJIT_API void assertionFailed(const char* exp, const char* file, int line);
#if defined(ASMJIT_DEBUG)
#define ASMJIT_ASSERT(_Exp_) \
do { \
if (!(_Exp_)) ::asmjit::assertionFailed(#_Exp_, __FILE__, __LINE__); \
} while (0)
#else
#define ASMJIT_ASSERT(_Exp_) ASMJIT_NOP()
#endif // DEBUG
//! \}
} // asmjit namespace
// ============================================================================
// [asmjit_cast<>]
// ============================================================================
//! \addtogroup asmjit_base_util
//! \{
//! Cast used to cast pointer to function. It's like reinterpret_cast<>,
//! but uses internally C style cast to work with MinGW.
//!
//! If you are using single compiler and `reinterpret_cast<>` works for you,
//! there is no reason to use `asmjit_cast<>`. If you are writing
//! cross-platform software with various compiler support, consider using
//! `asmjit_cast<>` instead of `reinterpret_cast<>`.
template<typename T, typename Z>
static ASMJIT_INLINE T asmjit_cast(Z* p) { return (T)p; }
//! \}
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_GLOBALS_H
@@ -0,0 +1,713 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_INTUTIL_H
#define _ASMJIT_BASE_INTUTIL_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
#if defined(_MSC_VER)
#pragma intrinsic(_BitScanForward)
#endif // ASMJIT_OS_WINDOWS
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::IntTraits]
// ============================================================================
//! \internal
template<typename T>
struct IntTraits {
enum {
kIsSigned = static_cast<T>(~static_cast<T>(0)) < static_cast<T>(0),
kIsUnsigned = !kIsSigned,
kIs8Bit = sizeof(T) == 1,
kIs16Bit = sizeof(T) == 2,
kIs32Bit = sizeof(T) == 4,
kIs64Bit = sizeof(T) == 8,
kIsIntPtr = sizeof(T) == sizeof(intptr_t)
};
};
// ============================================================================
// [asmjit::IntUtil]
// ============================================================================
//! Integer utilities.
struct IntUtil {
// --------------------------------------------------------------------------
// [Float <-> Int]
// --------------------------------------------------------------------------
//! \internal
union Float {
int32_t i;
float f;
};
//! \internal
union Double {
int64_t i;
double d;
};
//! Bit-cast `float` to 32-bit integer.
static ASMJIT_INLINE int32_t floatAsInt(float f) { Float m; m.f = f; return m.i; }
//! Bit-cast 32-bit integer to `float`.
static ASMJIT_INLINE float intAsFloat(int32_t i) { Float m; m.i = i; return m.f; }
//! Bit-cast `double` to 64-bit integer.
static ASMJIT_INLINE int64_t doubleAsInt(double d) { Double m; m.d = d; return m.i; }
//! Bit-cast 64-bit integer to `double`.
static ASMJIT_INLINE double intAsDouble(int64_t i) { Double m; m.i = i; return m.d; }
// --------------------------------------------------------------------------
// [AsmJit - Pack / Unpack]
// --------------------------------------------------------------------------
//! Pack two 8-bit integer and one 16-bit integer into a 32-bit integer as it
//! is an array of `{u0,u1,w2}`.
static ASMJIT_INLINE uint32_t pack32_2x8_1x16(uint32_t u0, uint32_t u1, uint32_t w2) {
#if defined(ASMJIT_HOST_LE)
return u0 + (u1 << 8) + (w2 << 16);
#else
return (u0 << 24) + (u1 << 16) + (w2);
#endif // ASMJIT_HOST
}
//! Pack four 8-bit integer into a 32-bit integer as it is an array of `{u0,u1,u2,u3}`.
static ASMJIT_INLINE uint32_t pack32_4x8(uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) {
#if defined(ASMJIT_HOST_LE)
return u0 + (u1 << 8) + (u2 << 16) + (u3 << 24);
#else
return (u0 << 24) + (u1 << 16) + (u2 << 8) + u3;
#endif // ASMJIT_HOST
}
//! Pack two 32-bit integer into a 64-bit integer as it is an array of `{u0,u1}`.
static ASMJIT_INLINE uint64_t pack64_2x32(uint32_t u0, uint32_t u1) {
#if defined(ASMJIT_HOST_LE)
return (static_cast<uint64_t>(u1) << 32) + u0;
#else
return (static_cast<uint64_t>(u0) << 32) + u1;
#endif // ASMJIT_HOST
}
// --------------------------------------------------------------------------
// [AsmJit - Min/Max]
// --------------------------------------------------------------------------
// NOTE: Because some environments declare min() and max() as macros, it has
// been decided to use different name so we never collide with them.
//! Get minimum value of `a` and `b`.
template<typename T>
static ASMJIT_INLINE T iMin(const T& a, const T& b) { return a < b ? a : b; }
//! Get maximum value of `a` and `b`.
template<typename T>
static ASMJIT_INLINE T iMax(const T& a, const T& b) { return a > b ? a : b; }
// --------------------------------------------------------------------------
// [AsmJit - MaxUInt]
// --------------------------------------------------------------------------
//! Get maximum unsigned value of `T`.
template<typename T>
static ASMJIT_INLINE T maxUInt() { return ~T(0); }
// --------------------------------------------------------------------------
// [AsmJit - InInterval]
// --------------------------------------------------------------------------
//! Get whether `x` is greater or equal than `start` and less or equal than `end`.
template<typename T>
static ASMJIT_INLINE bool inInterval(const T& x, const T& start, const T& end) {
return x >= start && x <= end;
}
// --------------------------------------------------------------------------
// [AsmJit - IsInt/IsUInt]
// --------------------------------------------------------------------------
//! Get whether the given integer `x` can be casted to 8-bit signed integer.
template<typename T>
static ASMJIT_INLINE bool isInt8(T x) {
if (IntTraits<T>::kIsSigned)
return sizeof(T) <= sizeof(int8_t) ? true : x >= T(-128) && x <= T(127);
else
return x <= T(127);
}
//! Get whether the given integer `x` can be casted to 8-bit unsigned integer.
template<typename T>
static ASMJIT_INLINE bool isUInt8(T x) {
if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= sizeof(uint8_t) ? true : x <= T(255));
else
return sizeof(T) <= sizeof(uint8_t) ? true : x <= T(255);
}
//! Get whether the given integer `x` can be casted to 16-bit signed integer.
template<typename T>
static ASMJIT_INLINE bool isInt16(T x) {
if (IntTraits<T>::kIsSigned)
return sizeof(T) <= sizeof(int16_t) ? true : x >= T(-32768) && x <= T(32767);
else
return x >= T(0) && (sizeof(T) <= sizeof(int16_t) ? true : x <= T(32767));
}
//! Get whether the given integer `x` can be casted to 16-bit unsigned integer.
template<typename T>
static ASMJIT_INLINE bool isUInt16(T x) {
if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= sizeof(uint16_t) ? true : x <= T(65535));
else
return sizeof(T) <= sizeof(uint16_t) ? true : x <= T(65535);
}
//! Get whether the given integer `x` can be casted to 32-bit signed integer.
template<typename T>
static ASMJIT_INLINE bool isInt32(T x) {
if (IntTraits<T>::kIsSigned)
return sizeof(T) <= sizeof(int32_t) ? true : x >= T(-2147483647) - 1 && x <= T(2147483647);
else
return x >= T(0) && (sizeof(T) <= sizeof(int32_t) ? true : x <= T(2147483647));
}
//! Get whether the given integer `x` can be casted to 32-bit unsigned integer.
template<typename T>
static ASMJIT_INLINE bool isUInt32(T x) {
if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= sizeof(uint32_t) ? true : x <= T(4294967295U));
else
return sizeof(T) <= sizeof(uint32_t) ? true : x <= T(4294967295U);
}
// --------------------------------------------------------------------------
// [AsmJit - IsPowerOf2]
// --------------------------------------------------------------------------
//! Get whether the `n` value is a power of two (only one bit is set).
template<typename T>
static ASMJIT_INLINE bool isPowerOf2(T n) {
return n != 0 && (n & (n - 1)) == 0;
}
// --------------------------------------------------------------------------
// [AsmJit - Mask]
// --------------------------------------------------------------------------
//! Generate a bit-mask that has `x` bit set.
static ASMJIT_INLINE uint32_t mask(uint32_t x) {
ASMJIT_ASSERT(x < 32);
return (1U << x);
}
//! Generate a bit-mask that has `x0` and `x1` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1) {
return mask(x0) | mask(x1);
}
//! Generate a bit-mask that has `x0`, `x1` and `x2` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2) {
return mask(x0) | mask(x1) | mask(x2);
}
//! Generate a bit-mask that has `x0`, `x1`, `x2` and `x3` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3);
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3` and `x4` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
mask(x4) ;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4` and `x5` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
mask(x4) | mask(x5) ;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5` and `x6` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
mask(x4) | mask(x5) | mask(x6) ;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6` and `x7` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
mask(x4) | mask(x5) | mask(x6) | mask(x7) ;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7` and `x8` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
mask(x4) | mask(x5) | mask(x6) | mask(x7) |
mask(x8) ;
}
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7`, `x8` and `x9` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8, uint32_t x9) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) |
mask(x4) | mask(x5) | mask(x6) | mask(x7) |
mask(x8) | mask(x9) ;
}
// --------------------------------------------------------------------------
// [AsmJit - Bits]
// --------------------------------------------------------------------------
//! Generate a bit-mask that has `x` most significant bits set.
static ASMJIT_INLINE uint32_t bits(uint32_t x) {
// Shifting more bits that the type has has undefined behavior. Everything
// we need is that application shouldn't crash because of that, but the
// content of register after shift is not defined. So in case that the
// requested shift is too large for the type we correct this undefined
// behavior by setting all bits to ones (this is why we generate an overflow
// mask).
uint32_t overflow = static_cast<uint32_t>(
-static_cast<int32_t>(x >= sizeof(uint32_t) * 8));
return ((static_cast<uint32_t>(1) << x) - 1U) | overflow;
}
// --------------------------------------------------------------------------
// [AsmJit - HasBit]
// --------------------------------------------------------------------------
//! Get whether `x` has bit `n` set.
static ASMJIT_INLINE bool hasBit(uint32_t x, uint32_t n) {
return static_cast<bool>((x >> n) & 0x1);
}
// --------------------------------------------------------------------------
// [AsmJit - BitCount]
// --------------------------------------------------------------------------
//! Get count of bits in `x`.
//!
//! Taken from http://graphics.stanford.edu/~seander/bithacks.html .
static ASMJIT_INLINE uint32_t bitCount(uint32_t x) {
x = x - ((x >> 1) & 0x55555555U);
x = (x & 0x33333333U) + ((x >> 2) & 0x33333333U);
return (((x + (x >> 4)) & 0x0F0F0F0FU) * 0x01010101U) >> 24;
}
// --------------------------------------------------------------------------
// [AsmJit - FindFirstBit]
// --------------------------------------------------------------------------
//! \internal
static ASMJIT_INLINE uint32_t findFirstBitSlow(uint32_t mask) {
// This is a reference (slow) implementation of findFirstBit(), used when
// we don't have compiler support for this task. The implementation speed
// has been improved to check for 2 bits per iteration.
uint32_t i = 1;
while (mask != 0) {
uint32_t two = mask & 0x3;
if (two != 0x0)
return i - (two & 0x1);
i += 2;
mask >>= 2;
}
return 0xFFFFFFFFU;
}
//! Find a first bit in `mask`.
static ASMJIT_INLINE uint32_t findFirstBit(uint32_t mask) {
#if defined(_MSC_VER)
DWORD i;
if (_BitScanForward(&i, mask)) {
ASMJIT_ASSERT(findFirstBitSlow(mask) == i);
return static_cast<uint32_t>(i);
}
return 0xFFFFFFFFU;
#else
return findFirstBitSlow(mask);
#endif
}
// --------------------------------------------------------------------------
// [AsmJit - Misc]
// --------------------------------------------------------------------------
static ASMJIT_INLINE uint32_t keepNOnesFromRight(uint32_t mask, uint32_t nBits) {
uint32_t m = 0x1;
do {
nBits -= (mask & m) == 0;
m <<= 1;
if (nBits == 0) {
m -= 1;
mask &= m;
break;
}
} while (m);
return mask;
}
static ASMJIT_INLINE uint32_t indexNOnesFromRight(uint8_t* dst, uint32_t mask, uint32_t nBits) {
uint32_t totalBits = nBits;
uint8_t i = 0;
uint32_t m = 0x1;
do {
if (mask & m) {
*dst++ = i;
if (--nBits == 0)
break;
}
m <<= 1;
i++;
} while (m);
return totalBits - nBits;
}
// --------------------------------------------------------------------------
// [AsmJit - Alignment]
// --------------------------------------------------------------------------
template<typename T>
static ASMJIT_INLINE bool isAligned(T base, T alignment) {
return (base % alignment) == 0;
}
//! Align `base` to `alignment`.
template<typename T>
static ASMJIT_INLINE T alignTo(T base, T alignment) {
return (base + (alignment - 1)) & ~(alignment - 1);
}
template<typename T>
static ASMJIT_INLINE T alignToPowerOf2(T base) {
// Implementation is from "Hacker's Delight" by Henry S. Warren, Jr.
base -= 1;
#if defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable: 4293)
#endif // _MSC_VER
base = base | (base >> 1);
base = base | (base >> 2);
base = base | (base >> 4);
// 8/16/32 constants are multiplied by the condition to prevent a compiler
// complaining about the 'shift count >= type width' (GCC).
if (sizeof(T) >= 2) base = base | (base >> ( 8 * (sizeof(T) >= 2))); // Base >> 8.
if (sizeof(T) >= 4) base = base | (base >> (16 * (sizeof(T) >= 4))); // Base >> 16.
if (sizeof(T) >= 8) base = base | (base >> (32 * (sizeof(T) >= 8))); // Base >> 32.
#if defined(_MSC_VER)
# pragma warning(pop)
#endif // _MSC_VER
return base + 1;
}
//! Get delta required to align `base` to `alignment`.
template<typename T>
static ASMJIT_INLINE T deltaTo(T base, T alignment) {
return alignTo(base, alignment) - base;
}
};
// ============================================================================
// [asmjit::UInt64]
// ============================================================================
union UInt64 {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE UInt64 fromUInt64(uint64_t val) {
UInt64 data;
data.setUInt64(val);
return data;
}
ASMJIT_INLINE UInt64 fromUInt64(const UInt64& val) {
UInt64 data;
data.setUInt64(val);
return data;
}
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
if (kArchHost64Bit) {
u64 = 0;
}
else {
u32[0] = 0;
u32[1] = 0;
}
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE uint64_t getUInt64() const {
return u64;
}
ASMJIT_INLINE UInt64& setUInt64(uint64_t val) {
u64 = val;
return *this;
}
ASMJIT_INLINE UInt64& setUInt64(const UInt64& val) {
if (kArchHost64Bit) {
u64 = val.u64;
}
else {
u32[0] = val.u32[0];
u32[1] = val.u32[1];
}
return *this;
}
ASMJIT_INLINE UInt64& setPacked_2x32(uint32_t u0, uint32_t u1) {
if (kArchHost64Bit) {
u64 = IntUtil::pack64_2x32(u0, u1);
}
else {
u32[0] = u0;
u32[1] = u1;
}
return *this;
}
// --------------------------------------------------------------------------
// [Add]
// --------------------------------------------------------------------------
ASMJIT_INLINE UInt64& add(uint64_t val) {
u64 += val;
return *this;
}
ASMJIT_INLINE UInt64& add(const UInt64& val) {
if (kArchHost64Bit) {
u64 += val.u64;
}
else {
u32[0] += val.u32[0];
u32[1] += val.u32[1];
}
return *this;
}
// --------------------------------------------------------------------------
// [Sub]
// --------------------------------------------------------------------------
ASMJIT_INLINE UInt64& sub(uint64_t val) {
u64 -= val;
return *this;
}
ASMJIT_INLINE UInt64& sub(const UInt64& val) {
if (kArchHost64Bit) {
u64 -= val.u64;
}
else {
u32[0] -= val.u32[0];
u32[1] -= val.u32[1];
}
return *this;
}
// --------------------------------------------------------------------------
// [And]
// --------------------------------------------------------------------------
ASMJIT_INLINE UInt64& and_(uint64_t val) {
u64 &= val;
return *this;
}
ASMJIT_INLINE UInt64& and_(const UInt64& val) {
if (kArchHost64Bit) {
u64 &= val.u64;
}
else {
u32[0] &= val.u32[0];
u32[1] &= val.u32[1];
}
return *this;
}
// --------------------------------------------------------------------------
// [AndNot]
// --------------------------------------------------------------------------
ASMJIT_INLINE UInt64& andNot(uint64_t val) {
u64 &= ~val;
return *this;
}
ASMJIT_INLINE UInt64& andNot(const UInt64& val) {
if (kArchHost64Bit) {
u64 &= ~val.u64;
}
else {
u32[0] &= ~val.u32[0];
u32[1] &= ~val.u32[1];
}
return *this;
}
// --------------------------------------------------------------------------
// [Or]
// --------------------------------------------------------------------------
ASMJIT_INLINE UInt64& or_(uint64_t val) {
u64 |= val;
return *this;
}
ASMJIT_INLINE UInt64& or_(const UInt64& val) {
if (kArchHost64Bit) {
u64 |= val.u64;
}
else {
u32[0] |= val.u32[0];
u32[1] |= val.u32[1];
}
return *this;
}
// --------------------------------------------------------------------------
// [Xor]
// --------------------------------------------------------------------------
ASMJIT_INLINE UInt64& xor_(uint64_t val) {
u64 ^= val;
return *this;
}
ASMJIT_INLINE UInt64& xor_(const UInt64& val) {
if (kArchHost64Bit) {
u64 ^= val.u64;
}
else {
u32[0] ^= val.u32[0];
u32[1] ^= val.u32[1];
}
return *this;
}
// --------------------------------------------------------------------------
// [Eq]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isZero() const {
return kArchHost64Bit ? u64 == 0 : (u32[0] | u32[1]) == 0;
}
ASMJIT_INLINE bool isNonZero() const {
return kArchHost64Bit ? u64 != 0 : (u32[0] | u32[1]) != 0;
}
ASMJIT_INLINE bool eq(uint64_t val) const {
return u64 == val;
}
ASMJIT_INLINE bool eq(const UInt64& val) const {
return kArchHost64Bit ? u64 == val.u64 : (u32[0] == val.u32[0]) & (u32[1] == val.u32[1]);
}
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE UInt64& operator+=(uint64_t val) { return add(val); }
ASMJIT_INLINE UInt64& operator+=(const UInt64& val) { return add(val); }
ASMJIT_INLINE UInt64& operator-=(uint64_t val) { return sub(val); }
ASMJIT_INLINE UInt64& operator-=(const UInt64& val) { return sub(val); }
ASMJIT_INLINE UInt64& operator&=(uint64_t val) { return and_(val); }
ASMJIT_INLINE UInt64& operator&=(const UInt64& val) { return and_(val); }
ASMJIT_INLINE UInt64& operator|=(uint64_t val) { return or_(val); }
ASMJIT_INLINE UInt64& operator|=(const UInt64& val) { return or_(val); }
ASMJIT_INLINE UInt64& operator^=(uint64_t val) { return xor_(val); }
ASMJIT_INLINE UInt64& operator^=(const UInt64& val) { return xor_(val); }
ASMJIT_INLINE bool operator==(uint64_t val) const { return eq(val); }
ASMJIT_INLINE bool operator==(const UInt64& val) const { return eq(val); }
ASMJIT_INLINE bool operator!=(uint64_t val) const { return !eq(val); }
ASMJIT_INLINE bool operator!=(const UInt64& val) const { return !eq(val); }
ASMJIT_INLINE bool operator<(uint64_t val) const { return u64 < val; }
ASMJIT_INLINE bool operator<(const UInt64& val) const { return u64 < val.u64; }
ASMJIT_INLINE bool operator<=(uint64_t val) const { return u64 <= val; }
ASMJIT_INLINE bool operator<=(const UInt64& val) const { return u64 <= val.u64; }
ASMJIT_INLINE bool operator>(uint64_t val) const { return u64 > val; }
ASMJIT_INLINE bool operator>(const UInt64& val) const { return u64 > val.u64; }
ASMJIT_INLINE bool operator>=(uint64_t val) const { return u64 >= val; }
ASMJIT_INLINE bool operator>=(const UInt64& val) const { return u64 >= val.u64; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint64_t u64;
uint32_t u32[2];
uint16_t u16[4];
uint8_t u8[8];
struct {
#if defined(ASMJIT_HOST_LE)
uint32_t lo, hi;
#else
uint32_t hi, lo;
#endif // ASMJIT_HOST_LE
};
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_INTUTIL_H
@@ -0,0 +1,131 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_LOCK_H
#define _ASMJIT_BASE_LOCK_H
// [Dependencies - AsmJit]
#include "../build.h"
// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <pthread.h>
#endif // ASMJIT_OS_POSIX
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::Lock]
// ============================================================================
//! Lock - used in thread-safe code for locking.
struct Lock {
ASMJIT_NO_COPY(Lock)
// --------------------------------------------------------------------------
// [Windows]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS)
typedef CRITICAL_SECTION Handle;
//! Create a new `Lock` instance.
ASMJIT_INLINE Lock() { InitializeCriticalSection(&_handle); }
//! Destroy the `Lock` instance.
ASMJIT_INLINE ~Lock() { DeleteCriticalSection(&_handle); }
//! Lock.
ASMJIT_INLINE void lock() { EnterCriticalSection(&_handle); }
//! Unlock.
ASMJIT_INLINE void unlock() { LeaveCriticalSection(&_handle); }
#endif // ASMJIT_OS_WINDOWS
// --------------------------------------------------------------------------
// [Posix]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_POSIX)
typedef pthread_mutex_t Handle;
//! Create a new `Lock` instance.
ASMJIT_INLINE Lock() { pthread_mutex_init(&_handle, NULL); }
//! Destroy the `Lock` instance.
ASMJIT_INLINE ~Lock() { pthread_mutex_destroy(&_handle); }
//! Lock.
ASMJIT_INLINE void lock() { pthread_mutex_lock(&_handle); }
//! Unlock.
ASMJIT_INLINE void unlock() { pthread_mutex_unlock(&_handle); }
#endif // ASMJIT_OS_POSIX
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get handle.
ASMJIT_INLINE Handle& getHandle() {
return _handle;
}
//! \overload
ASMJIT_INLINE const Handle& getHandle() const {
return _handle;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Handle.
Handle _handle;
};
// ============================================================================
// [asmjit::AutoLock]
// ============================================================================
//! Scoped lock.
struct AutoLock {
ASMJIT_NO_COPY(AutoLock)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Autolock `target`, scoped.
ASMJIT_INLINE AutoLock(Lock& target) : _target(target) {
_target.lock();
}
//! Autounlock `target`.
ASMJIT_INLINE ~AutoLock() {
_target.unlock();
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Pointer to target (lock).
Lock& _target;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_LOCK_H
@@ -0,0 +1,249 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_LOGGER_H
#define _ASMJIT_BASE_LOGGER_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_LOGGER)
// [Dependencies - AsmJit]
#include "../base/string.h"
// [Dependencies - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kLoggerOption]
// ============================================================================
//! Logger options.
ASMJIT_ENUM(kLoggerOption) {
//! Whether to output instructions also in binary form.
kLoggerOptionBinaryForm = 0,
//! Whether to output immediates as hexadecimal numbers.
kLoggerOptionHexImmediate = 1,
//! Whether to output displacements as hexadecimal numbers.
kLoggerOptionHexDisplacement = 2,
//! Count of logger options.
kLoggerOptionCount = 3
};
// ============================================================================
// [asmjit::kLoggerStyle]
// ============================================================================
//! Logger style.
ASMJIT_ENUM(kLoggerStyle) {
kLoggerStyleDefault = 0,
kLoggerStyleDirective = 1,
kLoggerStyleLabel = 2,
kLoggerStyleData = 3,
kLoggerStyleComment = 4,
kLoggerStyleCount = 5
};
// ============================================================================
// [asmjit::Logger]
// ============================================================================
//! Abstract logging class.
//!
//! This class can be inherited and reimplemented to fit into your logging
//! subsystem. When reimplementing use `Logger::log()` method to log into
//! a custom stream.
//!
//! This class also contain `_enabled` member that can be used to enable
//! or disable logging.
struct ASMJIT_VCLASS Logger {
ASMJIT_NO_COPY(Logger)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `Logger` instance.
ASMJIT_API Logger();
//! Destroy the `Logger` instance.
ASMJIT_API virtual ~Logger();
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
//! Log output.
virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex) = 0;
//! Log formatter message (like sprintf) sending output to `logString()` method.
ASMJIT_API void logFormat(uint32_t style, const char* fmt, ...);
//! Log binary data.
ASMJIT_API void logBinary(uint32_t style, const void* data, size_t size);
// --------------------------------------------------------------------------
// [Options]
// --------------------------------------------------------------------------
//! Get all logger options as a single integer.
ASMJIT_INLINE uint32_t getOptions() const {
return _options;
}
//! Get the given logger option.
ASMJIT_INLINE bool getOption(uint32_t id) const {
ASMJIT_ASSERT(id < kLoggerOptionCount);
return static_cast<bool>((_options >> id) & 0x1);
}
//! Set the given logger option.
ASMJIT_API void setOption(uint32_t id, bool value);
// --------------------------------------------------------------------------
// [Indentation]
// --------------------------------------------------------------------------
//! Get indentation.
ASMJIT_INLINE const char* getIndentation() const {
return _indentation;
}
//! Set indentation.
ASMJIT_API void setIndentation(const char* indentation);
//! Reset indentation.
ASMJIT_INLINE void resetIndentation() {
setIndentation(NULL);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Options, see `kLoggerOption`.
uint32_t _options;
//! Indentation.
char _indentation[12];
};
// ============================================================================
// [asmjit::FileLogger]
// ============================================================================
//! Logger that can log to standard C `FILE*` stream.
struct ASMJIT_VCLASS FileLogger : public Logger {
ASMJIT_NO_COPY(FileLogger)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `FileLogger` that logs to a `FILE` stream.
ASMJIT_API FileLogger(FILE* stream = NULL);
//! Destroy the `FileLogger`.
ASMJIT_API virtual ~FileLogger();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get `FILE*` stream.
//!
//! \note Return value can be `NULL`.
ASMJIT_INLINE FILE* getStream() const {
return _stream;
}
//! Set `FILE*` stream, can be set to `NULL` to disable logging, although
//! the `CodeGen` will still call `logString` even if there is no stream.
ASMJIT_INLINE void setStream(FILE* stream) {
_stream = stream;
}
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
ASMJIT_API virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! C file stream.
FILE* _stream;
};
// ============================================================================
// [asmjit::StringLogger]
// ============================================================================
//! String logger.
struct ASMJIT_VCLASS StringLogger : public Logger {
ASMJIT_NO_COPY(StringLogger)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create new `StringLogger`.
ASMJIT_API StringLogger();
//! Destroy the `StringLogger`.
ASMJIT_API virtual ~StringLogger();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get `char*` pointer which represents the resulting string.
//!
//! The pointer is owned by `StringLogger`, it can't be modified or freed.
ASMJIT_INLINE const char* getString() const {
return _stringBuilder.getData();
}
//! Clear the resulting string.
ASMJIT_INLINE void clearString() {
_stringBuilder.clear();
}
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
ASMJIT_API virtual void logString(uint32_t style, const char* buf, size_t len = kInvalidIndex);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Output.
StringBuilder _stringBuilder;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_LOGGER
#endif // _ASMJIT_BASE_LOGGER_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,262 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_RUNTIME_H
#define _ASMJIT_BASE_RUNTIME_H
// [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/vmem.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [Forward Declarations]
// ============================================================================
struct Assembler;
struct CpuInfo;
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kRuntimeType]
// ============================================================================
ASMJIT_ENUM(kRuntimeType) {
kRuntimeTypeNone = 0,
kRuntimeTypeJit = 1,
kRuntimeTypeRemote = 2
};
// ============================================================================
// [asmjit::Runtime]
// ============================================================================
//! Base runtime.
struct ASMJIT_VCLASS Runtime {
ASMJIT_NO_COPY(Runtime)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `Runtime` instance.
ASMJIT_API Runtime();
//! Destroy the `Runtime` instance.
ASMJIT_API virtual ~Runtime();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get runtime type.
ASMJIT_INLINE uint32_t getRuntimeType() const {
return _runtimeType;
}
//! Get whether the runtime has a base address.
//!
//! \sa \ref getBaseAddress()
ASMJIT_INLINE bool hasBaseAddress() const {
return _baseAddress == kNoBaseAddress;
}
//! Get the base address.
ASMJIT_INLINE Ptr getBaseAddress() const {
return _baseAddress;
}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Get CPU information.
virtual const CpuInfo* getCpuInfo() = 0;
//! Get stack alignment of target runtime.
virtual uint32_t getStackAlignment() = 0;
//! Allocate a memory needed for a code generated by `assembler` and
//! relocate it to the target location.
//!
//! The beginning of the memory allocated for the function is returned in
//! `dst`. Returns Status code as \ref kError, on failure `dst` is set to
//! `NULL`.
virtual Error add(void** dst, Assembler* assembler) = 0;
//! Release memory allocated by `add`.
virtual Error release(void* p) = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Maximum size of the code that can be added to the runtime (0=unlimited).
size_t _sizeLimit;
//! Base address (-1 means no base address).
Ptr _baseAddress;
//! Type of the runtime.
uint8_t _runtimeType;
//! Type of the allocation.
uint8_t _allocType;
//! \internal
uint8_t _reserved[sizeof(intptr_t) - 2];
};
// ============================================================================
// [asmjit::HostRuntime]
// ============================================================================
//! Base runtime for JIT code generation.
struct ASMJIT_VCLASS HostRuntime : public Runtime {
ASMJIT_NO_COPY(HostRuntime)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `HostRuntime` instance.
ASMJIT_API HostRuntime();
//! Destroy the `HostRuntime` instance.
ASMJIT_API virtual ~HostRuntime();
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
ASMJIT_API virtual const CpuInfo* getCpuInfo();
ASMJIT_API virtual uint32_t getStackAlignment();
//! Flush an instruction cache.
//!
//! This member function is called after the code has been copied to the
//! destination buffer. It is only useful for JIT code generation as it
//! causes a flush of the processor cache.
//!
//! Flushing is basically a NOP under X86/X64, but is needed by architectures
//! that do not have a transparent instruction cache.
//!
//! This function can also be overridden to improve compatibility with tools
//! such as Valgrind, however, it's not an official part of AsmJit.
ASMJIT_API virtual void flush(void* p, size_t size);
};
// ============================================================================
// [asmjit::StaticRuntime]
// ============================================================================
//! JIT static runtime.
//!
//! JIT static runtime can be used to generate code to a memory location that
//! is known.
struct ASMJIT_VCLASS StaticRuntime : public HostRuntime {
ASMJIT_NO_COPY(StaticRuntime)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `StaticRuntime` instance.
//!
//! The `address` specifies a fixed target address, which will be used as a
//! base address for relocation, and `sizeLimit` specified the maximum size
//! of a code that can be copied to it. If there is no limit `sizeLimit`
//! should be zero.
ASMJIT_API StaticRuntime(void* baseAddress, size_t sizeLimit = 0);
//! Destroy the `StaticRuntime` instance.
ASMJIT_API virtual ~StaticRuntime();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the base address.
ASMJIT_INLINE Ptr getBaseAddress() const {
return _baseAddress;
}
//! Get the maximum size of the code that can be relocated to the target
//! address or zero if unlimited.
ASMJIT_INLINE size_t getSizeLimit() const {
return _sizeLimit;
}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
ASMJIT_API virtual Error add(void** dst, Assembler* assembler);
ASMJIT_API virtual Error release(void* p);
};
// ============================================================================
// [asmjit::JitRuntime]
// ============================================================================
//! JIT runtime.
struct ASMJIT_VCLASS JitRuntime : public HostRuntime {
ASMJIT_NO_COPY(JitRuntime)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `JitRuntime` instance.
ASMJIT_API JitRuntime();
//! Destroy the `JitRuntime` instance.
ASMJIT_API virtual ~JitRuntime();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the type of allocation.
ASMJIT_INLINE uint32_t getAllocType() const {
return _allocType;
}
//! Set the type of allocation.
ASMJIT_INLINE void setAllocType(uint32_t allocType) {
_allocType = allocType;
}
//! Get the virtual memory manager.
ASMJIT_INLINE VMemMgr* getMemMgr() const {
return const_cast<VMemMgr*>(&_memMgr);
}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
ASMJIT_API virtual Error add(void** dst, Assembler* assembler);
ASMJIT_API virtual Error release(void* p);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Virtual memory manager.
VMemMgr _memMgr;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_RUNTIME_H
@@ -0,0 +1,372 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_STRING_H
#define _ASMJIT_BASE_STRING_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Dependencies - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kStringOp]
// ============================================================================
//! \internal
//!
//! String operation.
ASMJIT_ENUM(kStringOp) {
//! Replace the current string by a given content.
kStringOpSet = 0,
//! Append a given content to the current string.
kStringOpAppend = 1
};
// ============================================================================
// [asmjit::kStringFormat]
// ============================================================================
//! \internal
//!
//! String format flags.
ASMJIT_ENUM(kStringFormat) {
kStringFormatShowSign = 0x00000001,
kStringFormatShowSpace = 0x00000002,
kStringFormatAlternate = 0x00000004,
kStringFormatSigned = 0x80000000
};
// ============================================================================
// [asmjit::StringUtil]
// ============================================================================
//! String utilities.
struct StringUtil {
static ASMJIT_INLINE size_t nlen(const char* s, size_t maxlen) {
size_t i;
for (i = 0; i < maxlen; i++)
if (!s[i])
break;
return i;
}
};
// ============================================================================
// [asmjit::StringBuilder]
// ============================================================================
//! String builder.
//!
//! String builder was designed to be able to build a string using append like
//! operation to append numbers, other strings, or signle characters. It can
//! allocate it's own buffer or use a buffer created on the stack.
//!
//! String builder contains method specific to AsmJit functionality, used for
//! logging or HTML output.
struct StringBuilder {
ASMJIT_NO_COPY(StringBuilder)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API StringBuilder();
ASMJIT_API ~StringBuilder();
ASMJIT_INLINE StringBuilder(const _NoInit&) {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get string builder capacity.
ASMJIT_INLINE size_t getCapacity() const { return _capacity; }
//! Get length.
ASMJIT_INLINE size_t getLength() const { return _length; }
//! Get null-terminated string data.
ASMJIT_INLINE char* getData() { return _data; }
//! Get null-terminated string data (const).
ASMJIT_INLINE const char* getData() const { return _data; }
// --------------------------------------------------------------------------
// [Prepare / Reserve]
// --------------------------------------------------------------------------
//! Prepare to set/append.
ASMJIT_API char* prepare(uint32_t op, size_t len);
//! Reserve `to` bytes in string builder.
ASMJIT_API bool reserve(size_t to);
// --------------------------------------------------------------------------
// [Clear]
// --------------------------------------------------------------------------
//! Clear the content in String builder.
ASMJIT_API void clear();
// --------------------------------------------------------------------------
// [Op]
// --------------------------------------------------------------------------
ASMJIT_API bool _opString(uint32_t op, const char* str, size_t len = kInvalidIndex);
ASMJIT_API bool _opVFormat(uint32_t op, const char* fmt, va_list ap);
ASMJIT_API bool _opChar(uint32_t op, char c);
ASMJIT_API bool _opChars(uint32_t op, char c, size_t len);
ASMJIT_API bool _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0);
ASMJIT_API bool _opHex(uint32_t op, const void* data, size_t len);
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
//! Replace the current content by `str` of `len`.
ASMJIT_INLINE bool setString(const char* str, size_t len = kInvalidIndex) {
return _opString(kStringOpSet, str, len);
}
//! Replace the current content by formatted string `fmt`.
ASMJIT_INLINE bool setVFormat(const char* fmt, va_list ap) {
return _opVFormat(kStringOpSet, fmt, ap);
}
//! Replace the current content by formatted string `fmt`.
ASMJIT_API bool setFormat(const char* fmt, ...);
//! Replace the current content by `c` character.
ASMJIT_INLINE bool setChar(char c) {
return _opChar(kStringOpSet, c);
}
//! Replace the current content by `c` of `len`.
ASMJIT_INLINE bool setChars(char c, size_t len) {
return _opChars(kStringOpSet, c, len);
}
//! Replace the current content by formatted integer `i`.
ASMJIT_INLINE bool setInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpSet, i, base, width, flags | kStringFormatSigned);
}
//! Replace the current content by formatted integer `i`.
ASMJIT_INLINE bool setUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpSet, i, base, width, flags);
}
//! Replace the current content by the given `data` converted to a HEX string.
ASMJIT_INLINE bool setHex(const void* data, size_t len) {
return _opHex(kStringOpSet, data, len);
}
// --------------------------------------------------------------------------
// [Append]
// --------------------------------------------------------------------------
//! Append `str` of `len`.
ASMJIT_INLINE bool appendString(const char* str, size_t len = kInvalidIndex) {
return _opString(kStringOpAppend, str, len);
}
//! Append a formatted string `fmt` to the current content.
ASMJIT_INLINE bool appendVFormat(const char* fmt, va_list ap) {
return _opVFormat(kStringOpAppend, fmt, ap);
}
//! Append a formatted string `fmt` to the current content.
ASMJIT_API bool appendFormat(const char* fmt, ...);
//! Append `c` character.
ASMJIT_INLINE bool appendChar(char c) {
return _opChar(kStringOpAppend, c);
}
//! Append `c` of `len`.
ASMJIT_INLINE bool appendChars(char c, size_t len) {
return _opChars(kStringOpAppend, c, len);
}
//! Append `i`.
ASMJIT_INLINE bool appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpAppend, static_cast<uint64_t>(i), base, width, flags | kStringFormatSigned);
}
//! Append `i`.
ASMJIT_INLINE bool appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpAppend, i, base, width, flags);
}
//! Append the given `data` converted to a HEX string.
ASMJIT_INLINE bool appendHex(const void* data, size_t len) {
return _opHex(kStringOpAppend, data, len);
}
// --------------------------------------------------------------------------
// [_Append]
// --------------------------------------------------------------------------
//! Append `str` of `len`, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendString(const char* str, size_t len = kInvalidIndex) {
// len should be a constant if we are inlining.
if (len == kInvalidIndex) {
char* p = &_data[_length];
while (*str) {
ASMJIT_ASSERT(p < _data + _capacity);
*p++ = *str++;
}
*p = '\0';
_length = (size_t)(p - _data);
}
else {
ASMJIT_ASSERT(_capacity - _length >= len);
char* p = &_data[_length];
char* pEnd = p + len;
while (p < pEnd)
*p++ = *str++;
*p = '\0';
_length += len;
}
}
//! Append `c` character, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendChar(char c) {
ASMJIT_ASSERT(_capacity - _length >= 1);
_data[_length] = c;
_length++;
_data[_length] = '\0';
}
//! Append `c` of `len`, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendChars(char c, size_t len) {
ASMJIT_ASSERT(_capacity - _length >= len);
char* p = &_data[_length];
char* pEnd = p + len;
while (p < pEnd)
*p++ = c;
*p = '\0';
_length += len;
}
ASMJIT_INLINE void _appendUInt32(uint32_t i) {
char buf_[32];
char* pEnd = buf_ + ASMJIT_ARRAY_SIZE(buf_);
char* pBuf = pEnd;
do {
uint32_t d = i / 10;
uint32_t r = i % 10;
*--pBuf = static_cast<uint8_t>(r + '0');
i = d;
} while (i);
ASMJIT_ASSERT(_capacity - _length >= (size_t)(pEnd - pBuf));
char* p = &_data[_length];
do {
*p++ = *pBuf;
} while (++pBuf != pEnd);
*p = '\0';
_length = (size_t)(p - _data);
}
// --------------------------------------------------------------------------
// [Eq]
// --------------------------------------------------------------------------
//! Check for equality with other `str` of `len`.
ASMJIT_API bool eq(const char* str, size_t len = kInvalidIndex) const;
//! Check for equality with `other`.
ASMJIT_INLINE bool eq(const StringBuilder& other) const {
return eq(other._data);
}
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool operator==(const StringBuilder& other) const { return eq(other); }
ASMJIT_INLINE bool operator!=(const StringBuilder& other) const { return !eq(other); }
ASMJIT_INLINE bool operator==(const char* str) const { return eq(str); }
ASMJIT_INLINE bool operator!=(const char* str) const { return !eq(str); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! String data.
char* _data;
//! Length.
size_t _length;
//! Capacity.
size_t _capacity;
//! Whether the string can be freed.
size_t _canFree;
};
// ============================================================================
// [asmjit::StringBuilderT]
// ============================================================================
//! \internal
template<size_t N>
struct StringBuilderT : public StringBuilder {
ASMJIT_NO_COPY(StringBuilderT<N>)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE StringBuilderT() : StringBuilder(NoInit) {
_data = _embeddedData;
_data[0] = 0;
_length = 0;
_capacity = N;
_canFree = false;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Embedded data.
char _embeddedData[static_cast<size_t>(
N + 1 + sizeof(intptr_t)) & ~static_cast<size_t>(sizeof(intptr_t) - 1)];
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_STRING_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,240 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_VMEM_H
#define _ASMJIT_BASE_VMEM_H
// [Dependencies]
#include "../base/error.h"
#include "../base/lock.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kVMemAlloc]
// ============================================================================
//! Type of virtual memory allocation, see `VMemMgr::alloc()`.
ASMJIT_ENUM(kVMemAlloc) {
//! Normal memory allocation, has to be freed by `VMemMgr::release()`.
kVMemAllocFreeable = 0,
//! Allocate permanent memory, can't be freed.
kVMemAllocPermanent = 1
};
// ============================================================================
// [asmjit::kVMemFlags]
// ============================================================================
//! Type of virtual memory allocation, see `VMemMgr::alloc()`.
ASMJIT_ENUM(kVMemFlags) {
//! Memory is writable.
kVMemFlagWritable = 0x00000001,
//! Memory is executable.
kVMemFlagExecutable = 0x00000002
};
// ============================================================================
// [asmjit::VMemUtil]
// ============================================================================
//! Virtual memory utilities.
//!
//! Defines functions that provide facility to allocate and free memory that is
//! executable in a platform independent manner. If both the processor and host
//! operating system support data-execution-prevention then the only way how to
//! run machine code is to allocate it to a memory that has marked as executable.
//! VMemUtil is just unified interface to platform dependent APIs.
//!
//! `VirtualAlloc()` function is used on Windows operating system and `mmap()`
//! on POSIX. `VirtualAlloc()` and `mmap()` documentation provide a detailed
//! overview on how to use a platform specific APIs.
struct VMemUtil {
//! Get a size/alignment of a single virtual memory page.
static ASMJIT_API size_t getPageSize();
//! Get a recommended granularity for a single `alloc` call.
static ASMJIT_API size_t getPageGranularity();
//! Allocate virtual memory.
//!
//! Pages are readable/writeable, but they are not guaranteed to be
//! executable unless 'canExecute' is true. Returns the address of
//! allocated memory, or NULL on failure.
static ASMJIT_API void* alloc(size_t length, size_t* allocated, uint32_t flags);
#if defined(ASMJIT_OS_WINDOWS)
//! Allocate virtual memory of `hProcess`.
//!
//! \note This function is Windows specific.
static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags);
#endif // ASMJIT_OS_WINDOWS
//! Free memory allocated by `alloc()`.
static ASMJIT_API Error release(void* addr, size_t length);
#if defined(ASMJIT_OS_WINDOWS)
//! Release virtual memory of `hProcess`.
//!
//! \note This function is Windows specific.
static ASMJIT_API Error releaseProcessMemory(HANDLE hProcess, void* addr, size_t length);
#endif // ASMJIT_OS_WINDOWS
};
// ============================================================================
// [asmjit::VMemMgr]
// ============================================================================
//! Reference implementation of memory manager that uses `VMemUtil` to allocate
//! chunks of virtual memory and bit arrays to manage it.
struct VMemMgr {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
#if !defined(ASMJIT_OS_WINDOWS)
//! Create a `VMemMgr` instance.
ASMJIT_API VMemMgr();
#else
//! Create a `VMemMgr` instance.
//!
//! \note When running on Windows it's possible to specify a `hProcess` to
//! be used for memory allocation. This allows to allocate memory of remote
//! process.
ASMJIT_API VMemMgr(HANDLE hProcess = static_cast<HANDLE>(0));
#endif // ASMJIT_OS_WINDOWS
//! Destroy the `VMemMgr` instance and free all blocks.
ASMJIT_API ~VMemMgr();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Free all allocated memory.
ASMJIT_API void reset();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS)
//! Get the handle of the process memory manager is bound to.
ASMJIT_INLINE HANDLE getProcessHandle() const {
return _hProcess;
}
#endif // ASMJIT_OS_WINDOWS
//! Get how many bytes are currently allocated.
ASMJIT_INLINE size_t getAllocatedBytes() const {
return _allocatedBytes;
}
//! Get how many bytes are currently used.
ASMJIT_INLINE size_t getUsedBytes() const {
return _usedBytes;
}
//! Get whether to keep allocated memory after the `VMemMgr` is destroyed.
//!
//! \sa \ref setKeepVirtualMemory.
ASMJIT_INLINE bool getKeepVirtualMemory() const {
return _keepVirtualMemory;
}
//! Set whether to keep allocated memory after memory manager is
//! destroyed.
//!
//! This method is usable when patching code of remote process. You need to
//! allocate process memory, store generated assembler into it and patch the
//! method you want to redirect (into your code). This method affects only
//! VMemMgr destructor. After destruction all internal
//! structures are freed, only the process virtual memory remains.
//!
//! \note Memory allocated with kVMemAllocPermanent is always kept.
//!
//! \sa \ref getKeepVirtualMemory.
ASMJIT_INLINE void setKeepVirtualMemory(bool keepVirtualMemory) {
_keepVirtualMemory = keepVirtualMemory;
}
// --------------------------------------------------------------------------
// [Alloc / Release]
// --------------------------------------------------------------------------
//! Allocate a `size` bytes of virtual memory.
//!
//! Note that if you are implementing your own virtual memory manager then you
//! can quitly ignore type of allocation. This is mainly for AsmJit to memory
//! manager that allocated memory will be never freed.
ASMJIT_API void* alloc(size_t size, uint32_t type = kVMemAllocFreeable);
//! Free previously allocated memory at a given `address`.
ASMJIT_API Error release(void* p);
//! Free extra memory allocated with `p`.
ASMJIT_API Error shrink(void* p, size_t used);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS)
//! Process passed to `VirtualAllocEx` and `VirtualFree`.
HANDLE _hProcess;
#endif // ASMJIT_OS_WINDOWS
//! Lock to enable thread-safe functionality.
Lock _lock;
//! Default block size.
size_t _blockSize;
//! Default block density.
size_t _blockDensity;
// Whether to keep virtual memory after destroy.
bool _keepVirtualMemory;
//! How many bytes are currently allocated.
size_t _allocatedBytes;
//! How many bytes are currently used.
size_t _usedBytes;
//! \internal
//! \{
struct RbNode;
struct MemNode;
struct PermanentNode;
// Memory nodes root.
MemNode* _root;
// Memory nodes list.
MemNode* _first;
MemNode* _last;
MemNode* _optimal;
// Permanent memory.
PermanentNode* _permanent;
//! \}
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_VMEM_H
@@ -0,0 +1,221 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_ZONE_H
#define _ASMJIT_BASE_ZONE_H
// [Dependencies]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::Zone]
// ============================================================================
//! Zone memory allocator.
//!
//! Zone is an incremental memory allocator that allocates memory by simply
//! incrementing a pointer. It allocates blocks of memory by using standard
//! C library `malloc/free`, but divides these blocks into smaller segments
//! requirested by calling `Zone::alloc()` and friends.
//!
//! Zone memory allocators are designed to allocate data of short lifetime. The
//! data used by `Assembler` and `Compiler` has a very short lifetime, thus, is
//! allocated by `Zone`. The advantage is that `Zone` can free all of the data
//! allocated at once by calling `reset()` or by `Zone` destructor.
struct Zone {
// --------------------------------------------------------------------------
// [Block]
// --------------------------------------------------------------------------
//! \internal
//!
//! A single block of memory.
struct Block {
// ------------------------------------------------------------------------
// [Accessors]
// ------------------------------------------------------------------------
//! Get the size of the block.
ASMJIT_INLINE size_t getBlockSize() const {
return (size_t)(end - data);
}
//! Get count of remaining bytes in the block.
ASMJIT_INLINE size_t getRemainingSize() const {
return (size_t)(end - pos);
}
// ------------------------------------------------------------------------
// [Members]
// ------------------------------------------------------------------------
//! Current data pointer (pointer to the first available byte).
uint8_t* pos;
//! End data pointer (pointer to the first invalid byte).
uint8_t* end;
//! Link to the previous block.
Block* prev;
//! Link to the next block.
Block* next;
//! Data.
uint8_t data[sizeof(void*)];
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new instance of `Zone` allocator.
//!
//! The `blockSize` parameter describes the default size of the block. If the
//! `size` parameter passed to `alloc()` is greater than the default size
//! `Zone` will allocate and use a larger block, but it will not change the
//! default `blockSize`.
//!
//! It's not required, but it's good practice to set `blockSize` to a
//! reasonable value that depends on the usage of `Zone`. Greater block sizes
//! are generally safer and performs better than unreasonably low values.
ASMJIT_API Zone(size_t blockSize);
//! Destroy the `Zone` instance.
//!
//! This will destroy the `Zone` instance and release all blocks of memory
//! allocated by it. It performs implicit `reset(true)`.
ASMJIT_API ~Zone();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the `Zone` invalidating all blocks allocated.
//!
//! If `releaseMemory` is true all buffers will be released to the system.
ASMJIT_API void reset(bool releaseMemory = false);
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the default block size.
ASMJIT_INLINE size_t getBlockSize() const {
return _blockSize;
}
// --------------------------------------------------------------------------
// [Alloc]
// --------------------------------------------------------------------------
//! Allocate `size` bytes of memory.
//!
//! Pointer returned is valid until the `Zone` instance is destroyed or reset
//! by calling `reset()`. If you plan to make an instance of C++ from the
//! given pointer use placement `new` and `delete` operators:
//!
//! ~~~
//! using namespace asmjit;
//!
//! class SomeObject { ... };
//!
//! // Create Zone with default block size of 65536 bytes.
//! Zone zone(65536);
//!
//! // Create your objects using zone object allocating, for example:
//! Object* obj = static_cast<Object*>( zone.alloc(sizeof(SomeClass)) );
//
//! if (obj == NULL) {
//! // Handle out of memory error.
//! }
//!
//! // To instantiate class placement `new` and `delete` operators can be used.
//! new(obj) Object();
//!
//! // ... lifetime of your objects ...
//!
//! // To destroy the instance (if required).
//! obj->~Object();
//!
//! // Reset of destroy `Zone`.
//! zone.reset();
//! ~~~
ASMJIT_INLINE void* alloc(size_t size) {
Block* cur = _block;
uint8_t* ptr = cur->pos;
size_t remainingBytes = (size_t)(cur->end - ptr);
if (remainingBytes < size)
return _alloc(size);
cur->pos += size;
ASMJIT_ASSERT(cur->pos <= cur->end);
return (void*)ptr;
}
//! Allocate `size` bytes of zeroed memory.
//!
//! See \ref alloc() for more details.
ASMJIT_API void* allocZeroed(size_t size);
//! Like `alloc()`, but the return pointer is casted to `T*`.
template<typename T>
ASMJIT_INLINE T* allocT(size_t size = sizeof(T)) {
return static_cast<T*>(alloc(size));
}
//! Like `allocZeroed()`, but the return pointer is casted to `T*`.
template<typename T>
ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T)) {
return static_cast<T*>(allocZeroed(size));
}
//! \internal
ASMJIT_API void* _alloc(size_t size);
//! Helper to duplicate data.
ASMJIT_API void* dup(const void* data, size_t size);
//! Helper to duplicate string.
ASMJIT_API char* sdup(const char* str);
//! Helper to duplicate formatted string, maximum length is 256 bytes.
ASMJIT_API char* sformat(const char* str, ...);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! The current block.
Block* _block;
//! Default block size.
size_t _blockSize;
};
enum {
//! Zone allocator overhead.
kZoneOverhead = static_cast<int>(sizeof(Zone::Block) - sizeof(void*)) + kMemAllocOverhead
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ZONE_H
@@ -0,0 +1,59 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_HOST_H
#define _ASMJIT_HOST_H
// [Dependencies - Core]
#include "base.h"
// ============================================================================
// [asmjit::host - X86 / X64]
// ============================================================================
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
#include "x86.h"
namespace asmjit {
// Define `asmjit::host` namespace wrapping `asmjit::x86`.
namespace host { using namespace ::asmjit::x86; }
// Define host assembler.
typedef X86Assembler HostAssembler;
// Define host operands.
typedef X86GpReg GpReg;
typedef X86FpReg FpReg;
typedef X86MmReg MmReg;
typedef X86XmmReg XmmReg;
typedef X86YmmReg YmmReg;
typedef X86SegReg SegReg;
typedef X86Mem Mem;
// Define host utilities.
typedef X86CpuInfo HostCpuInfo;
// Define host compiler and related.
#if !defined(ASMJIT_DISABLE_COMPILER)
typedef X86Compiler HostCompiler;
typedef X86CallNode HostCallNode;
typedef X86FuncDecl HostFuncDecl;
typedef X86FuncNode HostFuncNode;
typedef X86GpVar GpVar;
typedef X86MmVar MmVar;
typedef X86XmmVar XmmVar;
typedef X86YmmVar YmmVar;
#endif // !ASMJIT_DISABLE_COMPILER
} // asmjit namespace
#endif // ASMJIT_HOST_X86 || ASMJIT_HOST_X64
// [Guard]
#endif // _ASMJIT_HOST_H
@@ -0,0 +1,21 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_X86_H
#define _ASMJIT_X86_H
// [Dependencies - AsmJit]
#include "base.h"
#include "x86/x86assembler.h"
#include "x86/x86compiler.h"
#include "x86/x86cpuinfo.h"
#include "x86/x86inst.h"
#include "x86/x86operand.h"
// [Guard]
#endif // _ASMJIT_X86_H
@@ -0,0 +1,314 @@
/* Header for BeaEngine 4.x */
#ifndef _BEA_ENGINE_
#define _BEA_ENGINE_
#include "Includes/export.h"
#include "Includes/basic_types.h"
#if !defined(BEA_ENGINE_STATIC)
#if defined(BUILD_BEA_ENGINE_DLL)
#define BEA_API bea__api_export__
#else
#define BEA_API bea__api_import__
#endif
#else
#define BEA_API
#endif
#define INSTRUCT_LENGTH 64
#pragma pack(1)
typedef struct {
UInt8 W_;
UInt8 R_;
UInt8 X_;
UInt8 B_;
UInt8 state;
} REX_Struct ;
#pragma pack()
#pragma pack(1)
typedef struct {
int Number;
int NbUndefined;
UInt8 LockPrefix;
UInt8 OperandSize;
UInt8 AddressSize;
UInt8 RepnePrefix;
UInt8 RepPrefix;
UInt8 FSPrefix;
UInt8 SSPrefix;
UInt8 GSPrefix;
UInt8 ESPrefix;
UInt8 CSPrefix;
UInt8 DSPrefix;
UInt8 BranchTaken;
UInt8 BranchNotTaken;
REX_Struct REX;
char alignment[2];
} PREFIXINFO ;
#pragma pack()
#pragma pack(1)
typedef struct {
UInt8 OF_;
UInt8 SF_;
UInt8 ZF_;
UInt8 AF_;
UInt8 PF_;
UInt8 CF_;
UInt8 TF_;
UInt8 IF_;
UInt8 DF_;
UInt8 NT_;
UInt8 RF_;
UInt8 alignment;
} EFLStruct ;
#pragma pack()
#pragma pack(4)
typedef struct {
Int32 BaseRegister;
Int32 IndexRegister;
Int32 Scale;
Int64 Displacement;
} MEMORYTYPE ;
#pragma pack()
#pragma pack(1)
typedef struct {
Int32 Category;
Int32 Opcode;
char Mnemonic[16];
Int32 BranchType;
EFLStruct Flags;
UInt64 AddrValue;
Int64 Immediat;
UInt32 ImplicitModifiedRegs;
} INSTRTYPE;
#pragma pack()
#pragma pack(1)
typedef struct {
char ArgMnemonic[64];
Int32 ArgType;
Int32 ArgSize;
Int32 ArgPosition;
UInt32 AccessMode;
MEMORYTYPE Memory;
UInt32 SegmentReg;
} ARGTYPE;
#pragma pack()
#pragma pack(1)
typedef struct _Disasm {
UIntPtr EIP;
UInt64 VirtualAddr;
UInt32 SecurityBlock;
char CompleteInstr[INSTRUCT_LENGTH];
UInt32 Archi;
UInt64 Options;
INSTRTYPE Instruction;
ARGTYPE Argument1;
ARGTYPE Argument2;
ARGTYPE Argument3;
PREFIXINFO Prefix;
UInt32 Reserved_[40];
} DISASM, *PDISASM, *LPDISASM;
#pragma pack()
#define ESReg 1
#define DSReg 2
#define FSReg 3
#define GSReg 4
#define CSReg 5
#define SSReg 6
#define InvalidPrefix 4
#define SuperfluousPrefix 2
#define NotUsedPrefix 0
#define MandatoryPrefix 8
#define InUsePrefix 1
#define LowPosition 0
#define HighPosition 1
enum INSTRUCTION_TYPE
{
GENERAL_PURPOSE_INSTRUCTION = 0x10000,
FPU_INSTRUCTION = 0x20000,
MMX_INSTRUCTION = 0x40000,
SSE_INSTRUCTION = 0x80000,
SSE2_INSTRUCTION = 0x100000,
SSE3_INSTRUCTION = 0x200000,
SSSE3_INSTRUCTION = 0x400000,
SSE41_INSTRUCTION = 0x800000,
SSE42_INSTRUCTION = 0x1000000,
SYSTEM_INSTRUCTION = 0x2000000,
VM_INSTRUCTION = 0x4000000,
UNDOCUMENTED_INSTRUCTION = 0x8000000,
AMD_INSTRUCTION = 0x10000000,
ILLEGAL_INSTRUCTION = 0x20000000,
AES_INSTRUCTION = 0x40000000,
CLMUL_INSTRUCTION = (int)0x80000000,
DATA_TRANSFER = 0x1,
ARITHMETIC_INSTRUCTION,
LOGICAL_INSTRUCTION,
SHIFT_ROTATE,
BIT_UInt8,
CONTROL_TRANSFER,
STRING_INSTRUCTION,
InOutINSTRUCTION,
ENTER_LEAVE_INSTRUCTION,
FLAG_CONTROL_INSTRUCTION,
SEGMENT_REGISTER,
MISCELLANEOUS_INSTRUCTION,
COMPARISON_INSTRUCTION,
LOGARITHMIC_INSTRUCTION,
TRIGONOMETRIC_INSTRUCTION,
UNSUPPORTED_INSTRUCTION,
LOAD_CONSTANTS,
FPUCONTROL,
STATE_MANAGEMENT,
CONVERSION_INSTRUCTION,
SHUFFLE_UNPACK,
PACKED_SINGLE_PRECISION,
SIMD128bits,
SIMD64bits,
CACHEABILITY_CONTROL,
FP_INTEGER_CONVERSION,
SPECIALIZED_128bits,
SIMD_FP_PACKED,
SIMD_FP_HORIZONTAL ,
AGENT_SYNCHRONISATION,
PACKED_ALIGN_RIGHT ,
PACKED_SIGN,
PACKED_BLENDING_INSTRUCTION,
PACKED_TEST,
PACKED_MINMAX,
HORIZONTAL_SEARCH,
PACKED_EQUALITY,
STREAMING_LOAD,
INSERTION_EXTRACTION,
DOT_PRODUCT,
SAD_INSTRUCTION,
ACCELERATOR_INSTRUCTION, /* crc32, popcnt (sse4.2) */
ROUND_INSTRUCTION
};
enum EFLAGS_STATES
{
TE_ = 1,
MO_ = 2,
RE_ = 4,
SE_ = 8,
UN_ = 0x10,
PR_ = 0x20
};
enum BRANCH_TYPE
{
JO = 1,
JC = 2,
JE = 3,
JA = 4,
JS = 5,
JP = 6,
JL = 7,
JG = 8,
JB = 2, /* JC == JB */
JECXZ = 10,
JmpType = 11,
CallType = 12,
RetType = 13,
JNO = -1,
JNC = -2,
JNE = -3,
JNA = -4,
JNS = -5,
JNP = -6,
JNL = -7,
JNG = -8,
JNB = -2 /* JNC == JNB */
};
enum ARGUMENTS_TYPE
{
NO_ARGUMENT = 0x10000000,
REGISTER_TYPE = 0x20000000,
MEMORY_TYPE = 0x40000000,
CONSTANT_TYPE = (int)0x80000000,
MMX_REG = 0x10000,
GENERAL_REG = 0x20000,
FPU_REG = 0x40000,
SSE_REG = 0x80000,
CR_REG = 0x100000,
DR_REG = 0x200000,
SPECIAL_REG = 0x400000,
MEMORY_MANAGEMENT_REG = 0x800000,
SEGMENT_REG = 0x1000000,
RELATIVE_ = 0x4000000,
ABSOLUTE_ = 0x8000000,
READ = 0x1,
WRITE = 0x2,
REG0 = 0x1,
REG1 = 0x2,
REG2 = 0x4,
REG3 = 0x8,
REG4 = 0x10,
REG5 = 0x20,
REG6 = 0x40,
REG7 = 0x80,
REG8 = 0x100,
REG9 = 0x200,
REG10 = 0x400,
REG11 = 0x800,
REG12 = 0x1000,
REG13 = 0x2000,
REG14 = 0x4000,
REG15 = 0x8000
};
enum SPECIAL_INFO
{
UNKNOWN_OPCODE = -1,
OUT_OF_BLOCK = 0,
/* === mask = 0xff */
NoTabulation = 0x00000000,
Tabulation = 0x00000001,
/* === mask = 0xff00 */
MasmSyntax = 0x00000000,
GoAsmSyntax = 0x00000100,
NasmSyntax = 0x00000200,
ATSyntax = 0x00000400,
/* === mask = 0xff0000 */
PrefixedNumeral = 0x00010000,
SuffixedNumeral = 0x00000000,
/* === mask = 0xff000000 */
ShowSegmentRegs = 0x01000000
};
#ifdef __cplusplus
extern "C"
#endif
BEA_API int __bea_callspec__ Disasm (LPDISASM pDisAsm);
BEA_API const__ char* __bea_callspec__ BeaEngineVersion (void);
BEA_API const__ char* __bea_callspec__ BeaEngineRevision (void);
#endif
@@ -0,0 +1,250 @@
/**
* @file basic_types.h
* @author <igor.gutnik@gmail.com>
* @date Thu Dec 24 19:31:22 2009
*
* @brief Definitions of fixed-size integer types for various platforms
*
* This file is part of BeaEngine.
*
* BeaEngine is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* BeaEngine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with BeaEngine. If not, see <http://www.gnu.org/licenses/>. */
#ifndef __BEA_BASIC_TYPES_HPP__
#define __BEA_BASIC_TYPES_HPP__
#include <stddef.h>
#if defined(__GNUC__) || defined (__INTEL_COMPILER) || defined(__LCC__)
#include <stdint.h>
#endif
#if defined(_MSC_VER)
/*
* Windows/Visual C++
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef signed __int64 Int64;
typedef unsigned __int64 UInt64;
#if defined(_WIN64)
#define BEA_PTR_IS_64_BIT 1
typedef signed __int64 IntPtr;
typedef unsigned __int64 UIntPtr;
#else
typedef signed long IntPtr;
typedef size_t UIntPtr;
#endif
#define BEA_HAVE_INT64 1
#elif defined(__GNUC__) || defined(__LCC__)
/*
* Unix/GCC
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef intptr_t IntPtr;
typedef uintptr_t UIntPtr;
#if defined(__LP64__)
#define BEA_PTR_IS_64_BIT 1
#define BEA_LONG_IS_64_BIT 1
typedef signed long Int64;
typedef unsigned long UInt64;
#else
#if defined (__INTEL_COMPILER) || defined (__ICC) || defined (_ICC)
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
#else
typedef signed long long Int64;
typedef unsigned long long UInt64;
#endif
#endif
#define BEA_HAVE_INT64 1
#elif defined(__DECCXX)
/*
* Compaq C++
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef signed __int64 Int64;
typedef unsigned __int64 UInt64;
#if defined(__VMS)
#if defined(__32BITS)
typedef signed long IntPtr;
typedef unsigned long UIntPtr;
#else
typedef Int64 IntPtr;
typedef UInt64 UIntPtr;
#define BEA_PTR_IS_64_BIT 1
#endif
#else
typedef signed long IntPtr;
typedef unsigned long UIntPtr;
#define BEA_PTR_IS_64_BIT 1
#define BEA_LONG_IS_64_BIT 1
#endif
#define BEA_HAVE_INT64 1
#elif defined(__HP_aCC)
/*
* HP Ansi C++
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef signed long IntPtr;
typedef unsigned long UIntPtr;
#if defined(__LP64__)
#define BEA_PTR_IS_64_BIT 1
#define BEA_LONG_IS_64_BIT 1
typedef signed long Int64;
typedef unsigned long UInt64;
#else
typedef signed long long Int64;
typedef unsigned long long UInt64;
#endif
#define BEA_HAVE_INT64 1
#elif defined(__SUNPRO_CC) || defined(__SUNPRO_C)
/*
* SUN Forte C++
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef signed long IntPtr;
typedef unsigned long UIntPtr;
#if defined(__sparcv9)
#define BEA_PTR_IS_64_BIT 1
#define BEA_LONG_IS_64_BIT 1
typedef signed long Int64;
typedef unsigned long UInt64;
#else
typedef signed long long Int64;
typedef unsigned long long UInt64;
#endif
#define BEA_HAVE_INT64 1
#elif defined(__IBMCPP__)
/*
* IBM XL C++
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef signed long IntPtr;
typedef unsigned long UIntPtr;
#if defined(__64BIT__)
#define BEA_PTR_IS_64_BIT 1
#define BEA_LONG_IS_64_BIT 1
typedef signed long Int64;
typedef unsigned long UInt64;
#else
typedef signed long long Int64;
typedef unsigned long long UInt64;
#endif
#define BEA_HAVE_INT64 1
#elif defined(__BORLANDC__)
/*
* Borland C/C++
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef unsigned __int64 Int64;
typedef signed __int64 UInt64;
typedef unsigned long UIntPtr;
#define BEA_HAVE_INT64 1
#elif defined(__WATCOMC__)
/*
* Watcom C/C++
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef unsigned __int64 Int64;
typedef signed __int64 UInt64;
#define BEA_HAVE_INT64 1
typedef size_t UIntPtr;
#elif defined(__sgi)
/*
* MIPSpro C++
*/
typedef signed char Int8;
typedef unsigned char UInt8;
typedef signed short Int16;
typedef unsigned short UInt16;
typedef signed int Int32;
typedef unsigned int UInt32;
typedef signed long IntPtr;
typedef unsigned long UIntPtr;
#if _MIPS_SZLONG == 64
#define BEA_PTR_IS_64_BIT 1
#define BEA_LONG_IS_64_BIT 1
typedef signed long Int64;
typedef unsigned long UInt64;
#else
typedef signed long long Int64;
typedef unsigned long long UInt64;
#endif
#define BEA_HAVE_INT64 1
#endif
#if defined(_MSC_VER) || defined(__BORLANDC__)
#define W64LIT(x) x##ui64
#else
#define W64LIT(x) x##ULL
#endif
#ifndef C_STATIC_ASSERT
#define C_STATIC_ASSERT(tag_name, x) \
typedef int cache_static_assert_ ## tag_name[(x) * 2-1]
#endif
C_STATIC_ASSERT(sizeof_Int8 , (sizeof(Int8) == 1));
C_STATIC_ASSERT(sizeof_UInt8, (sizeof(UInt8) == 1));
C_STATIC_ASSERT(sizeof_Int16 , (sizeof(Int16) == 2));
C_STATIC_ASSERT(sizeof_UInt16, (sizeof(UInt16) == 2));
C_STATIC_ASSERT(sizeof_Int32 , (sizeof(Int32) == 4));
C_STATIC_ASSERT(sizeof_UInt32, (sizeof(UInt32) == 4));
C_STATIC_ASSERT(sizeof_Int64 , (sizeof(Int64) == 8));
C_STATIC_ASSERT(sizeof_UInt64, (sizeof(UInt64) == 8));
#endif
@@ -0,0 +1,173 @@
/**
* @file export.h
* @author igor.gutnik@gmail.com
* @date Mon Sep 22 09:28:54 2008
*
* @brief This file sets things up for C dynamic library function definitions and
* static inlined functions
*
* This file is part of BeaEngine.
*
* BeaEngine is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* BeaEngine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with BeaEngine. If not, see <http://www.gnu.org/licenses/>. */
#ifndef __BEA_EXPORT_H__
#define __BEA_EXPORT_H__
/* Set up for C function definitions, even when using C++ */
#ifdef __cplusplus
#define CPP_VISIBLE_BEGIN extern "C" {
#define CPP_VISIBLE_END }
#else
#define CPP_VISIBLE_BEGIN
#define CPP_VISIBLE_END
#endif
#if defined(_MSC_VER)
#pragma warning( disable: 4251 )
#endif
/* Some compilers use a special export keyword */
#ifndef bea__api_export__
# if defined(__BEOS__)
# if defined(__GNUC__)
# define bea__api_export__ __declspec(dllexport)
# else
# define bea__api_export__ __declspec(export)
# endif
# elif defined(_WIN32) || defined(_WIN64)
# ifdef __BORLANDC__
# define bea__api_export__ __declspec(dllexport)
# define bea__api_import__ __declspec(dllimport)
# elif defined(__WATCOMC__)
# define bea__api_export__ __declspec(dllexport)
# define bea__api_import__
# else
# define bea__api_export__ __declspec(dllexport)
# define bea__api_import__ __declspec(dllimport)
# endif
# elif defined(__OS2__)
# ifdef __WATCOMC__
# define bea__api_export__ __declspec(dllexport)
# define bea__api_import__
# else
# define bea__api_export__
# define bea__api_import__
# endif
# else
# if defined(_WIN32) && defined(__GNUC__) && __GNUC__ >= 4
# define bea__api_export__ __attribubea__ ((visibility("default")))
# define bea__api_import__ __attribubea__ ((visibility("default")))
# else
# define bea__api_export__
# define bea__api_import__
# endif
# endif
#endif
/* Use C calling convention by default*/
#ifndef __bea_callspec__
#if defined(BEA_USE_STDCALL)
#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(_WIN64)
#if defined(__BORLANDC__) || defined(__WATCOMC__) || defined(_MSC_VER) || defined(__MINGW32__) || defined(__POCC__)
#define __bea_callspec__ __stdcall
#else
#define __bea_callspec__
#endif
#else
#ifdef __OS2__
#define __bea_callspec__ _System
#else
#define __bea_callspec__
#endif
#endif
#else
#define __bea_callspec__
#endif
#endif
#ifdef __SYMBIAN32__
# ifndef EKA2
# undef bea__api_export__
# undef bea__api_import__
# define bea__api_export__
# define bea__api_import__
# elif !defined(__WINS__)
# undef bea__api_export__
# undef bea__api_import__
# define bea__api_export__ __declspec(dllexport)
# define bea__api_import__ __declspec(dllexport)
# endif /* !EKA2 */
#endif /* __SYMBIAN32__ */
#if defined(__GNUC__) && (__GNUC__ > 2)
#define BEA_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1))
#define BEA_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0))
#else
#define BEA_EXPECT_CONDITIONAL(c) (c)
#define BEA_UNEXPECT_CONDITIONAL(c) (c)
#endif
/* Set up compiler-specific options for inlining functions */
#ifndef BEA_HAS_INLINE
#if defined(__GNUC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C)
#define BEA_HAS_INLINE
#else
/* Add any special compiler-specific cases here */
#if defined(_MSC_VER) || defined(__BORLANDC__) || \
defined(__DMC__) || defined(__SC__) || \
defined(__WATCOMC__) || defined(__LCC__) || \
defined(__DECC) || defined(__EABI__)
#ifndef __inline__
#define __inline__ __inline
#endif
#define BEA_HAS_INLINE
#else
#if !defined(__MRC__) && !defined(_SGI_SOURCE)
#ifndef __inline__
#define __inline__ inline
#endif
#define BEA_HAS_INLINE
#endif /* Not a funky compiler */
#endif /* Visual C++ */
#endif /* GNU C */
#endif /* CACHE_HAS_INLINE */
/* If inlining isn't supported, remove "__inline__", turning static
inlined functions into static functions (resulting in code bloat
in all files which include the offending header files)
*/
#ifndef BEA_HAS_INLINE
#define __inline__
#endif
/* fix a bug with gcc under windows */
#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(_WIN64)
#if defined(__MINGW32__)
#define const__
#else
#define const__ const
#endif
#else
#define const__ const
#endif
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,42 @@
// diacreate.h - creation helper functions for DIA initialization
//-----------------------------------------------------------------
//
// Copyright Microsoft Corporation. All Rights Reserved.
//
//---------------------------------------------------------------
#ifndef _DIACREATE_H_
#define _DIACREATE_H_
//
// Create a dia data source object from the dia dll (by dll name - does not access the registry).
//
HRESULT STDMETHODCALLTYPE NoRegCoCreate( const __wchar_t *dllName,
REFCLSID rclsid,
REFIID riid,
void **ppv);
#ifndef _NATIVE_WCHAR_T_DEFINED
#ifdef __cplusplus
HRESULT STDMETHODCALLTYPE NoRegCoCreate( const wchar_t *dllName,
REFCLSID rclsid,
REFIID riid,
void **ppv)
{
return NoRegCoCreate( (const __wchar_t *)dllName, rclsid, riid, ppv );
}
#endif
#endif
//
// Create a dia data source object from the dia dll (looks up the class id in the registry).
//
HRESULT STDMETHODCALLTYPE NoOleCoCreate( REFCLSID rclsid,
REFIID riid,
void **ppv);
#endif
@@ -0,0 +1,334 @@
#pragma once
#include <string>
#define VERSIONHELPERAPI inline bool
#define _WIN32_WINNT_NT4 0x0400
#define _WIN32_WINNT_WIN2K 0x0500
#define _WIN32_WINNT_WINXP 0x0501
#define _WIN32_WINNT_WS03 0x0502
#define _WIN32_WINNT_WIN6 0x0600
#define _WIN32_WINNT_VISTA 0x0600
#define _WIN32_WINNT_WS08 0x0600
#define _WIN32_WINNT_LONGHORN 0x0600
#define _WIN32_WINNT_WIN7 0x0601
#define _WIN32_WINNT_WIN8 0x0602
#define _WIN32_WINNT_WINBLUE 0x0603
#define _WIN32_WINNT_WIN10 0x0A00
using fnRtlGetVersion = NTSTATUS( NTAPI* )(PRTL_OSVERSIONINFOEXW lpVersionInformation);
enum eBuildThreshold
{
Build_RS0 = 10586,
Build_RS1 = 14393,
Build_RS2 = 15063,
Build_RS3 = 16299,
Build_RS4 = 17134,
Build_RS5 = 17763,
Build_19H1 = 18362,
Build_19H2 = 18363,
Build_20H1 = 19041,
Build_21H2 = 22000,
Build_22H2 = 22621,
Build_RS_MAX = 99999,
};
enum eVerShort
{
WinUnsupported, // Unsupported OS
WinXP, // Windows XP
Win7, // Windows 7
Win8, // Windows 8
Win8Point1, // Windows 8.1
Win10, // Windows 10
Win10_RS1, // Windows 10 Anniversary update
Win10_RS2, // Windows 10 Creators update
Win10_RS3, // Windows 10 Fall Creators update
Win10_RS4, // Windows 10 Spring Creators update
Win10_RS5, // Windows 10 October 2018 update
Win10_19H1, // Windows 10 May 2019 update
Win10_19H2, // Windows 10 November 2019 update
Win10_20H1, // Windows 10 April 2020 update
Win11_21H2, // Windows 11
Win11_22H2 // Windows 11 September 2022 update
};
struct WinVersion
{
eVerShort ver = WinUnsupported;
uint32_t revision = 0;
RTL_OSVERSIONINFOEXW native = { };
};
BLACKBONE_API inline WinVersion& WinVer()
{
static WinVersion g_WinVer;
return g_WinVer;
}
BLACKBONE_API inline uint32_t GetRevision()
{
HKEY hKey = NULL;
if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &hKey ) == 0)
{
wchar_t data[MAX_PATH] = {};
DWORD dataSize = sizeof( data );
DWORD type = REG_SZ;
if (RegQueryValueExW( hKey, L"BuildLabEx", nullptr, &type, reinterpret_cast<LPBYTE>(data), &dataSize ) == 0)
{
std::wstring buildStr = data;
size_t first = buildStr.find( L'.' );
size_t second = buildStr.find( L'.', first + 1 );
if (second > first && first != buildStr.npos)
{
RegCloseKey( hKey );
return std::wcstol( buildStr.substr( first + 1, second - first - 1 ).c_str(), nullptr, 10 );
}
}
RegCloseKey( hKey );
}
return 0;
}
BLACKBONE_API inline void InitVersion()
{
auto& g_WinVer = WinVer();
g_WinVer.native.dwOSVersionInfoSize = sizeof( g_WinVer.native );
auto RtlGetVersion = (fnRtlGetVersion)GetProcAddress( GetModuleHandleW( L"ntdll.dll" ), "RtlGetVersion" );
if (RtlGetVersion)
{
RtlGetVersion( &g_WinVer.native );
}
if (g_WinVer.native.dwMajorVersion != 0)
{
auto fullver = (g_WinVer.native.dwMajorVersion << 8) | g_WinVer.native.dwMinorVersion;
switch (fullver)
{
case _WIN32_WINNT_WIN10:
if (g_WinVer.native.dwBuildNumber >= Build_22H2)
g_WinVer.ver = Win11_22H2;
else if (g_WinVer.native.dwBuildNumber >= Build_21H2)
g_WinVer.ver = Win11_21H2;
else if (g_WinVer.native.dwBuildNumber >= Build_20H1)
g_WinVer.ver = Win10_20H1;
else if (g_WinVer.native.dwBuildNumber >= Build_19H2)
g_WinVer.ver = Win10_19H2;
else if (g_WinVer.native.dwBuildNumber >= Build_19H1)
g_WinVer.ver = Win10_19H1;
else if (g_WinVer.native.dwBuildNumber >= Build_RS5)
g_WinVer.ver = Win10_RS5;
else if (g_WinVer.native.dwBuildNumber >= Build_RS4)
g_WinVer.ver = Win10_RS4;
else if (g_WinVer.native.dwBuildNumber >= Build_RS3)
g_WinVer.ver = Win10_RS3;
else if (g_WinVer.native.dwBuildNumber >= Build_RS2)
g_WinVer.ver = Win10_RS2;
else if (g_WinVer.native.dwBuildNumber >= Build_RS1)
g_WinVer.ver = Win10_RS1;
else if (g_WinVer.native.dwBuildNumber >= Build_RS0)
g_WinVer.ver = Win10;
break;
case _WIN32_WINNT_WINBLUE:
g_WinVer.ver = Win8Point1;
break;
case _WIN32_WINNT_WIN8:
g_WinVer.ver = Win8;
break;
case _WIN32_WINNT_WIN7:
g_WinVer.ver = Win7;
break;
case _WIN32_WINNT_WINXP:
g_WinVer.ver = WinXP;
break;
default:
g_WinVer.ver = WinUnsupported;
}
}
g_WinVer.revision = GetRevision();
}
VERSIONHELPERAPI
IsWindowsVersionOrGreater( WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor, DWORD dwBuild )
{
auto& g_WinVer = WinVer();
if (g_WinVer.native.dwMajorVersion != 0)
{
if (g_WinVer.native.dwMajorVersion > wMajorVersion)
return true;
else if (g_WinVer.native.dwMajorVersion < wMajorVersion)
return false;
if (g_WinVer.native.dwMinorVersion > wMinorVersion)
return true;
else if (g_WinVer.native.dwMinorVersion < wMinorVersion)
return false;
if (g_WinVer.native.wServicePackMajor > wServicePackMajor)
return true;
else if (g_WinVer.native.wServicePackMajor < wServicePackMajor)
return false;
if (g_WinVer.native.dwBuildNumber >= dwBuild)
return true;
}
return false;
}
BLACKBONE_API
VERSIONHELPERAPI
IsWindowsXPOrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WINXP ), LOBYTE( _WIN32_WINNT_WINXP ), 0, 0 );
}
VERSIONHELPERAPI
IsWindowsXPSP1OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WINXP ), LOBYTE( _WIN32_WINNT_WINXP ), 1, 0 );
}
VERSIONHELPERAPI
IsWindowsXPSP2OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WINXP ), LOBYTE( _WIN32_WINNT_WINXP ), 2, 0 );
}
VERSIONHELPERAPI
IsWindowsXPSP3OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WINXP ), LOBYTE( _WIN32_WINNT_WINXP ), 3, 0 );
}
VERSIONHELPERAPI
IsWindowsVistaOrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_VISTA ), LOBYTE( _WIN32_WINNT_VISTA ), 0, 0 );
}
VERSIONHELPERAPI
IsWindowsVistaSP1OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_VISTA ), LOBYTE( _WIN32_WINNT_VISTA ), 1, 0 );
}
VERSIONHELPERAPI
IsWindowsVistaSP2OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_VISTA ), LOBYTE( _WIN32_WINNT_VISTA ), 2, 0 );
}
VERSIONHELPERAPI
IsWindows7OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN7 ), LOBYTE( _WIN32_WINNT_WIN7 ), 0, 0 );
}
VERSIONHELPERAPI
IsWindows7SP1OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN7 ), LOBYTE( _WIN32_WINNT_WIN7 ), 1, 0 );
}
VERSIONHELPERAPI
IsWindows8OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN8 ), LOBYTE( _WIN32_WINNT_WIN8 ), 0, 0 );
}
VERSIONHELPERAPI
IsWindows8Point1OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WINBLUE ), LOBYTE( _WIN32_WINNT_WINBLUE ), 0, 0 );
}
VERSIONHELPERAPI
IsWindows10OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, 0 );
}
VERSIONHELPERAPI
IsWindows10RS1OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_RS1 );
}
VERSIONHELPERAPI
IsWindows10RS2OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_RS2 );
}
VERSIONHELPERAPI
IsWindows10RS3OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_RS3 );
}
VERSIONHELPERAPI
IsWindows10RS4OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_RS4 );
}
VERSIONHELPERAPI
IsWindows10RS5OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_RS5 );
}
VERSIONHELPERAPI
IsWindows1019H1OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_19H1 );
}
VERSIONHELPERAPI
IsWindows1019H2OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_19H2 );
}
VERSIONHELPERAPI
IsWindows1020H1OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_20H1 );
}
VERSIONHELPERAPI
IsWindows1121H2OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_21H2);
}
VERSIONHELPERAPI
IsWindows1122H2OrGreater()
{
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_22H2 );
}
VERSIONHELPERAPI
IsWindowsServer()
{
OSVERSIONINFOEXW osvi = { sizeof( osvi ), 0, 0, 0, 0, { 0 }, 0, 0, 0, VER_NT_WORKSTATION };
DWORDLONG const dwlConditionMask = VerSetConditionMask( 0, VER_PRODUCT_TYPE, VER_EQUAL );
return !VerifyVersionInfoW( &osvi, VER_PRODUCT_TYPE, dwlConditionMask );
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,291 @@
//
// Copyright (C) Microsoft. All rights reserved.
//
/* this ALWAYS GENERATED file contains the definitions for the interfaces */
/* File created by MIDL compiler version 6.00.0366 */
//@@MIDL_FILE_HEADING( )
#pragma warning( disable: 4049 ) /* more than 64k source lines */
/* verify that the <rpcndr.h> version is high enough to compile this file*/
#ifndef __REQUIRED_RPCNDR_H_VERSION__
#define __REQUIRED_RPCNDR_H_VERSION__ 475
#endif
#include "rpc.h"
#include "rpcndr.h"
#ifndef __RPCNDR_H_VERSION__
#error this stub requires an updated version of <rpcndr.h>
#endif // __RPCNDR_H_VERSION__
#ifndef COM_NO_WINDOWS_H
#include "windows.h"
#include "ole2.h"
#endif /*COM_NO_WINDOWS_H*/
#ifndef __gchost_h__
#define __gchost_h__
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif
/* Forward Declarations */
#ifndef __IGCHost_FWD_DEFINED__
#define __IGCHost_FWD_DEFINED__
typedef interface IGCHost IGCHost;
#endif /* __IGCHost_FWD_DEFINED__ */
/* header files for imported files */
#include "unknwn.h"
#ifdef __cplusplus
extern "C"{
#endif
void * __RPC_USER MIDL_user_allocate(size_t);
void __RPC_USER MIDL_user_free( void * );
/* interface __MIDL_itf_gchost_0000 */
/* [local] */
typedef /* [public] */
enum __MIDL___MIDL_itf_gchost_0000_0001
{ COR_GC_COUNTS = 0x1,
COR_GC_MEMORYUSAGE = 0x2
} COR_GC_STAT_TYPES;
typedef /* [public] */
enum __MIDL___MIDL_itf_gchost_0000_0002
{ COR_GC_THREAD_HAS_PROMOTED_BYTES = 0x1
} COR_GC_THREAD_STATS_TYPES;
typedef struct _COR_GC_STATS
{
ULONG Flags;
SIZE_T ExplicitGCCount;
SIZE_T GenCollectionsTaken[ 3 ];
SIZE_T CommittedKBytes;
SIZE_T ReservedKBytes;
SIZE_T Gen0HeapSizeKBytes;
SIZE_T Gen1HeapSizeKBytes;
SIZE_T Gen2HeapSizeKBytes;
SIZE_T LargeObjectHeapSizeKBytes;
SIZE_T KBytesPromotedFromGen0;
SIZE_T KBytesPromotedFromGen1;
} COR_GC_STATS;
typedef struct _COR_GC_THREAD_STATS
{
ULONGLONG PerThreadAllocation;
ULONG Flags;
} COR_GC_THREAD_STATS;
extern RPC_IF_HANDLE __MIDL_itf_gchost_0000_v0_0_c_ifspec;
extern RPC_IF_HANDLE __MIDL_itf_gchost_0000_v0_0_s_ifspec;
#ifndef __IGCHost_INTERFACE_DEFINED__
#define __IGCHost_INTERFACE_DEFINED__
/* interface IGCHost */
/* [local][unique][uuid][object] */
EXTERN_C const IID IID_IGCHost;
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("FAC34F6E-0DCD-47b5-8021-531BC5ECCA63")
IGCHost : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimits(
/* [in] */ DWORD SegmentSize,
/* [in] */ DWORD MaxGen0Size) = 0;
virtual HRESULT STDMETHODCALLTYPE Collect(
/* [in] */ LONG Generation) = 0;
virtual HRESULT STDMETHODCALLTYPE GetStats(
/* [out][in] */ COR_GC_STATS *pStats) = 0;
virtual HRESULT STDMETHODCALLTYPE GetThreadStats(
/* [in] */ DWORD *pFiberCookie,
/* [out][in] */ COR_GC_THREAD_STATS *pStats) = 0;
virtual HRESULT STDMETHODCALLTYPE SetVirtualMemLimit(
/* [in] */ SIZE_T sztMaxVirtualMemMB) = 0;
};
#else /* C style interface */
typedef struct IGCHostVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IGCHost * This,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IGCHost * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IGCHost * This);
HRESULT ( STDMETHODCALLTYPE *SetGCStartupLimits )(
IGCHost * This,
/* [in] */ DWORD SegmentSize,
/* [in] */ DWORD MaxGen0Size);
HRESULT ( STDMETHODCALLTYPE *Collect )(
IGCHost * This,
/* [in] */ LONG Generation);
HRESULT ( STDMETHODCALLTYPE *GetStats )(
IGCHost * This,
/* [out][in] */ COR_GC_STATS *pStats);
HRESULT ( STDMETHODCALLTYPE *GetThreadStats )(
IGCHost * This,
/* [in] */ DWORD *pFiberCookie,
/* [out][in] */ COR_GC_THREAD_STATS *pStats);
HRESULT ( STDMETHODCALLTYPE *SetVirtualMemLimit )(
IGCHost * This,
/* [in] */ SIZE_T sztMaxVirtualMemMB);
END_INTERFACE
} IGCHostVtbl;
interface IGCHost
{
CONST_VTBL struct IGCHostVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define IGCHost_QueryInterface(This,riid,ppvObject) \
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
#define IGCHost_AddRef(This) \
(This)->lpVtbl -> AddRef(This)
#define IGCHost_Release(This) \
(This)->lpVtbl -> Release(This)
#define IGCHost_SetGCStartupLimits(This,SegmentSize,MaxGen0Size) \
(This)->lpVtbl -> SetGCStartupLimits(This,SegmentSize,MaxGen0Size)
#define IGCHost_Collect(This,Generation) \
(This)->lpVtbl -> Collect(This,Generation)
#define IGCHost_GetStats(This,pStats) \
(This)->lpVtbl -> GetStats(This,pStats)
#define IGCHost_GetThreadStats(This,pFiberCookie,pStats) \
(This)->lpVtbl -> GetThreadStats(This,pFiberCookie,pStats)
#define IGCHost_SetVirtualMemLimit(This,sztMaxVirtualMemMB) \
(This)->lpVtbl -> SetVirtualMemLimit(This,sztMaxVirtualMemMB)
#endif /* COBJMACROS */
#endif /* C style interface */
HRESULT STDMETHODCALLTYPE IGCHost_SetGCStartupLimits_Proxy(
IGCHost * This,
/* [in] */ DWORD SegmentSize,
/* [in] */ DWORD MaxGen0Size);
void __RPC_STUB IGCHost_SetGCStartupLimits_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
HRESULT STDMETHODCALLTYPE IGCHost_Collect_Proxy(
IGCHost * This,
/* [in] */ LONG Generation);
void __RPC_STUB IGCHost_Collect_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
HRESULT STDMETHODCALLTYPE IGCHost_GetStats_Proxy(
IGCHost * This,
/* [out][in] */ COR_GC_STATS *pStats);
void __RPC_STUB IGCHost_GetStats_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
HRESULT STDMETHODCALLTYPE IGCHost_GetThreadStats_Proxy(
IGCHost * This,
/* [in] */ DWORD *pFiberCookie,
/* [out][in] */ COR_GC_THREAD_STATS *pStats);
void __RPC_STUB IGCHost_GetThreadStats_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
HRESULT STDMETHODCALLTYPE IGCHost_SetVirtualMemLimit_Proxy(
IGCHost * This,
/* [in] */ SIZE_T sztMaxVirtualMemMB);
void __RPC_STUB IGCHost_SetVirtualMemLimit_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
#endif /* __IGCHost_INTERFACE_DEFINED__ */
/* Additional Prototypes for ALL interfaces */
/* end of Additional Prototypes */
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,386 @@
//
// Copyright (C) Microsoft. All rights reserved.
//
/* this ALWAYS GENERATED file contains the definitions for the interfaces */
/* File created by MIDL compiler version 6.00.0366 */
//@@MIDL_FILE_HEADING( )
#pragma warning( disable: 4049 ) /* more than 64k source lines */
/* verify that the <rpcndr.h> version is high enough to compile this file*/
#ifndef __REQUIRED_RPCNDR_H_VERSION__
#define __REQUIRED_RPCNDR_H_VERSION__ 475
#endif
#include "rpc.h"
#include "rpcndr.h"
#ifndef __RPCNDR_H_VERSION__
#error this stub requires an updated version of <rpcndr.h>
#endif // __RPCNDR_H_VERSION__
#ifndef COM_NO_WINDOWS_H
#include "windows.h"
#include "ole2.h"
#endif /*COM_NO_WINDOWS_H*/
#ifndef __ivalidator_h__
#define __ivalidator_h__
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif
/* Forward Declarations */
#ifndef __IValidator_FWD_DEFINED__
#define __IValidator_FWD_DEFINED__
typedef interface IValidator IValidator;
#endif /* __IValidator_FWD_DEFINED__ */
#ifndef __ICLRValidator_FWD_DEFINED__
#define __ICLRValidator_FWD_DEFINED__
typedef interface ICLRValidator ICLRValidator;
#endif /* __ICLRValidator_FWD_DEFINED__ */
/* header files for imported files */
#include "ivehandler.h"
#ifdef __cplusplus
extern "C"{
#endif
void * __RPC_USER MIDL_user_allocate(size_t);
void __RPC_USER MIDL_user_free( void * );
/* interface __MIDL_itf_ivalidator_0000 */
/* [local] */
enum ValidatorFlags
{ VALIDATOR_EXTRA_VERBOSE = 0x1,
VALIDATOR_SHOW_SOURCE_LINES = 0x2,
VALIDATOR_CHECK_ILONLY = 0x4,
VALIDATOR_CHECK_PEFORMAT_ONLY = 0x8,
VALIDATOR_NOCHECK_PEFORMAT = 0x10
} ;
extern RPC_IF_HANDLE __MIDL_itf_ivalidator_0000_v0_0_c_ifspec;
extern RPC_IF_HANDLE __MIDL_itf_ivalidator_0000_v0_0_s_ifspec;
#ifndef __IValidator_INTERFACE_DEFINED__
#define __IValidator_INTERFACE_DEFINED__
/* interface IValidator */
/* [unique][uuid][object] */
EXTERN_C const IID IID_IValidator;
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("63DF8730-DC81-4062-84A2-1FF943F59FAC")
IValidator : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE Validate(
/* [in] */ IVEHandler *veh,
/* [in] */ IUnknown *pAppDomain,
/* [in] */ unsigned long ulFlags,
/* [in] */ unsigned long ulMaxError,
/* [in] */ unsigned long token,
/* [in] */ LPWSTR fileName,
/* [size_is][in] */ BYTE *pe,
/* [in] */ unsigned long ulSize) = 0;
virtual HRESULT STDMETHODCALLTYPE FormatEventInfo(
/* [in] */ HRESULT hVECode,
/* [in] */ VEContext Context,
/* [out][in] */ LPWSTR msg,
/* [in] */ unsigned long ulMaxLength,
/* [in] */ SAFEARRAY * psa) = 0;
};
#else /* C style interface */
typedef struct IValidatorVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IValidator * This,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IValidator * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IValidator * This);
HRESULT ( STDMETHODCALLTYPE *Validate )(
IValidator * This,
/* [in] */ IVEHandler *veh,
/* [in] */ IUnknown *pAppDomain,
/* [in] */ unsigned long ulFlags,
/* [in] */ unsigned long ulMaxError,
/* [in] */ unsigned long token,
/* [in] */ LPWSTR fileName,
/* [size_is][in] */ BYTE *pe,
/* [in] */ unsigned long ulSize);
HRESULT ( STDMETHODCALLTYPE *FormatEventInfo )(
IValidator * This,
/* [in] */ HRESULT hVECode,
/* [in] */ VEContext Context,
/* [out][in] */ LPWSTR msg,
/* [in] */ unsigned long ulMaxLength,
/* [in] */ SAFEARRAY * psa);
END_INTERFACE
} IValidatorVtbl;
interface IValidator
{
CONST_VTBL struct IValidatorVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define IValidator_QueryInterface(This,riid,ppvObject) \
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
#define IValidator_AddRef(This) \
(This)->lpVtbl -> AddRef(This)
#define IValidator_Release(This) \
(This)->lpVtbl -> Release(This)
#define IValidator_Validate(This,veh,pAppDomain,ulFlags,ulMaxError,token,fileName,pe,ulSize) \
(This)->lpVtbl -> Validate(This,veh,pAppDomain,ulFlags,ulMaxError,token,fileName,pe,ulSize)
#define IValidator_FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) \
(This)->lpVtbl -> FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa)
#endif /* COBJMACROS */
#endif /* C style interface */
HRESULT STDMETHODCALLTYPE IValidator_Validate_Proxy(
IValidator * This,
/* [in] */ IVEHandler *veh,
/* [in] */ IUnknown *pAppDomain,
/* [in] */ unsigned long ulFlags,
/* [in] */ unsigned long ulMaxError,
/* [in] */ unsigned long token,
/* [in] */ LPWSTR fileName,
/* [size_is][in] */ BYTE *pe,
/* [in] */ unsigned long ulSize);
void __RPC_STUB IValidator_Validate_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
HRESULT STDMETHODCALLTYPE IValidator_FormatEventInfo_Proxy(
IValidator * This,
/* [in] */ HRESULT hVECode,
/* [in] */ VEContext Context,
/* [out][in] */ LPWSTR msg,
/* [in] */ unsigned long ulMaxLength,
/* [in] */ SAFEARRAY * psa);
void __RPC_STUB IValidator_FormatEventInfo_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
#endif /* __IValidator_INTERFACE_DEFINED__ */
#ifndef __ICLRValidator_INTERFACE_DEFINED__
#define __ICLRValidator_INTERFACE_DEFINED__
/* interface ICLRValidator */
/* [unique][uuid][object] */
EXTERN_C const IID IID_ICLRValidator;
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("63DF8730-DC81-4062-84A2-1FF943F59FDD")
ICLRValidator : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE Validate(
/* [in] */ IVEHandler *veh,
/* [in] */ unsigned long ulAppDomainId,
/* [in] */ unsigned long ulFlags,
/* [in] */ unsigned long ulMaxError,
/* [in] */ unsigned long token,
/* [in] */ LPWSTR fileName,
/* [size_is][in] */ BYTE *pe,
/* [in] */ unsigned long ulSize) = 0;
virtual HRESULT STDMETHODCALLTYPE FormatEventInfo(
/* [in] */ HRESULT hVECode,
/* [in] */ VEContext Context,
/* [out][in] */ LPWSTR msg,
/* [in] */ unsigned long ulMaxLength,
/* [in] */ SAFEARRAY * psa) = 0;
};
#else /* C style interface */
typedef struct ICLRValidatorVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
ICLRValidator * This,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
ICLRValidator * This);
ULONG ( STDMETHODCALLTYPE *Release )(
ICLRValidator * This);
HRESULT ( STDMETHODCALLTYPE *Validate )(
ICLRValidator * This,
/* [in] */ IVEHandler *veh,
/* [in] */ unsigned long ulAppDomainId,
/* [in] */ unsigned long ulFlags,
/* [in] */ unsigned long ulMaxError,
/* [in] */ unsigned long token,
/* [in] */ LPWSTR fileName,
/* [size_is][in] */ BYTE *pe,
/* [in] */ unsigned long ulSize);
HRESULT ( STDMETHODCALLTYPE *FormatEventInfo )(
ICLRValidator * This,
/* [in] */ HRESULT hVECode,
/* [in] */ VEContext Context,
/* [out][in] */ LPWSTR msg,
/* [in] */ unsigned long ulMaxLength,
/* [in] */ SAFEARRAY * psa);
END_INTERFACE
} ICLRValidatorVtbl;
interface ICLRValidator
{
CONST_VTBL struct ICLRValidatorVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define ICLRValidator_QueryInterface(This,riid,ppvObject) \
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
#define ICLRValidator_AddRef(This) \
(This)->lpVtbl -> AddRef(This)
#define ICLRValidator_Release(This) \
(This)->lpVtbl -> Release(This)
#define ICLRValidator_Validate(This,veh,ulAppDomainId,ulFlags,ulMaxError,token,fileName,pe,ulSize) \
(This)->lpVtbl -> Validate(This,veh,ulAppDomainId,ulFlags,ulMaxError,token,fileName,pe,ulSize)
#define ICLRValidator_FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) \
(This)->lpVtbl -> FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa)
#endif /* COBJMACROS */
#endif /* C style interface */
HRESULT STDMETHODCALLTYPE ICLRValidator_Validate_Proxy(
ICLRValidator * This,
/* [in] */ IVEHandler *veh,
/* [in] */ unsigned long ulAppDomainId,
/* [in] */ unsigned long ulFlags,
/* [in] */ unsigned long ulMaxError,
/* [in] */ unsigned long token,
/* [in] */ LPWSTR fileName,
/* [size_is][in] */ BYTE *pe,
/* [in] */ unsigned long ulSize);
void __RPC_STUB ICLRValidator_Validate_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
HRESULT STDMETHODCALLTYPE ICLRValidator_FormatEventInfo_Proxy(
ICLRValidator * This,
/* [in] */ HRESULT hVECode,
/* [in] */ VEContext Context,
/* [out][in] */ LPWSTR msg,
/* [in] */ unsigned long ulMaxLength,
/* [in] */ SAFEARRAY * psa);
void __RPC_STUB ICLRValidator_FormatEventInfo_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
#endif /* __ICLRValidator_INTERFACE_DEFINED__ */
/* Additional Prototypes for ALL interfaces */
unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * );
unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * );
unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * );
void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * );
/* end of Additional Prototypes */
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,244 @@
//
// Copyright (C) Microsoft. All rights reserved.
//
/* this ALWAYS GENERATED file contains the definitions for the interfaces */
/* File created by MIDL compiler version 6.00.0366 */
//@@MIDL_FILE_HEADING( )
#pragma warning( disable: 4049 ) /* more than 64k source lines */
/* verify that the <rpcndr.h> version is high enough to compile this file*/
#ifndef __REQUIRED_RPCNDR_H_VERSION__
#define __REQUIRED_RPCNDR_H_VERSION__ 475
#endif
#include "rpc.h"
#include "rpcndr.h"
#ifndef __RPCNDR_H_VERSION__
#error this stub requires an updated version of <rpcndr.h>
#endif // __RPCNDR_H_VERSION__
#ifndef COM_NO_WINDOWS_H
#include "windows.h"
#include "ole2.h"
#endif /*COM_NO_WINDOWS_H*/
#ifndef __ivehandler_h__
#define __ivehandler_h__
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif
/* Forward Declarations */
#ifndef __VEHandlerClass_FWD_DEFINED__
#define __VEHandlerClass_FWD_DEFINED__
#ifdef __cplusplus
typedef class VEHandlerClass VEHandlerClass;
#else
typedef struct VEHandlerClass VEHandlerClass;
#endif /* __cplusplus */
#endif /* __VEHandlerClass_FWD_DEFINED__ */
#ifndef __IVEHandler_FWD_DEFINED__
#define __IVEHandler_FWD_DEFINED__
typedef interface IVEHandler IVEHandler;
#endif /* __IVEHandler_FWD_DEFINED__ */
/* header files for imported files */
#include "unknwn.h"
#ifdef __cplusplus
extern "C"{
#endif
void * __RPC_USER MIDL_user_allocate(size_t);
void __RPC_USER MIDL_user_free( void * );
/* interface __MIDL_itf_ivehandler_0000 */
/* [local] */
typedef struct tag_VerError
{
unsigned long flags;
unsigned long opcode;
unsigned long uOffset;
unsigned long Token;
unsigned long item1_flags;
int *item1_data;
unsigned long item2_flags;
int *item2_data;
} _VerError;
typedef _VerError VEContext;
extern RPC_IF_HANDLE __MIDL_itf_ivehandler_0000_v0_0_c_ifspec;
extern RPC_IF_HANDLE __MIDL_itf_ivehandler_0000_v0_0_s_ifspec;
#ifndef __VEHandlerLib_LIBRARY_DEFINED__
#define __VEHandlerLib_LIBRARY_DEFINED__
/* library VEHandlerLib */
/* [helpstring][version][uuid] */
EXTERN_C const IID LIBID_VEHandlerLib;
EXTERN_C const CLSID CLSID_VEHandlerClass;
#ifdef __cplusplus
class DECLSPEC_UUID("856CA1B1-7DAB-11d3-ACEC-00C04F86C309")
VEHandlerClass;
#endif
#endif /* __VEHandlerLib_LIBRARY_DEFINED__ */
#ifndef __IVEHandler_INTERFACE_DEFINED__
#define __IVEHandler_INTERFACE_DEFINED__
/* interface IVEHandler */
/* [unique][uuid][object] */
EXTERN_C const IID IID_IVEHandler;
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("856CA1B2-7DAB-11d3-ACEC-00C04F86C309")
IVEHandler : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE VEHandler(
/* [in] */ HRESULT VECode,
/* [in] */ VEContext Context,
/* [in] */ SAFEARRAY * psa) = 0;
virtual HRESULT STDMETHODCALLTYPE SetReporterFtn(
/* [in] */ __int64 lFnPtr) = 0;
};
#else /* C style interface */
typedef struct IVEHandlerVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
IVEHandler * This,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
IVEHandler * This);
ULONG ( STDMETHODCALLTYPE *Release )(
IVEHandler * This);
HRESULT ( STDMETHODCALLTYPE *VEHandler )(
IVEHandler * This,
/* [in] */ HRESULT VECode,
/* [in] */ VEContext Context,
/* [in] */ SAFEARRAY * psa);
HRESULT ( STDMETHODCALLTYPE *SetReporterFtn )(
IVEHandler * This,
/* [in] */ __int64 lFnPtr);
END_INTERFACE
} IVEHandlerVtbl;
interface IVEHandler
{
CONST_VTBL struct IVEHandlerVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define IVEHandler_QueryInterface(This,riid,ppvObject) \
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
#define IVEHandler_AddRef(This) \
(This)->lpVtbl -> AddRef(This)
#define IVEHandler_Release(This) \
(This)->lpVtbl -> Release(This)
#define IVEHandler_VEHandler(This,VECode,Context,psa) \
(This)->lpVtbl -> VEHandler(This,VECode,Context,psa)
#define IVEHandler_SetReporterFtn(This,lFnPtr) \
(This)->lpVtbl -> SetReporterFtn(This,lFnPtr)
#endif /* COBJMACROS */
#endif /* C style interface */
HRESULT STDMETHODCALLTYPE IVEHandler_VEHandler_Proxy(
IVEHandler * This,
/* [in] */ HRESULT VECode,
/* [in] */ VEContext Context,
/* [in] */ SAFEARRAY * psa);
void __RPC_STUB IVEHandler_VEHandler_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
HRESULT STDMETHODCALLTYPE IVEHandler_SetReporterFtn_Proxy(
IVEHandler * This,
/* [in] */ __int64 lFnPtr);
void __RPC_STUB IVEHandler_SetReporterFtn_Stub(
IRpcStubBuffer *This,
IRpcChannelBuffer *_pRpcChannelBuffer,
PRPC_MESSAGE _pRpcMessage,
DWORD *_pdwStubPhase);
#endif /* __IVEHandler_INTERFACE_DEFINED__ */
/* Additional Prototypes for ALL interfaces */
unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * );
unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * );
unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * );
void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * );
/* end of Additional Prototypes */
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
/**
*
* WOW64Ext Library
*
* Copyright (c) 2014 ReWolf
* http://blog.rewolf.pl/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
class CMemPtr
{
private:
void** m_ptr;
bool watchActive;
public:
CMemPtr(void** ptr) : m_ptr(ptr), watchActive(true) {}
~CMemPtr()
{
if (*m_ptr && watchActive)
{
free(*m_ptr);
*m_ptr = 0;
}
}
void disableWatch() { watchActive = false; }
};
#define WATCH(ptr) \
CMemPtr watch_##ptr((void**)&ptr)
#define DISABLE_WATCH(ptr) \
watch_##ptr.disableWatch()
@@ -0,0 +1,73 @@
/**
*
* WOW64Ext Library
*
* Copyright (c) 2014 ReWolf
* http://blog.rewolf.pl/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#define EMIT(a) __asm __emit (a)
#define X64_Start_with_CS(_cs) \
{ \
EMIT(0x6A) EMIT(_cs) /* push _cs */ \
EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \
EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(5) /* add dword [esp], 5 */ \
EMIT(0xCB) /* retf */ \
}
#define X64_End_with_CS(_cs) \
{ \
EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \
EMIT(0xC7) EMIT(0x44) EMIT(0x24) EMIT(4) EMIT(_cs) EMIT(0) EMIT(0) EMIT(0) /* mov dword [rsp + 4], _cs */ \
EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(0xD) /* add dword [rsp], 0xD */ \
EMIT(0xCB) /* retf */ \
}
#define X64_Start() X64_Start_with_CS(0x33)
#define X64_End() X64_End_with_CS(0x23)
#define _RAX 0
#define _RCX 1
#define _RDX 2
#define _RBX 3
#define _RSP 4
#define _RBP 5
#define _RSI 6
#define _RDI 7
#define _R8 8
#define _R9 9
#define _R10 10
#define _R11 11
#define _R12 12
#define _R13 13
#define _R14 14
#define _R15 15
#define X64_Push(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x50 | ((r) & 7))
#define X64_Pop(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x58 | ((r) & 7))
#define REX_W EMIT(0x48) __asm
//to fool M$ inline asm compiler I'm using 2 DWORDs instead of DWORD64
//use of DWORD64 will generate wrong 'pop word ptr[]' and it will break stack
union reg64
{
DWORD64 v;
DWORD dw[2];
};
@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by wow64ext.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
@@ -0,0 +1,377 @@
/**
*
* WOW64Ext Library
*
* Copyright (c) 2014 ReWolf
* http://blog.rewolf.pl/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <windows.h>
#ifndef STATUS_SUCCESS
# define STATUS_SUCCESS 0
#endif
#pragma warning(disable : 4201)
#pragma pack(push)
#pragma pack(1)
template <class T>
struct _LIST_ENTRY_T
{
T Flink;
T Blink;
};
template <class T>
struct _UNICODE_STRING_T
{
union
{
struct
{
WORD Length;
WORD MaximumLength;
};
T dummy;
};
T Buffer;
};
template <class T>
struct _NT_TIB_T
{
T ExceptionList;
T StackBase;
T StackLimit;
T SubSystemTib;
T FiberData;
T ArbitraryUserPointer;
T Self;
};
template <class T>
struct _CLIENT_ID_T
{
T UniqueProcess;
T UniqueThread;
};
template <class T>
struct _TEB_T_
{
_NT_TIB_T<T> NtTib;
T EnvironmentPointer;
_CLIENT_ID_T<T> ClientId;
T ActiveRpcHandle;
T ThreadLocalStoragePointer;
T ProcessEnvironmentBlock;
DWORD LastErrorValue;
DWORD CountOfOwnedCriticalSections;
T CsrClientThread;
T Win32ThreadInfo;
DWORD User32Reserved[26];
//rest of the structure is not defined for now, as it is not needed
};
template <class T>
struct _LDR_DATA_TABLE_ENTRY_T
{
_LIST_ENTRY_T<T> InLoadOrderLinks;
_LIST_ENTRY_T<T> InMemoryOrderLinks;
_LIST_ENTRY_T<T> InInitializationOrderLinks;
T DllBase;
T EntryPoint;
union
{
DWORD SizeOfImage;
T dummy01;
};
_UNICODE_STRING_T<T> FullDllName;
_UNICODE_STRING_T<T> BaseDllName;
DWORD Flags;
WORD LoadCount;
WORD TlsIndex;
union
{
_LIST_ENTRY_T<T> HashLinks;
struct
{
T SectionPointer;
T CheckSum;
};
};
union
{
T LoadedImports;
DWORD TimeDateStamp;
};
T EntryPointActivationContext;
T PatchInformation;
_LIST_ENTRY_T<T> ForwarderLinks;
_LIST_ENTRY_T<T> ServiceTagLinks;
_LIST_ENTRY_T<T> StaticLinks;
T ContextInformation;
T OriginalBase;
_LARGE_INTEGER LoadTime;
};
template <class T>
struct _PEB_LDR_DATA_T
{
DWORD Length;
DWORD Initialized;
T SsHandle;
_LIST_ENTRY_T<T> InLoadOrderModuleList;
_LIST_ENTRY_T<T> InMemoryOrderModuleList;
_LIST_ENTRY_T<T> InInitializationOrderModuleList;
T EntryInProgress;
DWORD ShutdownInProgress;
T ShutdownThreadId;
};
template <class T, class NGF, int A>
struct _PEB_T
{
union
{
struct
{
BYTE InheritedAddressSpace;
BYTE ReadImageFileExecOptions;
BYTE BeingDebugged;
BYTE BitField;
};
T dummy01;
};
T Mutant;
T ImageBaseAddress;
T Ldr;
T ProcessParameters;
T SubSystemData;
T ProcessHeap;
T FastPebLock;
T AtlThunkSListPtr;
T IFEOKey;
T CrossProcessFlags;
T UserSharedInfoPtr;
DWORD SystemReserved;
DWORD AtlThunkSListPtr32;
T ApiSetMap;
T TlsExpansionCounter;
T TlsBitmap;
DWORD TlsBitmapBits[2];
T ReadOnlySharedMemoryBase;
T HotpatchInformation;
T ReadOnlyStaticServerData;
T AnsiCodePageData;
T OemCodePageData;
T UnicodeCaseTableData;
DWORD NumberOfProcessors;
union
{
DWORD NtGlobalFlag;
NGF dummy02;
};
LARGE_INTEGER CriticalSectionTimeout;
T HeapSegmentReserve;
T HeapSegmentCommit;
T HeapDeCommitTotalFreeThreshold;
T HeapDeCommitFreeBlockThreshold;
DWORD NumberOfHeaps;
DWORD MaximumNumberOfHeaps;
T ProcessHeaps;
T GdiSharedHandleTable;
T ProcessStarterHelper;
T GdiDCAttributeList;
T LoaderLock;
DWORD OSMajorVersion;
DWORD OSMinorVersion;
WORD OSBuildNumber;
WORD OSCSDVersion;
DWORD OSPlatformId;
DWORD ImageSubsystem;
DWORD ImageSubsystemMajorVersion;
T ImageSubsystemMinorVersion;
T ActiveProcessAffinityMask;
T GdiHandleBuffer[A];
T PostProcessInitRoutine;
T TlsExpansionBitmap;
DWORD TlsExpansionBitmapBits[32];
T SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
T pShimData;
T AppCompatInfo;
_UNICODE_STRING_T<T> CSDVersion;
T ActivationContextData;
T ProcessAssemblyStorageMap;
T SystemDefaultActivationContextData;
T SystemAssemblyStorageMap;
T MinimumStackCommit;
T FlsCallback;
_LIST_ENTRY_T<T> FlsListHead;
T FlsBitmap;
DWORD FlsBitmapBits[4];
T FlsHighIndex;
T WerRegistrationData;
T WerShipAssertPtr;
T pContextData;
T pImageHeaderHash;
T TracingFlags;
};
typedef _LDR_DATA_TABLE_ENTRY_T<DWORD> LDR_DATA_TABLE_ENTRY32;
typedef _LDR_DATA_TABLE_ENTRY_T<DWORD64> LDR_DATA_TABLE_ENTRY64;
typedef _TEB_T_<DWORD> TEB32;
typedef _TEB_T_<DWORD64> TEB64;
typedef _PEB_LDR_DATA_T<DWORD> PEB_LDR_DATA32;
typedef _PEB_LDR_DATA_T<DWORD64> PEB_LDR_DATA64;
typedef _PEB_T<DWORD, DWORD64, 34> PEB32;
typedef _PEB_T<DWORD64, DWORD, 30> PEB64;
struct _XSAVE_FORMAT64
{
WORD ControlWord;
WORD StatusWord;
BYTE TagWord;
BYTE Reserved1;
WORD ErrorOpcode;
DWORD ErrorOffset;
WORD ErrorSelector;
WORD Reserved2;
DWORD DataOffset;
WORD DataSelector;
WORD Reserved3;
DWORD MxCsr;
DWORD MxCsr_Mask;
_M128A FloatRegisters[8];
_M128A XmmRegisters[16];
BYTE Reserved4[96];
};
struct _CONTEXT64_2
{
DWORD64 P1Home;
DWORD64 P2Home;
DWORD64 P3Home;
DWORD64 P4Home;
DWORD64 P5Home;
DWORD64 P6Home;
DWORD ContextFlags;
DWORD MxCsr;
WORD SegCs;
WORD SegDs;
WORD SegEs;
WORD SegFs;
WORD SegGs;
WORD SegSs;
DWORD EFlags;
DWORD64 Dr0;
DWORD64 Dr1;
DWORD64 Dr2;
DWORD64 Dr3;
DWORD64 Dr6;
DWORD64 Dr7;
DWORD64 Rax;
DWORD64 Rcx;
DWORD64 Rdx;
DWORD64 Rbx;
DWORD64 Rsp;
DWORD64 Rbp;
DWORD64 Rsi;
DWORD64 Rdi;
DWORD64 R8;
DWORD64 R9;
DWORD64 R10;
DWORD64 R11;
DWORD64 R12;
DWORD64 R13;
DWORD64 R14;
DWORD64 R15;
DWORD64 Rip;
_XSAVE_FORMAT64 FltSave;
_M128A Header[2];
_M128A Legacy[8];
_M128A Xmm0;
_M128A Xmm1;
_M128A Xmm2;
_M128A Xmm3;
_M128A Xmm4;
_M128A Xmm5;
_M128A Xmm6;
_M128A Xmm7;
_M128A Xmm8;
_M128A Xmm9;
_M128A Xmm10;
_M128A Xmm11;
_M128A Xmm12;
_M128A Xmm13;
_M128A Xmm14;
_M128A Xmm15;
_M128A VectorRegister[26];
DWORD64 VectorControl;
DWORD64 DebugControl;
DWORD64 LastBranchToRip;
DWORD64 LastBranchFromRip;
DWORD64 LastExceptionToRip;
DWORD64 LastExceptionFromRip;
};
#pragma warning(default : 4201)
// Below defines for .ContextFlags field are taken from WinNT.h
#ifndef CONTEXT_AMD64
#define CONTEXT_AMD64 0x100000
#endif
#define CONTEXT64_CONTROL (CONTEXT_AMD64 | 0x1L)
#define CONTEXT64_INTEGER (CONTEXT_AMD64 | 0x2L)
#define CONTEXT64_SEGMENTS (CONTEXT_AMD64 | 0x4L)
#define CONTEXT64_FLOATING_POINT (CONTEXT_AMD64 | 0x8L)
#define CONTEXT64_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L)
#define CONTEXT64_FULL (CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_FLOATING_POINT)
#define CONTEXT64_ALL (CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_SEGMENTS | CONTEXT64_FLOATING_POINT | CONTEXT64_DEBUG_REGISTERS)
#define CONTEXT64_XSTATE (CONTEXT_AMD64 | 0x20L)
#pragma pack(pop)
#ifdef WOW64EXT_EXPORTS
# define SPEC dllexport
#else
# define SPEC dllimport
#endif
extern "C"
{
DWORD64 __cdecl X64Call(DWORD64 func, int argC, ...);
DWORD64 __cdecl GetModuleHandle64(const wchar_t* lpModuleName);
DWORD64 __cdecl getNTDLL64();
DWORD64 __cdecl GetProcAddress64(DWORD64 hModule, const char* funcName);
SIZE_T __cdecl VirtualQueryEx64(HANDLE hProcess, DWORD64 lpAddress, MEMORY_BASIC_INFORMATION64* lpBuffer, SIZE_T dwLength);
DWORD64 __cdecl VirtualAllocEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
BOOL __cdecl VirtualFreeEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD dwFreeType);
BOOL __cdecl VirtualProtectEx64(HANDLE hProcess, DWORD64 lpAddress, SIZE_T dwSize, DWORD flNewProtect, DWORD* lpflOldProtect);
BOOL __cdecl ReadProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesRead);
BOOL __cdecl WriteProcessMemory64(HANDLE hProcess, DWORD64 lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T *lpNumberOfBytesWritten);
BOOL __cdecl GetThreadContext64(HANDLE hThread, _CONTEXT64_2* lpContext);
BOOL __cdecl SetThreadContext64(HANDLE hThread, _CONTEXT64_2* lpContext);
VOID __cdecl SetLastErrorFromX64Call(DWORD64 status);
}
@@ -0,0 +1,240 @@
/*
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
winapifamily.h
Abstract:
Master include file for API family partitioning.
*/
#ifndef _INC_WINAPIFAMILY
#define _INC_WINAPIFAMILY
#if defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#if _MSC_VER >= 1200
#pragma warning(push)
#pragma warning(disable:4001) /* nonstandard extension 'single line comment' was used */
#endif
#pragma once
#endif // defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#include <winpackagefamily.h>
/*
* When compiling C and C++ code using SDK header files, the development
* environment can specify a target platform by #define-ing the
* pre-processor symbol WINAPI_FAMILY to one of the following values.
* Each FAMILY value denotes an application family for which a different
* subset of the total set of header-file-defined APIs are available.
* Setting the WINAPI_FAMILY value will effectively hide from the
* editing and compilation environments the existence of APIs that
* are not applicable to the family of applications targeting a
* specific platform.
*/
/* In Windows 10, WINAPI_PARTITIONs will be used to add additional
* device specific APIs to a particular WINAPI_FAMILY.
* For example, when writing Windows Universal apps, specifying
* WINAPI_FAMILY_APP will hide phone APIs from compilation.
* However, specifying WINAPI_PARTITION_PHONE_APP=1 additionally, will
* unhide any API hidden behind the partition, to the compiler.
* The following partitions are currently defined:
* WINAPI_PARTITION_DESKTOP // usable for Desktop Win32 apps (but not store apps)
* WINAPI_PARTITION_APP // usable for Windows Universal store apps
* WINAPI_PARTITION_PC_APP // specific to Desktop-only store apps
* WINAPI_PARTITION_PHONE_APP // specific to Phone-only store apps
* WINAPI_PARTITION_SYSTEM // specific to System applications
* The following partitions are indirect partitions and defined in
* winpackagefamily.h. These partitions are related to package based
* partitions. For example, specifying WINAPI_PARTITION_SERVER=1 will light up
* any API hidden behind the package based partitions that are bound to
* WINAPI_PARTITION_SERVER, to the compiler.
* WINAPI_PARTITION_SERVER // specific to Server applications
*/
/*
* The WINAPI_FAMILY values of 0 and 1 are reserved to ensure that
* an error will occur if WINAPI_FAMILY is set to any
* WINAPI_PARTITION value (which must be 0 or 1, see below).
*/
#define WINAPI_FAMILY_PC_APP 2 /* Windows Store Applications */
#define WINAPI_FAMILY_PHONE_APP 3 /* Windows Phone Applications */
#define WINAPI_FAMILY_SYSTEM 4 /* Windows Drivers and Tools */
#define WINAPI_FAMILY_SERVER 5 /* Windows Server Applications */
#define WINAPI_FAMILY_DESKTOP_APP 100 /* Windows Desktop Applications */
/* The value of WINAPI_FAMILY_DESKTOP_APP may change in future SDKs. */
/* Additional WINAPI_FAMILY values may be defined in future SDKs. */
/*
* For compatibility with Windows 8 header files, the following
* synonym for WINAPI_FAMILY_PC_APP is temporarily #define'd.
* Use of this symbol should be considered deprecated.
*/
#define WINAPI_FAMILY_APP WINAPI_FAMILY_PC_APP
/*
* If no WINAPI_FAMILY value is specified, then all APIs available to
* Windows desktop applications are exposed.
*/
#ifndef WINAPI_FAMILY
#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
#endif
/*
* API PARTITONs are part of an indirection mechanism for mapping between
* individual APIs and the FAMILYs to which they apply.
* Each PARTITION is a category or subset of named APIs. PARTITIONs
* are permitted to have overlapping membership -- some single API
* might be part of more than one PARTITION. PARTITIONS are each #define-ed
* to be either 1 or 0 or depending on the platform at which the app is targeted.
*/
/*
* The mapping between families and partitions is summarized here.
* An X indicates that the given partition is active for the given
* platform/family.
*
* +-------------------+---+
* | *Partition* | |
* +---+---+---+---+---+---+
* | | | | | | |
* | | | | | | |
* | | | | P | | |
* | | | | H | | |
* | D | | | O | | |
* | E | | P | N | S | S |
* | S | | C | E | Y | E |
* | K | | _ | _ | S | R |
* | T | A | A | A | T | V |
* +-------------------------+----+ O | P | P | P | E | E |
* | *Platform/Family* \| P | P | P | P | M | R |
* +------------------------------+---+---+---+---+---+---+
* | WINAPI_FAMILY_DESKTOP_APP | X | X | X | | | |
* +------------------------------+---+---+---+---+---+---+
* | WINAPI_FAMILY_PC_APP | | X | X | | | |
* +------------------------------+---+---+---+---+---+---+
* | WINAPI_FAMILY_PHONE_APP | | X | | X | | |
* +----------------------------- +---+---+---+---+---+---+
* | WINAPI_FAMILY_SYSTEM | | | | | X | |
* +----------------------------- +---+---+---+---+---+---+
* | WINAPI_FAMILY_SERVER | | | | | X | X |
* +------------------------------+---+---+---+---+---+---+
*
* The table above is encoded in the following expressions,
* each of which evaluates to 1 or 0.
*
* Whenever a new family is added, all of these expressions
* need to be reconsidered.
*/
#if WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP && \
WINAPI_FAMILY != WINAPI_FAMILY_PC_APP && \
WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP && \
WINAPI_FAMILY != WINAPI_FAMILY_SYSTEM && \
WINAPI_FAMILY != WINAPI_FAMILY_SERVER
#error Unknown WINAPI_FAMILY value. Was it defined in terms of a WINAPI_PARTITION_* value?
#endif
#ifndef WINAPI_PARTITION_DESKTOP
#define WINAPI_PARTITION_DESKTOP (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
#endif
#ifndef WINAPI_PARTITION_APP
#define WINAPI_PARTITION_APP \
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP || \
WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || \
WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#endif
#ifndef WINAPI_PARTITION_PC_APP
#define WINAPI_PARTITION_PC_APP \
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP || \
WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
#endif
#ifndef WINAPI_PARTITION_PHONE_APP
#define WINAPI_PARTITION_PHONE_APP (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
#endif
/*
* SYSTEM is the only partition defined here.
* All other System based editions are defined as packages
* on top of the System partition.
* See winpackagefamily.h for packages level partitions
*/
#ifndef WINAPI_PARTITION_SYSTEM
#define WINAPI_PARTITION_SYSTEM \
(WINAPI_FAMILY == WINAPI_FAMILY_SYSTEM || \
WINAPI_FAMILY == WINAPI_FAMILY_SERVER)
#endif
/*
* For compatibility with Windows Phone 8 header files, the following
* synonym for WINAPI_PARTITION_PHONE_APP is temporarily #define'd.
* Use of this symbol should be regarded as deprecated.
*/
#define WINAPI_PARTITION_PHONE WINAPI_PARTITION_PHONE_APP
/*
* Header files use the WINAPI_FAMILY_PARTITION macro to assign one or
* more declarations to some group of partitions. The macro chooses
* whether the preprocessor will emit or omit a sequence of declarations
* bracketed by an #if/#endif pair. All header file references to the
* WINAPI_PARTITION_* values should be in the form of occurrences of
* WINAPI_FAMILY_PARTITION(...).
*
* For example, the following usage of WINAPI_FAMILY_PARTITION identifies
* a sequence of declarations that are part of both the Windows Desktop
* Partition and the Windows-Phone-Specific Store Partition:
*
* #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PHONE_APP)
* ...
* #endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PHONE_APP)
*
* The comment on the closing #endif allow tools as well as people to find the
* matching #ifdef properly.
*
* Usages of WINAPI_FAMILY_PARTITION may be combined, when the partitition definitions are
* related. In particular one might use declarations like
*
* #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
*
* or
*
* #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
*
* Direct references to WINAPI_PARTITION_ values (eg #if !WINAPI_FAMILY_PARTITION_...)
* should not be used.
*/
#define WINAPI_FAMILY_PARTITION(Partitions) (Partitions)
/*
* Macro used to #define or typedef a symbol used for selective deprecation
* of individual methods of a COM interfaces that are otherwise available
* for a given set of partitions.
*/
#define _WINAPI_DEPRECATED_DECLARATION __declspec(deprecated("This API cannot be used in the context of the caller's application type."))
/*
* For compatibility with Windows 8 header files, the following
* symbol is temporarily conditionally #define'd. Additional symbols
* like this should be not defined in winapifamily.h, but rather should be
* introduced locally to the header files of the component that needs them.
*/
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
# define APP_DEPRECATED_HRESULT HRESULT _WINAPI_DEPRECATED_DECLARATION
#endif // WINAPIFAMILY_PARTITION(WINAPI_PARTITION_APP) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#if defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#if _MSC_VER >= 1200
#pragma warning(pop)
#endif
#endif
#endif /* !_INC_WINAPIFAMILY */
@@ -0,0 +1,91 @@
/*
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
winpackagefamily.h
Abstract:
API family partitioning based on packages.
*/
#ifndef _INC_WINPACKAGEFAMILY
#define _INC_WINPACKAGEFAMILY
#if defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#if _MSC_VER >= 1200
#pragma warning(push)
#pragma warning(disable:4001) /* nonstandard extension 'single line comment' was used */
#endif
#pragma once
#endif // defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#ifndef WINAPI_PARTITION_SERVER
#define WINAPI_PARTITION_SERVER (WINAPI_FAMILY == WINAPI_FAMILY_SERVER)
#endif
/*
* PARTITIONS based on packages are each #undef'ed below, and then will be #define-ed
* to be either 1 or 0 or depending on the active WINAPI_FAMILY.
*/
#undef WINAPI_PARTITION_PKG_WINTRUST
#undef WINAPI_PARTITION_PKG_WEBSERVICES
#undef WINAPI_PARTITION_PKG_EVENTLOGSERVICE
#undef WINAPI_PARTITION_PKG_VHD
#undef WINAPI_PARTITION_PKG_PERFCOUNTER
#undef WINAPI_PARTITION_PKG_SECURESTARTUP
#undef WINAPI_PARTITION_PKG_REMOTEFS
#undef WINAPI_PARTITION_PKG_BOOTABLESKU
#undef WINAPI_PARTITION_PKG_CMDTOOLS
#undef WINAPI_PARTITION_PKG_DISM
#undef WINAPI_PARTITION_PKG_CORESETUP
#undef WINAPI_PARTITION_PKG_APPRUNTIME
#undef WINAPI_PARTITION_PKG_ESENT
#undef WINAPI_PARTITION_PKG_WINMGMT
#undef WINAPI_PARTITION_PKG_WNV
#undef WINAPI_PARTITION_PKG_CLUSTER
#undef WINAPI_PARTITION_PKG_VSS
#undef WINAPI_PARTITION_PKG_TRAFFIC
#undef WINAPI_PARTITION_PKG_ISCSI
#undef WINAPI_PARTITION_PKG_STORAGE
#undef WINAPI_PARTITION_PKG_MPSSVC
#undef WINAPI_PARTITION_PKG_APPXDEPLOYMENT
#undef WINAPI_PARTITION_PKG_WER
/*
* PARTITIONS for feature packages. Each package might be active for one or more editions
*/
#define WINAPI_PARTITION_PKG_WINTRUST (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_WEBSERVICES (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_EVENTLOGSERVICE (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_VHD (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_PERFCOUNTER (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_SECURESTARTUP (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_REMOTEFS (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_BOOTABLESKU (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_CMDTOOLS (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_DISM (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_CORESETUP (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_APPRUNTIME (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_ESENT (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_WINMGMT (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_WNV (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_CLUSTER (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_VSS (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_TRAFFIC (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_ISCSI (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_STORAGE (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_MPSSVC (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_APPXDEPLOYMENT (WINAPI_PARTITION_SERVER == 1)
#define WINAPI_PARTITION_PKG_WER (WINAPI_PARTITION_SERVER == 1)
#if defined(_MSC_VER) && !defined(MOFCOMP_PASS)
#if _MSC_VER >= 1200
#pragma warning(pop)
#endif
#endif
#endif /* !_INC_WINPACKAGEFAMILY */
@@ -0,0 +1,89 @@
#pragma once
#include "../Config.h"
#include "../Include/Types.h"
#include "AsmHelper64.h"
#include "AsmHelper32.h"
namespace blackbone
{
using AsmHelperPtr = std::unique_ptr<IAsmHelper>;
/// <summary>
/// Get suitable asm generator
/// </summary>
class AsmFactory
{
public:
enum eAsmArch
{
asm32, // x86
asm64 // x86_64
};
/// <summary>
/// Get suitable asm generator
/// </summary>
/// <param name="arch">Desired CPU architecture</param>
/// <returns>AsmHelperBase interface</returns>
static AsmHelperPtr GetAssembler( eAsmArch arch )
{
switch (arch)
{
case asm32:
return std::make_unique<AsmHelper32>();
case asm64:
return std::make_unique<AsmHelper64>();
default:
return nullptr;
}
}
/// <summary>
/// Get suitable asm generator
/// </summary>
/// <param name="mt">Desired PE module architecture</param>
/// <returns>AsmHelperBase interface</returns>
static AsmHelperPtr GetAssembler( eModType mt )
{
if (mt == mt_default)
mt = sizeof( intptr_t ) > sizeof( int32_t ) ? mt_mod64 : mt_mod32;
switch (mt)
{
case mt_mod32:
return GetAssembler( asm32 );
case mt_mod64:
return GetAssembler( asm64 );
default:
return nullptr;
}
}
/// <summary>
/// Get suitable asm generator
/// </summary>
/// <param name="wow64process">Target process CPU architecture</param>
/// <returns>AsmHelperBase interface</returns>
static AsmHelperPtr GetAssembler( bool wow64process )
{
return GetAssembler( wow64process ? asm32 : asm64 );
}
/// <summary>
/// Get default asm generator
/// </summary>
/// <returns></returns>
static AsmHelperPtr GetAssembler()
{
#ifdef USE64
return std::make_unique<AsmHelper64>();
#else
return std::make_unique<AsmHelper32>();
#endif
}
};
}
@@ -0,0 +1,88 @@
#pragma once
#include "IAsmHelper.h"
namespace blackbone
{
/// <summary>
/// 32 bit assembler helper
/// </summary>
class AsmHelper32 : public IAsmHelper
{
public:
BLACKBONE_API AsmHelper32( );
BLACKBONE_API ~AsmHelper32( void );
/// <summary>
/// Generate function prologue code
/// </summary>
/// <param name="switchMode">Unused</param>
virtual void GenPrologue( bool switchMode = false );
/// <summary>
/// Generate function epilogue code
/// </summary>
/// <param name="switchMode">Unused</param>
/// <param name="retSize">Stack change value</param>
virtual void GenEpilogue( bool switchMode = false, int retSize = -1 );
/// <summary>
/// Generate function call
/// </summary>
/// <param name="pFN">Function pointer</param>
/// <param name="args">Function arguments</param>
/// <param name="cc">Calling convention</param>
virtual void GenCall( const AsmFunctionPtr& pFN, const std::vector<AsmVariant>& args, eCalligConvention cc = cc_stdcall );
/// <summary>
/// Save eax value and terminate current thread
/// </summary>
/// <param name="pExitThread">NtTerminateThread address</param>
/// <param name="resultPtr">Memory where eax value will be saved</param>
virtual void ExitThreadWithStatus( uint64_t pExitThread, uint64_t resultPtr );
/// <summary>
/// Save return value and signal thread return event
/// </summary>
/// <param name="pSetEvent">NtSetEvent address</param>
/// <param name="ResultPtr">Result value memory location</param>
/// <param name="EventPtr">Event memory location</param>
/// <param name="errPtr">Error code memory location</param>
/// <param name="rtype">Return type</param>
virtual void SaveRetValAndSignalEvent(
uint64_t pSetEvent,
uint64_t ResultPtr,
uint64_t EventPtr,
uint64_t errPtr,
eReturnType rtype = rt_int32
);
/// <summary>
/// Does nothing under x86
/// </summary>
/// <param name="">Unused</param>
virtual void EnableX64CallStack( bool ) { }
private:
AsmHelper32( const AsmHelper32& ) = delete;
AsmHelper32& operator = (const AsmHelper32&) = delete;
/// <summary>
/// Push function argument
/// </summary>
/// <param name="arg">Argument.</param>
/// <param name="regidx">Push type(register or stack)</param>
void PushArg( const AsmVariant& arg, eArgType regidx = at_stack );
/// <summary>
/// Push argument into function
/// </summary>
/// <param name="arg">Argument</param>
/// <param name="index">Argument location</param>
template<typename _Type>
void PushArgp( _Type arg, eArgType index );
};
}
@@ -0,0 +1,92 @@
#pragma once
#include "IAsmHelper.h"
#include "../Include/Macro.h"
namespace blackbone
{
class AsmHelper64 : public IAsmHelper
{
public:
BLACKBONE_API AsmHelper64();
BLACKBONE_API ~AsmHelper64( void );
/// <summary>
/// Generate function prologue code
/// </summary>
/// <param name="switchMode">true if execution must be swithed to x64 mode</param>
virtual void GenPrologue( bool switchMode = false );
/// <summary>
/// Generate function epilogue code
/// </summary>
/// <param name="switchMode">true if execution must be swithed to x86 mode</param>
/// <param name="retSize">Stack change value</param>
virtual void GenEpilogue( bool switchMode = false, int retSize = -1 );
/// <summary>
/// Generate function call
/// </summary>
/// <param name="pFN">Function pointer</param>
/// <param name="args">Function arguments</param>
/// <param name="cc">Ignored</param>
virtual void GenCall( const AsmFunctionPtr& pFN, const std::vector<AsmVariant>& args, eCalligConvention cc = cc_stdcall );
/// <summary>
/// Save rax value and terminate current thread
/// </summary>
/// <param name="pExitThread">NtTerminateThread address</param>
/// <param name="resultPtr">Memory where rax value will be saved</param>
virtual void ExitThreadWithStatus( uint64_t pExitThread, uint64_t resultPtr );
/// <summary>
/// Save return value and signal thread return event
/// </summary>
/// <param name="pSetEvent">NtSetEvent address</param>
/// <param name="ResultPtr">Result value memory location</param>
/// <param name="EventPtr">Event memory location</param>
/// <param name="errPtr">Error code memory location</param>
/// <param name="rtype">Return type</param>
virtual void SaveRetValAndSignalEvent(
uint64_t pSetEvent,
uint64_t ResultPtr,
uint64_t EventPtr,
uint64_t lastStatusPtr,
eReturnType rtype = rt_int32
);
/// <summary>
/// Set stack reservation policy on call generation
/// </summary>
/// <param name="state">
/// If true - stack space will be reserved during each call generation
/// If false - no automatic stack reservation, user must allocate stack by hand
/// </param>
virtual void EnableX64CallStack( bool state );
private:
AsmHelper64( const AsmHelper64& ) = delete;
AsmHelper64& operator = (const AsmHelper64&) = delete;
/// <summary>
/// Push function argument
/// </summary>
/// <param name="arg">Argument.</param>
/// <param name="regidx">Push type(register or stack)</param>
void PushArg( const AsmVariant& arg, int32_t index );
/// <summary>
/// Push function argument
/// </summary>
/// <param name="arg">Argument</param>
/// <param name="index">Argument index</param>
/// <param name="fpu">true if argument is a floating point value</param>
template<typename _Type>
void PushArgp( const _Type& arg, int32_t index, bool fpu = false );
private:
bool _stackEnabled; // if true - GenCall will allocate shadow stack space
};
}
@@ -0,0 +1,89 @@
#pragma once
#pragma warning(push)
#pragma warning(disable : 4100)
#include "../../3rd_party/AsmJit/AsmJit.h"
#pragma warning(pop)
#include "../Include/Macro.h"
#include <stdint.h>
namespace blackbone
{
class AsmStackAllocator
{
public:
BLACKBONE_API AsmStackAllocator( asmjit::X86Assembler* pAsm, int32_t baseval = 0x28 )
: _pAsm( pAsm )
, disp_ofst( pAsm->getArch() == asmjit::kArch::kArchX64 ? baseval : sizeof( uint64_t ) )
{
}
/// <summary>
/// Allocate stack variable
/// </summary>
/// <param name="size">Variable size</param>
/// <returns>Variable memory object</returns>
BLACKBONE_API asmjit::Mem AllocVar( int32_t size )
{
bool x64 = _pAsm->getArch() == asmjit::kArch::kArchX64;
// Align on word length
size = static_cast<int32_t>(Align( size, x64 ? sizeof( uint64_t ) : sizeof( uint32_t ) ));
asmjit::Mem val;
if (x64)
val = asmjit::Mem( _pAsm->zsp, disp_ofst, size );
else
val = asmjit::Mem( _pAsm->zbp, -disp_ofst - size, size );
disp_ofst += size;
return val;
}
/// <summary>
/// Allocate array of stack variables
/// </summary>
/// <param name="arr">Output array</param>
/// <param name="count">Array elements count.</param>
/// <param name="size">Element size.</param>
/// <returns>true on success</returns>
BLACKBONE_API bool AllocArray( asmjit::Mem arr[], int count, int32_t size )
{
for (int i = 0; i < count; i++)
{
if (_pAsm->getArch() == asmjit::kArch::kArchX64)
arr[i] = asmjit::Mem( _pAsm->zsp, disp_ofst, size );
else
arr[i] = asmjit::Mem( _pAsm->zbp, -disp_ofst - size, size );
disp_ofst += size;
}
return true;
}
/// <summary>
/// Get total size of all stack variables
/// </summary>
/// <returns></returns>
BLACKBONE_API inline intptr_t getTotalSize() const { return disp_ofst; };
private:
asmjit::X86Assembler* _pAsm; // Underlying assembler
int32_t disp_ofst; // Next variable stack offset
};
//
// Helpers
//
#define ALLOC_STACK_VAR(worker, name, type) asmjit::Mem name( worker.AllocVar( sizeof(type) ) );
#define ALLOC_STACK_VAR_S(worker, name, size) asmjit::Mem name( worker.AllocVar( size ) );
#define ALLOC_STACK_ARRAY(worker, name, type, count) \
asmjit::Mem name[count]; \
worker.AllocArray( name, count, sizeof(type) );
}
@@ -0,0 +1,227 @@
#pragma once
#include "../Config.h"
#pragma warning(disable : 4100)
#include "../../3rd_party/AsmJit/AsmJit.h"
#pragma warning(default : 4100)
#include <vector>
namespace blackbone
{
/// <summary>
/// General purpose assembly variable
/// </summary>
struct AsmVariant
{
template<typename T>
using cleanup_t = std::remove_cv_t<std::remove_pointer_t<T>>;
template<typename T, typename S>
static constexpr bool is_string_ptr = (std::is_pointer_v<T> && std::is_same_v<cleanup_t<T>, S>);
template<typename T>
static constexpr bool is_number = (std::is_integral_v<T> || std::is_enum_v<T>);
template<typename T>
static constexpr bool is_void_ptr = (std::is_pointer_v<T> && std::is_void_v<cleanup_t<T>>);
enum eType
{
noarg, // void
reg, // register
imm, // immediate value (e.g. address)
imm_double, // double or long double
imm_float, // float
dataPtr, // pointer to local data (e.g. string or pointer to structure)
dataStruct, // structure passed by value
structRet, // pointer to space into which return value is copied (used when returning structures by value)
mem, // stack variable
mem_ptr // pointer to stack variable
};
template<typename T>
AsmVariant( T&& arg )
{
using RAW_T = std::decay_t<T>;
constexpr size_t argSize = sizeof( RAW_T );
// bool, short, int, unsigned long long, etc.
if constexpr (is_number<RAW_T>)
{
set( imm, argSize, static_cast<uint64_t>(arg) );
}
// Array of elements
else if constexpr(std::is_array_v<std::remove_reference_t<T>>)
{
set( dataPtr, sizeof( arg ), reinterpret_cast<uint64_t>(arg) );
}
// char*, const char*, etc.
else if constexpr(is_string_ptr<RAW_T, char>)
{
set( dataPtr, strlen( arg ) + 1, reinterpret_cast<uint64_t>(arg) );
}
// wchar_t*, const wchar_t*, etc.
else if constexpr(is_string_ptr<RAW_T, wchar_t>)
{
set( dataPtr, (wcslen( arg ) + 1) * sizeof( wchar_t ), reinterpret_cast<uint64_t>(arg) );
}
// void*, const void*, etc.
else if constexpr(is_void_ptr<RAW_T>)
{
set( imm, argSize, reinterpret_cast<uint64_t>(arg) );
}
// dirty hack to threat HWND as a simple pointer
else if constexpr(std::is_same_v<RAW_T, HWND>)
{
set( imm, argSize, reinterpret_cast<uint64_t>(arg) );
}
// Function pointer
else if constexpr(std::is_function_v<cleanup_t<RAW_T>>)
{
set( imm, argSize, reinterpret_cast<uint64_t>(arg) );
}
// Arbitrary pointer
else if constexpr(std::is_pointer_v<RAW_T>)
{
set( dataPtr, sizeof( cleanup_t<RAW_T> ), reinterpret_cast<uint64_t>(arg) );
}
// Arbitrary variable passed by value
// Can fit into register
else if constexpr (argSize <= sizeof( uintptr_t ))
{
type = imm;
size = argSize;
memcpy( &imm_val64, &arg, argSize );
}
else
{
buf.resize( argSize );
set( dataStruct, argSize, reinterpret_cast<uint64_t>(buf.data()) );
memcpy( buf.data(), &arg, argSize );
}
}
// Custom size pointer
template <typename T>
explicit AsmVariant( T* ptr, size_t size_ )
: type( dataPtr )
, size( size_ )
, imm_val64( reinterpret_cast<uint64_t>(ptr) ) { }
BLACKBONE_API AsmVariant( float _imm_fpu )
: type( imm_float )
, size( sizeof( float ) )
, imm_float_val( _imm_fpu ) { }
BLACKBONE_API AsmVariant( double _imm_fpu )
: type( imm_double )
, size( sizeof( double ) )
, imm_double_val( _imm_fpu ) { }
BLACKBONE_API AsmVariant( asmjit::GpReg _reg )
: type( reg )
, size( sizeof( uintptr_t ) )
, reg_val( _reg ) { }
// Stack variable
BLACKBONE_API AsmVariant( asmjit::Mem _mem )
: type( mem )
, size( sizeof( uintptr_t ) )
, mem_val( _mem ) { }
// Pointer to stack address
BLACKBONE_API AsmVariant( asmjit::Mem* _mem )
: type( mem_ptr )
, size( sizeof( uintptr_t ) )
, mem_val( *_mem ) { }
BLACKBONE_API AsmVariant( const asmjit::Mem* _mem )
: AsmVariant( const_cast<asmjit::Mem*>(_mem) ) { }
BLACKBONE_API AsmVariant( const AsmVariant& ) = default;
BLACKBONE_API AsmVariant( AsmVariant&& ) = default;
BLACKBONE_API AsmVariant& operator =( const AsmVariant& ) = default;
//
// Get floating point value as raw data
//
BLACKBONE_API inline uint32_t getImm_float() const { return *(reinterpret_cast<const uint32_t*>(&imm_float_val)); }
BLACKBONE_API inline uint64_t getImm_double() const { return *(reinterpret_cast<const uint64_t*>(&imm_double_val)); }
/// <summary>
/// Check if argument can be passed in x86 register
/// </summary>
/// <returns>true if can</returns>
BLACKBONE_API inline bool reg86Compatible() const
{
if (type == dataStruct || type == imm_float || type == imm_double || type == structRet)
return false;
/*if (type == imm && size > sizeof( uint32_t ))
return false;*/
return true;
}
inline void set( eType type_, size_t size_, uint64_t val )
{
type = type_;
size = size_;
imm_val64 = val;
}
eType type = noarg; // Variable type
size_t size = 0; // Variable size
asmjit::GpReg reg_val; // General purpose register
asmjit::Mem mem_val; // Memory pointer
// Immediate values
union
{
uint64_t imm_val64 = 0;
uintptr_t imm_val;
uint32_t imm_val32;
double imm_double_val;
float imm_float_val;
};
uint64_t new_imm_val = 0; // Replaced immediate value for dataPtr type
std::vector<uint8_t> buf; // Value buffer
};
/// <summary>
/// Remote function pointer
/// </summary>
struct AsmFunctionPtr: public AsmVariant
{
AsmFunctionPtr( int ptr )
: AsmVariant( ptr ) { }
AsmFunctionPtr( unsigned int ptr )
: AsmVariant( ptr ) { }
AsmFunctionPtr( long ptr )
: AsmVariant( ptr ) { }
AsmFunctionPtr( unsigned long ptr )
: AsmVariant( ptr ) { }
AsmFunctionPtr( long long ptr )
: AsmVariant( ptr ) { }
AsmFunctionPtr( unsigned long long ptr )
: AsmVariant( ptr ) { }
AsmFunctionPtr( void* ptr )
: AsmVariant( reinterpret_cast<uintptr_t>(ptr) ) { }
AsmFunctionPtr( const void* ptr )
: AsmVariant( reinterpret_cast<uintptr_t>(ptr) ) { }
AsmFunctionPtr( asmjit::GpReg reg_ )
: AsmVariant( reg_ ) { }
};
}
@@ -0,0 +1,101 @@
#pragma once
#include "AsmVariant.hpp"
#include "AsmStack.hpp"
#include "../Include/Macro.h"
#include <initializer_list>
#include <vector>
namespace blackbone
{
//
// Function calling convention
//
enum eCalligConvention
{
cc_cdecl, // cdecl
cc_stdcall, // stdcall
cc_thiscall, // thiscall
cc_fastcall // fastcall
};
//
// Function return type
// Do not change numeric values!
//
enum eReturnType
{
rt_int32 = 4, // 32bit value
rt_int64 = 8, // 64bit value
rt_float = 1, // float value
rt_double = 2, // double value
rt_struct = 3, // structure returned by value
};
// Argument pass method
enum eArgType
{
at_ecx = 0, // In ecx
at_edx = 1, // In edx
at_stack = 2, // On stack
};
/// <summary>
/// Assembly generation helper
/// </summary>
class IAsmHelper
{
public:
BLACKBONE_API IAsmHelper( uint32_t arch = asmjit::kArchHost )
: _assembler( &_runtime, arch ) { }
virtual ~IAsmHelper() { }
virtual void GenPrologue( bool switchMode = false ) = 0;
virtual void GenEpilogue( bool switchMode = false, int retSize = -1) = 0;
virtual void GenCall( const AsmFunctionPtr&, const std::vector<AsmVariant>& args, eCalligConvention cc = cc_stdcall ) = 0;
virtual void ExitThreadWithStatus( uint64_t pExitThread, uint64_t resultPtr ) = 0;
virtual void SaveRetValAndSignalEvent( uint64_t pSetEvent, uint64_t ResultPtr, uint64_t EventPtr, uint64_t errPtr, eReturnType rtype = rt_int32 ) = 0;
virtual void EnableX64CallStack( bool state ) = 0;
/// <summary>
/// Switch processor into WOW64 emulation mode
/// </summary>
BLACKBONE_API void SwitchTo86()
{
asmjit::Label l = _assembler.newLabel();
_assembler.call( l ); _assembler.bind( l );
_assembler.mov( asmjit::host::dword_ptr( asmjit::host::esp, 4 ), 0x23 );
_assembler.add( asmjit::host::dword_ptr( asmjit::host::esp ), 0xD );
_assembler.db( 0xCB ); // retf
}
/// <summary>
/// Switch processor into x64 mode (long mode)
/// </summary>
BLACKBONE_API void SwitchTo64()
{
asmjit::Label l = _assembler.newLabel();
_assembler.push( 0x33 );
_assembler.call( l ); _assembler.bind( l );
//_assembler.add( asmjit::host::dword_ptr( asmjit::host::esp ), 5 );
_assembler.dd( '\x83\x04\x24\x05' );
_assembler.db( 0xCB ); // retf
}
BLACKBONE_API inline asmjit::X86Assembler* assembler() { return &_assembler; }
BLACKBONE_API inline asmjit::X86Assembler* operator ->() { return &_assembler; }
private:
IAsmHelper( const IAsmHelper& ) = delete;
IAsmHelper& operator =(const IAsmHelper&) = delete;
protected:
asmjit::JitRuntime _runtime;
asmjit::X86Assembler _assembler;
};
}
@@ -0,0 +1,50 @@
#ifndef _LDASM_
#define _LDASM_
#include "../Config.h"
#include <stdint.h>
#include <string.h>
#ifdef USE64
#define is_x64 1
#else
#define is_x64 0
#endif//USE64
#ifdef __cplusplus
extern "C"
{
#endif
#define F_INVALID 0x01
#define F_PREFIX 0x02
#define F_REX 0x04
#define F_MODRM 0x08
#define F_SIB 0x10
#define F_DISP 0x20
#define F_IMM 0x40
#define F_RELATIVE 0x80
typedef struct _ldasm_data
{
uint8_t flags;
uint8_t rex;
uint8_t modrm;
uint8_t sib;
uint8_t opcd_offset;
uint8_t opcd_size;
uint8_t disp_offset;
uint8_t disp_size;
uint8_t imm_offset;
uint8_t imm_size;
} ldasm_data;
BLACKBONE_API unsigned int __fastcall ldasm( void *code, ldasm_data *ld, uint32_t is64 );
BLACKBONE_API unsigned long __fastcall SizeOfProc( void *Proc );
BLACKBONE_API void* __fastcall ResolveJmp( void *Proc );
#ifdef __cplusplus
}
#endif
#endif//_LDASM_
@@ -0,0 +1,38 @@
#pragma once
// Lib/Dll switch
#if !defined(BLACKBONE_EXPORTS) && !defined(BLACKBONE_IMPORTS) && !defined(BLACKBONE_STATIC)
#define BLACKBONE_STATIC
#endif
#if defined(_MSC_VER)
#ifndef COMPILER_MSVC
#define COMPILER_MSVC 1
#endif
#if defined(BLACKBONE_IMPORTS)
#define BLACKBONE_API __declspec(dllimport)
#elif defined(BLACKBONE_EXPORTS)
#define BLACKBONE_API __declspec(dllexport)
#else
#define BLACKBONE_API
#endif
#elif defined(__GNUC__)
#define COMPILER_GCC
#define BLACKBONE_API
#else
#error "Unknown or unsupported compiler"
#endif
// No IA64 support
#if defined (_M_AMD64) || defined (__x86_64__)
#define USE64
#elif defined (_M_IX86) || defined (__i386__)
#define USE32
#else
#error "Unknown or unsupported platform"
#endif
@@ -0,0 +1,322 @@
#pragma once
#include "../Include/Winheaders.h"
#include "../Include/Types.h"
#include "../Include/Macro.h"
#include "../Include/HandleGuard.h"
#include "../../BlackBoneDrv/BlackBoneDef.h"
#include <string>
#include <map>
#include <vector>
ENUM_OPS( KMmapFlags );
namespace blackbone
{
// [Original ptr, size] <--> [Mapped ptr]
using mapMemoryMap = std::map<std::pair<ptr_t, uint32_t>, ptr_t>;
struct MapMemoryResult
{
ptr_t hostSharedPage; // Shared page address in current process
ptr_t targetSharedPage; // Shared page address in target process
HANDLE targetPipe; // Hook pipe handle in the target process
mapMemoryMap regions; // Mapped regions info
};
struct MapMemoryRegionResult
{
ptr_t originalPtr; // Address of region in the target process
ptr_t newPtr; // Address of mapped region in the current process
ptr_t removedPtr; // Address of region unmapped because of address conflict
uint32_t size; // Size of mapped region
uint32_t removedSize; // Size of unmapped region
};
class DriverControl
{
public:
BLACKBONE_API DriverControl();
BLACKBONE_API ~DriverControl();
BLACKBONE_API static DriverControl& Instance();
/// <summary>
/// Try to load driver if it isn't loaded
/// </summary>
/// <param name="path">Path to the driver file</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS EnsureLoaded( const std::wstring& path = L"" );
/// <summary>
/// Reload driver
/// </summary>
/// <param name="path">Path to the driver file</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS Reload( std::wstring path = L"" );
/// <summary>
/// Unload driver
/// </summary>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS Unload();
/// <summary>
/// Disable DEP for process
/// Has no effect on native x64 processes
/// </summary>
/// <param name="pid">Target PID</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS DisableDEP( DWORD pid );
/// <summary>
/// Change process protection flag
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="protection">Process protection policy</param>
/// <param name="dynamicCode">Prohibit dynamic code</param>
/// <param name="binarySignature">Prohibit loading non-microsoft dlls</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS ProtectProcess(
DWORD pid,
PolicyOpt protection,
PolicyOpt dynamicCode = Policy_Keep,
PolicyOpt binarySignature = Policy_Keep
);
/// <summary>
/// Change handle access rights
/// </summary>
/// <param name="pid">Target PID.</param>
/// <param name="handle">Handle</param>
/// <param name="access">New access</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS PromoteHandle( DWORD pid, HANDLE handle, DWORD access );
/// <summary>
/// Allocate virtual memory
/// </summary>
/// <param name="pid">Tarhet PID</param>
/// <param name="base">Desired base. If 0 address is chosed by the system</param>
/// <param name="size">Region size</param>
/// <param name="type">Allocation type - MEM_RESERVE/MEM_COMMIT</param>
/// <param name="protection">Memory protection</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS AllocateMem( DWORD pid, ptr_t& base, ptr_t& size, DWORD type, DWORD protection, bool physical = false );
/// <summary>
/// Free virtual memory
/// </summary>
/// <param name="pid">Tarhet PID</param>
/// <param name="base">Desired base. If 0 address is chosed by the system</param>
/// <param name="size">Region size</param>
/// <param name="type">Free type - MEM_RELEASE/MEM_DECOMMIT</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS FreeMem( DWORD pid, ptr_t base, ptr_t size, DWORD type );
/// <summary>
/// Read process memory
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="base">Target base</param>
/// <param name="size">Data size</param>
/// <param name="buffer">Buffer address</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS ReadMem( DWORD pid, ptr_t base, ptr_t size, PVOID buffer );
/// <summary>
/// Write process memory
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="base">Target base</param>
/// <param name="size">Data size</param>
/// <param name="buffer">Buffer address</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS WriteMem( DWORD pid, ptr_t base, ptr_t size, PVOID buffer );
/// <summary>
/// Change memory protection
/// </summary>
/// <param name="pid">Target PID.</param>
/// <param name="base">Regiod base address</param>
/// <param name="size">Region size</param>
/// <param name="protection">New protection</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS ProtectMem( DWORD pid, ptr_t base, ptr_t size, DWORD protection );
/// <summary>
/// Maps target process memory into current process
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="pipeName">Pipe name to use for hook data transfer</param>
/// <param name="mapSections">The map sections.</param>
/// <param name="result">Results</param>
/// <returns>Status code </returns>
BLACKBONE_API NTSTATUS MapMemory( DWORD pid, const std::wstring& pipeName, bool mapSections, MapMemoryResult& result );
/// <summary>
/// Maps single memory region into current process
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="base">Region base address</param>
/// <param name="size">Region size</param>
/// <param name="result">Mapped region info</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS MapMemoryRegion( DWORD pid, ptr_t base, uint32_t size, MapMemoryRegionResult& result );
/// <summary>
/// Unmap memory of the target process from current
/// </summary>
/// <param name="pid">Target PID</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS UnmapMemory( DWORD pid );
/// <summary>
/// Unmap single memory region
/// If unmapped region size is smaller than the size specified during map, function will return info about
/// 2 regions that emerged after unmap
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="base">Region base</param>
/// <param name="size">Region size</param>
/// <param name="result">Unampped region info</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS UnmapMemoryRegion( DWORD pid, ptr_t base, uint32_t size );
/// <summary>
/// Inject DLL into arbitrary process
/// </summary>
/// <param name="pid">Target PID.</param>
/// <param name="path">Full qualified dll path.</param>
/// <param name="itype">Injection type</param>
/// <param name="initRVA">Init routine RVA</param>
/// <param name="initArg">Init routine argument</param>
/// <param name="unlink">Unlink module after injection</param>
/// <param name="erasePE">Erase PE headers after injection</param>
/// <param name="wait">Wait for injection</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS InjectDll(
DWORD pid,
const std::wstring& path,
InjectType itype,
uint32_t initRVA = 0,
const std::wstring& initArg = L"",
bool unlink = false,
bool erasePE = false,
bool wait = true
);
/// <summary>
/// Manually map PE image
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="path">Full qualified image path</param>
/// <param name="flags">Mapping flags</param>
/// <param name="initRVA">Init routine RVA</param>
/// <param name="initArg">Init routine argument</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS MmapDll(
DWORD pid,
const std::wstring& path,
KMmapFlags flags,
uint32_t initRVA = 0,
const std::wstring& initArg = L""
);
/// <summary>
/// Manually map PE image
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="address">Memory location of the image to map</param>
/// <param name="size">Image size</param>
/// <param name="asImage">Memory chunk has image layout</param>
/// <param name="flags">Mapping flags</param>
/// <param name="initRVA">Init routine RVA</param>
/// <param name="initArg">Init routine argument</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS MmapDll(
DWORD pid,
void* address,
uint32_t size,
bool asImage,
KMmapFlags flags,
uint32_t initRVA = 0,
const std::wstring& initArg = L""
);
/// <summary>
/// Manually map another system driver into system space
/// </summary>
/// <param name="path">Fully quialified path to the drver</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS MMapDriver( const std::wstring& path );
/// <summary>
/// Make VAD region appear as PAGE_NO_ACESS to NtQueryVirtualMemory
/// </summary>
/// <param name="pid">Target process ID</param>
/// <param name="base">Region base</param>
/// <param name="size">Region size</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS ConcealVAD( DWORD pid, ptr_t base, uint32_t size );
/// <summary>
/// Unlink process handle table from HandleListHead
/// </summary>
/// <param name="pid">Target process ID</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS UnlinkHandleTable( DWORD pid );
/// <summary>
/// Enumerate committed, accessible, non-guarded memory regions
/// </summary>
/// <param name="pid">Target process ID</param>
/// <param name="regions">Found regions</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS EnumMemoryRegions( DWORD pid, std::vector<MEMORY_BASIC_INFORMATION64>& regions );
/// <summary>
/// Check if driver is loaded
/// </summary>
/// <returns></returns>
BLACKBONE_API inline bool loaded() const { return _hDriver.valid(); }
BLACKBONE_API inline NTSTATUS status() const { return _loadStatus; }
private:
DriverControl( const DriverControl& ) = delete;
DriverControl& operator = (const DriverControl&) = delete;
/// <summary>
/// Load arbitrary driver
/// </summary>
/// <param name="svcName">Driver service name</param>
/// <param name="path">Driver file path</param>
/// <returns>Status</returns>
NTSTATUS LoadDriver( const std::wstring& svcName, const std::wstring& path );
/// <summary>
/// Unload arbitrary driver
/// </summary>
/// <param name="svcName">Driver service name</param>
/// <returns>Status</returns>
NTSTATUS UnloadDriver( const std::wstring& svcName );
/// <summary>
/// Fill minimum driver registry entry
/// </summary>
/// <param name="svcName">Driver service name</param>
/// <param name="path">Driver path</param>
/// <returns>Status code</returns>
LSTATUS PrepareDriverRegEntry( const std::wstring& svcName, const std::wstring& path );
private:
Handle _hDriver;
NTSTATUS _loadStatus = STATUS_NOT_FOUND;
};
// Syntax sugar
inline DriverControl& Driver() { return DriverControl::Instance(); }
}
@@ -0,0 +1,183 @@
#pragma once
#include "Winheaders.h"
//
// Api schema structures
//
//
// Win 10
//
typedef struct _API_SET_VALUE_ENTRY_10
{
ULONG Flags;
ULONG NameOffset;
ULONG NameLength;
ULONG ValueOffset;
ULONG ValueLength;
} API_SET_VALUE_ENTRY_10, *PAPI_SET_VALUE_ENTRY_10;
typedef struct _API_SET_VALUE_ARRAY_10
{
ULONG Flags;
ULONG NameOffset;
ULONG Unk;
ULONG NameLength;
ULONG DataOffset;
ULONG Count;
inline PAPI_SET_VALUE_ENTRY_10 entry( void* pApiSet, DWORD i )
{
return (PAPI_SET_VALUE_ENTRY_10)((BYTE*)pApiSet + DataOffset + i * sizeof( API_SET_VALUE_ENTRY_10 ));
}
} API_SET_VALUE_ARRAY_10, *PAPI_SET_VALUE_ARRAY_10;
typedef struct _API_SET_NAMESPACE_ENTRY_10
{
ULONG Limit;
ULONG Size;
} API_SET_NAMESPACE_ENTRY_10, *PAPI_SET_NAMESPACE_ENTRY_10;
typedef struct _API_SET_NAMESPACE_ARRAY_10
{
ULONG Version;
ULONG Size;
ULONG Flags;
ULONG Count;
ULONG Start;
ULONG End;
ULONG Unk[2];
inline PAPI_SET_NAMESPACE_ENTRY_10 entry( DWORD i )
{
return (PAPI_SET_NAMESPACE_ENTRY_10)((BYTE*)this + End + i * sizeof( API_SET_NAMESPACE_ENTRY_10 ));
}
inline PAPI_SET_VALUE_ARRAY_10 valArray( PAPI_SET_NAMESPACE_ENTRY_10 pEntry )
{
return (PAPI_SET_VALUE_ARRAY_10)((BYTE*)this + Start + sizeof( API_SET_VALUE_ARRAY_10 ) * pEntry->Size);
}
inline ULONG apiName( PAPI_SET_NAMESPACE_ENTRY_10 pEntry, wchar_t* output )
{
auto pArray = valArray( pEntry );
memcpy( output, (char*)this + pArray->NameOffset, pArray->NameLength );
return pArray->NameLength;
}
} API_SET_NAMESPACE_ARRAY_10, *PAPI_SET_NAMESPACE_ARRAY_10;
//
// Win 8.1
//
typedef struct _API_SET_VALUE_ENTRY
{
ULONG Flags;
ULONG NameOffset;
ULONG NameLength;
ULONG ValueOffset;
ULONG ValueLength;
} API_SET_VALUE_ENTRY, *PAPI_SET_VALUE_ENTRY;
typedef struct _API_SET_VALUE_ARRAY
{
ULONG Flags;
ULONG Count;
API_SET_VALUE_ENTRY Array[ANYSIZE_ARRAY];
inline PAPI_SET_VALUE_ENTRY entry( void* /*pApiSet*/, DWORD i )
{
return Array + i;
}
} API_SET_VALUE_ARRAY, *PAPI_SET_VALUE_ARRAY;
typedef struct _API_SET_NAMESPACE_ENTRY
{
ULONG Flags;
ULONG NameOffset;
ULONG NameLength;
ULONG AliasOffset;
ULONG AliasLength;
ULONG DataOffset;
} API_SET_NAMESPACE_ENTRY, *PAPI_SET_NAMESPACE_ENTRY;
typedef struct _API_SET_NAMESPACE_ARRAY
{
ULONG Version;
ULONG Size;
ULONG Flags;
ULONG Count;
API_SET_NAMESPACE_ENTRY Array[ANYSIZE_ARRAY];
inline PAPI_SET_NAMESPACE_ENTRY entry( DWORD i )
{
return Array + i;
}
inline PAPI_SET_VALUE_ARRAY valArray( PAPI_SET_NAMESPACE_ENTRY pEntry )
{
return (PAPI_SET_VALUE_ARRAY)((BYTE*)this + pEntry->DataOffset);
}
inline ULONG apiName( PAPI_SET_NAMESPACE_ENTRY pEntry, wchar_t* output )
{
memcpy( output, (char*)this + pEntry->NameOffset, pEntry->NameLength );
return pEntry->NameLength;
}
} API_SET_NAMESPACE_ARRAY, *PAPI_SET_NAMESPACE_ARRAY;
//
// Win 8 and 7
//
typedef struct _API_SET_VALUE_ENTRY_V2
{
ULONG NameOffset;
ULONG NameLength;
ULONG ValueOffset;
ULONG ValueLength;
} API_SET_VALUE_ENTRY_V2, *PAPI_SET_VALUE_ENTRY_V2;
typedef struct _API_SET_VALUE_ARRAY_V2
{
ULONG Count;
API_SET_VALUE_ENTRY_V2 Array[ANYSIZE_ARRAY];
inline PAPI_SET_VALUE_ENTRY_V2 entry( void* /*pApiSet*/, DWORD i )
{
return Array + i;
}
} API_SET_VALUE_ARRAY_V2, *PAPI_SET_VALUE_ARRAY_V2;
typedef struct _API_SET_NAMESPACE_ENTRY_V2
{
ULONG NameOffset;
ULONG NameLength;
ULONG DataOffset; // API_SET_VALUE_ARRAY
} API_SET_NAMESPACE_ENTRY_V2, *PAPI_SET_NAMESPACE_ENTRY_V2;
typedef struct _API_SET_NAMESPACE_ARRAY_V2
{
ULONG Version;
ULONG Count;
API_SET_NAMESPACE_ENTRY_V2 Array[ANYSIZE_ARRAY];
inline PAPI_SET_NAMESPACE_ENTRY_V2 entry( DWORD i )
{
return Array + i;
}
inline PAPI_SET_VALUE_ARRAY_V2 valArray( PAPI_SET_NAMESPACE_ENTRY_V2 pEntry )
{
return (PAPI_SET_VALUE_ARRAY_V2)((BYTE*)this + pEntry->DataOffset);
}
inline ULONG apiName( PAPI_SET_NAMESPACE_ENTRY_V2 pEntry, wchar_t* output )
{
memcpy( output, (char*)this + pEntry->NameOffset, pEntry->NameLength );
return pEntry->NameLength;
}
} API_SET_NAMESPACE_ARRAY_V2, *PAPI_SET_NAMESPACE_ARRAY_V2;
@@ -0,0 +1,99 @@
#pragma once
#if _MSC_VER >= 1910
#include <optional>
#include <cassert>
namespace blackbone
{
/// <summary>
/// Function result or failure status
/// </summary>
template <typename T>
struct call_result_t
{
NTSTATUS status = STATUS_UNSUCCESSFUL; // Execution status
std::optional<T> result_data = std::nullopt; // Returned value
call_result_t() = default;
call_result_t( T result_, NTSTATUS status_ = STATUS_SUCCESS )
: status ( status_ )
, result_data ( std::move( result_ ) )
{
assert( result_data.has_value() );
}
call_result_t( NTSTATUS status_ )
: status ( status_ )
{
assert( status_ != STATUS_SUCCESS );
}
inline bool success() const { return NT_SUCCESS( status ); }
inline T& result() { return result_data.value(); }
inline const T& result() const { return result_data.value(); }
inline T result( const T& def_val ) const { return result_data.value_or( def_val ); }
inline explicit operator bool() const { return NT_SUCCESS( status ); }
inline explicit operator T() const { return result_data.value(); }
inline T* operator ->() { return &result_data.value(); }
inline T& operator *() { return result_data.value(); }
};
}
#else
#include <memory>
#include <cassert>
namespace blackbone
{
/// <summary>
/// Function result or failure status
/// </summary>
template <typename T>
struct call_result_t
{
NTSTATUS status = STATUS_UNSUCCESSFUL; // Execution status
std::unique_ptr<T> result_data; // Returned value
call_result_t() = default;
call_result_t(T result_, NTSTATUS status_ = STATUS_SUCCESS)
: status(status_)
, result_data(std::make_unique<T>(std::move(result_)))
{
assert(result_data.get());
}
call_result_t(NTSTATUS status_)
: status(status_)
{
assert(status_ != STATUS_SUCCESS);
}
private:
inline T* value() {
if (!result_data) {
throw std::logic_error("bad optional access.");
}
return result_data.get();
}
public:
inline bool success() const { return NT_SUCCESS( status ); }
inline T& result() { return *value(); }
inline const T& result() const { return *value(); }
inline T result(const T& def_val) const { return result_data ? *result_data.get() : def_val; }
inline explicit operator bool() const { return NT_SUCCESS( status ); }
inline explicit operator T() const { return *value(); }
inline T* operator ->() { return value(); }
inline T& operator *() { return *value(); }
};
}
#endif
@@ -0,0 +1,297 @@
#pragma once
#include "../Config.h"
#include "NativeStructures.h"
namespace blackbone
{
// NtCreateEvent
typedef NTSTATUS( NTAPI* fnNtCreateEvent )(
OUT PHANDLE EventHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN ULONG EventType,
IN BOOLEAN InitialState
);
// NtOpenEvent
typedef NTSTATUS( NTAPI* fnNtOpenEvent )(
OUT PHANDLE EventHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
// NtQueryVirtualMemory
typedef NTSTATUS( NTAPI* fnNtQueryVirtualMemory )(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN MEMORY_INFORMATION_CLASS MemoryInformationClass,
OUT PVOID MemoryInformation,
IN SIZE_T MemoryInformationLength,
OUT PSIZE_T ReturnLength
);
// NtWow64QueryInformationProcess64
typedef NTSTATUS( NTAPI *fnNtWow64QueryInformationProcess64 )(
IN HANDLE ProcessHandle,
IN ULONG ProcessInformationClass,
OUT PVOID ProcessInformation64,
IN ULONG Length,
OUT PULONG ReturnLength OPTIONAL
);
// NtWow64ReadVirtualMemory64
typedef NTSTATUS( NTAPI *fnNtWow64ReadVirtualMemory64 )(
IN HANDLE ProcessHandle,
IN ULONG64 BaseAddress,
OUT PVOID Buffer,
IN ULONG64 BufferLength,
OUT PULONG64 ReturnLength OPTIONAL
);
// NtWow64WriteVirtualMemory64
using fnNtWow64WriteVirtualMemory64 = fnNtWow64ReadVirtualMemory64;
// NtWow64AllocateVirtualMemory64
typedef NTSTATUS( NTAPI *fnNtWow64AllocateVirtualMemory64 )(
IN HANDLE ProcessHandle,
IN PULONG64 BaseAddress,
IN ULONG64 ZeroBits,
IN PULONG64 Size,
IN ULONG AllocationType,
IN ULONG Protection
);
// NtWow64QueryVirtualMemory64
typedef NTSTATUS( NTAPI *fnNtWow64QueryVirtualMemory64 )(
IN HANDLE ProcessHandle,
IN ULONG64 BaseAddress,
IN DWORD MemoryInformationClass,
OUT PVOID Buffer,
IN ULONG64 Length,
OUT PULONG ResultLength OPTIONAL
);
// RtlDosApplyFileIsolationRedirection_Ustr
typedef NTSTATUS( NTAPI *fnRtlDosApplyFileIsolationRedirection_Ustr )(
IN ULONG Flags,
IN PUNICODE_STRING OriginalName,
IN PUNICODE_STRING Extension,
IN OUT PUNICODE_STRING StaticString,
IN OUT PUNICODE_STRING DynamicString,
IN OUT PUNICODE_STRING *NewName,
IN PULONG NewFlags,
IN PSIZE_T FileNameSize,
IN PSIZE_T RequiredLength
);
// RtlDosPathNameToNtPathName_U
typedef BOOLEAN( NTAPI *fnRtlDosPathNameToNtPathName_U )(
IN PCWSTR DosFileName,
OUT PUNICODE_STRING NtFileName,
OUT OPTIONAL PWSTR *FilePart,
OUT OPTIONAL PVOID RelativeName
);
// RtlHashUnicodeString
typedef NTSTATUS( NTAPI *fnRtlHashUnicodeString )(
IN PCUNICODE_STRING String,
IN BOOLEAN CaseInSensitive,
IN ULONG HashAlgorithm,
OUT PULONG HashValue
);
// RtlRemoteCall
typedef NTSTATUS( NTAPI *fnRtlRemoteCall )(
IN HANDLE Process,
IN HANDLE Thread,
IN PVOID CallSite,
IN ULONG ArgumentCount,
IN PULONG Arguments,
IN BOOLEAN PassContext,
IN BOOLEAN AlreadySuspended
);
// NtCreateThreadEx
typedef NTSTATUS( NTAPI* fnNtCreateThreadEx )(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN DWORD Flags,
IN SIZE_T StackZeroBits,
IN SIZE_T SizeOfStackCommit,
IN SIZE_T SizeOfStackReserve,
OUT LPVOID lpBytesBuffer
);
// NtLockVirtualMemory
typedef NTSTATUS( NTAPI* fnNtLockVirtualMemory )(
IN HANDLE process,
IN OUT PVOID* baseAddress,
IN OUT ULONG* size,
IN ULONG flags
);
// RtlRbInsertNodeEx
typedef int (NTAPI* fnRtlRbInsertNodeEx)(
_RTL_RB_TREE<DWORD_PTR>* Tree,
_RTL_BALANCED_NODE<DWORD_PTR>* Parent,
BOOLEAN Right,
_RTL_BALANCED_NODE<DWORD_PTR> * Node
);
// NtSetInformationProcess
typedef NTSTATUS( NTAPI* fnNtSetInformationProcess )(
IN HANDLE ProcessHandle,
IN PROCESSINFOCLASS ProcessInformationClass,
IN PVOID ProcessInformation,
IN ULONG ProcessInformationLength
);
// NtDuplicateObject
typedef NTSTATUS( NTAPI* fnNtDuplicateObject )(
IN HANDLE SourceProcessHandle,
IN HANDLE SourceHandle,
IN HANDLE TargetProcessHandle,
IN PHANDLE TargetHandle,
IN ACCESS_MASK DesiredAccess,
IN ULONG Attributes,
IN ULONG Options
);
// RtlRbRemoveNode
typedef int (NTAPI* fnRtlRbRemoveNode)(
_RTL_RB_TREE<DWORD_PTR>* Tree,
_RTL_BALANCED_NODE<DWORD_PTR>* Node
);
// RtlUpcaseUnicodeChar
typedef WCHAR( NTAPI *fnRtlUpcaseUnicodeChar )(
WCHAR chr
);
// RtlEncodeSystemPointer
typedef PVOID( NTAPI *fnRtlEncodeSystemPointer )(
IN PVOID Pointer
);
// NtLoadDriver
typedef NTSTATUS( NTAPI* fnNtLoadDriver )(
IN PUNICODE_STRING path
);
// NtUnloadDriver
typedef NTSTATUS( NTAPI* fnNtUnloadDriver )(
IN PUNICODE_STRING path
);
// NtQuerySection
typedef DWORD( NTAPI* fnNtQuerySection )(
HANDLE hSection,
SECTION_INFORMATION_CLASS InfoClass,
PVOID Buffer,
ULONG BufferSize,
PULONG ReturnLength
);
// NtSuspendProcess
typedef NTSTATUS( NTAPI* fnNtSuspendProcess )(
HANDLE ProcessHandle
);
// NtResumeProcess
typedef NTSTATUS( NTAPI* fnNtResumeProcess )(
HANDLE ProcessHandle
);
// RtlCreateActivationContext
typedef NTSTATUS( NTAPI *fnRtlCreateActivationContext )(
IN ULONG Flags,
IN PACTCTXW ActivationContextData,
IN ULONG ExtraBytes,
IN PVOID NotificationRoutine,
IN PVOID NotificationContext,
OUT PVOID* ActCtx
);
// NtQueueApcThread
typedef NTSTATUS( NTAPI* fnNtQueueApcThread )(
IN HANDLE ThreadHandle,
IN PVOID ApcRoutine, /*PKNORMAL_ROUTINE*/
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
);
// RtlQueueApcWow64Thread
using fnRtlQueueApcWow64Thread = fnNtQueueApcThread;
// RtlImageNtHeader
typedef PIMAGE_NT_HEADERS( NTAPI* fnRtlImageNtHeader )(
IN PVOID ModuleAddress
);
// RtlInitUnicodeString
using fnRtlInitUnicodeString = decltype(&RtlInitUnicodeString);
// RtlFreeUnicodeString
using fnRtlFreeUnicodeString = decltype(&RtlFreeUnicodeString);
// NtQuerySystemInformation
using fnNtQuerySystemInformation = decltype(&NtQuerySystemInformation);
// NtQueryInformationProcess
using fnNtQueryInformationProcess = decltype(&NtQueryInformationProcess);
// NtQueryInformationThread
using fnNtQueryInformationThread = decltype(&NtQueryInformationThread);
// NtQueryObject
using fnNtQueryObject = decltype(&NtQueryObject);
//
// GCC compatibility
//
// Wow64GetThreadContext
typedef BOOL( __stdcall* fnWow64GetThreadContext )
(
HANDLE hThread,
PWOW64_CONTEXT lpContext
);
// Wow64SetThreadContext
typedef BOOL( __stdcall* fnWow64SetThreadContext )
(
HANDLE hThread,
const WOW64_CONTEXT *lpContext
);
// Wow64SuspendThread
typedef DWORD( __stdcall* fnWow64SuspendThread )
(
HANDLE hThread
);
// GetProcessDEPPolicy
typedef BOOL( __stdcall* fnGetProcessDEPPolicy )
(
HANDLE hProcess,
LPDWORD lpFlags,
PBOOL lpPermanent
);
// QueryFullProcessImageNameW
typedef BOOL( __stdcall* fnQueryFullProcessImageNameW)
(
HANDLE hProcess,
DWORD dwFlags,
PWSTR lpExeName,
PDWORD lpdwSize
);
}
@@ -0,0 +1,134 @@
#pragma once
#include "Winheaders.h"
#include <memory>
namespace blackbone
{
template<typename T>
struct non_zero
{
static bool call( T handle ) noexcept
{
return intptr_t( handle ) != 0;
}
};
template<typename T>
struct non_negative
{
static bool call( T handle ) noexcept
{
return intptr_t( handle ) > 0;
}
};
template<template<typename> typename wrapped_t, typename T>
struct with_pseudo_t
{
static bool call( T handle ) noexcept
{
if (wrapped_t<T>::call( handle ))
return true;
// Check if it's a pseudo handle
auto h = (HANDLE)(uintptr_t)handle;
return h == GetCurrentProcess() || h == GetCurrentThread();
}
};
template<template<typename> typename wrapped_t>
struct with_pseudo
{
template<typename T>
using type = with_pseudo_t<wrapped_t, T>;
};
/// <summary>
/// Strong exception guarantee
/// </summary>
template<typename handle_t, auto close, template<typename> typename is_valid = non_negative>
class HandleGuard
{
public:
static constexpr handle_t zero_handle = handle_t( 0 );
public:
explicit HandleGuard( handle_t handle = zero_handle ) noexcept
: _handle( handle )
{
}
HandleGuard( HandleGuard&& rhs ) noexcept
: _handle( rhs._handle )
{
rhs._handle = zero_handle;
}
~HandleGuard()
{
if (non_negative<handle_t>::call( _handle ))
close( _handle );
}
HandleGuard( const HandleGuard& ) = delete;
HandleGuard& operator =( const HandleGuard& ) = delete;
HandleGuard& operator =( HandleGuard&& rhs ) noexcept
{
if (std::addressof( rhs ) == this)
return *this;
reset( rhs._handle );
rhs._handle = zero_handle;
return *this;
}
HandleGuard& operator =( handle_t handle ) noexcept
{
reset( handle );
return *this;
}
void reset( handle_t handle = zero_handle ) noexcept
{
if (handle == _handle)
return;
if (non_negative<handle_t>::call( _handle ))
close( _handle );
_handle = handle;
}
handle_t release() noexcept
{
auto tmp = _handle;
_handle = zero_handle;
return tmp;
}
handle_t get() const noexcept { return _handle; }
bool valid() const noexcept { return is_valid<handle_t>::call( _handle ); }
operator handle_t() const noexcept { return _handle; }
explicit operator bool() const noexcept { return valid(); }
handle_t* operator &() noexcept { return &_handle; }
bool operator ==( const HandleGuard& rhs ) const noexcept { return _handle == rhs._handle; }
bool operator <( const HandleGuard& rhs ) const noexcept { return _handle < rhs._handle; }
private:
handle_t _handle;
};
using Handle = HandleGuard<HANDLE, &CloseHandle>;
using ProcessHandle = HandleGuard<HANDLE, &CloseHandle, with_pseudo<non_negative>::type>;
using ACtxHandle = HandleGuard<HANDLE, &ReleaseActCtx>;
using RegHandle = HandleGuard<HKEY, &RegCloseKey>;
using Mapping = HandleGuard<void*, & UnmapViewOfFile, non_zero>;
}
@@ -0,0 +1,138 @@
#pragma once
#include "../Config.h"
#include <stdint.h>
// Architecture-dependent pointer size
#define BlackBoneWordSize sizeof(void*)
// Rebase address
#define MAKE_PTR(T, pRVA, base) (T)((ptr_t)pRVA + (ptr_t)base)
#define REBASE(pRVA, baseOld, baseNew) ((ptr_t)pRVA - (ptr_t)baseOld + (ptr_t)baseNew)
// Field offset info
#define FIELD_OFFSET2(type, field) ((LONG)(LONG_PTR)&(((type)0)->field))
#define GET_FIELD_PTR(entry, field) (uintptr_t)((uint8_t*)entry + FIELD_OFFSET2(decltype(entry), field))
#define CALL_64_86(b, f, ...) (b ? f<uint64_t>(__VA_ARGS__) : f<uint32_t>(__VA_ARGS__))
#define FIELD_PTR_64_86(b, e, t, f) (b ? fieldPtr( e, &t<uint64_t>::f ) : fieldPtr( e, &t<uint32_t>::f ))
#define LODWORD(l) ((uint32_t)(((uint64_t)(l)) & 0xffffffff))
#define HIDWORD(l) ((uint32_t)((((uint64_t)(l)) >> 32) & 0xffffffff))
// Set or reset particular bit
#define SET_BIT(v, b) v |= (1ull << b)
#define RESET_BIT(v, b) v &= ~(1ull << b)
// Register aliases
#ifdef USE64
#define NAX Rax
#define NSP Rsp
#define NIP Rip
#define NDI Rdi
#define BitScanForwardT _BitScanForward64
#define BitScanReverseT _BitScanReverse64
#define BitTestAndSetT _bittestandset64
#define BitTestAndResetT _bittestandreset64
#define SET_JUMP(_src,_dst) *(uintptr_t*)(_src) = 0x25FF; *(uintptr_t*)((_src) + 6) = (uintptr_t)_dst;
#else
#define NAX Eax
#define NSP Esp
#define NIP Eip
#define NDI Edi
#define BitScanForwardT _BitScanForward
#define BitScanReverseT _BitScanReverse
#define BitTestAndSetT _bittestandset
#define BitTestAndResetT _bittestandreset
#define SET_JUMP(_src,_dst) *(uint8_t*)(_src) = 0xE9; *(uintptr_t*)((_src) + 1) = (uintptr_t)(_dst) - (uintptr_t)(_src) - 5
#endif
#define ENUM_OPS(e) \
inline e operator |(e a1, e a2) { \
return static_cast<e>(static_cast<int>(a1) | static_cast<int>(a2)); \
} \
\
inline e operator |= (e& a1, e a2) { \
return a1 = a1 | a2; \
} \
\
inline e operator &(e a1, e a2) { \
return static_cast<e>(static_cast<int>(a1)& static_cast<int>(a2)); \
} \
\
inline e operator &= (e& a1, e a2) { \
return a1 = a1 & a2; \
} \
\
inline e operator ~(e a1) { \
return static_cast<e>(~static_cast<int>(a1)); \
}
template<int s>
struct CompileTimeSizeOf;
// offsetof alternative
template<typename T, typename U>
constexpr size_t offsetOf( U T::*member )
{
return reinterpret_cast<size_t>(&(reinterpret_cast<T*>(nullptr)->*member));
}
template<typename T, typename U>
constexpr uint64_t fieldPtr( uint64_t base, U T::*member )
{
return base + offsetOf( member );
}
// CONTAINING_RECORD alternative
template<typename T, typename U>
constexpr uint64_t structBase( uint64_t ptr, U T::*member )
{
return ptr - offsetOf( member );
}
// Type-unsafe cast.
template<typename _Tgt, typename _Src>
inline _Tgt brutal_cast( const _Src& src )
{
static_assert(sizeof( _Tgt ) == sizeof( _Src ), "Operand size mismatch");
union _u { _Src s; _Tgt t; } u;
u.s = src;
return u.t;
}
// Align value
inline size_t Align( size_t val, size_t alignment )
{
return (val % alignment == 0) ? val : (val / alignment + 1) * alignment;
}
// Offset of 'LastStatus' field in TEB
#define LAST_STATUS_OFS (0x598 + 0x197 * BlackBoneWordSize)
using NTSTATUS = long;
/// <summary>
/// Get last NT status
/// </summary>
/// <returns></returns>
inline NTSTATUS LastNtStatus()
{
return *(NTSTATUS*)((unsigned char*)NtCurrentTeb() + LAST_STATUS_OFS);
}
/// <summary>
/// Set last NT status
/// </summary>
/// <param name="status">The status.</param>
/// <returns></returns>
inline NTSTATUS SetLastNtStatus( NTSTATUS status )
{
return *(NTSTATUS*)((unsigned char*)NtCurrentTeb() + LAST_STATUS_OFS) = status;
}
#define SharedUserData32 ((KUSER_SHARED_DATA* const)0x7FFE0000)
@@ -0,0 +1,65 @@
#pragma once
namespace blackbone
{
enum MEMORY_INFORMATION_CLASS
{
MemoryBasicInformation = 0,
MemoryWorkingSetList,
MemorySectionName,
MemoryBasicVlmInformation,
MemoryWorkingSetExList
};
enum SECTION_INFORMATION_CLASS
{
SectionBasicInformation,
SectionImageInformation
};
enum POOL_TYPE
{
NonPagedPool,
PagedPool,
NonPagedPoolMustSucceed,
DontUseThisType,
NonPagedPoolCacheAligned,
PagedPoolCacheAligned,
NonPagedPoolCacheAlignedMustS
};
//
// Loader related
//
enum _LDR_DDAG_STATE
{
LdrModulesMerged = -5,
LdrModulesInitError = -4,
LdrModulesSnapError = -3,
LdrModulesUnloaded = -2,
LdrModulesUnloading = -1,
LdrModulesPlaceHolder = 0,
LdrModulesMapping = 1,
LdrModulesMapped = 2,
LdrModulesWaitingForDependencies = 3,
LdrModulesSnapping = 4,
LdrModulesSnapped = 5,
LdrModulesCondensed = 6,
LdrModulesReadyToInit = 7,
LdrModulesInitializing = 8,
LdrModulesReadyToRun = 9
};
enum _LDR_DLL_LOAD_REASON
{
LoadReasonStaticDependency = 0,
LoadReasonStaticForwarderDependency = 1,
LoadReasonDynamicForwarderDependency = 2,
LoadReasonDelayloadDependency = 3,
LoadReasonDynamicLoad = 4,
LoadReasonAsImageLoad = 5,
LoadReasonAsDataLoad = 6,
LoadReasonUnknown = -1
};
}
@@ -0,0 +1,818 @@
#pragma once
#include "../Config.h"
#include "NativeEnums.h"
#include "Winheaders.h"
#include <stdint.h>
#include <type_traits>
namespace blackbone
{
template <int n>
using const_int = std::integral_constant<int, n>;
template<typename T>
constexpr bool is32bit = std::is_same_v<T, uint32_t>;
template<typename T, typename T32, typename T64>
using type_32_64 = std::conditional_t<is32bit<T>, T32, T64>;
template<typename T, int v32, int v64>
constexpr int int_32_64 = std::conditional_t<is32bit<T>, const_int<v32>, const_int<v64>>::value;
// nonstandard extension used : nameless struct/union
#pragma warning(disable : 4201)
template <typename T>
struct _LIST_ENTRY_T
{
T Flink;
T Blink;
};
template <typename T>
struct _UNICODE_STRING_T
{
using type = T;
uint16_t Length;
uint16_t MaximumLength;
T Buffer;
};
template <typename T>
struct _NT_TIB_T
{
T ExceptionList;
T StackBase;
T StackLimit;
T SubSystemTib;
T FiberData;
T ArbitraryUserPointer;
T Self;
};
template <typename T>
struct _CLIENT_ID_T
{
T UniqueProcess;
T UniqueThread;
};
template <typename T>
struct _GDI_TEB_BATCH_T
{
uint32_t Offset;
T HDC;
uint32_t Buffer[310];
};
template <typename T>
struct _ACTIVATION_CONTEXT_STACK_T
{
T ActiveFrame;
_LIST_ENTRY_T<T> FrameListCache;
uint32_t Flags;
uint32_t NextCookieSequenceNumber;
uint32_t StackId;
};
template <typename T>
struct _TEB_T
{
struct Specific32_1
{
uint8_t InstrumentationCallbackDisabled;
uint8_t SpareBytes[23];
uint32_t TxFsContext;
};
struct Specific64_1
{
uint32_t TxFsContext;
uint32_t InstrumentationCallbackDisabled;
};
struct Specific64_2
{
T TlsExpansionSlots;
T DeallocationBStore;
T BStoreLimit;
};
struct Specific32_2
{
T TlsExpansionSlots;
};
_NT_TIB_T<T> NtTib;
T EnvironmentPointer;
_CLIENT_ID_T<T> ClientId;
T ActiveRpcHandle;
T ThreadLocalStoragePointer;
T ProcessEnvironmentBlock;
uint32_t LastErrorValue;
uint32_t CountOfOwnedCriticalSections;
T CsrClientThread;
T Win32ThreadInfo;
uint32_t User32Reserved[26];
uint32_t UserReserved[5];
T WOW32Reserved;
uint32_t CurrentLocale;
uint32_t FpSoftwareStatusRegister;
T ReservedForDebuggerInstrumentation[16];
T SystemReserved1[int_32_64<T, 26, 30>];
uint8_t PlaceholderCompatibilityMode;
uint8_t PlaceholderReserved[11];
uint32_t ProxiedProcessId;
_ACTIVATION_CONTEXT_STACK_T<T> ActivationStack;
uint8_t WorkingOnBehalfTicket[8];
uint32_t ExceptionCode;
T ActivationContextStackPointer;
T InstrumentationCallbackSp;
T InstrumentationCallbackPreviousPc;
T InstrumentationCallbackPreviousSp;
type_32_64<T, Specific32_1, Specific64_1> spec1;
_GDI_TEB_BATCH_T<T> GdiTebBatch;
_CLIENT_ID_T<T> RealClientId;
T GdiCachedProcessHandle;
uint32_t GdiClientPID;
uint32_t GdiClientTID;
T GdiThreadLocalInfo;
T Win32ClientInfo[62];
T glDispatchTable[233];
T glReserved1[29];
T glReserved2;
T glSectionInfo;
T glSection;
T glTable;
T glCurrentRC;
T glContext;
uint32_t LastStatusValue;
_UNICODE_STRING_T<T> StaticUnicodeString;
wchar_t StaticUnicodeBuffer[261];
T DeallocationStack;
T TlsSlots[64];
_LIST_ENTRY_T<T> TlsLinks;
T Vdm;
T ReservedForNtRpc;
T DbgSsReserved[2];
uint32_t HardErrorMode;
T Instrumentation[int_32_64<T, 9, 11>];
GUID ActivityId;
T SubProcessTag;
T PerflibData;
T EtwTraceData;
T WinSockData;
uint32_t GdiBatchCount; // TEB64 pointer
uint32_t IdealProcessorValue;
uint32_t GuaranteedStackBytes;
T ReservedForPerf;
T ReservedForOle;
uint32_t WaitingOnLoaderLock;
T SavedPriorityState;
T ReservedForCodeCoverage;
T ThreadPoolData;
type_32_64<T, Specific32_2, Specific64_2> spec2;
uint32_t MuiGeneration;
uint32_t IsImpersonating;
T NlsCache;
T pShimData;
uint16_t HeapVirtualAffinity;
uint16_t LowFragHeapDataSlot;
T CurrentTransactionHandle;
T ActiveFrame;
T FlsData;
T PreferredLanguages;
T UserPrefLanguages;
T MergedPrefLanguages;
uint32_t MuiImpersonation;
uint16_t CrossTebFlags;
union
{
uint16_t SameTebFlags;
struct
{
uint16_t SafeThunkCall : 1;
uint16_t InDebugPrint : 1;
uint16_t HasFiberData : 1;
uint16_t SkipThreadAttach : 1;
uint16_t WerInShipAssertCode : 1;
uint16_t RanProcessInit : 1;
uint16_t ClonedThread : 1;
uint16_t SuppressDebugMsg : 1;
uint16_t DisableUserStackWalk : 1;
uint16_t RtlExceptionAttached : 1;
uint16_t InitialThread : 1;
uint16_t SessionAware : 1;
uint16_t LoadOwner : 1;
uint16_t LoaderWorker : 1;
uint16_t SkipLoaderInit : 1;
uint16_t SpareSameTebBits : 1;
};
};
T TxnScopeEnterCallback;
T TxnScopeExitCallback;
T TxnScopeContext;
uint32_t LockCount;
uint32_t WowTebOffset;
T ResourceRetValue;
T ReservedForWdf;
uint64_t ReservedForCrt;
GUID EffectiveContainerId;
};
template<typename T>
struct _PEB_T
{
static_assert( std::is_same_v<T, uint32_t> || std::is_same_v<T, uint64_t>, "T must be uint32_t or uint64_t" );
uint8_t InheritedAddressSpace;
uint8_t ReadImageFileExecOptions;
uint8_t BeingDebugged;
union
{
uint8_t BitField;
struct
{
uint8_t ImageUsesLargePages : 1;
uint8_t IsProtectedProcess : 1;
uint8_t IsImageDynamicallyRelocated : 1;
uint8_t SkipPatchingUser32Forwarders : 1;
uint8_t IsPackagedProcess : 1;
uint8_t IsAppContainer : 1;
uint8_t IsProtectedProcessLight : 1;
uint8_t SpareBits : 1;
};
};
T Mutant;
T ImageBaseAddress;
T Ldr;
T ProcessParameters;
T SubSystemData;
T ProcessHeap;
T FastPebLock;
T AtlThunkSListPtr;
T IFEOKey;
union
{
T CrossProcessFlags;
struct
{
uint32_t ProcessInJob : 1;
uint32_t ProcessInitializing : 1;
uint32_t ProcessUsingVEH : 1;
uint32_t ProcessUsingVCH : 1;
uint32_t ProcessUsingFTH : 1;
uint32_t ReservedBits0 : 27;
};
};
union
{
T KernelCallbackTable;
T UserSharedInfoPtr;
};
uint32_t SystemReserved;
uint32_t AtlThunkSListPtr32;
T ApiSetMap;
union
{
uint32_t TlsExpansionCounter;
T Padding2;
};
T TlsBitmap;
uint32_t TlsBitmapBits[2];
T ReadOnlySharedMemoryBase;
T SparePvoid0;
T ReadOnlyStaticServerData;
T AnsiCodePageData;
T OemCodePageData;
T UnicodeCaseTableData;
uint32_t NumberOfProcessors;
uint32_t NtGlobalFlag;
LARGE_INTEGER CriticalSectionTimeout;
T HeapSegmentReserve;
T HeapSegmentCommit;
T HeapDeCommitTotalFreeThreshold;
T HeapDeCommitFreeBlockThreshold;
uint32_t NumberOfHeaps;
uint32_t MaximumNumberOfHeaps;
T ProcessHeaps;
T GdiSharedHandleTable;
T ProcessStarterHelper;
union
{
uint32_t GdiDCAttributeList;
T Padding3;
};
T LoaderLock;
uint32_t OSMajorVersion;
uint32_t OSMinorVersion;
uint16_t OSBuildNumber;
uint16_t OSCSDVersion;
uint32_t OSPlatformId;
uint32_t ImageSubsystem;
uint32_t ImageSubsystemMajorVersion;
union
{
uint32_t ImageSubsystemMinorVersion;
T Padding4;
};
T ActiveProcessAffinityMask;
uint32_t GdiHandleBuffer[int_32_64<T, 34, 60>];
T PostProcessInitRoutine;
T TlsExpansionBitmap;
uint32_t TlsExpansionBitmapBits[32];
union
{
uint32_t SessionId;
T Padding5;
};
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
T pShimData;
T AppCompatInfo;
_UNICODE_STRING_T<T> CSDVersion;
T ActivationContextData;
T ProcessAssemblyStorageMap;
T SystemDefaultActivationContextData;
T SystemAssemblyStorageMap;
T MinimumStackCommit;
T FlsCallback;
_LIST_ENTRY_T<T> FlsListHead;
T FlsBitmap;
uint32_t FlsBitmapBits[4];
uint32_t FlsHighIndex;
T WerRegistrationData;
T WerShipAssertPtr;
T pUnused;
T pImageHeaderHash;
union
{
uint64_t TracingFlags;
struct
{
uint32_t HeapTracingEnabled : 1;
uint32_t CritSecTracingEnabled : 1;
uint32_t LibLoaderTracingEnabled : 1;
uint32_t SpareTracingBits : 29;
};
};
T CsrServerReadOnlySharedMemoryBase;
};
#pragma warning(default : 4201)
template<typename T>
struct _ACTCTXW_T
{
uint32_t cbSize;
uint32_t dwFlags;
T lpSource;
uint16_t wProcessorArchitecture;
LANGID wLangId;
T lpAssemblyDirectory;
T lpResourceName;
T lpApplicationName;
T hModule;
};
template<typename T>
struct _PROCESS_BASIC_INFORMATION_T
{
NTSTATUS ExitStatus;
uint32_t Reserved0;
T PebBaseAddress;
T AffinityMask;
LONG BasePriority;
ULONG Reserved1;
T uUniqueProcessId;
T uInheritedFromUniqueProcessId;
};
template<typename T>
struct _SECTION_BASIC_INFORMATION_T
{
T Base;
uint32_t Attributes;
LARGE_INTEGER Size;
};
template<typename T>
struct _PROCESS_EXTENDED_BASIC_INFORMATION_T
{
T Size; // Must be set to structure size on input
_PROCESS_BASIC_INFORMATION_T<T> BasicInfo;
struct
{
uint32_t IsProtectedProcess : 1;
uint32_t IsWow64Process : 1;
uint32_t IsProcessDeleting : 1;
uint32_t IsCrossSessionCreate : 1;
uint32_t IsFrozen : 1;
uint32_t IsBackground : 1;
uint32_t IsStronglyNamed : 1;
uint32_t SpareBits : 25;
}Flags;
};
template<typename T>
struct _THREAD_BASIC_INFORMATION_T
{
NTSTATUS ExitStatus;
T TebBaseAddress;
_CLIENT_ID_T<T> ClientID;
T AffinityMask;
LONG Priority;
LONG BasePriority;
};
template<typename T>
struct _VM_COUNTERS_T
{
T PeakVirtualSize;
T VirtualSize;
uint32_t PageFaultCount;
T PeakWorkingSetSize;
T WorkingSetSize;
T QuotaPeakPagedPoolUsage;
T QuotaPagedPoolUsage;
T QuotaPeakNonPagedPoolUsage;
T QuotaNonPagedPoolUsage;
T PagefileUsage;
T PeakPagefileUsage;
};
template<typename T>
struct _SYSTEM_THREAD_INFORMATION_T
{
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER CreateTime;
uint32_t WaitTime;
T StartAddress;
_CLIENT_ID_T<T> ClientId;
LONG Priority;
LONG BasePriority;
uint32_t ContextSwitches;
uint32_t ThreadState;
uint32_t WaitReason;
};
template<typename T>
struct _SYSTEM_EXTENDED_THREAD_INFORMATION_T
{
_SYSTEM_THREAD_INFORMATION_T<T> ThreadInfo;
T StackBase;
T StackLimit;
T Win32StartAddress;
T TebBase;
T Reserved[3];
};
template<typename T>
struct _SYSTEM_PROCESS_INFORMATION_T
{
uint32_t NextEntryOffset;
uint32_t NumberOfThreads;
LARGE_INTEGER WorkingSetPrivateSize;
uint32_t HardFaultCount;
uint32_t NumberOfThreadsHighWatermark;
ULONGLONG CycleTime;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
_UNICODE_STRING_T<T> ImageName;
LONG BasePriority;
T UniqueProcessId;
T InheritedFromUniqueProcessId;
uint32_t HandleCount;
uint32_t SessionId;
T UniqueProcessKey;
_VM_COUNTERS_T<T> VmCounters;
T PrivatePageCount;
IO_COUNTERS IoCounters;
_SYSTEM_EXTENDED_THREAD_INFORMATION_T<T> Threads[1];
};
template<typename T>
struct _SYSTEM_HANDLE_T
{
uint32_t ProcessId;
uint8_t ObjectTypeNumber;
uint8_t Flags;
uint16_t Handle;
T Object;
ACCESS_MASK GrantedAccess;
};
template<typename T>
struct _SYSTEM_HANDLE_INFORMATION_T
{
uint32_t HandleCount;
_SYSTEM_HANDLE_T<T> Handles[1];
};
template<typename T>
struct _OBJECT_TYPE_INFORMATION_T
{
_UNICODE_STRING_T<T> Name;
uint32_t TotalNumberOfObjects;
uint32_t TotalNumberOfHandles;
uint32_t TotalPagedPoolUsage;
uint32_t TotalNonPagedPoolUsage;
uint32_t TotalNamePoolUsage;
uint32_t TotalHandleTableUsage;
uint32_t HighWaterNumberOfObjects;
uint32_t HighWaterNumberOfHandles;
uint32_t HighWaterPagedPoolUsage;
uint32_t HighWaterNonPagedPoolUsage;
uint32_t HighWaterNamePoolUsage;
uint32_t HighWaterHandleTableUsage;
uint32_t InvalidAttributes;
GENERIC_MAPPING GenericMapping;
uint32_t ValidAccess;
BOOLEAN SecurityRequired;
BOOLEAN MaintainHandleCount;
uint16_t MaintainTypeList;
POOL_TYPE PoolType;
uint32_t PagedPoolUsage;
uint32_t NonPagedPoolUsage;
};
template<typename T>
struct _OBJECT_ATTRIBUTES_T
{
uint32_t Length;
T RootDirectory;
T ObjectName;
uint32_t Attributes;
T SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR
T SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE
};
struct _XSAVE_FORMAT64
{
uint16_t ControlWord;
uint16_t StatusWord;
uint8_t TagWord;
uint8_t Reserved1;
uint16_t ErrorOpcode;
uint32_t ErrorOffset;
uint16_t ErrorSelector;
uint16_t Reserved2;
uint32_t DataOffset;
uint16_t DataSelector;
uint16_t Reserved3;
uint32_t MxCsr;
uint32_t MxCsr_Mask;
_M128A FloatRegisters[8];
_M128A XmmRegisters[16];
uint8_t Reserved4[96];
};
template<typename T>
struct _CONTEXT_T;
template<>
struct _CONTEXT_T<uint32_t>
{
uint32_t ContextFlags;
uint32_t Dr0;
uint32_t Dr1;
uint32_t Dr2;
uint32_t Dr3;
uint32_t Dr6;
uint32_t Dr7;
WOW64_FLOATING_SAVE_AREA FloatSave;
uint32_t SegGs;
uint32_t SegFs;
uint32_t SegEs;
uint32_t SegDs;
uint32_t Edi;
uint32_t Esi;
uint32_t Ebx;
uint32_t Edx;
uint32_t Ecx;
uint32_t Eax;
uint32_t Ebp;
uint32_t Eip;
uint32_t SegCs; // MUST BE SANITIZED
uint32_t EFlags; // MUST BE SANITIZED
uint32_t Esp;
uint32_t SegSs;
uint8_t ExtendedRegisters[WOW64_MAXIMUM_SUPPORTED_EXTENSION];
};
template<>
struct _CONTEXT_T<uint64_t>
{
uint64_t P1Home;
uint64_t P2Home;
uint64_t P3Home;
uint64_t P4Home;
uint64_t P5Home;
uint64_t P6Home;
uint32_t ContextFlags;
uint32_t MxCsr;
uint16_t SegCs;
uint16_t SegDs;
uint16_t SegEs;
uint16_t SegFs;
uint16_t SegGs;
uint16_t SegSs;
uint32_t EFlags;
uint64_t Dr0;
uint64_t Dr1;
uint64_t Dr2;
uint64_t Dr3;
uint64_t Dr6;
uint64_t Dr7;
uint64_t Rax;
uint64_t Rcx;
uint64_t Rdx;
uint64_t Rbx;
uint64_t Rsp;
uint64_t Rbp;
uint64_t Rsi;
uint64_t Rdi;
uint64_t R8;
uint64_t R9;
uint64_t R10;
uint64_t R11;
uint64_t R12;
uint64_t R13;
uint64_t R14;
uint64_t R15;
uint64_t Rip;
_XSAVE_FORMAT64 FltSave;
_M128A Header[2];
_M128A Legacy[8];
_M128A Xmm0;
_M128A Xmm1;
_M128A Xmm2;
_M128A Xmm3;
_M128A Xmm4;
_M128A Xmm5;
_M128A Xmm6;
_M128A Xmm7;
_M128A Xmm8;
_M128A Xmm9;
_M128A Xmm10;
_M128A Xmm11;
_M128A Xmm12;
_M128A Xmm13;
_M128A Xmm14;
_M128A Xmm15;
_M128A VectorRegister[26];
uint64_t VectorControl;
uint64_t DebugControl;
uint64_t LastBranchToRip;
uint64_t LastBranchFromRip;
uint64_t LastExceptionToRip;
uint64_t LastExceptionFromRip;
_CONTEXT_T<uint64_t>& FromCtx32( const _CONTEXT_T<uint32_t>& ctx32 )
{
ContextFlags = ctx32.ContextFlags;
Dr0 = ctx32.Dr0;
Dr1 = ctx32.Dr1;
Dr2 = ctx32.Dr2;
Dr3 = ctx32.Dr3;
Dr6 = ctx32.Dr6;
Dr7 = ctx32.Dr7;
SegGs = static_cast<uint16_t>(ctx32.SegGs);
SegFs = static_cast<uint16_t>(ctx32.SegFs);
SegEs = static_cast<uint16_t>(ctx32.SegEs);
SegDs = static_cast<uint16_t>(ctx32.SegDs);
SegCs = static_cast<uint16_t>(ctx32.SegCs);
SegSs = static_cast<uint16_t>(ctx32.SegSs);
Rdi = ctx32.Edi;
Rsi = ctx32.Esi;
Rbx = ctx32.Ebx;
Rdx = ctx32.Edx;
Rcx = ctx32.Ecx;
Rax = ctx32.Eax;
Rbp = ctx32.Ebp;
Rip = ctx32.Eip;
Rsp = ctx32.Esp;
EFlags = ctx32.EFlags;
return *this;
}
};
#ifndef CONTEXT_AMD64
#define CONTEXT_AMD64 0x100000
#endif
#define CONTEXT64_CONTROL (CONTEXT_AMD64 | 0x1L)
#define CONTEXT64_INTEGER (CONTEXT_AMD64 | 0x2L)
#define CONTEXT64_SEGMENTS (CONTEXT_AMD64 | 0x4L)
#define CONTEXT64_FLOATING_POINT (CONTEXT_AMD64 | 0x8L)
#define CONTEXT64_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L)
#define CONTEXT64_FULL (CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_FLOATING_POINT)
#define CONTEXT64_ALL (CONTEXT64_CONTROL | CONTEXT64_INTEGER | CONTEXT64_SEGMENTS | CONTEXT64_FLOATING_POINT | CONTEXT64_DEBUG_REGISTERS)
#define CONTEXT64_XSTATE (CONTEXT_AMD64 | 0x20L)
template<typename T>
struct _PEB_LDR_DATA2_T
{
uint32_t Length;
uint8_t Initialized;
T SsHandle;
_LIST_ENTRY_T<T> InLoadOrderModuleList;
_LIST_ENTRY_T<T> InMemoryOrderModuleList;
_LIST_ENTRY_T<T> InInitializationOrderModuleList;
T EntryInProgress;
uint8_t ShutdownInProgress;
T ShutdownThreadId;
};
template<typename T>
struct _LDR_DATA_TABLE_ENTRY_BASE_T
{
_LIST_ENTRY_T<T> InLoadOrderLinks;
_LIST_ENTRY_T<T> InMemoryOrderLinks;
_LIST_ENTRY_T<T> InInitializationOrderLinks;
T DllBase;
T EntryPoint;
uint32_t SizeOfImage;
_UNICODE_STRING_T<T> FullDllName;
_UNICODE_STRING_T<T> BaseDllName;
uint32_t Flags;
uint16_t LoadCount;
uint16_t TlsIndex;
_LIST_ENTRY_T<T> HashLinks;
uint32_t TimeDateStamp;
T EntryPointActivationContext;
T PatchInformation;
};
template<typename T>
struct _RTL_INVERTED_FUNCTION_TABLE_ENTRY
{
T ExceptionDirectory; // PIMAGE_RUNTIME_FUNCTION_ENTRY
T ImageBase;
uint32_t ImageSize;
uint32_t SizeOfTable;
};
using _UNICODE_STRING32 = _UNICODE_STRING_T<uint32_t>;
using _UNICODE_STRING64 = _UNICODE_STRING_T<uint64_t>;
using UNICODE_STRING_T = _UNICODE_STRING_T<uintptr_t>;
using _PEB32 = _PEB_T<uint32_t>;
using _PEB64 = _PEB_T<uint64_t>;
using PEB_T = _PEB_T<uintptr_t>;
using _TEB32 = _TEB_T<uint32_t>;
using _TEB64 = _TEB_T<uint64_t>;
using TEB_T = _TEB_T<uintptr_t>;
using _PEB_LDR_DATA232 = _PEB_LDR_DATA2_T<uint32_t>;
using _PEB_LDR_DATA264 = _PEB_LDR_DATA2_T<uint64_t>;
using PEB_LDR_DATA_T = _PEB_LDR_DATA2_T<uintptr_t>;
using _LDR_DATA_TABLE_ENTRY_BASE32 = _LDR_DATA_TABLE_ENTRY_BASE_T<uint32_t>;
using _LDR_DATA_TABLE_ENTRY_BASE64 = _LDR_DATA_TABLE_ENTRY_BASE_T<uint64_t>;
using LDR_DATA_TABLE_ENTRY_BASE_T = _LDR_DATA_TABLE_ENTRY_BASE_T<uintptr_t>;
using _CONTEXT32 = _CONTEXT_T<uint32_t>;
using _CONTEXT64 = _CONTEXT_T<uint64_t>;
using CONTEXT_T = _CONTEXT_T<uintptr_t>;
using _SECTION_BASIC_INFORMATION32 = _SECTION_BASIC_INFORMATION_T<uint32_t>;
using _SECTION_BASIC_INFORMATION64 = _SECTION_BASIC_INFORMATION_T<uint64_t>;
using SECTION_BASIC_INFORMATION_T = _SECTION_BASIC_INFORMATION_T<uintptr_t>;
using _SYSTEM_HANDLE_INFORMATION32 = _SYSTEM_HANDLE_INFORMATION_T<uint32_t>;
using _SYSTEM_HANDLE_INFORMATION64 = _SYSTEM_HANDLE_INFORMATION_T<uint64_t>;
using SYSTEM_HANDLE_INFORMATION_T = _SYSTEM_HANDLE_INFORMATION_T<uintptr_t>;
using _OBJECT_TYPE_INFORMATION32 = _OBJECT_TYPE_INFORMATION_T<uint32_t>;
using _OBJECT_TYPE_INFORMATION64 = _OBJECT_TYPE_INFORMATION_T<uint64_t>;
using OBJECT_TYPE_INFORMATION_T = _OBJECT_TYPE_INFORMATION_T<uintptr_t>;
using _OBJECT_ATTRIBUTES32 = _OBJECT_ATTRIBUTES_T<uint32_t>;
using _OBJECT_ATTRIBUTES64 = _OBJECT_ATTRIBUTES_T<uint64_t>;
using OBJECT_ATTRIBUTES_T = _OBJECT_ATTRIBUTES_T<uintptr_t>;
using _ACTCTXW32 = _ACTCTXW_T<uint32_t>;
using _ACTCTXW64 = _ACTCTXW_T<uint64_t>;
using ACTCTXW_T = _ACTCTXW_T<uintptr_t>;
}
#include "ApiSet.h"
// OS specific structures
#include "Win7Specific.h"
#include "Win8Specific.h"
#ifdef XP_BUILD
#include "WinXPSpecific.h"
#endif
@@ -0,0 +1,84 @@
#pragma once
#include "NativeStructures.h"
#include "FunctionTypes.h"
#include <stdint.h>
#include <string>
#include <memory>
namespace blackbone
{
using ptr_t = uint64_t; // Generic pointer in remote process
using module_t = ptr_t; // Module base pointer
// Type of barrier
enum eBarrier
{
wow_32_32 = 0, // Both processes are WoW64
wow_64_64, // Both processes are x64
wow_32_64, // Managing x64 process from WoW64 process
wow_64_32, // Managing WOW64 process from x64 process
};
struct Wow64Barrier
{
eBarrier type = wow_32_32;
bool sourceWow64 = false;
bool targetWow64 = false;
bool x86OS = false;
bool mismatch = false;
};
// Module type
enum eModType
{
mt_mod32, // 32 bit module
mt_mod64, // 64 bit module
mt_default, // type is deduced from target process
mt_unknown // Failed to detect type
};
// Module search method
enum eModSeachType
{
LdrList, // InLoadOrder list
Sections, // Scan for section objects
PEHeaders, // Scan for PE headers in memory
};
// Switch created wow64 thread to long mode
enum eThreadModeSwitch
{
NoSwitch, // Never switch
ForceSwitch, // Always switch
AutoSwitch // Switch depending on wow64 barrier
};
// Module info
struct ModuleData
{
module_t baseAddress; // Base image address
std::wstring name; // File name
std::wstring fullPath; // Full file path
uint32_t size; // Size of image
eModType type; // Module type
ptr_t ldrPtr; // LDR_DATA_TABLE_ENTRY_BASE_T address
bool manual; // Image is manually mapped
bool operator ==(const ModuleData& other) const
{
return (baseAddress == other.baseAddress);
}
bool operator <(const ModuleData& other)
{
return baseAddress < other.baseAddress;
}
};
using ModuleDataPtr = std::shared_ptr<const ModuleData>;
}
@@ -0,0 +1,27 @@
#pragma once
#include "Winheaders.h"
namespace blackbone
{
template<typename T>
struct _LDR_DATA_TABLE_ENTRY_W7 : _LDR_DATA_TABLE_ENTRY_BASE_T<T>
{
_LIST_ENTRY_T<T> ForwarderLinks;
_LIST_ENTRY_T<T> ServiceTagLinks;
_LIST_ENTRY_T<T> StaticLinks;
T ContextInformation;
uint32_t OriginalBase;
LARGE_INTEGER LoadTime;
};
template<typename T>
struct _RTL_INVERTED_FUNCTION_TABLE7
{
uint32_t Count;
uint32_t MaxCount;
uint32_t Epoch;
_RTL_INVERTED_FUNCTION_TABLE_ENTRY<T> Entries[0x200];
};
}
@@ -0,0 +1,74 @@
#pragma once
#include "Winheaders.h"
namespace blackbone
{
template<typename T>
struct _RTL_RB_TREE
{
T Root;
T Min;
};
template<typename T>
struct _RTL_BALANCED_NODE
{
T Left;
T Right;
T ParentValue;
};
template<typename T>
struct _LDR_DDAG_NODE
{
_LIST_ENTRY_T<T> Modules;
T ServiceTagList;
uint32_t LoadCount;
uint32_t ReferenceCount;
uint32_t DependencyCount;
T RemovalLink;
T IncomingDependencies;
_LDR_DDAG_STATE State;
T CondenseLink;
uint32_t PreorderNumber;
uint32_t LowestLink;
};
template<typename T>
struct _LDR_DATA_TABLE_ENTRY_W8 : _LDR_DATA_TABLE_ENTRY_BASE_T<T>
{
T DdagNode; // _LDR_DDAG_NODE*
_LIST_ENTRY_T<T> NodeModuleLink;
T SnapContext;
T ParentDllBase;
T SwitchBackContext;
_RTL_BALANCED_NODE<T> BaseAddressIndexNode;
_RTL_BALANCED_NODE<T> MappingInfoIndexNode;
T OriginalBase;
LARGE_INTEGER LoadTime;
uint32_t BaseNameHashValue;
_LDR_DLL_LOAD_REASON LoadReason;
uint32_t ImplicitPathOptions;
};
template<typename T>
struct _RTL_INVERTED_FUNCTION_TABLE8
{
ULONG Count;
ULONG MaxCount;
ULONG Epoch;
UCHAR Overflow;
_RTL_INVERTED_FUNCTION_TABLE_ENTRY<T> Entries[0x200];
};
using _LDR_DATA_TABLE_ENTRY_W832 = _LDR_DATA_TABLE_ENTRY_W8<uint32_t>;
using _LDR_DATA_TABLE_ENTRY_W864 = _LDR_DATA_TABLE_ENTRY_W8<uint64_t>;
using LDR_DATA_TABLE_ENTRY_W8T = _LDR_DATA_TABLE_ENTRY_W8<uintptr_t>;
using _LDR_DDAG_NODE_32 = _LDR_DDAG_NODE<uint32_t>;
using _LDR_DDAG_NODE_64 = _LDR_DDAG_NODE<uint64_t>;
using LDR_DDAG_NODE_T = _LDR_DDAG_NODE<uintptr_t>;
}
@@ -0,0 +1,37 @@
#pragma once
#include "Winheaders.h"
namespace blackbone
{
#pragma warning(push)
#pragma warning(disable : 4201)
typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR
{
union
{
DWORD AllAttributes;
struct {
DWORD RvaBased : 1; // Delay load version 2
DWORD ReservedAttributes : 31;
};
} 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;
#pragma warning(pop)
typedef struct _EXCEPTION_REGISTRATION_RECORD
{
_EXCEPTION_REGISTRATION_RECORD *Next;
PEXCEPTION_ROUTINE Handler;
} EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;
}
@@ -0,0 +1,16 @@
#pragma once
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <winternl.h>
#include <winioctl.h>
#include <TlHelp32.h>
#include <Shlwapi.h>
#pragma warning(push)
#pragma warning(disable : 4005)
#include <ntstatus.h>
#pragma warning(pop)
@@ -0,0 +1,69 @@
#pragma once
namespace blackbone
{
template<typename R, typename... Args, class C>
struct HookHandler<R( __cdecl* )(Args...), C> : public DetourBase
{
using ReturnType = std::conditional_t<std::is_same_v<R, void>, int, R>;
using type = R( __cdecl* )(Args...);
using hktype = R( __cdecl* )(Args&...);
using hktypeC = R( C::* )(Args&...);
//
// Workaround for void return type
//
using typeR = ReturnType( __cdecl* )(Args...);
using hktypeR = ReturnType( __cdecl* )(Args&...);
using hktypeCR = ReturnType( C::* )(Args&...);
static __declspec(noinline) ReturnType __cdecl Handler( Args... args )
{
HookHandler* pInst = (HookHandler*)((_NT_TIB*)NtCurrentTeb())->ArbitraryUserPointer;
return pInst->HandlerP( std::forward<Args>( args )... );
}
ReturnType HandlerP( Args&&... args )
{
ReturnType val_new, val_original;
DisableHook();
if (_order == CallOrder::HookFirst)
{
val_new = CallCallback( std::forward<Args>( args )... );
val_original = CallOriginal( std::forward<Args>( args )... );
}
else if (_order == CallOrder::HookLast)
{
val_original = CallOriginal( std::forward<Args>( args )... );
val_new = CallCallback( std::forward<Args>( args )... );
}
else
{
val_original = val_new = CallCallback( std::forward<Args>( args )... );
}
if (this->_hooked)
EnableHook();
return (_retType == ReturnMethod::UseOriginal ? val_original : val_new);
}
inline ReturnType CallOriginal( Args&&... args )
{
return (reinterpret_cast<typeR>(_callOriginal))(args...);
}
inline ReturnType CallCallback( Args&&... args )
{
if (_callbackClass != nullptr)
return (reinterpret_cast<C*>(_callbackClass)->*brutal_cast<hktypeCR>(_callback))(args...);
else
return (reinterpret_cast<hktypeR>(_callback))(args...);
}
};
}
@@ -0,0 +1,69 @@
#pragma once
namespace blackbone
{
template<typename R, typename... Args, class C>
struct HookHandler<R( __fastcall* )(Args...), C> : public DetourBase
{
using ReturnType = std::conditional_t<std::is_same_v<R, void>, int, R>;
using type = R( __fastcall* )(Args...);
using hktype = R( __fastcall* )(Args&...);
using hktypeC = R( C::* )(Args&...);
//
// Workaround for void return type
//
using typeR = ReturnType( __fastcall* )(Args...);
using hktypeR = ReturnType( __fastcall* )(Args&...);
using hktypeCR = ReturnType( C::* )(Args&...);
static __declspec(noinline) ReturnType __fastcall Handler( Args... args )
{
HookHandler* pInst = (HookHandler*)((_NT_TIB*)NtCurrentTeb())->ArbitraryUserPointer;
return pInst->HandlerP( std::forward<Args>( args )... );
}
ReturnType HandlerP( Args&&... args )
{
ReturnType val_new, val_original;
DisableHook();
if (_order == CallOrder::HookFirst)
{
val_new = CallCallback( std::forward<Args>( args )... );
val_original = CallOriginal( std::forward<Args>( args )... );
}
else if (_order == CallOrder::HookLast)
{
val_original = CallOriginal( std::forward<Args>( args )... );
val_new = CallCallback( std::forward<Args>( args )... );
}
else
{
val_original = val_new = CallCallback( std::forward<Args>( args )... );
}
if (this->_hooked)
EnableHook();
return (_retType == ReturnMethod::UseOriginal ? val_original : val_new);
}
inline ReturnType CallOriginal( Args&&... args )
{
return (reinterpret_cast<typeR>(_callOriginal))(args...);
}
inline ReturnType CallCallback( Args&&... args )
{
if (_callbackClass != nullptr)
return ((C*)_callbackClass->*brutal_cast<hktypeCR>(_callback))(args...);
else
return (reinterpret_cast<hktypeR>(_callback))(args...);
}
};
}
@@ -0,0 +1,69 @@
#pragma once
namespace blackbone
{
template<typename R, typename... Args, class C>
struct HookHandler<R( __stdcall* )(Args...), C> : public DetourBase
{
using ReturnType = std::conditional_t<std::is_same_v<R, void>, int, R>;
using type = R( __stdcall* )(Args...);
using hktype = R( __stdcall* )(Args&...);
using hktypeC = R( C::* )(Args&...);
//
// Workaround for void return type
//
using typeR = ReturnType( __stdcall* )(Args...);
using hktypeR = ReturnType( __stdcall* )(Args&...);
using hktypeCR = ReturnType( C::* )(Args&...);
static __declspec(noinline) ReturnType __stdcall Handler( Args... args )
{
HookHandler* pInst = (HookHandler*)((_NT_TIB*)NtCurrentTeb())->ArbitraryUserPointer;
return pInst->HandlerP( std::forward<Args>( args )... );
}
ReturnType HandlerP( Args&&... args )
{
ReturnType val_new, val_original;
DisableHook();
if (_order == CallOrder::HookFirst)
{
val_new = CallCallback( std::forward<Args>( args )... );
val_original = CallOriginal( std::forward<Args>( args )... );
}
else if (_order == CallOrder::HookLast)
{
val_original = CallOriginal( std::forward<Args>( args )... );
val_new = CallCallback( std::forward<Args>( args )... );
}
else
{
val_original = val_new = CallCallback( std::forward<Args>( args )... );
}
if (this->_hooked)
EnableHook();
return (_retType == ReturnMethod::UseOriginal ? val_original : val_new);
}
inline ReturnType CallOriginal( Args&&... args )
{
return (reinterpret_cast<typeR>(_callOriginal))(args...);
}
inline ReturnType CallCallback( Args&&... args )
{
if (_callbackClass != nullptr)
return ((C*)_callbackClass->*brutal_cast<hktypeCR>(_callback))(args...);
else
return (reinterpret_cast<hktypeR>(_callback))(args...);
}
};
}
@@ -0,0 +1,69 @@
#pragma once
namespace blackbone
{
template<typename R, typename... Args, class C>
struct HookHandler<R( __thiscall* )(Args...), C> : public DetourBase
{
using ReturnType = std::conditional_t<std::is_same_v<R, void>, int, R>;
using type = R( __thiscall* )(Args...);
using hktype = R( __stdcall* )(Args&...);
using hktypeC = R( C::* )(Args&...);
//
// Workaround for void return type
//
using typeR = ReturnType( __thiscall* )(Args...);
using hktypeR = ReturnType( __stdcall* )(Args&...);
using hktypeCR = ReturnType( C::* )(Args&...);
static __declspec(noinline) ReturnType __thiscall Handler( Args... args )
{
HookHandler* pInst = (HookHandler*)((_NT_TIB*)NtCurrentTeb())->ArbitraryUserPointer;
return pInst->HandlerP( std::forward<Args>( args )... );
}
ReturnType HandlerP( Args&&... args )
{
ReturnType val_new, val_original;
DisableHook();
if (_order == CallOrder::HookFirst)
{
val_new = CallCallback( std::forward<Args>( args )... );
val_original = CallOriginal( std::forward<Args>( args )... );
}
else if (_order == CallOrder::HookLast)
{
val_original = CallOriginal( std::forward<Args>( args )... );
val_new = CallCallback( std::forward<Args>( args )... );
}
else
{
val_original = val_new = CallCallback( std::forward<Args>( args )... );
}
if (this->_hooked)
EnableHook();
return (_retType == ReturnMethod::UseOriginal ? val_original : val_new);
}
inline ReturnType CallOriginal( Args&&... args )
{
return (reinterpret_cast<typeR>(_callOriginal))( args...);
}
inline ReturnType CallCallback( Args&&... args )
{
if (_callbackClass != nullptr)
return ((C*)_callbackClass->*brutal_cast<hktypeCR>(_callback))( args...);
else
return (reinterpret_cast<hktypeR>(_callback))( args...);
}
};
}
@@ -0,0 +1,19 @@
#pragma once
#include "LocalHookBase.h"
namespace blackbone
{
class BLACKBONE_API NoClass { };
template<typename Fn, class C>
struct HookHandler;
}
#include "HookHandlerCdecl.h"
#ifndef USE64
#include "HookHandlerStdcall.h"
#include "HookHandlerThiscall.h"
#include "HookHandlerFastcall.h"
#endif
@@ -0,0 +1,252 @@
#pragma once
#include "HookHandlers.h"
#include "../Process/Process.h"
namespace blackbone
{
template<typename Fn, class C = NoClass>
class Detour: public HookHandler<Fn, C>
{
public:
using type = typename HookHandler<Fn, C>::type;
using hktype = typename HookHandler<Fn, C>::hktype;
using hktypeC = typename HookHandler<Fn, C>::hktypeC;
public:
Detour()
{
this->_internalHandler = &HookHandler<Fn, C>::Handler;
}
~Detour()
{
Restore();
}
/// <summary>
/// Hook function
/// </summary>
/// <param name="ptr">Target function address</param>
/// <param name="hkPtr">Hook function address</param>
/// <param name="type">Hooking method</param>
/// <param name="order">Call order. Hook before original or vice versa</param>
/// <param name="retType">Return value. Use origianl or value from hook</param>
/// <returns>true on success</returns>
bool Hook(
type ptr,
hktype hkPtr,
HookType::e type,
CallOrder::e order = CallOrder::HookFirst,
ReturnMethod::e retType = ReturnMethod::UseOriginal
)
{
if (this->_hooked)
return false;
this->_type = type;
this->_order = order;
this->_retType = retType;
this->_callOriginal = this->_original = ptr;
this->_callback = hkPtr;
if (!DetourBase::AllocateBuffer( reinterpret_cast<uint8_t*>(ptr) ))
return false;
switch (this->_type)
{
case HookType::Inline:
return HookInline();
case HookType::Int3:
return HookInt3();
case HookType::HWBP:
return HookHWBP();
default:
return false;
}
}
/// <summary>
/// Hook function
/// </summary>
/// <param name="Ptr">Target function address</param>
/// <param name="hkPtr">Hook class member address</param>
/// <param name="pClass">Hook class address</param>
/// <param name="type">Hooking method</param>
/// <param name="order">Call order. Hook before original or vice versa</param>
/// <param name="retType">Return value. Use origianl or value from hook</param>
/// <returns>true on success</returns>
bool Hook(
type Ptr,
hktypeC hkPtr,
C* pClass,
HookType::e type,
CallOrder::e order = CallOrder::HookFirst,
ReturnMethod::e retType = ReturnMethod::UseOriginal
)
{
this->_callbackClass = pClass;
return Hook( Ptr, brutal_cast<hktype>(hkPtr), type, order, retType );
}
/// <summary>
/// Restore hooked function
/// </summary>
/// <returns>true on success, false if not hooked</returns>
bool Restore()
{
if (!this->_hooked)
return false;
switch (this->_type)
{
case HookType::Inline:
case HookType::InternalInline:
case HookType::Int3:
{
DWORD flOld = 0;
if (!VirtualProtect(this->_original, this->_origSize, PAGE_EXECUTE_READWRITE, &flOld))
return false;
memcpy(this->_original, this->_origCode, this->_origSize);
VirtualProtect(this->_original, this->_origSize, flOld, &flOld);
}
break;
case HookType::HWBP:
{
Process thisProc;
thisProc.Attach( GetCurrentProcessId() );
for (auto& thd : thisProc.threads().getAll())
thd->RemoveHWBP( reinterpret_cast<ptr_t>(this->_original) );
this->_hwbpIdx.clear();
}
break;
default:
break;
}
this->_hooked = false;
return true;
}
private:
/// <summary>
/// Perform inline hook
/// </summary>
/// <returns>true on success</returns>
bool HookInline()
{
auto jmpToHook = AsmFactory::GetAssembler();
auto jmpToThunk = AsmFactory::GetAssembler();
//
// Construct jump to thunk
//
#ifdef USE64
(*jmpToThunk)->mov( asmjit::host::rax, (uint64_t)this->_buf );
(*jmpToThunk)->jmp( asmjit::host::rax );
this->_origSize = (*jmpToThunk)->getCodeSize();
#else
(*jmpToThunk)->jmp( (asmjit::Ptr)this->_buf );
this->_origSize = (*jmpToThunk)->getCodeSize();
#endif
DetourBase::CopyOldCode( (uint8_t*)this->_original );
// Construct jump to hook handler
#ifdef USE64
// mov gs:[0x28], this
(*jmpToHook)->mov( asmjit::host::rax, (uint64_t)this );
(*jmpToHook)->mov( asmjit::host::qword_ptr_abs( 0x28 ).setSegment( asmjit::host::gs ), asmjit::host::rax );
#else
// mov fs:[0x14], this
(*jmpToHook)->mov( asmjit::host::dword_ptr_abs( 0x14 ).setSegment( asmjit::host::fs ) , (uint32_t)this );
#endif // USE64
(*jmpToHook)->jmp( (asmjit::Ptr)&HookHandler<Fn, C>::Handler );
(*jmpToHook)->relocCode( this->_buf );
(*jmpToThunk)->setBaseAddress( (uintptr_t)this->_original );
auto codeSize = (*jmpToThunk)->relocCode( this->_newCode );
DWORD flOld = 0;
if (!VirtualProtect( this->_original, codeSize, PAGE_EXECUTE_READWRITE, &flOld ))
return false;
memcpy( this->_original, this->_newCode, codeSize );
VirtualProtect( this->_original, codeSize, flOld, &flOld );
this->_hooked = (codeSize != 0);
return this->_hooked;
}
/// <summary>
/// Perform int3 hook
/// </summary>
/// <returns>true on success</returns>
bool HookInt3()
{
this->_newCode[0] = 0xCC;
this->_origSize = sizeof( this->_newCode[0] );
// Setup handler
if (this->_vecHandler == nullptr)
this->_vecHandler = AddVectoredExceptionHandler( 1, &DetourBase::VectoredHandler );
if (!this->_vecHandler)
return false;
this->_breakpoints.insert( std::make_pair( this->_original, (DetourBase*)this ) );
// Save original code
memcpy( this->_origCode, this->_original, this->_origSize );
// Write break instruction
DWORD flOld = 0;
if (!VirtualProtect(this->_original, this->_origSize, PAGE_EXECUTE_READWRITE, &flOld))
return false;
memcpy( this->_original, this->_newCode, this->_origSize );
VirtualProtect( this->_original, this->_origSize, flOld, &flOld );
return this->_hooked = TRUE;
}
/// <summary>
/// Perform hardware breakpoint hook
/// </summary>
/// <returns>true on success</returns>
bool HookHWBP()
{
Process thisProc;
thisProc.Attach( GetCurrentProcessId() );
// Setup handler
if (this->_vecHandler == nullptr)
this->_vecHandler = AddVectoredExceptionHandler( 1, &DetourBase::VectoredHandler );
if (!this->_vecHandler)
return false;
this->_breakpoints.insert( std::make_pair( this->_original, (DetourBase*)this ) );
// Add breakpoint to every thread
for (auto& thd : thisProc.threads().getAll())
this->_hwbpIdx[thd->id()] = thd->AddHWBP( reinterpret_cast<ptr_t>(this->_original), hwbp_execute, hwbp_1 ).result();
return this->_hooked = true;
}
};
}
@@ -0,0 +1,128 @@
#pragma once
#include "../Config.h"
#include "../Include/Winheaders.h"
#include "../Asm/AsmFactory.h"
#include "../Asm/LDasm.h"
#include "../Include/Macro.h"
#include <tuple>
#include <unordered_map>
namespace blackbone
{
namespace CallOrder
{
enum e
{
HookFirst, // Hook called before original function
HookLast, // Hook called after original function
NoOriginal, // Original function doesn't get called
};
}
namespace HookType
{
enum e
{
Inline, // Patch first few bytes
Int3, // Place Int3 breakpoint
HWBP, // Set hardware breakpoint
// Reserved for internal use
VTable,
InternalInline
};
}
namespace ReturnMethod
{
enum e
{
UseNew, // Return value returned by hook
UseOriginal // Return original function value
};
}
class DetourBase
{
using mapIdx = std::unordered_map<DWORD, int>;
public:
BLACKBONE_API DetourBase();
BLACKBONE_API ~DetourBase();
protected:
/// <summary>
/// Allocate detour buffer as close to target as possible
/// </summary>
/// <param name="nearest">Target address</param>
/// <returns>true on success</returns>
BLACKBONE_API bool AllocateBuffer( uint8_t* nearest );
/// <summary>
/// Temporarily disable hook
/// </summary>
/// <returns>true on success</returns>
BLACKBONE_API bool DisableHook();
/// <summary>
/// Enable disabled hook
/// </summary>
/// <returns>true on success</returns>
BLACKBONE_API bool EnableHook();
/// <summary>
/// Toggle hardware breakpoint for current thread
/// </summary>
/// <param name="index">Breakpoint index ( 0-4 )</param>
/// <param name="enable">true to enable, false to disable</param>
/// <returns>true on success</returns>
BLACKBONE_API bool ToggleHBP( int index, bool enable );
/// <summary>
/// Copy original function bytes
/// </summary>
/// <param name="Ptr">Origianl function address</param>
BLACKBONE_API void CopyOldCode( uint8_t* Ptr );
/// <summary>
/// Exception handlers
/// </summary>
/// <param name="excpt">Exception information</param>
/// <returns>Exception disposition</returns>
BLACKBONE_API static LONG NTAPI VectoredHandler ( PEXCEPTION_POINTERS excpt );
BLACKBONE_API static LONG NTAPI Int3Handler ( PEXCEPTION_POINTERS excpt );
BLACKBONE_API static LONG NTAPI AVHandler ( PEXCEPTION_POINTERS excpt );
BLACKBONE_API static LONG NTAPI StepHandler ( PEXCEPTION_POINTERS excpt );
protected:
bool _hooked = false; // Hook is installed
void* _callback = nullptr; // User supplied hook function
void* _callbackClass = nullptr; // Class pointer for user hook
void* _original = nullptr; // Original function address
void* _internalHandler = nullptr; // Pointer to hook handler
void* _callOriginal = nullptr; // Pointer to original function
mapIdx _hwbpIdx; // Thread HWBP index
size_t _origSize = 0; // Original code size
uint8_t* _buf = nullptr; // Trampoline buffer
uint8_t* _origCode = nullptr; // Original function bytes
uint8_t* _origThunk = nullptr; // Original bytes adjusted for relocation
uint8_t* _newCode = nullptr; // Trampoline bytes
HookType::e _type = HookType::Inline;
CallOrder::e _order = CallOrder::HookFirst;
ReturnMethod::e _retType = ReturnMethod::UseOriginal;
// Global hook instances relationship
BLACKBONE_API static std::unordered_map<void*, DetourBase*> _breakpoints;
// Exception handler
BLACKBONE_API static void* _vecHandler;
};
}
@@ -0,0 +1,161 @@
#pragma once
#include "../Include/WinHeaders.h"
#include <stdint.h>
#include <vector>
#include <map>
#include <unordered_map>
namespace blackbone
{
enum TraceState
{
TS_Start, // Initial state. Internal use only
TS_Step, // Do single-step
TS_StepOut, // Break on function return
TS_StepInto, // Step into specific function
TS_WaitReturn, // Wait for break-on-return
};
struct PathNode
{
TraceState action;
uintptr_t arg;
PathNode( TraceState _action, uintptr_t _arg = 0 )
: action( _action )
, arg( _arg ) { }
};
/// <summary>
/// Hook-related data
/// </summary>
struct HookContext
{
using mapHooks = std::unordered_map<uintptr_t, std::pair<uintptr_t, bool>>;
using vecState = std::vector<PathNode>;
uintptr_t lastIP = 0; // Previous EIP/RIP value
uintptr_t lastSP = 0; // Previous ESP/RSP value
uintptr_t targetPtr = 0; // Address causing exception
uintptr_t origPtrVal = 0; // Original pointer value
uintptr_t checkIP = 0; // Address of instruction that checks target pointer
uintptr_t breakValue = 0; // Value used to generate exception
uintptr_t stateIdx = 0; // Current state index in state vector
TraceState state = TS_Start; // Current tracing state
vecState tracePath; // Function trace path
mapHooks hooks; // List of hooks associated with current pointer
/// <summary>
/// Reset tracing state
/// </summary>
void reset()
{
state = TS_Start;
lastIP = lastSP = 0;
stateIdx = 0;
// Mark hooks as non-called
for (auto& item : hooks)
item.second.second = false;
}
};
class TraceHook
{
public:
using mapContext = std::map<uintptr_t, HookContext>;
using vecStackFrames = std::vector <std::pair<uintptr_t, uintptr_t>>;
public:
~TraceHook();
BLACKBONE_API static TraceHook& Instance();
/// <summary>
/// Setup hook
/// </summary>
/// <param name="targetFunc">Target function to be hooked</param>
/// <param name="hookFunc">New function</param>
/// <param name="ptrAddress">Address of pointer to destroy</param>
/// <param name="tracePath">Function tracing path</param>
/// <param name="checkIP">Optional. Address of instruction that checks target pointer</param>
/// <returns>true on success, false if already hooked</returns>
BLACKBONE_API bool ApplyHook( void* targetFunc,
void* hookFunc,
void* ptrAddress,
const HookContext::vecState& tracePath = HookContext::vecState(),
void* checkIP = 0 );
/// <summary>
/// Remove existing hook
/// </summary>
/// <param name="targetFunc">Target function ptr</param>
/// <returns>true on success, false if not found</returns>
BLACKBONE_API bool RemoveHook( void* targetFunc );
private:
//
// Singleton
//
TraceHook();
TraceHook( const TraceHook& ) = delete;
TraceHook& operator =( const TraceHook& ) = delete;
//
// Exception handlers
//
static LONG __stdcall VecHandler( PEXCEPTION_POINTERS ExceptionInfo );
LONG VecHandlerP( PEXCEPTION_POINTERS ExceptionInfo );
/// <summary>
/// Capture stack frames
/// </summary>
/// <param name="ip">Current instruction pointer</param>
/// <param name="sp">Current stack pointer</param>
/// <param name="results">Found frames.</param>
/// <param name="depth">Frame depth limit</param>
/// <returns>Number of found frames</returns>
size_t StackBacktrace( uintptr_t ip, uintptr_t sp, vecStackFrames& results, uintptr_t depth = 10 );
/// <summary>
/// Setup exception upon function return
/// </summary>
/// <param name="ExceptionInfo">The exception information</param>
inline void BreakOnReturn( uintptr_t sp );
/// <summary>
/// Check if last instruction caused branching
/// </summary>
/// <param name="ctx">Current hook info</param>
/// <param name="ip">Instruction pointer</param>
/// <param name="sp">Stack pointer</param>
/// <returns>True if branching has occurred</returns>
bool CheckBranching( const HookContext& ctx, uintptr_t ip, uintptr_t sp );
/// <summary>
/// Handle branching
/// </summary>
/// <param name="ctx">Current hook context</param>
/// <param name="exptContex">Thread context</param>
void HandleBranch( HookContext& ctx, PCONTEXT exptContex );
/// <summary>
/// Restore original pointer value
/// </summary>
/// <param name="ctx">The CTX.</param>
/// <param name="ExceptionInfo">The exception information</param>
/// <returns>true on success, false if no invalid register was found</returns>
bool RestorePtr( const HookContext& ctx, PEXCEPTION_POINTERS ExceptionInfo );
private:
PVOID _pExptHandler = nullptr; // Exception handler
mapContext _contexts; // Hook contexts
uintptr_t _breakPtr = 0x2000; // Exception pointer generator
};
}
@@ -0,0 +1,182 @@
#pragma once
#include "LocalHook.hpp"
#include "../Misc/DynImport.h"
namespace blackbone
{
template<typename Fn, class C = NoClass>
class VTableDetour : public Detour<Fn, C>
{
public:
using type = typename HookHandler<Fn, C>::type;
using hktype = typename HookHandler<Fn, C>::hktype;
using hktypeC = typename HookHandler<Fn, C>::hktypeC;
public:
VTableDetour()
{
DetourBase::AllocateBuffer( nullptr );
}
~VTableDetour()
{
Restore();
}
/// <summary>
/// Hook function in vtable
/// </summary>
/// <param name="ppVtable">Pointer to vtable pointer</param>
/// <param name="index">Function index</param>
/// <param name="hkPtr">Hook function address</param>
/// <param name="order">Call order. Hook before original or vice versa</param>
/// <param name="retType">Return value. Use origianl or value from hook</param>
/// <param name="copyVtable">if true, vtable will be copied and edited, otherwise existing vtable will be edited</param>
/// <param name="vtableLen">Optional. Valid only when copyVtable is true. Number of function in vtable.
/// Used to determine number of function to copy</param>
/// <returns>true on success</returns>
bool Hook(
void** ppVtable,
int index,
hktype hkPtr,
CallOrder::e order = CallOrder::HookFirst,
ReturnMethod::e retType = ReturnMethod::UseOriginal,
bool copyVtable = false,
int vtableLen = 0
)
{
auto jmpToHook = AsmFactory::GetAssembler();
this->_type = HookType::VTable;
this->_order = order;
this->_retType = retType;
this->_callOriginal = this->_original = (*(void***)ppVtable)[index];
this->_callback = hkPtr;
this->_internalHandler = &HookHandler<Fn, C>::Handler;
this->_ppVtable = ppVtable;
this->_pVtable = *ppVtable;
this->_vtIndex = index;
this->_vtCopied = copyVtable;
// Construct jump to hook handler
#ifdef USE64
// mov gs:[0x28], this
(*jmpToHook)->mov( asmjit::host::rax, (uint64_t)this );
(*jmpToHook)->mov( asmjit::host::qword_ptr_abs( 0x28 ).setSegment( asmjit::host::gs ), asmjit::host::rax );
#else
// mov fs:[0x14], this
(*jmpToHook)->mov( asmjit::host::dword_ptr_abs( 0x14 ).setSegment( asmjit::host::fs ), (uint32_t)this );
#endif // USE64
(*jmpToHook)->jmp( (asmjit::Ptr)this->_internalHandler );
(*jmpToHook)->relocCode( this->_buf );
// Modify VTable copy
if (copyVtable)
{
// Copy VTable
if (vtableLen != 0)
{
memcpy( this->_buf + 0x300 - sizeof( void* ), (*(void***)ppVtable) - 1, vtableLen * sizeof( void* ) );
}
else
{
Process proc;
proc.Attach( GetCurrentProcessId() );
auto vptr = (*(uintptr_t**)ppVtable)[index];
auto mod = proc.modules().GetModule( vptr, false );
uintptr_t imageBase = static_cast<uintptr_t>(mod->baseAddress);
uintptr_t imageSzie = mod->size;
for (;; vtableLen++)
{
vptr = (*(uintptr_t**)ppVtable)[vtableLen];
if (vptr < imageBase || vptr >= imageBase + imageSzie)
{
memcpy( this->_buf + 0x300 - sizeof( void* ), (*(void***)ppVtable) - 1, vtableLen * sizeof( void* ) );
break;
}
}
}
// Replace pointer to VTable
((void**)this->_buf + 0x300 / sizeof( uintptr_t ))[index] = this->_buf;
*ppVtable = this->_buf + 0x300;
}
// Modify pointer in-place
else
{
DWORD flOld = 0;
VirtualProtect( *(uintptr_t**)ppVtable + index, sizeof(void*), PAGE_EXECUTE_READWRITE, &flOld );
(*(void***)ppVtable)[index] = this->_buf;
VirtualProtect( *(uintptr_t**)ppVtable + index, sizeof(void*), flOld, &flOld );
}
return (this->_hooked = true);
}
/// <summary>
/// Hooks function in vtable
/// </summary>
/// <param name="ppVtable">Pointer to vtable pointer</param>
/// <param name="index">Function index</param>
/// <param name="hkPtr">Hook class member address</param>
/// <param name="pClass">Hook class address</param>
/// <param name="order">Call order. Hook before original or vice versa</param>
/// <param name="retType">Return value. Use origianl or value from hook</param>
/// <param name="copyVtable">if true, vtable will be copied and edited, otherwise existing vtable will be edited</param>
/// <param name="vtableLen">Optional. Valid only when copyVtable is true. Number of function in vtable.
/// Used to determine number of function to copy</param>
/// <returns>true on success</returns>
bool Hook(
void** ppVtable,
int index,
hktypeC hkPtr,
C* pClass,
CallOrder::e order = CallOrder::HookFirst,
ReturnMethod::e retType = ReturnMethod::UseOriginal,
bool copyVtable = false,
int vtableLen = 0
)
{
this->_callbackClass = pClass;
return Hook( ppVtable, index, brutal_cast<hktype>(hkPtr), order, retType, copyVtable, vtableLen );
}
/// <summary>
/// Restore hooked function
/// </summary>
/// <returns>true on success, false if not hooked</returns>
bool Restore()
{
if (!this->_hooked)
return false;
if (this->_vtCopied)
{
*this->_ppVtable = this->_pVtable;
}
else
{
DWORD flOld = 0;
VirtualProtect( *(uintptr_t**)this->_ppVtable + this->_vtIndex, sizeof( void* ), PAGE_EXECUTE_READWRITE, &flOld );
(*(void***)this->_ppVtable)[this->_vtIndex] = this->_original;
VirtualProtect( *(uintptr_t**)this->_ppVtable + this->_vtIndex, sizeof( void* ), flOld, &flOld );
}
this->_hooked = false;
return true;
}
private:
bool _vtCopied = false; // VTable was copied
void** _ppVtable = nullptr; // Pointer to VTable pointer
void* _pVtable = nullptr; // Pointer to VTable
int _vtIndex = 0; // VTable function index
};
}
@@ -0,0 +1,72 @@
#pragma once
#include "../Include/Winheaders.h"
#include "../Process/MemBlock.h"
namespace blackbone
{
/// <summary>
/// x64 exception module info
/// </summary>
struct ExceptionModule
{
ptr_t base;
ptr_t size;
};
/// <summary>
/// x64 module table
/// </summary>
struct ModuleTable
{
ptr_t count; // Number of used entries
ExceptionModule entry[250]; // Module data
};
/// <summary>
/// Exception handling support for arbitrary code
/// </summary>
class MExcept
{
public:
BLACKBONE_API MExcept() = default;
BLACKBONE_API ~MExcept() = default;
MExcept( const MExcept& ) = delete;
MExcept& operator =( const MExcept& ) = delete;
/// <summary>
/// Inject VEH wrapper into process
/// Used to enable execution of SEH handlers out of image
/// </summary>
/// <param name="proc">Target process</param>
/// <param name="mod">Target module</param>
/// <param name="partial">Partial exception support</param>
/// <returns>Error code</returns>
BLACKBONE_API NTSTATUS CreateVEH( class Process& proc, ModuleData& mod, bool partial );
/// <summary>
/// Removes VEH from target process
/// </summary>
/// <param name="proc">Target process</param>
/// <param name="partial">Partial exception support</param>
/// <param name="mt">Module type</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS RemoveVEH( class Process& proc, bool partial, eModType mt );
/// <summary>
/// Reset data
/// </summary>
BLACKBONE_API void reset() { _pModTable.Free(); }
private:
MemBlock _pVEHCode; // VEH function codecave
MemBlock _pModTable; // x64 module address range table
uint64_t _hVEH = 0; // VEH handle
static uint8_t _handler32[];
static uint8_t _handler64[];
};
}
@@ -0,0 +1,399 @@
#pragma once
#include "../Config.h"
#include "../Include/Winheaders.h"
#include "../Include/Macro.h"
#include "../PE/PEImage.h"
#include "../Process/MemBlock.h"
#include "../ManualMap/Native/NtLoader.h"
#include "MExcept.h"
#include <array>
#include <vector>
#include <map>
#include <tuple>
namespace blackbone
{
class CustomArgs_t
{
public:
void push_back( const void* ptr, size_t size )
{
append( ptr, size );
}
template<typename T>
void push_back( const T* ptr )
{
append( ptr, sizeof( T ) );
}
template<typename T>
void push_back( const std::basic_string<T>& str )
{
append( str.data(), str.size() * sizeof( T ) );
}
template<class T>
void push_back( const std::vector<T>& cVec )
{
append( cVec.data(), cVec.size() * sizeof( T ) );
}
template<class T, size_t N>
void push_back( const std::array<T, N>& arr )
{
append( arr.data(), arr.size() * sizeof( T ) );
}
#if _MSC_VER >= 1900
template<typename... Args>
void push_back( const std::tuple<Args...>& tpl )
{
tuple_detail::copyTuple( tpl, _buffer );
}
#endif
/// <summary>
/// Get raw data size
/// </summary>
/// <returns></returns>
inline size_t size() const { return _buffer.size(); }
/// <summary>
/// Get raw data
/// </summary>
/// <returns>Data ptr</returns>
inline uint8_t* data() { return _buffer.data(); }
inline const uint8_t* data() const { return _buffer.data(); }
private:
/// <summary>
/// Append buffer from raw memory
/// </summary>
/// <param name="ptr">Raw pointer</param>
/// <param name="size">Data size</param>
void append( const void* ptr, size_t size )
{
if (ptr)
{
const auto offset = _buffer.size();
_buffer.resize( offset + size );
memcpy( _buffer.data() + offset, ptr, size );
}
}
private:
std::vector<uint8_t> _buffer;
};
// Loader flags
enum eLoadFlags
{
NoFlags = 0x00, // No flags
ManualImports = 0x01, // Manually map import libraries
CreateLdrRef = 0x02, // Create module references for native loader
WipeHeader = 0x04, // Wipe image PE headers
HideVAD = 0x10, // Make image appear as PAGE_NOACESS region
MapInHighMem = 0x20, // Try to map image in address space beyond 4GB limit
RebaseProcess = 0x40, // If target image is an .exe file, process base address will be replaced with mapped module value
NoThreads = 0x80, // Don't create new threads, use hijacking
ForceRemap = 0x100, // Force remapping module even if it's already loaded
NoExceptions = 0x01000, // Do not create custom exception handler
PartialExcept = 0x02000, // Only create Inverted function table, without VEH
NoDelayLoad = 0x04000, // Do not resolve delay import
NoSxS = 0x08000, // Do not apply SxS activation context
NoTLS = 0x10000, // Skip TLS initialization and don't execute TLS callbacks
IsDependency = 0x20000, // Module is a dependency
};
ENUM_OPS( eLoadFlags )
// Image mapping type
enum MappingType
{
MT_Default, // Use eLoadFlags value
MT_Native, // Use native loader
MT_Manual, // Manually map
MT_None, // Don't load
};
struct LoadData
{
MappingType mtype = MT_Default;
enum LdrRefFlags ldrFlags = static_cast<enum LdrRefFlags>(0);
LoadData() = default;
LoadData( MappingType mtype_, enum LdrRefFlags ldrFlags_ )
: mtype( mtype_ )
, ldrFlags( ldrFlags_ ) { }
};
// Image mapping callback
enum CallbackType
{
PreCallback, // Called before loading. Loading type is decided here
PostCallback // Called after manual mapping, but before entry point invocation. Loader flags are decided here
};
using MapCallback = LoadData( *)(CallbackType type, void* context, Process& process, const ModuleData& modInfo);
/// <summary>
/// Image data
/// </summary>
struct ImageContext
{
using vecPtr = std::vector<ptr_t>;
pe::PEImage peImage; // PE image data
MemBlock imgMem; // Target image memory region
NtLdrEntry ldrEntry; // Native loader module information
vecPtr tlsCallbacks; // TLS callback routines
ptr_t pExpTableAddr = 0; // Exception table address (amd64 only)
eLoadFlags flags = NoFlags; // Image loader flags
bool initialized = false; // Image entry point was called
};
using ImageContextPtr = std::shared_ptr<ImageContext>;
using vecImageCtx = std::vector<ImageContextPtr>;
/// <summary>
/// Manual image mapper
/// </summary>
class MMap
{
public:
BLACKBONE_API MMap( class Process& proc );
BLACKBONE_API ~MMap( void );
/// <summary>
/// Manually map PE image into underlying target process
/// </summary>
/// <param name="path">Image path</param>
/// <param name="flags">Image mapping flags</param>
/// <param name="mapCallback">Mapping callback. Triggers for each mapped module</param>
/// <param name="context">User-supplied callback context</param>
/// <returns>Mapped image info </returns>
BLACKBONE_API call_result_t<ModuleDataPtr> MapImage(
const std::wstring& path,
eLoadFlags flags = NoFlags,
MapCallback mapCallback = nullptr,
void* context = nullptr,
CustomArgs_t* pCustomArgs_t = nullptr
);
/// <summary>
///Manually map PE image into underlying target process
/// </summary>
/// <param name="buffer">Image data buffer</param>
/// <param name="size">Buffer size.</param>
/// <param name="asImage">If set to true - buffer has image memory layout</param>
/// <param name="flags">Image mapping flags</param>
/// <param name="mapCallback">Mapping callback. Triggers for each mapped module</param>
/// <param name="context">User-supplied callback context</param>
/// <returns>Mapped image info</returns>
BLACKBONE_API call_result_t<ModuleDataPtr> MapImage(
size_t size, void* buffer,
bool asImage = false,
eLoadFlags flags = NoFlags,
MapCallback mapCallback = nullptr,
void* context = nullptr,
CustomArgs_t* pCustomArgs_t = nullptr
);
/// <summary>
/// Unmap all manually mapped modules
/// </summary>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS UnmapAllModules();
/// <summary>
/// Remove any traces from remote process
/// </summary>
/// <returns></returns>
BLACKBONE_API void Cleanup();
/// <summary>
/// Reset local data
/// </summary>
BLACKBONE_API inline void reset() { _images.clear(); _pAContext.Reset(); _usedBlocks.clear(); }
private:
/// <summary>
/// Manually map PE image into underlying target process
/// </summary>
/// <param name="path">Image path</param>
/// <param name="buffer">Image data buffer</param>
/// <param name="size">Buffer size.</param>
/// <param name="asImage">If set to true - buffer has image memory layout</param>
/// <param name="flags">Image mapping flags</param>
/// <param name="mapCallback">Mapping callback. Triggers for each mapped module</param>
/// <param name="context">User-supplied callback context</param>
/// <returns>Mapped image info</returns>
call_result_t<ModuleDataPtr> MapImageInternal(
const std::wstring& path,
void* buffer, size_t size,
bool asImage = false,
eLoadFlags flags = NoFlags,
MapCallback ldrCallback = nullptr,
void* ldrContext = nullptr,
CustomArgs_t* pCustomArgs_t = nullptr
);
/// <summary>
/// Fix image path for pure managed mapping
/// </summary>
/// <param name="base">Image base</param>
/// <param name="path">New image path</param>
template<typename T>
void FixManagedPath( ptr_t base, const std::wstring &path );
/// <summary>
/// Get existing module or map it if absent
/// </summary>
/// <param name="path">Image path</param>
/// <param name="flags">Mapping flags</param>
/// <returns>Module info</returns>
call_result_t<ModuleDataPtr> FindOrMapModule(
const std::wstring& path,
void* buffer, size_t size, bool asImage,
eLoadFlags flags = NoFlags
);
/// <summary>
/// Run module initializers(TLS and entry point).
/// </summary>
/// <param name="pImage">Image data</param>
/// <param name="dwReason">one of the following:
/// DLL_PROCESS_ATTACH
/// DLL_THREAD_ATTACH
/// DLL_PROCESS_DETACH
/// DLL_THREAD_DETTACH
/// </param>
/// <returns>DllMain result</returns>
call_result_t<uint64_t> RunModuleInitializers( ImageContextPtr pImage, DWORD dwReason, CustomArgs_t* pCustomArgs_t = nullptr );
/// <summary>
/// Copies image into target process
/// </summary>
/// <param name="pImage">Image data</param>
/// <returns>Status code</returns>
NTSTATUS CopyImage( ImageContextPtr pImage );
/// <summary>
/// Adjust image memory protection
/// </summary>
/// <param name="pImage">image data</param>
/// <returns>Status code</returns>
NTSTATUS ProtectImageMemory( ImageContextPtr pImage );
/// <summary>
/// Fix relocations if image wasn't loaded at base address
/// </summary>
/// <param name="pImage">image data</param>
/// <returns>true on success</returns>
NTSTATUS RelocateImage( ImageContextPtr pImage );
/// <summary>
/// Resolves image import or delayed image import
/// </summary>
/// <param name="pImage">Image data</param>
/// <param name="useDelayed">Resolve delayed import instead</param>
/// <returns>Status code</returns>
NTSTATUS ResolveImport( ImageContextPtr pImage, bool useDelayed = false );
/// <summary>
/// Resolve static TLS storage
/// </summary>
/// <param name="pImage">image data</param>
/// <returns>Status code</returns>
NTSTATUS InitStaticTLS( ImageContextPtr pImage );
/// <summary>
/// Set custom exception handler to bypass SafeSEH under DEP
/// </summary>
/// <param name="pImage">image data</param>
/// <returns>Status code</returns>
NTSTATUS EnableExceptions( ImageContextPtr pImage );
/// <summary>
/// Remove custom exception handler
/// </summary>
/// <param name="pImage">image data</param>
/// <returns>true on success</returns>
NTSTATUS DisableExceptions( ImageContextPtr pImage );
/// <summary>
/// Calculate and set security cookie
/// </summary>
/// <param name="pImage">image data</param>
/// <returns>Status code</returns>
NTSTATUS InitializeCookie( ImageContextPtr pImage );
/// <summary>
/// Return existing or load missing dependency
/// </summary>
/// <param name="pImage">Currently mapped image data</param>
/// <param name="path">Dependency path</param>
/// <returns></returns>
call_result_t<ModuleDataPtr> FindOrMapDependency( ImageContextPtr pImage, std::wstring& path );
/// <summary>
/// Create activation context
/// Target memory layout:
/// -----------------------------
/// | hCtx | ACTCTX | file_path |
/// -----------------------------
/// </summary>
/// <param name="path">Manifest container path</param>
/// <param name="id">Manifest resource id</param>
/// <param name="asImage">if true - 'path' points to a valid PE file, otherwise - 'path' points to separate manifest file</param>
/// <returns>true on success</returns>
NTSTATUS CreateActx( const pe::PEImage& image );
/// <summary>
/// Do SxS path probing in the target process
/// </summary>
/// <param name="path">Path to probe</param>
/// <returns>Status code</returns>
NTSTATUS ProbeRemoteSxS( std::wstring& path );
/// <summary>
/// Hide memory VAD node
/// </summary>
/// <param name="imageMem">Image to purge</param>
/// <returns>Status code</returns>
NTSTATUS ConcealVad( const MemBlock& imageMem );
/// <summary>
/// Allocates memory region beyond 4GB limit
/// </summary>
/// <param name="imageMem">Image data</param>
/// <param name="size">Block size</param>
/// <returns>Status code</returns>
NTSTATUS AllocateInHighMem( MemBlock& imageMem, size_t size );
/// <summary>
/// Transform section characteristics into memory protection flags
/// </summary>
/// <param name="characteristics">Section characteristics</param>
/// <returns>Memory protection value</returns>
DWORD GetSectionProt( DWORD characteristics );
private:
class Process& _process; // Target process manager
MExcept _expMgr; // Exception handler manager
vecImageCtx _images; // Mapped images
MemBlock _pAContext; // SxS activation context memory address
MapCallback _mapCallback = nullptr; // Loader callback for adding image into loader lists
void* _userContext = nullptr; // user context for _ldrCallback
std::vector<std::pair<ptr_t, size_t>> _usedBlocks; // Used memory blocks
};
}
@@ -0,0 +1,233 @@
#pragma once
#include "../../Include/Winheaders.h"
#include "../../PE/PEImage.h"
#include "../../Include/Types.h"
#include "../../Include/NativeStructures.h"
#include "../../Include/Macro.h"
#include "../../Include/CallResult.h"
namespace blackbone
{
enum LdrRefFlags
{
Ldr_None = 0x00, // Do not create any reference
Ldr_ModList = 0x01, // Add to module list - LdrpModuleIndex( win8 only ), InMemoryOrderModuleList( win7 only )
Ldr_HashTable = 0x02, // Add to LdrpHashTable
Ldr_ThdCall = 0x04, // Add to thread callback list (dllmain will be called with THREAD_ATTACH/DETACH reasons)
Ldr_All = 0xFF, // Add to everything
Ldr_Ignore = 0xDE // Only valid in mod callback, mod callback value will be ignored
};
ENUM_OPS( LdrRefFlags )
struct NtLdrEntry : ModuleData
{
LdrRefFlags flags = Ldr_None;
ptr_t entryPoint = 0;
ULONG hash = 0;
bool safeSEH = false;
};
class NtLdr
{
public:
BLACKBONE_API NtLdr( class Process& proc );
/// <summary>
/// Initialize some loader stuff
/// </summary>
/// <param name="initFor">Target module type</param>
/// <returns>true on success</returns>
BLACKBONE_API bool Init( eModType initFor = mt_default );
/// <summary>
/// Add module to some loader structures
/// (LdrpHashTable, LdrpModuleIndex( win8 only ), InMemoryOrderModuleList( win7 only ))
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>true on success</returns>
BLACKBONE_API bool CreateNTReference( NtLdrEntry& mod );
/// <summary>
/// Create thread static TLS array
/// </summary>
/// <param name="mod">Module data</param>
/// <param name="tlsPtr">TLS directory of target image</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS AddStaticTLSEntry( NtLdrEntry& mod, ptr_t tlsPtr );
/// <summary>
/// Create module record in LdrpInvertedFunctionTable
/// Used to create fake SAFESEH entries
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>true on success</returns>
BLACKBONE_API bool InsertInvertedFunctionTable( NtLdrEntry& mod );
/// <summary>
/// Free static TLS
/// </summary>
/// <param name="mod">Target module</param>
/// <param name="noThread">Don't create new threads during remote call</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS UnloadTLS( const NtLdrEntry& mod, bool noThread = false );
/// <summary>
/// Unlink module from Ntdll loader
/// </summary>
/// <param name="mod">Module data</param>
/// <param name="noThread">Don't create new threads during unlink</param>
/// <returns>true on success</returns>
BLACKBONE_API bool Unlink( const ModuleData& mod, bool noThread = false );
private:
/// <summary>
/// Find LdrpHashTable[] variable
/// </summary>
/// <returns>true on success</returns>
template<typename T>
bool FindLdrpHashTable();
/// <summary>
/// Find LdrpModuleIndex variable under win8
/// </summary>
/// <returns>true on success</returns>
template<typename T>
bool FindLdrpModuleIndexBase();
/// <summary>
/// Find Loader heap base
/// </summary>
/// <returns>true on success</returns>
template<typename T>
bool FindLdrHeap();
/// <summary>
/// Initialize OS-specific module entry
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>Pointer to created entry</returns>
template<typename T>
ptr_t InitBaseNode( NtLdrEntry& mod );
/// <summary>
/// Initialize OS-specific module entry
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>Pointer to created entry</returns>
template<typename T>
ptr_t InitW8Node( NtLdrEntry& mod );
/// <summary>
/// Initialize OS-specific module entry
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>Pointer to created entry</returns>
template<typename T>
ptr_t InitW7Node( NtLdrEntry& mod );
/// <summary>
/// Insert entry into win8 module graph
/// </summary>
/// <param name="nodePtr">Node to insert</param>
/// <param name="mod">Module data</param>
template<typename T>
void InsertTreeNode( ptr_t nodePtr, const NtLdrEntry& mod );
/// <summary>
/// Insert entry into LdrpHashTable[]
/// </summary>
/// <param name="pNodeLink">Link of entry to be inserted</param>
/// <param name="hash">Module hash</param>
template<typename T>
void InsertHashNode( ptr_t pNodeLink, ULONG hash );
/// <summary>
/// Insert entry into InLoadOrderModuleList and InMemoryOrderModuleList
/// </summary>
/// <param name="pNodeMemoryOrderLink">InMemoryOrderModuleList link of entry to be inserted</param>
/// <param name="pNodeLoadOrderLink">InLoadOrderModuleList link of entry to be inserted</param>
template<typename T>
void InsertMemModuleNode( ptr_t pNodeMemoryOrderLink, ptr_t pNodeLoadOrderLink, ptr_t pNodeInitOrderLink );
/// <summary>
/// Insert entry into standard double linked list
/// </summary>
/// <param name="ListHead">List head pointer</param>
/// <param name="Entry">Entry list link to be inserted</param>
template<typename T>
void InsertTailList( ptr_t ListHead, ptr_t Entry );
/// <summary>
/// Hash image name
/// </summary>
/// <param name="str">Image name</param>
/// <returns>Hash</returns>
ULONG HashString( const std::wstring& str );
/// <summary>
/// Allocate memory from heap if possible
/// </summary>
/// <param name="size">Module type</param>
/// <param name="size">Size to allocate</param>
/// <returns>Allocated address</returns>
call_result_t<ptr_t> AllocateInHeap( eModType mt, size_t size );
/// <summary>
/// Get module native node ptr or create new
/// </summary>
/// <param name="ptr">node pointer (if nullptr - new dummy node is allocated)</param>
/// <param name="pModule">Module base address</param>
/// <returns>Node address</returns>
template<typename T, typename Module>
ptr_t SetNode( ptr_t ptr, Module pModule );
/// <summary>
/// Unlink module from PEB_LDR_DATA
/// </summary>
/// <param name="mod">Module data</param>
/// <returns>Address of removed record</returns>
template<typename T>
ptr_t UnlinkFromLdr( const ModuleData& mod );
/// <summary>
/// Finds LDR entry for module
/// </summary>
/// <param name="moduleBase">Target module base</param>
/// <param name="found">Found entry</param>
/// <returns>Found LDR entry address</returns>
template<typename T>
ptr_t FindLdrEntry( module_t moduleBase, _LDR_DATA_TABLE_ENTRY_BASE_T<T>* found = nullptr );
/// <summary>
/// Remove record from LIST_ENTRY structure
/// </summary>
/// <param name="pListLink">Entry link</param>
template<typename T>
void UnlinkListEntry( ptr_t pListLink );
/// <summary>
/// Unlink from module graph
/// </summary>
/// <param name="mod">Module data</param>
/// <param name="ldrEntry">Module LDR entry</param>
/// <param name="noThread">Don't create new threads during unlink</param>
/// <returns>Address of removed record</returns>
template<typename T>
ptr_t UnlinkTreeNode( const ModuleData& mod, ptr_t ldrEntry, bool noThread = false );
NtLdr( const NtLdr& ) = delete;
NtLdr& operator =( const NtLdr& ) = delete;
private:
class Process& _process; // Process memory routines
ptr_t _LdrpHashTable = 0; // LdrpHashTable address
ptr_t _LdrpModuleIndexBase = 0; // LdrpModuleIndex address
ptr_t _LdrHeapBase = 0; // Loader heap base address
eModType _initializedFor = mt_unknown; // Loader initialization target
std::map<ptr_t, ptr_t> _nodeMap; // Allocated native structures
};
}
@@ -0,0 +1,118 @@
#pragma once
#include "../Include/Types.h"
#include "../Include/Winheaders.h"
#include "Utils.h"
#include "InitOnce.h"
#include <unordered_map>
namespace blackbone
{
/// <summary>
/// Dynamic import
/// </summary>
class DynImport
{
public:
BLACKBONE_API static DynImport& Instance()
{
static DynImport instance;
return instance;
}
DynImport() = default;
DynImport( const DynImport& ) = delete;
/// <summary>
/// Get dll function
/// </summary>
/// <param name="name">Function name</param>
/// <returns>Function pointer</returns>
template<typename T>
T get( const std::string& name )
{
InitializeOnce();
CSLock lck( _mapGuard );
auto iter = _funcs.find( name );
if (iter != _funcs.end())
return reinterpret_cast<T>(iter->second);
return nullptr;
}
/// <summary>
/// Safely call import
/// If import not found - return STATUS_ORDINAL_NOT_FOUND
/// </summary>
/// <param name="name">Import name.</param>
/// <param name="...args">Function args</param>
/// <returns>Function result or STATUS_ORDINAL_NOT_FOUND if import not found</returns>
template<typename T, typename... Args>
NTSTATUS safeNativeCall( const std::string& name, Args&&... args )
{
auto pfn = DynImport::get<T>( name );
return pfn ? pfn( std::forward<Args>( args )... ) : STATUS_ORDINAL_NOT_FOUND;
}
/// <summary>
/// Safely call import
/// If import not found - return 0
/// </summary>
/// <param name="name">Import name.</param>
/// <param name="...args">Function args</param>
/// <returns>Function result or 0 if import not found</returns>
template<typename T, typename... Args>
auto safeCall( const std::string& name, Args&&... args )
{
auto pfn = DynImport::get<T>( name );
return pfn ? pfn( std::forward<Args>( args )... ) : std::invoke_result_t<T, Args...>();
}
/// <summary>
/// Load function into database
/// </summary>
/// <param name="name">Function name</param>
/// <param name="module">Module name</param>
/// <returns>true on success</returns>
BLACKBONE_API FARPROC load( const std::string& name, const std::wstring& modName )
{
auto mod = GetModuleHandleW( modName.c_str() );
return load( name, mod );
}
/// <summary>
/// Load function into database
/// </summary>
/// <param name="name">Function name</param>
/// <param name="hMod">Module base</param>
/// <returns>true on success</returns>
BLACKBONE_API FARPROC load( const std::string& name, HMODULE hMod )
{
CSLock lck( _mapGuard );
auto proc = GetProcAddress( hMod, name.c_str() );
if (proc)
{
_funcs.insert( std::make_pair( name, proc ) );
return proc;
}
return nullptr;
}
private:
std::unordered_map<std::string, FARPROC> _funcs; // function database
CriticalSection _mapGuard; // function database guard
};
// Syntax sugar
#define LOAD_IMPORT(name, mod) (DynImport::Instance().load( name, mod ))
#define GET_IMPORT(name) (DynImport::Instance().get<fn ## name>( #name ))
#define SAFE_NATIVE_CALL(name, ...) (DynImport::Instance().safeNativeCall<fn ## name>( #name, __VA_ARGS__ ))
#define SAFE_CALL(name, ...) (DynImport::Instance().safeCall<fn ## name>( #name, __VA_ARGS__ ))
}
@@ -0,0 +1,7 @@
#pragma once
#include "../Config.h"
namespace blackbone
{
BLACKBONE_API bool InitializeOnce();
}
@@ -0,0 +1,91 @@
#pragma once
#include "../Include/Winheaders.h"
#include "../Include/Types.h"
#include <unordered_map>
#include <vector>
#include <string>
namespace blackbone
{
class NameResolve
{
using mapApiSchema = std::unordered_map<std::wstring, std::vector<std::wstring>>;
public:
enum eResolveFlag
{
Default = 0, // Full resolve
ApiSchemaOnly = 1, // Resolve only Api schema dlls
EnsureFullPath = 2, // Make sure resulting path is full-qualified
NoSearch = 4, // Don't perform file search, only resolve name
Wow64 = 8, // Redirect System32 files to SysWow64
};
public:
BLACKBONE_API ~NameResolve() = default;
BLACKBONE_API static NameResolve& Instance();
/// <summary>
/// Initialize api set map
/// </summary>
/// <returns></returns>
BLACKBONE_API bool Initialize();
/// <summary>
/// Resolve image path.
/// </summary>
/// <param name="path">Image to resolve</param>
/// <param name="baseName">Name of parent image. Used only when resolving import images</param>
/// <param name="searchDir">Directory where source image is located</param>
/// <param name="flags">Resolve flags</param>
/// <param name="proc">Process. Used to search process executable directory</param>
/// <param name="actx">Activation context</param>
/// <returns>Status</returns>
BLACKBONE_API NTSTATUS ResolvePath(
std::wstring& path,
const std::wstring& baseName,
const std::wstring& searchDir,
eResolveFlag flags,
class Process& proc,
HANDLE actx = INVALID_HANDLE_VALUE
);
/// <summary>
/// Try SxS redirection
/// </summary>
/// <param name="path">Image path.</param>
/// <param name="proc">Process. Used to search process executable directory</param>
/// <param name="actx">Activation context</param>
/// <returns></returns>
BLACKBONE_API NTSTATUS ProbeSxSRedirect( std::wstring& path, class Process& proc, HANDLE actx = INVALID_HANDLE_VALUE );
private:
// Ensure singleton
NameResolve() = default;
NameResolve( const NameResolve& ) = delete;
NameResolve& operator =( const NameResolve& ) = delete;
/// <summary>
/// Gets the process executable directory
/// </summary>
/// <param name="pid">Process ID</param>
/// <returns>Process executable directory</returns>
std::wstring GetProcessDirectory( DWORD pid );
/// <summary>
/// OS dependent api set initialization
/// </summary>
/// <returns>true on success</returns>
template<typename PApiSetMap, typename PApiSetEntry, typename PHostArray, typename PHostEntry>
bool InitializeP();
private:
mapApiSchema _apiSchema; // Api schema table
};
}
@@ -0,0 +1,97 @@
#include "../Config.h"
#include <stdint.h>
#include <winnt.h>
// Thunk code
#pragma pack(push, 1)
struct ThunkData
{
#ifndef USE64
/*
mov eax, pInstance
mov fs:[0x14], eax
mov eax, pMethod
jmp eax
*/
uint8_t mov1 = 0xB8;
void* pInst = nullptr;
uint16_t fs1 = '\x64\xA3';
uint8_t fs2 = FIELD_OFFSET( NT_TIB, ArbitraryUserPointer );
uint8_t fs3 = 0;
uint16_t fs4 = 0;
uint8_t mov2 = 0xB8;
void* pFn = nullptr;
uint16_t jmp1 = '\xFF\xE0';
#else
/*
mov rax, pInstance
mov gs:[0x28], rax
mov rax, pMethod
jmp rax
*/
uint16_t mov1 = '\x48\xB8';
void* pInst = nullptr;
uint32_t fs1 = '\x65\x48\x89\x04';
uint8_t fs2 = 0x25;
uint8_t fs3 = FIELD_OFFSET( NT_TIB, ArbitraryUserPointer );
uint8_t fs4 = 0;
uint16_t fs5 = 0;
uint16_t mov2 = '\x48\xB8';
void* pFn = nullptr;
uint16_t jmp1 = '\xFF\xE0';
#endif
void setup( void* pInstance, void* pMethod )
{
pInst = pInstance;
pFn = pMethod;
}
};
#pragma pack(pop)
template<typename fn, typename C>
class Win32Thunk;
template<typename R, typename... Args, typename C>
class Win32Thunk < R( __stdcall* )(Args...), C >
{
public:
using TypeMember = R( C::* )(Args...);
using TypeFree = R( __stdcall* )(Args...);
public:
Win32Thunk( TypeMember pfn, C* pInstance )
: _pMethod( pfn )
, _pInstance( pInstance )
{
DWORD dwOld = 0;
VirtualProtect( &_thunk, sizeof( _thunk ), PAGE_EXECUTE_READWRITE, &dwOld );
_thunk.setup( this, &Win32Thunk::WrapHandler );
}
/// <summary>
/// Redirect call
/// </summary>
/// <param name="...args">Arguments</param>
/// <returns>Call result</returns>
static R __stdcall WrapHandler( Args... args )
{
auto _this = reinterpret_cast<Win32Thunk*>(((PNT_TIB)NtCurrentTeb())->ArbitraryUserPointer);
return (_this->_pInstance->*_this->_pMethod)(args...);
}
/// <summary>
/// Get thunk
/// </summary>
/// <returns></returns>
TypeFree GetThunk()
{
return reinterpret_cast<TypeFree>(&_thunk);
}
private:
TypeMember _pMethod = nullptr; // Member function to call
C* _pInstance = nullptr; // Bound instance
ThunkData _thunk; // Thunk code
};
@@ -0,0 +1,54 @@
#pragma once
#include <cstdio>
#include <cstdlib>
#pragma warning(push)
#pragma warning(disable : 4091)
#include <DbgHelp.h>
#pragma warning(pop)
namespace blackbone
{
#ifndef BLACKBONE_NO_TRACE
inline void DoTraceV( const char* fmt, va_list va_args )
{
char buf[2048], userbuf[1024];
vsprintf_s( userbuf, fmt, va_args );
sprintf_s( buf, "BlackBone: %s\r\n", userbuf );
OutputDebugStringA( buf );
#ifdef CONSOLE_TRACE
printf_s( buf );
#endif
}
inline void DoTraceV( const wchar_t* fmt, va_list va_args )
{
wchar_t buf[2048], userbuf[1024];
vswprintf_s( userbuf, fmt, va_args );
swprintf_s( buf, L"BlackBone: %ls\r\n", userbuf );
OutputDebugStringW( buf );
#ifdef CONSOLE_TRACE
wprintf_s( buf );
#endif
}
template<typename Ch>
inline void DoTrace( const Ch* fmt, ... )
{
va_list va_args;
va_start( va_args, fmt );
DoTraceV( fmt, va_args );
va_end( va_args );
}
#define BLACKBONE_TRACE(fmt, ...) DoTrace(fmt, ##__VA_ARGS__)
#else
#define BLACKBONE_TRACE(...)
#endif
}
@@ -0,0 +1,208 @@
#pragma once
#include "../Include/Winheaders.h"
#include <string>
#include <vector>
#include <tuple>
namespace blackbone
{
class Utils
{
public:
/// <summary>
/// Convert UTF-8 string to wide char one
/// </summary>
/// <param name="str">UTF-8 string</param>
/// <returns>wide char string</returns>
BLACKBONE_API static std::wstring UTF8ToWstring( const std::string& str );
/// <summary>
/// Convert wide string to UTF-8
/// </summary>
/// <param name="str">UTF-8 string</param>
/// <returns>wide char string</returns>
BLACKBONE_API static std::string WstringToUTF8( const std::wstring& str );
/// <summary>
/// Convert ANSI string to wide char one
/// </summary>
/// <param name="input">ANSI string.</param>
/// <param name="locale">String locale</param>
/// <returns>wide char string</returns>
BLACKBONE_API static std::wstring AnsiToWstring( const std::string& input, DWORD locale = CP_ACP );
/// <summary>
/// Convert wide char string to ANSI one
/// </summary>
/// <param name="input">wide char string.</param>
/// <param name="locale">String locale</param>
/// <returns>ANSI string</returns>
BLACKBONE_API static std::string WstringToAnsi( const std::wstring& input, DWORD locale = CP_ACP );
/// <summary>
/// Format string
/// </summary>
/// <param name="fmt">Format specifier</param>
/// <param name="">Arguments</param>
/// <returns>Formatted string</returns>
BLACKBONE_API static std::wstring FormatString( const wchar_t* fmt, ... );
/// <summary>
/// Get filename from full-qualified path
/// </summary>
/// <param name="path">File path</param>
/// <returns>Filename</returns>
BLACKBONE_API static std::wstring StripPath( const std::wstring& path );
/// <summary>
/// Get parent directory
/// </summary>
/// <param name="path">File path</param>
/// <returns>Parent directory</returns>
BLACKBONE_API static std::wstring GetParent( const std::wstring& path );
/// <summary>
/// Get current process exe file directory
/// </summary>
/// <returns>Exe directory</returns>
BLACKBONE_API static std::wstring GetExeDirectory();
/// <summary>
/// Cast string characters to lower case
/// </summary>
/// <param name="str">Source string.</param>
/// <returns>Result string</returns>
BLACKBONE_API static std::wstring ToLower( std::wstring str );
/// <summary>
/// Generate random alpha-numeric string
/// </summary>
/// <param name="length">Desired length. 0 - random length from 5 to 15</param>
/// <returns>Generated string</returns>
BLACKBONE_API static std::wstring RandomANString( int length = 0 );
/// <summary>
/// Get system error description
/// </summary>
/// <param name="code">The code.</param>
/// <returns>Error message</returns>
BLACKBONE_API static std::wstring GetErrorDescription( NTSTATUS code );
/// <summary>
/// Check if file exists
/// </summary>
/// <param name="path">Full-qualified file path</param>
/// <returns>true if exists</returns>
BLACKBONE_API static bool FileExists( const std::wstring& path );
};
/// <summary>
/// std::mutex alternative
/// </summary>
class CriticalSection
{
public:
BLACKBONE_API CriticalSection()
{
InitializeCriticalSection( &_native );
}
BLACKBONE_API ~CriticalSection()
{
DeleteCriticalSection( &_native );
}
BLACKBONE_API void lock()
{
EnterCriticalSection( &_native );
}
BLACKBONE_API void unlock()
{
LeaveCriticalSection( &_native );
}
private:
CRITICAL_SECTION _native;
};
/// <summary>
/// std::lock_guard alternative
/// </summary>
class CSLock
{
public:
BLACKBONE_API CSLock( CriticalSection& cs )
: _cs( cs )
{
cs.lock();
}
BLACKBONE_API ~CSLock()
{
_cs.unlock();
}
private:
CSLock( const CSLock& ) = delete;
CSLock& operator = ( const CSLock& ) = delete;
private:
CriticalSection& _cs;
};
/// <summary>
/// System32 helper
/// </summary>
class FsRedirector
{
public:
FsRedirector( bool wow64 )
: _wow64( wow64 )
{
#ifndef XP_BUILD
if (wow64)
Wow64DisableWow64FsRedirection( &_fsRedirection );
#endif
}
~FsRedirector()
{
#ifndef XP_BUILD
if (_wow64)
Wow64RevertWow64FsRedirection( _fsRedirection );
#endif
}
private:
PVOID _fsRedirection = nullptr;
bool _wow64;
};
#if _MSC_VER >= 1900
namespace tuple_detail
{
template<typename T, typename F, size_t... Is>
void visit_each( T&& t, F f, std::index_sequence<Is...> ) { auto l = { (f( std::get<Is>( t ) ), 0)... }; }
template<typename... Ts>
void copyTuple( std::tuple<Ts...> const& from, std::vector<char>& to )
{
auto func = [&to]( auto& v )
{
auto ptr = to.size();
to.resize( ptr + sizeof( v ) );
memcpy( to.data() + ptr, &v, sizeof( v ) );
return 0;
};
visit_each( from, func, std::index_sequence_for<Ts...>() );
}
}
#endif
}
@@ -0,0 +1,66 @@
#pragma once
#include "../Config.h"
#ifdef COMPILER_MSVC
#include "../Include/Winheaders.h"
#include <map>
#if _MSC_VER >= 1920
#include <string>
#endif
#pragma warning(push)
#pragma warning(disable : 4091)
#include "cor.h"
#include <atlbase.h>
#pragma warning(pop)
namespace blackbone
{
/// <summary>
/// .NET metadata parser
/// </summary>
class ImageNET
{
public:
using mapMethodRVA = std::map<std::pair<std::wstring, std::wstring>, uintptr_t>;
public:
BLACKBONE_API ImageNET(void);
BLACKBONE_API ~ImageNET(void);
/// <summary>
/// Initialize COM classes
/// </summary>
/// <param name="path">Image file path</param>
/// <returns>true on success</returns>
BLACKBONE_API bool Init( const std::wstring& path );
/// <summary>
/// Extract methods from image
/// </summary>
/// <param name="methods">Found Methods</param>
/// <returns>true on success</returns>
BLACKBONE_API bool Parse( mapMethodRVA* methods = nullptr );
/// <summary>
/// Get image .NET runtime version
/// </summary>
/// <returns>runtime version, "n/a" if nothing found</returns>
BLACKBONE_API static std::wstring GetImageRuntimeVer( const wchar_t* ImagePath );
private:
std::wstring _path; // Image path
mapMethodRVA _methods; // Image methods
// COM helpers
CComPtr<IMetaDataDispenserEx> _pMetaDisp;
CComPtr<IMetaDataImport> _pMetaImport;
CComPtr<IMetaDataAssemblyImport> _pAssemblyImport;
};
}
#endif
@@ -0,0 +1,348 @@
#pragma once
#include "../Config.h"
#include "../Include/Winheaders.h"
#include "../Include/Types.h"
#include "../Include/HandleGuard.h"
#include "../Misc/Utils.h"
#ifdef COMPILER_MSVC
#include "ImageNET.h"
#endif // COMPILER_MSVC
#include <string>
#include <memory>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <list>
namespace blackbone
{
namespace pe
{
enum AddressType
{
RVA, // Relative virtual
VA, // Absolute virtual
RPA, // Relative physical
};
// Relocation block information
struct RelocData
{
ULONG PageRVA;
ULONG BlockSize;
struct
{
WORD Offset : 12;
WORD Type : 4;
}Item[1];
};
/// <summary>
/// Import information
/// </summary>
struct ImportData
{
std::string importName; // Function name
uintptr_t ptrRVA; // Function pointer RVA in
WORD importOrdinal; // Function ordinal
bool importByOrd; // Function is imported by ordinal
};
/// <summary>
/// Export function info
/// </summary>
struct ExportData
{
std::string name;
uint32_t RVA = 0;
ExportData( const std::string& name_, uint32_t rva_ )
: name( name_ )
, RVA( rva_ ) { }
bool operator == (const ExportData& other)
{
return name == other.name;
}
bool operator < (const ExportData& other)
{
return name < other.name;
}
};
// Imports and sections related
using mapImports = std::unordered_map<std::wstring, std::vector<ImportData>>;
using vecSections = std::vector<IMAGE_SECTION_HEADER>;
using vecExports = std::vector<ExportData>;
/// <summary>
/// Primitive PE parsing class
/// </summary>
class PEImage
{
using PCHDR32 = const IMAGE_NT_HEADERS32*;
using PCHDR64 = const IMAGE_NT_HEADERS64*;
public:
BLACKBONE_API PEImage( void );
BLACKBONE_API ~PEImage( void );
BLACKBONE_API PEImage( PEImage&& other ) = default;
/// <summary>
/// Load image from file
/// </summary>
/// <param name="path">File path</param>
/// <param name="skipActx">If true - do not initialize activation context</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS Load( const std::wstring& path, bool skipActx = false );
/// <summary>
/// Load image from memory location
/// </summary>
/// <param name="pData">Image data</param>
/// <param name="size">Data size.</param>
/// <param name="plainData">If false - data has image layout</param>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS Load( void* pData, size_t size, bool plainData = true );
/// <summary>
/// Reload closed image
/// </summary>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS Reload();
/// <summary>
/// Release mapping, if any
/// </summary>
/// <param name="temporary">Preserve file paths for file reopening</param>
BLACKBONE_API void Release( bool temporary = false );
/// <summary>
/// Parses PE image
/// </summary>
/// <returns>Status code</returns>
BLACKBONE_API NTSTATUS Parse( void* pImageBase = nullptr );
/// <summary>
/// Processes image imports
/// </summary>
/// <param name="useDelayed">Process delayed import instead</param>
/// <returns>Import data</returns>
BLACKBONE_API mapImports& GetImports( bool useDelayed = false );
/// <summary>
/// Retrieve all exported functions with names
/// </summary>
/// <param name="names">Found exports</param>
BLACKBONE_API void GetExports( vecExports& exports );
/// <summary>
/// Retrieve image TLS callbacks
/// Callbacks are rebased for target image
/// </summary>
/// <param name="targetBase">Target image base</param>
/// <param name="result">Found callbacks</param>
/// <returns>Number of TLS callbacks in image</returns>
BLACKBONE_API int GetTLSCallbacks( module_t targetBase, std::vector<ptr_t>& result ) const;
/// <summary>
/// Retrieve data directory address
/// </summary>
/// <param name="index">Directory index</param>
/// <param name="keepRelative">Keep address relative to image base</param>
/// <returns>Directory address</returns>
BLACKBONE_API uintptr_t DirectoryAddress( int index, AddressType type = VA ) const;
/// <summary>
/// Get data directory size
/// </summary>
/// <param name="index">Data directory index</param>
/// <returns>Data directory size</returns>
BLACKBONE_API size_t DirectorySize( int index ) const;
/// <summary>
/// Resolve virtual memory address to physical file offset
/// </summary>
/// <param name="Rva">Memory address</param>
/// <param name="type">Address type to return</param>
/// <returns>Resolved address</returns>
BLACKBONE_API uintptr_t ResolveRVAToVA( uintptr_t Rva, AddressType type = VA ) const;
/// <summary>
/// Get image path
/// </summary>
/// <returns>Image path</returns>
BLACKBONE_API inline const std::wstring& path() const { return _imagePath; }
/// <summary>
/// Get image name
/// </summary>
/// <returns>Image name</returns>
BLACKBONE_API inline std::wstring name() const { return Utils::StripPath( _imagePath ); }
/// <summary>
/// Get image load address
/// </summary>
/// <returns>Image base</returns>
BLACKBONE_API inline void* base() const { return _pFileBase; }
/// <summary>
/// Get image base address
/// </summary>
/// <returns>Image base</returns>
BLACKBONE_API inline module_t imageBase() const { return _imgBase; }
/// <summary>
/// Get image size in bytes
/// </summary>
/// <returns>Image size</returns>
BLACKBONE_API inline uint32_t imageSize() const { return _imgSize; }
/// <summary>
/// Get size of image headers
/// </summary>
/// <returns>Size of image headers</returns>
BLACKBONE_API inline size_t headersSize() const { return _hdrSize; }
/// <summary>
/// Get image entry point rebased to another image base
/// </summary>
/// <param name="base">New image base</param>
/// <returns>New entry point address</returns>
BLACKBONE_API inline ptr_t entryPoint( module_t base ) const { return ((_epRVA != 0) ? (_epRVA + base) : 0); };
/// <summary>
/// Get image sections
/// </summary>
/// <returns>Image sections</returns>
BLACKBONE_API inline const vecSections& sections() const { return _sections; }
/// <summary>
/// Check if image is an executable file and not a dll
/// </summary>
/// <returns>true if image is an *.exe</returns>
BLACKBONE_API inline bool isExe() const { return _isExe; }
/// <summary>
/// Check if image is pure IL image
/// </summary>
/// <returns>true on success</returns>
BLACKBONE_API inline bool pureIL() const { return _isPureIL; }
BLACKBONE_API inline int32_t ilFlagOffset() const { return _ILFlagOffset; }
/// <summary>
/// Get image type. 32/64 bit
/// </summary>
/// <returns>Image type</returns>
BLACKBONE_API inline eModType mType() const { return _is64 ? mt_mod64 : mt_mod32; }
/// <summary>
/// Get activation context handle
/// </summary>
/// <returns>Actx handle</returns>
BLACKBONE_API inline HANDLE actx() const { return _hctx; }
/// <summary>
/// true if image is mapped as plain data file
/// </summary>
/// <returns>true if mapped as plain data file, false if mapped as image</returns>
BLACKBONE_API inline bool isPlainData() const { return _isPlainData; }
/// <summary>
/// Get manifest resource ID
/// </summary>
/// <returns>Manifest resource ID</returns>
BLACKBONE_API inline int manifestID() const { return _manifestIdx; }
/// <summary>
/// Get image subsystem
/// </summary>
/// <returns>Image subsystem</returns>
BLACKBONE_API inline uint32_t subsystem() const { return _subsystem; }
/// <summary>
/// Get manifest resource file
/// </summary>
/// <returns>Manifest resource file</returns>
BLACKBONE_API inline const std::wstring& manifestFile() const { return _manifestPath; }
/// <summary>
/// If true - no actual PE file available on disk
/// </summary>
/// <returns>Flag</returns>
BLACKBONE_API inline bool noPhysFile() const { return _noFile; }
/// <summary>
/// DllCharacteristics field of header
/// </summary>
/// <returns>DllCharacteristics</returns>
BLACKBONE_API inline uint32_t DllCharacteristics() const { return _DllCharacteristics; }
#ifdef COMPILER_MSVC
/// <summary>
/// .NET image parser
/// </summary>
/// <returns>.NET image parser</returns>
BLACKBONE_API ImageNET& net() { return _netImage; }
#endif
private:
/// <summary>
/// Prepare activation context
/// </summary>
/// <param name="filepath">Path to PE file. If nullptr - manifest is extracted from memory to disk</param>
/// <returns>Status code</returns>
NTSTATUS PrepareACTX( const wchar_t* filepath = nullptr );
/// <summary>
/// Get manifest from image data
/// </summary>
/// <param name="size">Manifest size</param>
/// <param name="manifestID">Mmanifest ID</param>
/// <returns>Manifest data</returns>
void* GetManifest( uint32_t& size, int32_t& manifestID );
private:
Handle _hFile; // Target file HANDLE
Handle _hMapping; // Memory mapping object
Mapping _pFileBase; // Mapping base
bool _isPlainData = false; // File mapped as plain data file
bool _is64 = false; // Image is 64 bit
bool _isExe = false; // Image is an .exe file
bool _isPureIL = false; // Pure IL image
bool _noFile = false; // Parsed from memory, no underlying PE file available
PCHDR32 _pImageHdr32 = nullptr; // PE header info
PCHDR64 _pImageHdr64 = nullptr; // PE header info
ptr_t _imgBase = 0; // Image base
uint32_t _imgSize = 0; // Image size
uint32_t _epRVA = 0; // Entry point RVA
uint32_t _hdrSize = 0; // Size of headers
ACtxHandle _hctx; // Activation context
int32_t _manifestIdx = 0; // Manifest resource ID
uint32_t _subsystem = 0; // Image subsystem
int32_t _ILFlagOffset = 0; // Offset of pure IL flag
uint32_t _DllCharacteristics = 0; // DllCharacteristics flags
vecSections _sections; // Section info
mapImports _imports; // Import functions
mapImports _delayImports; // Import functions
std::wstring _imagePath; // Image path
std::wstring _manifestPath; // Image manifest container
#ifdef COMPILER_MSVC
ImageNET _netImage; // .net image info
#endif
};
}
}
@@ -0,0 +1,224 @@
#pragma once
#include "../Include/Types.h"
#include <string>
#include <vector>
#include <functional>
#include <initializer_list>
namespace blackbone
{
class PatternSearch
{
public:
/// <summary>
/// Callback to handle a matching address for the Search*WithHandler() methods.
/// If the handler returns true, the search is stopped, else the search continues.
/// </summary>
typedef std::function<bool (ptr_t)> MatchHandler;
public:
// logAlignment can be used to speed-up the search in some cases. For example, if you know that the start of the pattern
// is always 8-byte-aligned, you can pass logAlignment=3 (2^3 = 8) to skip searching at all addresses that aren't multiples
// of 8. Note that for smaller alignments and depending on the exact pattern, this may not always be faster (it may even be
// a tiny bit slower), so profile it if you care about performance.
BLACKBONE_API PatternSearch( const std::vector<uint8_t>& pattern, size_t logAlignment = 0 );
BLACKBONE_API PatternSearch( const std::initializer_list<uint8_t>&& pattern, size_t logAlignment = 0 );
BLACKBONE_API PatternSearch( const std::string& pattern, size_t logAlignment = 0 );
BLACKBONE_API PatternSearch( const char* pattern, size_t len = 0, size_t logAlignment = 0 );
BLACKBONE_API PatternSearch( const uint8_t* pattern, size_t len = 0, size_t logAlignment = 0 );
BLACKBONE_API ~PatternSearch() = default;
/// <summary>
/// Default pattern matching with wildcards and a callback handler for matches.
/// std::search is approximately 2x faster than naive approach.
/// </summary>
/// <param name="wildcard">Pattern wildcard</param>
/// <param name="scanStart">Starting address</param>
/// <param name="scanSize">Size of region to scan</param>
/// <param name="handler">Callback that is called for every match. If it returns true, the search is stopped prematurely.</param>
/// <param name="value_offset">Value that will be added to resulting addresses</param>
/// <returns>true if the callback handler ever returned true (i.e. the search ended prematurely), false otherwise.</returns>
BLACKBONE_API bool SearchWithHandler(
uint8_t wildcard,
void* scanStart,
size_t scanSize,
MatchHandler handler,
ptr_t value_offset = 0
) const;
/// <summary>
/// Full pattern match, no wildcards, with a callback handler for matches.
/// Uses BoyerMooreHorspool algorithm.
/// </summary>
/// <param name="scanStart">Starting address</param>
/// <param name="scanSize">Size of region to scan</param>
/// <param name="handler">Callback that is called for every match. If it returns true, the search is stopped prematurely.</param>
/// <param name="value_offset">Value that will be added to resulting addresses</param>
/// <returns>true if the callback handler ever returned true (i.e. the search ended prematurely), false otherwise.</returns>
BLACKBONE_API bool SearchWithHandler(
void* scanStart,
size_t scanSize,
MatchHandler handler,
ptr_t value_offset = 0
) const;
/// <summary>
/// Search pattern in remote process with a callback handler for matches
/// </summary>
/// <param name="remote">Remote process</param>
/// <param name="wildcard">Pattern wildcard</param>
/// <param name="scanStart">Starting address</param>
/// <param name="scanSize">Size of region to scan</param>
/// <param name="handler">Callback that is called for every match. If it returns true, the search is stopped prematurely.</param>
/// <returns>true if the callback handler ever returned true (i.e. the search ended prematurely), false otherwise.</returns>
BLACKBONE_API bool SearchRemoteWithHandler(
class Process& remote,
uint8_t wildcard,
ptr_t scanStart,
size_t scanSize,
MatchHandler handler
) const;
/// <summary>
/// Search pattern in remote process with a callback handler for matches
/// </summary>
/// <param name="remote">Remote process</param>
/// <param name="scanStart">Starting address</param>
/// <param name="scanSize">Size of region to scan</param>
/// <param name="handler">Callback that is called for every match. If it returns true, the search is stopped prematurely.</param>
/// <returns>true if the callback handler ever returned true (i.e. the search ended prematurely), false otherwise.</returns>
BLACKBONE_API bool SearchRemoteWithHandler(
class Process& remote,
ptr_t scanStart,
size_t scanSize,
MatchHandler handler
) const;
/// <summary>
/// Search pattern in whole address space of remote process with a callback handler for matches
/// </summary>
/// <param name="remote">Remote process</param>
/// <param name="useWildcard">True if pattern contains wildcards</param>
/// <param name="wildcard">Pattern wildcard</param>
/// <param name="handler">Callback that is called for every match. If it returns true, the search is stopped prematurely.</param>
/// <returns>true if the callback handler ever returned true (i.e. the search ended prematurely), false otherwise.</returns>
BLACKBONE_API bool SearchRemoteWholeWithHandler(
class Process& remote,
bool useWildcard,
uint8_t wildcard,
MatchHandler handler
) const;
/// <summary>
/// Default pattern matching with wildcards.
/// std::search is approximately 2x faster than naive approach.
/// </summary>
/// <param name="wildcard">Pattern wildcard</param>
/// <param name="scanStart">Starting address</param>
/// <param name="scanSize">Size of region to scan</param>
/// <param name="out">Found results</param>
/// <param name="value_offset">Value that will be added to resulting addresses</param>
/// <param name="maxMatches">Maximum number of matches to collect</param>
/// <returns>Number of found addresses</returns>
BLACKBONE_API size_t Search(
uint8_t wildcard,
void* scanStart,
size_t scanSize,
std::vector<ptr_t>& out,
ptr_t value_offset = 0,
size_t maxMatches = SIZE_MAX
) const;
/// <summary>
/// Full pattern match, no wildcards.
/// Uses BoyerMooreHorspool algorithm.
/// </summary>
/// <param name="scanStart">Starting address</param>
/// <param name="scanSize">Size of region to scan</param>
/// <param name="out">Found results</param>
/// <param name="value_offset">Value that will be added to resulting addresses</param>
/// <param name="maxMatches">Maximum number of matches to collect</param>
/// <returns>Number of found addresses</returns>
BLACKBONE_API size_t Search(
void* scanStart,
size_t scanSize,
std::vector<ptr_t>& out,
ptr_t value_offset = 0,
size_t maxMatches = SIZE_MAX
) const;
/// <summary>
/// Search pattern in remote process
/// </summary>
/// <param name="remote">Remote process</param>
/// <param name="wildcard">Pattern wildcard</param>
/// <param name="scanStart">Starting address</param>
/// <param name="scanSize">Size of region to scan</param>
/// <param name="out">Found results</param>
/// <param name="maxMatches">Maximum number of matches to collect</param>
/// <returns>Number of found addresses</returns>
BLACKBONE_API size_t SearchRemote(
class Process& remote,
uint8_t wildcard,
ptr_t scanStart,
size_t scanSize,
std::vector<ptr_t>& out,
size_t maxMatches = SIZE_MAX
) const;
/// <summary>
/// Search pattern in remote process
/// </summary>
/// <param name="remote">Remote process</param>
/// <param name="scanStart">Starting address</param>
/// <param name="scanSize">Size of region to scan</param>
/// <param name="out">Found results</param>
/// <param name="maxMatches">Maximum number of matches to collect</param>
/// <returns>Number of found addresses</returns>
BLACKBONE_API size_t SearchRemote(
class Process& remote,
ptr_t scanStart,
size_t scanSize,
std::vector<ptr_t>& out,
size_t maxMatches = SIZE_MAX
) const;
/// <summary>
/// Search pattern in whole address space of remote process
/// </summary>
/// <param name="remote">Remote process</param>
/// <param name="useWildcard">True if pattern contains wildcards</param>
/// <param name="wildcard">Pattern wildcard</param>
/// <param name="out">Found results</param>
/// <param name="maxMatches">Maximum number of matches to collect</param>
/// <returns>Number of found addresses</returns>
BLACKBONE_API size_t SearchRemoteWhole(
class Process& remote,
bool useWildcard,
uint8_t wildcard,
std::vector<ptr_t>& out,
size_t maxMatches = SIZE_MAX
) const;
private:
static inline bool collectAllMatchHandler(ptr_t addr, std::vector<ptr_t>& out, size_t maxMatches)
{
out.emplace_back(addr);
return out.size() >= maxMatches;
}
private:
std::vector<uint8_t> _pattern; // Pattern to search
size_t logAlignment;
};
}
@@ -0,0 +1,282 @@
#pragma once
#include "../Include/Winheaders.h"
#include "../Include/Macro.h"
#include "../Include/Types.h"
#include "../Include/CallResult.h"
#include <stdint.h>
#include <memory>
namespace blackbone
{
/// <summary>
/// Get rid of EXECUTABLE flag if DEP isn't enabled
/// </summary>
/// <param name="prot">Memory protection flags</param>
/// <param name="bDEP">DEP flag</param>
/// <returns>New protection flags</returns>
inline DWORD CastProtection( DWORD prot, bool bDEP )
{
if (bDEP == true)
{
return prot;
}
else
{
if (prot == PAGE_EXECUTE_READ)
return PAGE_READONLY;
else if (prot == PAGE_EXECUTE_READWRITE)
return PAGE_READWRITE;
else if (prot == PAGE_EXECUTE_WRITECOPY)
return PAGE_WRITECOPY;
else
return prot;
}
}
class MemBlock
{
public:
class MemBlockImpl
{
friend class MemBlock;
public:
MemBlockImpl() = default;
/// <summary>
/// MemBlock_p ctor
/// </summary>
/// <param name="mem">Process memory routines</param>
/// <param name="ptr">Memory address</param>
/// <param name="size">Block size</param>
/// <param name="prot">Memory protection</param>
/// <param name="own">true if caller will be responsible for block deallocation</param>
MemBlockImpl( class ProcessMemory* mem, ptr_t ptr, size_t size, DWORD prot, bool own = true, bool physical = false );
~MemBlockImpl()
{
if (_own)
Free();
}
/// <summary>
/// Free memory
/// </summary>
/// <param name="size">Size of memory chunk to free. If 0 - whole block is freed</param>
NTSTATUS Free( size_t size = 0 );
private:
ptr_t _ptr = 0; // Raw memory pointer
size_t _size = 0; // Region size
DWORD _protection = 0; // Region protection
bool _own = true; // Memory will be freed in destructor
bool _physical = false; // Memory allocated as direct physical
class ProcessMemory* _memory; // Target process routines
};
public:
/// <summary>
/// MemBlock ctor
/// </summary>
BLACKBONE_API MemBlock() = default;
/// <summary>
/// MemBlock ctor
/// </summary>
/// <param name="mem">Process memory routines</param>
/// <param name="ptr">Memory address</param>
/// <param name="own">true if caller will be responsible for block deallocation</param>
BLACKBONE_API MemBlock( class ProcessMemory* mem, ptr_t ptr, bool own = true );
/// <summary>
/// MemBlock ctor
/// </summary>
/// <param name="mem">Process memory routines</param>
/// <param name="ptr">Memory address</param>
/// <param name="size">Block size</param>
/// <param name="prot">Memory protection</param>
/// <param name="own">true if caller will be responsible for block deallocation</param>
BLACKBONE_API MemBlock( class ProcessMemory* mem, ptr_t ptr, size_t size, DWORD prot, bool own = true, bool physical = false );
/// <summary>
/// Move ctor
/// </summary>
/// <param name="rhs">Move from</param>
BLACKBONE_API MemBlock( MemBlock&& rhs ) { _pImpl.swap( rhs._pImpl ); }
BLACKBONE_API MemBlock& operator = ( MemBlock&& rhs )
{
// Self assign
if (_pImpl == rhs._pImpl)
return *this;
_pImpl.swap( rhs._pImpl );
return *this;
}
/// <summary>
/// Allocate new memory block
/// </summary>
/// <param name="process">Process memory routines</param>
/// <param name="size">Block size</param>
/// <param name="desired">Desired base address of new block</param>
/// <param name="protection">Win32 Memory protection flags</param>
/// <param name="own">false if caller will be responsible for block deallocation</param>
/// <returns>Memory block. If failed - returned block will be invalid</returns>
BLACKBONE_API static call_result_t<MemBlock> Allocate(
class ProcessMemory& process,
size_t size,
ptr_t desired = 0,
DWORD protection = PAGE_EXECUTE_READWRITE,
bool own = true
);
/// <summary>
/// Allocate new memory block as close to a given location as possible.
/// </summary>
/// <param name="process">Process memory routines</param>
/// <param name="size">Block size</param>
/// <param name="desired">Desired base address of new block</param>
/// <param name="protection">Win32 Memory protection flags</param>
/// <param name="own">false if caller will be responsible for block deallocation</param>
/// <returns>Memory block. If failed - returned block will be invalid</returns>
BLACKBONE_API static call_result_t<MemBlock> AllocateClosest(
class ProcessMemory& process,
size_t size,
ptr_t desired,
DWORD protection = PAGE_EXECUTE_READWRITE,
bool own = true
);
/// <summary>
/// Reallocate existing block for new size
/// </summary>
/// <param name="size">New block size</param>
/// <param name="desired">Desired base address of new block</param>
/// <param name="protection">Memory protection</param>
/// <returns>New block address</returns>
BLACKBONE_API call_result_t<ptr_t> Realloc( size_t size, ptr_t desired = 0, DWORD protection = PAGE_EXECUTE_READWRITE );
/// <summary>
/// Change memory protection
/// </summary>
/// <param name="protection">New protection flags</param>
/// <param name="offset">Memory offset in block</param>
/// <param name="size">Block size</param>
/// <param name="pOld">Old protection flags</param>
/// <returns>Status</returns>
BLACKBONE_API NTSTATUS Protect( DWORD protection, uintptr_t offset = 0, size_t size = 0, DWORD* pOld = nullptr );
/// <summary>
/// Free memory
/// </summary>
/// <param name="size">Size of memory chunk to free. If 0 - whole block is freed</param>
BLACKBONE_API NTSTATUS Free( size_t size = 0 );
/// <summary>
/// Read data
/// </summary>
/// <param name="offset">Data offset in block</param>
/// <param name="size">Size of data to read</param>
/// <param name="pResult">Output buffer</param>
/// <param name="handleHoles">
/// If true, function will try to read all committed pages in range ignoring uncommitted.
/// Otherwise function will fail if there is at least one non-committed page in region.
/// </param>
/// <returns>Status</returns>
BLACKBONE_API NTSTATUS Read( uintptr_t offset, size_t size, PVOID pResult, bool handleHoles = false );
/// <summary>
/// Write data
/// </summary>
/// <param name="offset">Data offset in block</param>
/// <param name="size">Size of data to write</param>
/// <param name="pData">Buffer to write</param>
/// <returns>Status</returns>
BLACKBONE_API NTSTATUS Write( uintptr_t offset, size_t size, const void* pData );
/// <summary>
/// Read data
/// </summary>
/// <param name="offset">Data offset in block</param>
/// <param name="def_val">Defult return value if read has failed</param>
/// <returns>Read data</returns>
template<typename T>
T Read( uintptr_t offset, const T& def_val )
{
T res = def_val;
Read( offset, sizeof( T ), &res );
return res;
}
/// <summary>
/// Read data
/// </summary>
/// <param name="offset">Data offset in block</param>
/// <param name="def_val">Read data</param>
/// <returns>Status code</returns>
template<typename T>
NTSTATUS Read( size_t offset, T& val )
{
return Read( offset, sizeof( val ), &val );
}
/// <summary>
/// Write data
/// </summary>
/// <param name="offset">Offset in block</param>
/// <param name="data">Data to write</param>
/// <returns>Status</returns>
template<typename T>
NTSTATUS Write( uintptr_t offset, const T& data )
{
return Write( offset, sizeof( data ), &data );
}
/// <summary>
/// Try to free memory and reset pointers
/// </summary>
BLACKBONE_API void Reset();
/// <summary>
/// Memory will not be deallocated upon object destruction
/// </summary>
BLACKBONE_API inline void Release() { if (_pImpl) _pImpl->_own = false; }
/// <summary>
/// Get memory pointer
/// </summary>
/// <returns>Memory pointer</returns>
template<typename T = ptr_t>
inline T ptr() const { return _pImpl ? (T)_pImpl->_ptr : T( 0 ); }
/// <summary>
/// Get block size
/// </summary>
/// <returns>Block size</returns>
BLACKBONE_API inline size_t size() const { return _pImpl ? _pImpl->_size : 0; }
/// <summary>
/// Get block memory protection
/// </summary>
/// <returns>Memory protection flags</returns>
BLACKBONE_API inline DWORD protection() const { return _pImpl ? _pImpl->_protection : 0; }
/// <summary>
/// Validate memory block
/// <returns>true if memory pointer isn't 0</returns>
BLACKBONE_API inline bool valid() const { return( _pImpl.get() != nullptr && _pImpl->_ptr != 0); }
/// <summary>
/// Get memory pointer
/// </summary>
/// <returns>Memory pointer</returns>
BLACKBONE_API inline operator ptr_t() const { return _pImpl ? _pImpl->_ptr : 0; }
private:
std::shared_ptr<MemBlockImpl> _pImpl;
};
}

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