├── src ├── BlackBone │ ├── PatternSearch.cpp │ ├── PatternSearch.h │ ├── BlackBone.vcxproj.user │ ├── AsmHelper.h │ ├── AsmHelperBase.cpp │ ├── Winheaders.h │ ├── AsmJit │ │ ├── ApiEnd.h │ │ ├── MemoryMarker.cpp │ │ ├── Operand.h │ │ ├── ApiBegin.h │ │ ├── Assembler.h │ │ ├── Defs.cpp │ │ ├── MemoryMarker.h │ │ ├── Logger.cpp │ │ ├── Config.h │ │ ├── CodeGenerator.cpp │ │ ├── Regenerate.py │ │ ├── Util_p.h │ │ ├── CodeGenerator.h │ │ ├── Util.cpp │ │ ├── Platform.cpp │ │ ├── Logger.h │ │ ├── Platform.h │ │ ├── MemoryManager.h │ │ └── Compiler.cpp │ ├── Win7Specific.h │ ├── LDasm.h │ ├── DynImport.cpp │ ├── MExcept.h │ ├── ImageNET.h │ ├── DynImport.h │ ├── Types.h │ ├── Threads.h │ ├── FileProjection.h │ ├── ProcessCore.cpp │ ├── AsmStack.hpp │ ├── Win8Specific.h │ ├── Utils.h │ ├── x86Subsystem.h │ ├── ProcessCore.h │ ├── NameResolve.h │ ├── AsmHelperBase.h │ ├── FileProjection.cpp │ ├── AsmHelper32.h │ ├── Process.h │ ├── AsmHelper64.h │ ├── Macro.h │ ├── ProcessMemory.h │ ├── Threads.cpp │ ├── Process.cpp │ ├── ProcessMemory.cpp │ ├── x86Subsystem.cpp │ ├── Utils.cpp │ ├── MemBlock.cpp │ ├── Wow64Subsystem.h │ ├── FunctionTypes.h │ ├── PEParser.h │ ├── ProcessModules.h │ ├── ImageNET.cpp │ ├── Thread.h │ ├── MemBlock.h │ ├── AsmVariant.hpp │ └── RemoteFunction.hpp └── TestApp │ ├── TestApp.vcxproj.filters │ └── TestApp.vcxproj.user ├── .gitignore ├── LICENSE ├── BlackBone.sln └── README.md /src/BlackBone/PatternSearch.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TopoIogist/Blackbone/HEAD/src/BlackBone/PatternSearch.cpp -------------------------------------------------------------------------------- /src/BlackBone/PatternSearch.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TopoIogist/Blackbone/HEAD/src/BlackBone/PatternSearch.h -------------------------------------------------------------------------------- /src/BlackBone/BlackBone.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/BlackBone/AsmHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef _M_AMD64 4 | #define AsmJitHelper AsmHelper64 5 | #include "AsmHelper64.h" 6 | #else 7 | #include "AsmHelper32.h" 8 | #define AsmJitHelper AsmHelper32 9 | #endif // _M_AMD64 10 | -------------------------------------------------------------------------------- /src/TestApp/TestApp.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/BlackBone/AsmHelperBase.cpp: -------------------------------------------------------------------------------- 1 | #include "AsmHelperBase.h" 2 | 3 | namespace ds_mmap 4 | { 5 | CAsmHelperBase::CAsmHelperBase(AsmJit::Assembler& _a) 6 | : a(_a) 7 | { 8 | } 9 | 10 | CAsmHelperBase::~CAsmHelperBase(void) 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/BlackBone/Winheaders.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef WIN32_LEAN_AND_MEAN 4 | #define WIN32_LEAN_AND_MEAN 5 | #endif 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma warning(disable : 4005) 14 | #include 15 | #pragma warning(default : 4005) 16 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/ApiEnd.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | #if defined(_MSC_VER) 8 | 9 | // Pop disabled warnings by ApiBegin.h 10 | #pragma warning(pop) 11 | 12 | // Rename symbols back. 13 | #undef vsnprintf 14 | #undef snprintf 15 | 16 | #endif // _MSC_VER 17 | -------------------------------------------------------------------------------- /src/TestApp/TestApp.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WindowsLocalDebugger 5 | NativeOnly 6 | 7 | 8 | NativeOnly 9 | 10 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/MemoryMarker.cpp: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Dependencies] 8 | #include "Build.h" 9 | #include "MemoryMarker.h" 10 | 11 | // [Api-Begin] 12 | #include "ApiBegin.h" 13 | 14 | namespace AsmJit { 15 | 16 | // ============================================================================ 17 | // [AsmJit::MemoryMarker] 18 | // ============================================================================ 19 | 20 | MemoryMarker::MemoryMarker() ASMJIT_NOTHROW {} 21 | MemoryMarker::~MemoryMarker() ASMJIT_NOTHROW {} 22 | 23 | } // AsmJit namespace 24 | 25 | // [Api-End] 26 | #include "ApiEnd.h" 27 | -------------------------------------------------------------------------------- /src/BlackBone/Win7Specific.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | 5 | namespace blackbone 6 | { 7 | #pragma warning(disable : 4201) 8 | 9 | struct _LDR_DATA_TABLE_ENTRY_W7 : LDR_DATA_TABLE_ENTRY_BASE_T 10 | { 11 | _LIST_ENTRY ForwarderLinks; 12 | _LIST_ENTRY ServiceTagLinks; 13 | _LIST_ENTRY StaticLinks; 14 | void * ContextInformation; 15 | unsigned long OriginalBase; 16 | _LARGE_INTEGER LoadTime; 17 | }; 18 | 19 | typedef struct _RTL_INVERTED_FUNCTION_TABLE7 20 | { 21 | ULONG Count; 22 | ULONG MaxCount; 23 | ULONG Pad[0x1]; 24 | RTL_INVERTED_FUNCTION_TABLE_ENTRY Entries[0x200]; 25 | 26 | } RTL_INVERTED_FUNCTION_TABLE7, *PRTL_INVERTED_FUNCTION_TABLE7; 27 | 28 | #pragma warning(default : 4201) 29 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Operand.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Guard] 8 | #ifndef _ASMJIT_OPERAND_H 9 | #define _ASMJIT_OPERAND_H 10 | 11 | // [Dependencies] 12 | #include "Build.h" 13 | 14 | namespace AsmJit { 15 | 16 | //! @addtogroup AsmJit_Core 17 | //! @{ 18 | 19 | // There is currently no platform independent code. 20 | 21 | //! @} 22 | 23 | } // AsmJit namespace 24 | 25 | // ============================================================================ 26 | // [Platform Specific] 27 | // ============================================================================ 28 | 29 | #if defined(ASMJIT_X86) || defined(ASMJIT_X64) 30 | #include "OperandX86X64.h" 31 | #endif // ASMJIT_X86 || ASMJIT_X64 32 | 33 | // [Guard] 34 | #endif // _ASMJIT_OPERAND_H 35 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/ApiBegin.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // MSVC 8 | #if defined(_MSC_VER) 9 | 10 | // Disable some warnings we know about 11 | #pragma warning(push) 12 | #pragma warning(disable: 4127) // conditional expression is constant 13 | #pragma warning(disable: 4251) // struct needs to have dll-interface to be used 14 | // by clients of struct ... 15 | #pragma warning(disable: 4275) // non dll-interface struct ... used as base for 16 | // dll-interface struct 17 | #pragma warning(disable: 4355) // this used in base member initializer list 18 | #pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' 19 | 20 | // Rename symbols. 21 | #define vsnprintf _vsnprintf 22 | #define snprintf _snprintf 23 | 24 | #endif // _MSC_VER 25 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Assembler.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Guard] 8 | #ifndef _ASMJIT_ASSEMBLER_H 9 | #define _ASMJIT_ASSEMBLER_H 10 | 11 | // [Dependencies] 12 | #include "Build.h" 13 | 14 | namespace AsmJit { 15 | 16 | // ============================================================================ 17 | // [Forward Declarations] 18 | // ============================================================================ 19 | 20 | struct Logger; 21 | struct MemoryManager; 22 | struct EInstruction; 23 | 24 | } // AsmJit namespace 25 | 26 | // ============================================================================ 27 | // [Platform Specific] 28 | // ============================================================================ 29 | 30 | // [X86 / X64] 31 | #if defined(ASMJIT_X86) || defined(ASMJIT_X64) 32 | #include "AssemblerX86X64.h" 33 | #endif // ASMJIT_X86 || ASMJIT_X64 34 | 35 | // [Guard] 36 | #endif // _ASMJIT_ASSEMBLER_H 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #OS junk files 2 | [Tt]humbs.db 3 | *.DS_Store 4 | 5 | #Visual Studio files 6 | *.[Oo]bj 7 | #*.user 8 | *.aps 9 | *.pch 10 | *.vspscc 11 | *.vssscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.[Cc]ache 20 | *.ilk 21 | *.log 22 | *.tlog 23 | *.pdb 24 | *.cer 25 | *.lib 26 | *.sbr 27 | *.sdf 28 | *.opensdf 29 | *.unsuccessfulbuild 30 | *.lastbuildstate 31 | ipch/ 32 | obj/ 33 | [Bb]in 34 | [Dd]ebug*/ 35 | [Rr]elease*/ 36 | Ankh.NoLoad 37 | 38 | #MonoDevelop 39 | *.pidb 40 | *.userprefs 41 | 42 | #Tooling 43 | _ReSharper*/ 44 | *.resharper 45 | [Tt]est[Rr]esult* 46 | *.sass-cache 47 | 48 | #Project files 49 | [Bb]uild/ 50 | 51 | #Subversion files 52 | .svn 53 | 54 | # Office Temp Files 55 | ~$* 56 | 57 | #NuGet 58 | packages/ 59 | 60 | #ncrunch 61 | *ncrunch* 62 | *crunch*.local.xml 63 | 64 | # visual studio database projects 65 | *.dbmdl 66 | 67 | #Test files 68 | *.testsettings 69 | 70 | #Generated libraries 71 | *.dll 72 | *.bin 73 | *.sys 74 | #and files 75 | GeneratedFiles*/ 76 | 77 | *.ggpk 78 | 79 | /VADPurge/export.h 80 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Defs.cpp: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Dependencies] 8 | #include "Defs.h" 9 | 10 | // [Api-Begin] 11 | #include "ApiBegin.h" 12 | 13 | namespace AsmJit { 14 | 15 | const char* getErrorString(uint32_t error) ASMJIT_NOTHROW 16 | { 17 | static const char* errorMessage[] = { 18 | "No error", 19 | 20 | "No heap memory", 21 | "No virtual memory", 22 | 23 | "Unknown instruction", 24 | "Illegal instruction", 25 | "Illegal addressing", 26 | "Illegal short jump", 27 | 28 | "No function defined", 29 | "Incomplete function", 30 | 31 | "Not enough registers", 32 | "Registers overlap", 33 | 34 | "Incompatible argument", 35 | "Incompatible return value", 36 | 37 | "Unknown error" 38 | }; 39 | 40 | // Saturate error code to be able to use errorMessage[]. 41 | if (error > _ERROR_COUNT) error = _ERROR_COUNT; 42 | 43 | return errorMessage[error]; 44 | } 45 | 46 | } // AsmJit 47 | 48 | // [Api-End] 49 | #include "ApiEnd.h" 50 | -------------------------------------------------------------------------------- /src/BlackBone/LDasm.h: -------------------------------------------------------------------------------- 1 | #ifndef _LDASM_ 2 | #define _LDASM_ 3 | 4 | #include "string.h" 5 | 6 | #ifdef _M_AMD64 7 | #define is_x64 1 8 | #else 9 | #define is_x64 0 10 | #endif//_M_AMD64 11 | 12 | #ifdef __cplusplus 13 | extern "C" 14 | { 15 | #endif 16 | 17 | #define F_INVALID 0x01 18 | #define F_PREFIX 0x02 19 | #define F_REX 0x04 20 | #define F_MODRM 0x08 21 | #define F_SIB 0x10 22 | #define F_DISP 0x20 23 | #define F_IMM 0x40 24 | #define F_RELATIVE 0x80 25 | 26 | typedef unsigned char u8; 27 | typedef unsigned long u32; 28 | 29 | typedef struct _ldasm_data 30 | { 31 | u8 flags; 32 | u8 rex; 33 | u8 modrm; 34 | u8 sib; 35 | u8 opcd_offset; 36 | u8 opcd_size; 37 | u8 disp_offset; 38 | u8 disp_size; 39 | u8 imm_offset; 40 | u8 imm_size; 41 | } ldasm_data; 42 | 43 | unsigned int __fastcall ldasm( void *code, ldasm_data *ld, u32 is64 ); 44 | unsigned long __fastcall SizeOfProc( void *Proc ); 45 | void* __fastcall ResolveJmp( void *Proc ); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif//_LDASM_ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 DarthTon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/BlackBone/DynImport.cpp: -------------------------------------------------------------------------------- 1 | #include "DynImport.h" 2 | 3 | std::unordered_map blackbone::DynImport::_funcs; 4 | std::mutex blackbone::DynImport::_mapGuard; 5 | 6 | namespace blackbone 7 | { 8 | 9 | /// 10 | /// Load function into database 11 | /// 12 | /// Function name 13 | /// Module name 14 | /// true on success 15 | bool DynImport::load( const std::string& name, const std::wstring& module ) 16 | { 17 | auto mod = GetModuleHandleW( module.c_str() ); 18 | return load( name, mod ); 19 | } 20 | 21 | /// 22 | /// Load function into database 23 | /// 24 | /// Function name 25 | /// Module base 26 | /// true on success 27 | bool blackbone::DynImport::load( const std::string& name, HMODULE hMod ) 28 | { 29 | std::lock_guard lg( _mapGuard ); 30 | 31 | auto proc = GetProcAddress( hMod, name.c_str() ); 32 | if (proc) 33 | { 34 | _funcs.insert( std::make_pair( name, proc ) ); 35 | return true; 36 | } 37 | 38 | return false; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/BlackBone/MExcept.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "MemBlock.h" 5 | 6 | namespace blackbone 7 | { 8 | 9 | /// 10 | /// Exception handling support for arbitrary code 11 | /// 12 | class MExcept 13 | { 14 | public: 15 | // For debug purposes only 16 | static void* g_pImageBase; 17 | static size_t g_imageSize; 18 | 19 | protected: 20 | MExcept( class Process& proc ); 21 | ~MExcept(); 22 | 23 | /// 24 | /// Inject VEH wrapper into process 25 | /// Used to enable execution of SEH handlers out of image 26 | /// 27 | /// Target image base address 28 | /// Size of the image 29 | /// Error code 30 | NTSTATUS CreateVEH( size_t pTargetBase, size_t imageSize ); 31 | 32 | /// 33 | /// Removes VEH from target process 34 | /// 35 | /// 36 | NTSTATUS RemoveVEH(); 37 | 38 | private: 39 | MExcept( const MExcept& ) = delete; 40 | MExcept& operator =(const MExcept&) = delete; 41 | 42 | private: 43 | class Process& _proc; // Underlying process 44 | MemBlock _pVEHCode; // VEH function codecave 45 | size_t _hVEH = 0; // VEH handle 46 | }; 47 | 48 | } -------------------------------------------------------------------------------- /src/BlackBone/ImageNET.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace blackbone 11 | { 12 | 13 | /// 14 | /// .NET metadata parser 15 | /// 16 | class ImageNET 17 | { 18 | public: 19 | typedef std::map, size_t> mapMethodRVA; 20 | 21 | public: 22 | ImageNET(void); 23 | ~ImageNET(void); 24 | 25 | /// 26 | /// Initialize COM classes 27 | /// 28 | /// Image file path 29 | /// true on success 30 | bool Init( const std::wstring& path ); 31 | 32 | /// 33 | /// Extract methods from image 34 | /// 35 | /// Found Methods 36 | /// true on success 37 | bool Parse( mapMethodRVA& methods ); 38 | 39 | /// 40 | /// Get image .NET runtime version 41 | /// 42 | /// runtime version, "n/a" if nothing found 43 | static std::wstring GetImageRuntimeVer( const wchar_t* ImagePath ); 44 | private: 45 | std::wstring _path; // Image path 46 | mapMethodRVA _methods; // Image methods 47 | 48 | // COM helpers 49 | CComPtr _pMetaDisp; 50 | CComPtr _pMetaImport; 51 | CComPtr _pAssemblyImport; 52 | }; 53 | 54 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/MemoryMarker.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Guard] 8 | #ifndef _ASMJIT_MEMORYMARKER_H 9 | #define _ASMJIT_MEMORYMARKER_H 10 | 11 | // [Dependencies] 12 | #include "Build.h" 13 | #include "Defs.h" 14 | 15 | // [Api-Begin] 16 | #include "ApiBegin.h" 17 | 18 | namespace AsmJit { 19 | 20 | //! @addtogroup AsmJit_MemoryManagement 21 | //! @{ 22 | 23 | // ============================================================================ 24 | // [AsmJit::MemoryMarker] 25 | // ============================================================================ 26 | 27 | //! @brief Virtual memory marker interface. 28 | struct ASMJIT_API MemoryMarker 29 | { 30 | // -------------------------------------------------------------------------- 31 | // [Construction / Destruction] 32 | // -------------------------------------------------------------------------- 33 | 34 | MemoryMarker() ASMJIT_NOTHROW; 35 | virtual ~MemoryMarker() ASMJIT_NOTHROW; 36 | 37 | // -------------------------------------------------------------------------- 38 | // [Interface] 39 | // -------------------------------------------------------------------------- 40 | 41 | virtual void mark(const void* ptr, sysuint_t size) ASMJIT_NOTHROW = 0; 42 | 43 | private: 44 | ASMJIT_DISABLE_COPY(MemoryMarker) 45 | }; 46 | 47 | //! @} 48 | 49 | } // AsmJit namespace 50 | 51 | // [Api-End] 52 | #include "ApiEnd.h" 53 | 54 | // [Guard] 55 | #endif // _ASMJIT_MEMORYMARKER_H 56 | -------------------------------------------------------------------------------- /src/BlackBone/DynImport.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Types.h" 4 | #include "Winheaders.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace blackbone 10 | { 11 | 12 | /// 13 | /// Dynamic import 14 | /// 15 | class DynImport 16 | { 17 | public: 18 | /// 19 | /// Get dll function 20 | /// 21 | /// Function name 22 | /// Function pointer 23 | template 24 | inline static T get( const std::string& name ) 25 | { 26 | std::lock_guard lg( _mapGuard ); 27 | 28 | auto iter = _funcs.find( name ); 29 | if (iter != _funcs.end()) 30 | return reinterpret_cast(iter->second); 31 | 32 | return nullptr; 33 | } 34 | 35 | /// 36 | /// Load function into database 37 | /// 38 | /// Function name 39 | /// Module name 40 | /// true on success 41 | static bool load( const std::string& name, const std::wstring& module ); 42 | 43 | /// 44 | /// Load function into database 45 | /// 46 | /// Function name 47 | /// Module base 48 | /// true on success 49 | static bool load( const std::string& name, HMODULE hMod ); 50 | 51 | private: 52 | static std::unordered_map _funcs; // function database 53 | static std::mutex _mapGuard; // function database guard 54 | }; 55 | 56 | // Syntax sugar 57 | #define GET_IMPORT(name) (DynImport::get( #name )) 58 | 59 | } -------------------------------------------------------------------------------- /src/BlackBone/Types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NativeStructures.h" 4 | #include "FunctionTypes.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace blackbone 10 | { 11 | 12 | typedef uint64_t ptr_t; // Generic pointer in remote process 13 | typedef ptr_t module_t; // Module base pointer 14 | 15 | // PEB helper 16 | template 17 | struct _PEB_T2 18 | { 19 | typedef typename std::conditional::value, _PEB32, _PEB64>::type type; 20 | }; 21 | 22 | // Type of barrier 23 | enum WoW64Type 24 | { 25 | wow_32_32 = 0, // Both processes are WoW64 26 | wow_64_64, // Both processes are x64 27 | wow_32_64, // Managing x64 process from WoW64 process 28 | wow_64_32, // Managing WOW64 process from x64 process 29 | }; 30 | 31 | struct Wow64Barrier 32 | { 33 | WoW64Type type; 34 | bool sourceWow64; 35 | bool targetWow64; 36 | }; 37 | 38 | // Module type 39 | enum eModType 40 | { 41 | mt_mod32, // 64 bit module 42 | mt_mod64, // 32 bit module 43 | mt_default // type is deduced from target process 44 | }; 45 | 46 | // Module search method 47 | enum eModSeachType 48 | { 49 | LdrList, // InLoadOrder list 50 | Sections, // Scan for section objects 51 | PEHeaders, // Scan for PE headers in memory 52 | }; 53 | 54 | // Module info 55 | struct ModuleData 56 | { 57 | ptr_t baseAddress; // Base image address 58 | std::wstring name; // File name 59 | std::wstring fullPath; // Full file path 60 | size_t size; // Size of image 61 | eModType type; // Module type 62 | bool manual; // Image is manually mapped 63 | 64 | bool operator ==(const ModuleData& value) const 65 | { 66 | return (baseAddress == value.baseAddress); 67 | } 68 | }; 69 | 70 | // Wow64 register helper 71 | union reg64 72 | { 73 | uint32_t dw[2]; 74 | uint64_t v; 75 | }; 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/BlackBone/Threads.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "Thread.h" 5 | 6 | #include 7 | 8 | namespace blackbone 9 | { 10 | 11 | class ProcessThreads 12 | { 13 | public: 14 | ProcessThreads( class ProcessCore& core ); 15 | ~ProcessThreads(); 16 | 17 | /// 18 | /// Create the thread. 19 | /// 20 | /// Thread enty point 21 | /// Thread argument. 22 | /// Thread creation flags 23 | /// New thread object 24 | Thread CreateNew( ptr_t threadProc, ptr_t arg, DWORD flags = 0 ); 25 | 26 | /// 27 | /// Gets all process threads 28 | /// 29 | /// Return already existing thread list 30 | /// Threads collection 31 | std::vector& getAll( bool dontUpdate = false ); 32 | 33 | /// 34 | /// Get main process thread 35 | /// 36 | /// Pointer to thread object, nullptr if failed 37 | Thread* getMain(); 38 | 39 | /// 40 | /// Get least executed thread 41 | /// 42 | /// Pointer to thread object, nullptr if failed 43 | Thread* getLeastExecuted(); 44 | 45 | /// 46 | /// Get least executed thread 47 | /// 48 | /// Pointer to thread object, nullptr if failed 49 | Thread* getRandom(); 50 | 51 | /// 52 | /// Get thread by ID 53 | /// 54 | /// Thread ID 55 | /// Pointer to thread object, nullptr if failed 56 | Thread* get( DWORD id ); 57 | 58 | private: 59 | ProcessThreads( const ProcessThreads& ) = delete; 60 | ProcessThreads& operator =(const ProcessThreads&) = delete; 61 | 62 | private: 63 | class ProcessCore& _core; // Core process functions 64 | std::vector _threads; // Process thread snapshot 65 | }; 66 | 67 | } -------------------------------------------------------------------------------- /src/BlackBone/FileProjection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include 5 | 6 | namespace blackbone 7 | { 8 | 9 | /// 10 | /// Load file as PE image 11 | /// 12 | class FileProjection 13 | { 14 | public: 15 | FileProjection(void); 16 | FileProjection( const std::wstring& path ); 17 | ~FileProjection(void); 18 | 19 | /// 20 | /// Memory-map specified file 21 | /// 22 | /// Image path 23 | /// File address in memory, nullptr if failed 24 | void* Project( const std::wstring& path ); 25 | 26 | /// 27 | /// Release mapping, if any 28 | /// 29 | void Release(); 30 | 31 | /// 32 | /// Base of file in memory 33 | /// 34 | /// 35 | inline void* base() const { return _pData; } 36 | 37 | /// 38 | /// Get activation context handle 39 | /// 40 | /// 41 | inline HANDLE actx() const { return _hctx; } 42 | 43 | /// 44 | /// true if image is mapped as plain data file 45 | /// 46 | /// 47 | inline bool isPlainData() const { return _plainData; } 48 | 49 | /// 50 | /// Get manifest resource ID 51 | /// 52 | /// 53 | inline int manifestID() const { return _manifestIdx; } 54 | 55 | /// 56 | /// Base of file in memory 57 | /// 58 | /// 59 | inline operator void*() const { return _pData; } 60 | 61 | private: 62 | HANDLE _hFile = INVALID_HANDLE_VALUE; // Target file HANDLE 63 | HANDLE _hMapping = NULL; // Memory mapping object 64 | void* _pData = nullptr; // Mapping base 65 | bool _plainData = false; // File mapped as plain data file 66 | HANDLE _hctx = INVALID_HANDLE_VALUE; // Activation context 67 | int _manifestIdx = 0; // Manifest resource ID 68 | }; 69 | 70 | }; 71 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Logger.cpp: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // We are using sprintf() here. 8 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 9 | #define _CRT_SECURE_NO_WARNINGS 10 | #endif // _MSC_VER 11 | 12 | // [Dependencies] 13 | #include "Logger.h" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | // [Api-Begin] 20 | #include "ApiBegin.h" 21 | 22 | namespace AsmJit { 23 | 24 | // ============================================================================ 25 | // [AsmJit::Logger] 26 | // ============================================================================ 27 | 28 | Logger::Logger() ASMJIT_NOTHROW : 29 | _enabled(true), 30 | _used(true), 31 | _logBinary(false) 32 | { 33 | } 34 | 35 | Logger::~Logger() ASMJIT_NOTHROW 36 | { 37 | } 38 | 39 | void Logger::logFormat(const char* fmt, ...) ASMJIT_NOTHROW 40 | { 41 | char buf[1024]; 42 | sysuint_t len; 43 | 44 | va_list ap; 45 | va_start(ap, fmt); 46 | len = vsnprintf(buf, 1023, fmt, ap); 47 | va_end(ap); 48 | 49 | logString(buf, len); 50 | } 51 | 52 | void Logger::setEnabled(bool enabled) ASMJIT_NOTHROW 53 | { 54 | _enabled = enabled; 55 | _used = enabled; 56 | } 57 | 58 | // ============================================================================ 59 | // [AsmJit::FileLogger] 60 | // ============================================================================ 61 | 62 | FileLogger::FileLogger(FILE* stream) ASMJIT_NOTHROW 63 | : _stream(NULL) 64 | { 65 | setStream(stream); 66 | } 67 | 68 | void FileLogger::logString(const char* buf, sysuint_t len) ASMJIT_NOTHROW 69 | { 70 | if (!_used) return; 71 | 72 | if (len == (sysuint_t)-1) len = strlen(buf); 73 | fwrite(buf, 1, len, _stream); 74 | } 75 | 76 | void FileLogger::setEnabled(bool enabled) ASMJIT_NOTHROW 77 | { 78 | _enabled = enabled; 79 | _used = (_enabled == true) & (_stream != NULL); 80 | } 81 | 82 | //! @brief Set file stream. 83 | void FileLogger::setStream(FILE* stream) ASMJIT_NOTHROW 84 | { 85 | _stream = stream; 86 | _used = (_enabled == true) & (_stream != NULL); 87 | } 88 | 89 | } // AsmJit namespace 90 | 91 | // [Api-End] 92 | #include "ApiEnd.h" 93 | -------------------------------------------------------------------------------- /src/BlackBone/ProcessCore.cpp: -------------------------------------------------------------------------------- 1 | #include "ProcessCore.h" 2 | #include "Macro.h" 3 | 4 | namespace blackbone 5 | { 6 | 7 | ProcessCore::ProcessCore() 8 | : _native( nullptr ) 9 | { 10 | } 11 | 12 | ProcessCore::~ProcessCore() 13 | { 14 | Close(); 15 | } 16 | 17 | /// 18 | /// Attach to existing process 19 | /// 20 | /// Process ID 21 | /// Access mask 22 | /// Status 23 | NTSTATUS ProcessCore::Open( DWORD pid, DWORD access ) 24 | { 25 | // Prevent handle leak 26 | Close(); 27 | 28 | // Handle current process differently 29 | _hProcess = (pid == GetCurrentProcessId()) ? GetCurrentProcess() : OpenProcess( access, false, pid ); 30 | 31 | if (_hProcess != NULL) 32 | { 33 | _pid = pid; 34 | 35 | // Detect x86 OS 36 | SYSTEM_INFO info = { 0 }; 37 | GetNativeSystemInfo( &info ); 38 | 39 | if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) 40 | { 41 | _native.reset( new x86Native( _hProcess ) ); 42 | } 43 | else 44 | { 45 | // Detect wow64 barrier 46 | BOOL wowSrc = FALSE; 47 | IsWow64Process( GetCurrentProcess(), &wowSrc ); 48 | 49 | if (wowSrc == TRUE) 50 | _native.reset( new NativeWow64( _hProcess ) ); 51 | else 52 | _native.reset( new Native( _hProcess ) ); 53 | } 54 | 55 | // Get DEP info 56 | // For native x64 processes DEP is always enabled 57 | if (_native->GetWow64Barrier().targetWow64 == false) 58 | { 59 | _dep = true; 60 | } 61 | else 62 | { 63 | DWORD flags = 0; 64 | BOOL perm = 0; 65 | 66 | if (GetProcessDEPPolicy( _hProcess, &flags, &perm )) 67 | _dep = static_cast(flags & PROCESS_DEP_ENABLE); 68 | } 69 | 70 | return STATUS_SUCCESS; 71 | } 72 | 73 | return LastNtStatus(); 74 | } 75 | 76 | /// 77 | /// Close current process handle 78 | /// 79 | void ProcessCore::Close() 80 | { 81 | if (_hProcess) 82 | { 83 | CloseHandle( _hProcess ); 84 | 85 | _hProcess = NULL; 86 | _pid = 0; 87 | _native.reset( nullptr ); 88 | } 89 | } 90 | 91 | } -------------------------------------------------------------------------------- /BlackBone.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 13.00 3 | # Visual Studio 2013 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlackBone", "src\BlackBone\BlackBone.vcxproj", "{A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestApp", "src\TestApp\TestApp.vcxproj", "{D31B07B5-C75F-4382-B07F-D95922764BD7}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB} = {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB} 9 | EndProjectSection 10 | EndProject 11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{80C66F70-26E2-400D-9FF8-6C0A83EDF9F9}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Win32 = Debug|Win32 16 | Debug|x64 = Debug|x64 17 | Release|Win32 = Release|Win32 18 | Release|x64 = Release|x64 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug|Win32.ActiveCfg = Debug|Win32 22 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug|Win32.Build.0 = Debug|Win32 23 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug|x64.ActiveCfg = Debug|x64 24 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Debug|x64.Build.0 = Debug|x64 25 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release|Win32.ActiveCfg = Release|Win32 26 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release|Win32.Build.0 = Release|Win32 27 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release|x64.ActiveCfg = Release|x64 28 | {A2C53563-46F5-4D87-903F-3F1F2FDB2DEB}.Release|x64.Build.0 = Release|x64 29 | {D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|Win32.ActiveCfg = Debug|Win32 30 | {D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|Win32.Build.0 = Debug|Win32 31 | {D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|x64.ActiveCfg = Debug|x64 32 | {D31B07B5-C75F-4382-B07F-D95922764BD7}.Debug|x64.Build.0 = Debug|x64 33 | {D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|Win32.ActiveCfg = Release|Win32 34 | {D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|Win32.Build.0 = Release|Win32 35 | {D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|x64.ActiveCfg = Release|x64 36 | {D31B07B5-C75F-4382-B07F-D95922764BD7}.Release|x64.Build.0 = Release|x64 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /src/BlackBone/AsmStack.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AsmJit/Assembler.h" 4 | #include "Macro.h" 5 | 6 | #include 7 | 8 | namespace blackbone 9 | { 10 | 11 | class AsmStackAllocator 12 | { 13 | public: 14 | AsmStackAllocator( intptr_t baseval = 0x28 ) 15 | : disp_ofst( sizeof(size_t) ) 16 | { 17 | #ifdef _M_AMD64 18 | disp_ofst = baseval; 19 | #else 20 | UNREFERENCED_PARAMETER( baseval ); 21 | #endif 22 | } 23 | 24 | /// 25 | /// Allocate stack variable 26 | /// 27 | /// Variable size 28 | /// Variable memory object 29 | AsmJit::Mem AllocVar( intptr_t size ) 30 | { 31 | // Align on word length 32 | size = Align( size, sizeof(size_t) ); 33 | 34 | #ifdef _M_AMD64 35 | auto val = AsmJit::Mem( AsmJit::nsp, disp_ofst, size ); 36 | #else 37 | auto val = AsmJit::Mem( AsmJit::nbp, -disp_ofst - size, size ); 38 | #endif 39 | disp_ofst += size; 40 | return val; 41 | } 42 | 43 | /// 44 | /// Allocate array of stack variables 45 | /// 46 | /// Output array 47 | /// Array elements count. 48 | /// Element size. 49 | /// true on success 50 | bool AllocArray( AsmJit::Mem arr[], int count, intptr_t size ) 51 | { 52 | for (int i = 0; i < count; i++) 53 | { 54 | #ifdef _M_AMD64 55 | arr[i] = AsmJit::Mem( AsmJit::nsp, disp_ofst, size ); 56 | #else 57 | arr[i] = AsmJit::Mem( AsmJit::nbp, -disp_ofst - size, size ); 58 | #endif 59 | disp_ofst += size; 60 | } 61 | 62 | return true; 63 | } 64 | 65 | /// 66 | /// Get total size of all stack variables 67 | /// 68 | /// 69 | inline intptr_t getTotalSize() const { return disp_ofst; }; 70 | 71 | private: 72 | intptr_t disp_ofst; // Next variable stack offset 73 | }; 74 | 75 | // 76 | // Helpers 77 | // 78 | #define ALLOC_STACK_VAR(worker, name, type) AsmJit::Mem name( worker.AllocVar( sizeof(type) ) ); 79 | #define ALLOC_STACK_VAR_S(worker, name, size) AsmJit::Mem name( worker.AllocVar( size ) ); 80 | 81 | #define ALLOC_STACK_ARRAY(worker, name, type, count) \ 82 | AsmJit::Mem name[count]; \ 83 | worker.AllocArray( name, count, sizeof(type) ); 84 | 85 | } -------------------------------------------------------------------------------- /src/BlackBone/Win8Specific.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | 5 | namespace blackbone 6 | { 7 | #pragma warning(disable : 4201) 8 | 9 | typedef struct _RTL_RB_TREE 10 | { 11 | struct _RTL_BALANCED_NODE * Root; 12 | struct _RTL_BALANCED_NODE * Min; 13 | } RTL_RB_TREE, *PRTL_RB_TREE; 14 | 15 | typedef struct _RTL_BALANCED_NODE 16 | { 17 | union 18 | { 19 | struct _RTL_BALANCED_NODE * Children[2]; 20 | struct 21 | { 22 | struct _RTL_BALANCED_NODE * Left; 23 | struct _RTL_BALANCED_NODE * Right; 24 | }; 25 | }; 26 | union 27 | { 28 | union 29 | { 30 | struct 31 | { 32 | unsigned char Red : 1; 33 | }; 34 | struct 35 | { 36 | unsigned char Balance : 2; 37 | }; 38 | }; 39 | 40 | size_t ParentValue; 41 | }; 42 | } RTL_BALANCED_NODE, *PRTL_BALANCED_NODE; 43 | 44 | struct _LDR_DDAG_NODE 45 | { 46 | _LIST_ENTRY Modules; 47 | struct _LDR_SERVICE_TAG_RECORD * ServiceTagList; 48 | unsigned long LoadCount; 49 | unsigned long ReferenceCount; 50 | unsigned long DependencyCount; 51 | _SINGLE_LIST_ENTRY RemovalLink; 52 | void* IncomingDependencies; 53 | _LDR_DDAG_STATE State; 54 | struct _SINGLE_LIST_ENTRY CondenseLink; 55 | unsigned long PreorderNumber; 56 | unsigned long LowestLink; 57 | }; 58 | 59 | struct _LDR_DATA_TABLE_ENTRY_W8 : LDR_DATA_TABLE_ENTRY_BASE_T 60 | { 61 | _LDR_DDAG_NODE * DdagNode; 62 | _LIST_ENTRY NodeModuleLink; 63 | struct _LDRP_DLL_SNAP_CONTEXT * SnapContext; 64 | void * ParentDllBase; 65 | void * SwitchBackContext; 66 | _RTL_BALANCED_NODE BaseAddressIndexNode; 67 | _RTL_BALANCED_NODE MappingInfoIndexNode; 68 | unsigned long OriginalBase; 69 | union _LARGE_INTEGER LoadTime; 70 | unsigned long BaseNameHashValue; 71 | _LDR_DLL_LOAD_REASON LoadReason; 72 | }; 73 | 74 | typedef struct _RTL_INVERTED_FUNCTION_TABLE8 75 | { 76 | ULONG Count; 77 | ULONG MaxCount; 78 | ULONG Pad[0x2]; 79 | RTL_INVERTED_FUNCTION_TABLE_ENTRY Entries[0x200]; 80 | 81 | } RTL_INVERTED_FUNCTION_TABLE8, *PRTL_INVERTED_FUNCTION_TABLE8; 82 | 83 | #pragma warning(default : 4201) 84 | } -------------------------------------------------------------------------------- /src/BlackBone/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include 5 | 6 | namespace blackbone 7 | { 8 | 9 | class Utils 10 | { 11 | public: 12 | /// 13 | /// Convert UTF-8 string to wide char one 14 | /// 15 | /// UTF-8 string 16 | /// wide char string 17 | static std::wstring UTF8ToWstring( const std::string& str ); 18 | 19 | /// 20 | /// Convert ANSI string to wide char one 21 | /// 22 | /// ANSI string. 23 | /// String locale 24 | /// wide char string 25 | static std::wstring AnsiToWstring( const std::string& input, DWORD locale = CP_ACP ); 26 | 27 | /// 28 | /// Get filename from full-qualified path 29 | /// 30 | /// File path 31 | /// Filename 32 | static std::wstring StripPath( const std::wstring& path ); 33 | 34 | /// 35 | /// Get parent directory 36 | /// 37 | /// File path 38 | /// Parent directory 39 | static std::wstring GetParent( const std::wstring& path ); 40 | 41 | /// 42 | /// Get current process exe file directory 43 | /// 44 | /// Exe directory 45 | static std::wstring GetExeDirectory(); 46 | 47 | /// 48 | /// Cast string characters to lower case 49 | /// 50 | /// Source string. 51 | /// Result string 52 | static std::wstring ToLower( const std::wstring& str ); 53 | 54 | /// 55 | /// Get system error description 56 | /// 57 | /// The code. 58 | /// Error message 59 | static std::wstring GetErrorDescription( NTSTATUS code ); 60 | 61 | /// 62 | /// Check if file exists 63 | /// 64 | /// Full-qualified file path 65 | /// true if exists 66 | static bool FileExists( const std::wstring& path ); 67 | 68 | /// 69 | /// Load arbitrary driver 70 | /// 71 | /// Driver service name 72 | /// Driver file path 73 | /// Status 74 | static NTSTATUS LoadDriver( const std::wstring& svcName, const std::wstring& path ); 75 | }; 76 | 77 | } -------------------------------------------------------------------------------- /src/BlackBone/x86Subsystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NativeSubsystem.h" 4 | 5 | namespace blackbone 6 | { 7 | 8 | /// 9 | /// X86 OS subsystem. Used 10 | /// 11 | class x86Native : public Native 12 | { 13 | public: 14 | x86Native( HANDLE hProcess ); 15 | ~x86Native(); 16 | 17 | /// 18 | /// Query virtual memory 19 | /// 20 | /// Address to query 21 | /// Retrieved memory info 22 | /// Status code 23 | virtual NTSTATUS VirtualQueryExT( ptr_t lpAddress, PMEMORY_BASIC_INFORMATION64 lpBuffer ); 24 | 25 | /// 26 | /// Get WOW64 thread context 27 | /// 28 | /// Thread handle. 29 | /// Thread context 30 | /// Status code 31 | virtual NTSTATUS GetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ); 32 | 33 | /// 34 | /// Get native thread context 35 | /// 36 | /// Thread handle. 37 | /// Thread context 38 | /// Status code 39 | virtual NTSTATUS GetThreadContextT( HANDLE hThread, _CONTEXT64& ctx ); 40 | 41 | /// 42 | /// Set WOW64 thread context 43 | /// 44 | /// Thread handle. 45 | /// Thread context 46 | /// Status code 47 | virtual NTSTATUS SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ); 48 | 49 | /// 50 | /// Set native thread context 51 | /// 52 | /// Thread handle. 53 | /// Thread context 54 | /// Status code 55 | virtual NTSTATUS SetThreadContextT( HANDLE hThread, _CONTEXT64& ctx ); 56 | 57 | /// 58 | /// Gets WOW64 PEB 59 | /// 60 | /// Retrieved PEB 61 | /// PEB pointer 62 | virtual ptr_t getPEB( _PEB32* ppeb ); 63 | 64 | /// 65 | /// Get native PEB 66 | /// 67 | /// Retrieved PEB 68 | /// PEB pointer 69 | virtual ptr_t getPEB( _PEB64* ppeb ); 70 | 71 | /// 72 | /// Get WOW64 TEB 73 | /// 74 | /// Retrieved TEB 75 | /// TEB pointer 76 | virtual ptr_t getTEB( HANDLE hThread, _TEB32* pteb ); 77 | 78 | /// 79 | /// Get native TEB 80 | /// 81 | /// Retrieved TEB 82 | /// TEB pointer 83 | virtual ptr_t getTEB( HANDLE hThread, _TEB64* pteb ); 84 | 85 | private: 86 | }; 87 | 88 | } -------------------------------------------------------------------------------- /src/BlackBone/ProcessCore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "NativeStructures.h" 5 | #include "Wow64Subsystem.h" 6 | #include "x86Subsystem.h" 7 | 8 | #include 9 | #include 10 | 11 | namespace blackbone 12 | { 13 | 14 | class ProcessCore 15 | { 16 | friend class Process; 17 | 18 | typedef std::unique_ptr ptrNative; 19 | 20 | public: 21 | 22 | /// 23 | /// Check if target process is running in WOW64 mode 24 | /// 25 | /// true if process is WOW64 26 | inline bool isWow64() const { return _native->GetWow64Barrier().targetWow64; } 27 | 28 | /// 29 | /// Get process handle 30 | /// 31 | /// Process handle 32 | inline HANDLE handle() const { return _hProcess; } 33 | 34 | /// 35 | /// Get process ID 36 | /// 37 | /// Process ID 38 | inline DWORD pid() const { return _pid; } 39 | 40 | /// 41 | /// Get process data execution prevention state 42 | /// 43 | /// true if DEP is enabled for process 44 | inline bool DEP() const { return _dep; }; 45 | 46 | /// 47 | /// Get system routines 48 | /// 49 | /// 50 | inline Native* native() { return _native.get(); } 51 | 52 | /// 53 | /// Get WOW64 PEB 54 | /// 55 | /// Retrieved PEB 56 | /// PEB pointer 57 | inline ptr_t peb( _PEB32* ppeb ) { return _native->getPEB( ppeb ); } 58 | 59 | /// 60 | /// Get native PEB 61 | /// 62 | /// Retrieved PEB 63 | /// PEB pointer 64 | inline ptr_t peb( _PEB64* ppeb ) { return _native->getPEB( ppeb ); } 65 | 66 | /// 67 | /// Get PEB 68 | /// 69 | /// Retrieved PEB 70 | /// PEB pointer 71 | inline ptr_t peb() { return peb( (PEB_T*)nullptr ); } 72 | 73 | private: 74 | ProcessCore(); 75 | ProcessCore( const ProcessCore& ) = delete; 76 | ~ProcessCore(); 77 | 78 | /// 79 | /// Attach to existing process 80 | /// 81 | /// Process ID 82 | /// Access mask 83 | /// Status 84 | NTSTATUS Open( DWORD pid, DWORD access ); 85 | 86 | /// 87 | /// Close current process handle 88 | /// 89 | void Close(); 90 | 91 | private: 92 | HANDLE _hProcess = NULL; // Process handle 93 | DWORD _pid = 0; // Process ID 94 | ptrNative _native; // Api wrapper 95 | bool _dep = false; // DEP state for process 96 | }; 97 | 98 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Config.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // This file is designed to be modifyable. Platform specific changes should 8 | // be applied to this file so it's guaranteed that never versions of AsmJit 9 | // library will never overwrite generated config files. 10 | // 11 | // So modify this file by your build system or by hand. 12 | 13 | // [Guard] 14 | #ifndef _ASMJIT_CONFIG_H 15 | #define _ASMJIT_CONFIG_H 16 | 17 | // ============================================================================ 18 | // [AsmJit - OS] 19 | // ============================================================================ 20 | 21 | // Provides definitions about your operating system. It's detected by default, 22 | // so override it if you have problems with automatic detection. 23 | // 24 | // #define ASMJIT_WINDOWS 1 25 | // #define ASMJIT_POSIX 2 26 | 27 | // ============================================================================ 28 | // [AsmJit - Architecture] 29 | // ============================================================================ 30 | 31 | // Provides definitions about your cpu architecture. It's detected by default, 32 | // so override it if you have problems with automatic detection. 33 | 34 | // #define ASMJIT_X86 35 | // #define ASMJIT_X64 36 | 37 | // ============================================================================ 38 | // [AsmJit - API] 39 | // ============================================================================ 40 | 41 | // If you are embedding AsmJit library into your project (statically), undef 42 | // ASMJIT_API macro. ASMJIT_HIDDEN macro can contain visibility (used by GCC) 43 | // to hide some AsmJit symbols that shouldn't be never exported. 44 | // 45 | // If you have problems with throw() in compilation time, undef ASMJIT_NOTHROW 46 | // to disable this feature. ASMJIT_NOTHROW marks functions that never throws 47 | // an exception. 48 | 49 | // #define ASMJIT_HIDDEN 50 | #define ASMJIT_API 51 | // #define ASMJIT_NOTHROW 52 | 53 | 54 | // ============================================================================ 55 | // [AsmJit - Memory Management] 56 | // ============================================================================ 57 | 58 | // #define ASMJIT_MALLOC ::malloc 59 | // #define ASMJIT_REALLOC ::realloc 60 | // #define ASMJIT_FREE ::free 61 | 62 | // ============================================================================ 63 | // [AsmJit - Debug] 64 | // ============================================================================ 65 | 66 | // Turn debug on/off (to bypass autodetection) 67 | // #define ASMJIT_DEBUG 68 | // #define ASMJIT_NO_DEBUG 69 | 70 | // Setup custom assertion code. 71 | // #define ASMJIT_ASSERT(exp) do { if (!(exp)) ::AsmJit::assertionFailure(__FILE__, __LINE__, #exp); } while(0) 72 | 73 | // [Guard] 74 | #endif // _ASMJIT_CONFIG_H 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Blackbone 2 | ========= 3 | 4 | # Windows memory hacking library # 5 | 6 | ## Features ## 7 | 8 | - x86 and x64 support 9 | 10 | - **Process interaction** 11 | - Manage PEB32/PEB64 12 | - Manage process through WOW64 barrier 13 | 14 | - **Process Memory** 15 | - Allocate and free virtual memory 16 | - Change memory protection 17 | - Read/Write virtual memory 18 | 19 | - **Process modules** 20 | - Enumerate all (32/64 bit) modules loaded. Enumerate modules using Loader list/Section objects/PE headers methods. 21 | - Get exported function address 22 | - Get the main module 23 | - Unlink module from loader lists 24 | - Inject and eject modules (including pure IL images) 25 | - Inject 64bit modules into WOW64 processes 26 | - Manually map native PE images 27 | 28 | - **Threads** 29 | - Enumerate threads 30 | - Create and terminate threads. Support for cross-session thread creation. 31 | - Get thread exit code 32 | - Get main thread 33 | - Manage TEB32/TEB64 34 | - Join threads 35 | - Suspend and resume threads 36 | - Set/Remove hardware breakpoints 37 | 38 | - **Pattern search** 39 | - Search for arbitrary pattern in local or remote process 40 | 41 | - **Remote code execution** 42 | - Execute functions in remote process 43 | - Assemble own code and execute it remotely 44 | - Support for cdecl/stdcall/thiscall/fastcall conventions 45 | - Support for arguments passed by value, pointer or reference, including structures 46 | - FPU types are supported 47 | - Execute code in new thread or any existing one 48 | 49 | - **Remote hooking** 50 | - Hook functions in remote process using int3 or hardware breakpoints 51 | - Hook functions upon return 52 | 53 | - **Manual map features** 54 | - x86 and x64 image support 55 | - Mapping into any arbitrary unprotected process 56 | - Section mapping with proper memory protection flags 57 | - Image relocations (only 2 types supported. I haven't seen a single PE image with some other relocation types) 58 | - Imports and Delayed imports are resolved 59 | - Bound import is resolved as a side effect, I think 60 | - Module exports 61 | - Loading of forwarded export images 62 | - Api schema name redirection 63 | - SxS redirection and isolation 64 | - Activation context support 65 | - Dll path resolving similar to native load order 66 | - TLS callbacks. Only for one thread and only with PROCESS_ATTACH/PROCESS_DETACH reasons. 67 | - Static TLS 68 | - Exception handling support (SEH and C++) 69 | - Adding module to some native loader structures(for basic module api support: GetModuleHandle, GetProcAdress, etc.) 70 | - Security cookie initialization 71 | - C++/CLI images are supported 72 | - Image unloading 73 | - Increase reference counter for import libraries in case of manual import mapping 74 | - Cyclic dependencies are handled properly 75 | 76 | ## License ## 77 | Blackbone is licensed under the MIT License. Dependencies are under their respective licenses. -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/CodeGenerator.cpp: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Dependencies] 8 | #include "Assembler.h" 9 | #include "CodeGenerator.h" 10 | #include "Defs.h" 11 | #include "MemoryManager.h" 12 | #include "MemoryMarker.h" 13 | 14 | namespace AsmJit { 15 | 16 | // ============================================================================ 17 | // [AsmJit::CodeGenerator - Construction / Destruction] 18 | // ============================================================================ 19 | 20 | CodeGenerator::CodeGenerator() 21 | { 22 | } 23 | 24 | CodeGenerator::~CodeGenerator() 25 | { 26 | } 27 | 28 | // ============================================================================ 29 | // [AsmJit::CodeGenerator - GetGlobal] 30 | // ============================================================================ 31 | 32 | JitCodeGenerator* CodeGenerator::getGlobal() 33 | { 34 | static JitCodeGenerator global; 35 | return &global; 36 | } 37 | 38 | // ============================================================================ 39 | // [AsmJit::JitCodeGenerator - Construction / Destruction] 40 | // ============================================================================ 41 | 42 | JitCodeGenerator::JitCodeGenerator() : 43 | _memoryManager(NULL), 44 | _memoryMarker(NULL), 45 | _allocType(MEMORY_ALLOC_FREEABLE) 46 | { 47 | } 48 | 49 | JitCodeGenerator::~JitCodeGenerator() 50 | { 51 | } 52 | 53 | // ============================================================================ 54 | // [AsmJit::JitCodeGenerator - Generate] 55 | // ============================================================================ 56 | 57 | uint32_t JitCodeGenerator::generate(void** dest, Assembler* assembler) 58 | { 59 | // Disallow empty code generation. 60 | sysuint_t codeSize = assembler->getCodeSize(); 61 | if (codeSize == 0) 62 | { 63 | *dest = NULL; 64 | return AsmJit::ERROR_NO_FUNCTION; 65 | } 66 | 67 | // Switch to global memory manager if not provided. 68 | MemoryManager* memmgr = getMemoryManager(); 69 | 70 | if (memmgr == NULL) 71 | { 72 | memmgr = MemoryManager::getGlobal(); 73 | } 74 | 75 | void* p = memmgr->alloc(codeSize, getAllocType()); 76 | if (p == NULL) 77 | { 78 | *dest = NULL; 79 | return ERROR_NO_VIRTUAL_MEMORY; 80 | } 81 | 82 | // Relocate the code. 83 | sysuint_t relocatedSize = assembler->relocCode(p); 84 | 85 | // Return unused memory to MemoryManager. 86 | if (relocatedSize < codeSize) 87 | { 88 | memmgr->shrink(p, relocatedSize); 89 | } 90 | 91 | // Mark memory if MemoryMarker provided. 92 | if (_memoryMarker) 93 | { 94 | _memoryMarker->mark(p, relocatedSize); 95 | } 96 | 97 | // Return the code. 98 | *dest = p; 99 | return ERROR_NONE; 100 | } 101 | 102 | } // AsmJit namespace 103 | -------------------------------------------------------------------------------- /src/BlackBone/NameResolve.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "Types.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace blackbone 11 | { 12 | 13 | class NameResolve 14 | { 15 | typedef std::unordered_map> mapApiSchema; 16 | 17 | public: 18 | enum eResolveFlag 19 | { 20 | Default = 0, // Full resolve 21 | ApiSchemaOnly = 1, // Resolve only Api schema dlls 22 | EnsureFullPath = 2, // Make sure resulting path is full-qualified 23 | NoSearch = 4, // Don't perform file search, only resolve name 24 | Wow64 = 8, // Reserved 25 | }; 26 | 27 | public: 28 | ~NameResolve(); 29 | 30 | static NameResolve& Instance(); 31 | 32 | /// 33 | /// Initialize api set map 34 | /// 35 | /// 36 | bool Initialize(); 37 | 38 | /// 39 | /// Resolve image path. 40 | /// 41 | /// Image to resolve 42 | /// Name of parent image. Used only when resolving import images 43 | /// Directory where source image is located 44 | /// Resolve flags 45 | /// Process ID. Used to search process executable directory 46 | /// Activation context 47 | /// Status 48 | NTSTATUS ResolvePath( std::wstring& path, 49 | const std::wstring& baseName, 50 | const std::wstring& searchDir, 51 | eResolveFlag flags, 52 | DWORD procID, 53 | HANDLE actx = INVALID_HANDLE_VALUE ); 54 | 55 | /// 56 | /// Try SxS redirection 57 | /// 58 | /// Image path. 59 | /// Activation context 60 | /// 61 | NTSTATUS ProbeSxSRedirect( std::wstring& path, HANDLE actx = INVALID_HANDLE_VALUE ); 62 | 63 | private: 64 | // Ensure singleton 65 | NameResolve(); 66 | NameResolve( const NameResolve& ) = delete; 67 | NameResolve& operator =( const NameResolve& ) = delete; 68 | 69 | /// 70 | /// Gets the process executable directory 71 | /// 72 | /// Process ID 73 | /// Process executable directory 74 | std::wstring GetProcessDirectory( DWORD pid ); 75 | 76 | /// 77 | /// OS dependent api set initialization 78 | /// 79 | /// true on success 80 | template 81 | bool InitializeP(); 82 | 83 | private: 84 | mapApiSchema _apiSchema; // Api schema table 85 | }; 86 | 87 | 88 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmHelperBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AsmVariant.hpp" 4 | #include "AsmStack.hpp" 5 | #include "Macro.h" 6 | 7 | #include 8 | #include 9 | 10 | namespace blackbone 11 | { 12 | // 13 | // Function calling convention 14 | // 15 | enum eCalligConvention 16 | { 17 | cc_cdecl, // cdecl 18 | cc_stdcall, // stdcall 19 | cc_thiscall, // thiscall 20 | cc_fastcall // fastcall 21 | }; 22 | 23 | // 24 | // Function return type 25 | // Do not change numeric values! 26 | // 27 | enum eReturnType 28 | { 29 | rt_int32 = 4, // 32bit value 30 | rt_int64 = 8, // 64bit value 31 | rt_float = 1, // float value 32 | rt_double = 2, // double value 33 | rt_struct = 3, // structure returned by value 34 | }; 35 | 36 | // Argument pass method 37 | enum eArgType 38 | { 39 | at_ecx = 0, // In ecx 40 | at_edx = 1, // In edx 41 | at_stack = 2, // On stack 42 | }; 43 | 44 | 45 | /// 46 | /// Assembly generation helper 47 | /// 48 | class AsmHelperBase 49 | { 50 | public: 51 | AsmHelperBase( AsmJit::Assembler& _a ) : a( _a ) { } 52 | virtual ~AsmHelperBase() { } 53 | 54 | virtual void GenPrologue( bool switchMode = false ) = 0; 55 | virtual void GenEpilogue( bool switchMode = false, int retSize = -1) = 0; 56 | virtual void GenCall( const AsmVariant&, const std::vector& args, eCalligConvention cc = cc_stdcall ) = 0; 57 | virtual void ExitThreadWithStatus( size_t resultPtr ) = 0; 58 | virtual void SaveRetValAndSignalEvent( size_t ResultPtr, size_t EventPtr, size_t errPtr, eReturnType rtype = rt_int32 ) = 0; 59 | virtual void SetTebPtr() = 0; 60 | virtual void EnableX64CallStack( bool state ) = 0; 61 | 62 | /// 63 | /// Switch processor into WOW64 emulation mode 64 | /// 65 | void SwitchTo86() 66 | { 67 | AsmJit::Label l = a.newLabel(); 68 | 69 | a.call( l ); a.bind( l ); 70 | a.mov( AsmJit::dword_ptr( AsmJit::esp, 4 ), 0x23 ); 71 | a.add( AsmJit::dword_ptr( AsmJit::esp ), 0xD ); 72 | a._emitByte( 0xCB ); // retf 73 | } 74 | 75 | /// 76 | /// Switch processor into x64 mode (long mode) 77 | /// 78 | void SwitchTo64() 79 | { 80 | AsmJit::Label l = a.newLabel(); 81 | 82 | a.push( 0x33 ); 83 | a.call( l ); a.bind( l ); 84 | a.add( AsmJit::dword_ptr( AsmJit::esp ), 5 ); 85 | a._emitByte( 0xCB ); // retf 86 | } 87 | 88 | private: 89 | AsmHelperBase( const AsmHelperBase& ) = delete; 90 | AsmHelperBase& operator =(const AsmHelperBase&) = delete; 91 | 92 | protected: 93 | AsmJit::Assembler& a; 94 | }; 95 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Regenerate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # ============================================================================= 4 | # [Regenerate.py - Description] 5 | # 6 | # This Python script will regenerate instruction names in Assembler{$ARCH}.cpp 7 | # files. Idea is that there can be big instruction table and this script tries 8 | # to minimize runtime relocation data of AsmJit library. 9 | # ============================================================================= 10 | 11 | # ============================================================================= 12 | # [Configuration] 13 | # ============================================================================= 14 | 15 | # Files to process. 16 | FILES = [ 17 | "DefsX86X64.cpp" 18 | ] 19 | 20 | # ============================================================================= 21 | # [Imports] 22 | # ============================================================================= 23 | 24 | import os, re, string 25 | 26 | # ============================================================================= 27 | # [Helpers] 28 | # ============================================================================= 29 | 30 | def readFile(fileName): 31 | handle = open(fileName, "rb") 32 | data = handle.read() 33 | handle.close() 34 | return data 35 | 36 | def writeFile(fileName, data): 37 | handle = open(fileName, "wb") 38 | handle.truncate() 39 | handle.write(data) 40 | handle.close() 41 | 42 | # ============================================================================= 43 | # [Main] 44 | # ============================================================================= 45 | 46 | def processFile(fileName): 47 | data = readFile(fileName); 48 | 49 | din = data 50 | r = re.compile(r"instructionDescription\[\][\s]*=[\s]*{(?P[^}])*}") 51 | m = r.search(din) 52 | 53 | if not m: 54 | print "Cannot match instruction data in " + fileName 55 | exit(0) 56 | 57 | din = din[m.start():m.end()] 58 | dout = "" 59 | 60 | dinst = [] 61 | daddr = [] 62 | hinst = {} 63 | 64 | r = re.compile(r'\"(?P[A-Za-z0-9_ ]+)\"') 65 | dpos = 0 66 | for m in r.finditer(din): 67 | inst = m.group("INST") 68 | 69 | if not inst in hinst: 70 | dinst.append(inst) 71 | hinst[inst] = dpos 72 | 73 | daddr.append(dpos) 74 | dpos += len(inst) + 1 75 | 76 | dout += "const char instructionName[] =\n" 77 | for i in xrange(len(dinst)): 78 | dout += " \"" + dinst[i] + "\\0\"\n" 79 | dout += " ;\n" 80 | 81 | dout += "\n" 82 | 83 | for i in xrange(len(dinst)): 84 | dout += "#define INST_" + dinst[i].upper().replace(" ", "_") + "_INDEX" + " " + str(daddr[i]) + "\n" 85 | 86 | mb_string = "// ${INSTRUCTION_DATA_BEGIN}\n" 87 | me_string = "// ${INSTRUCTION_DATA_END}\n" 88 | 89 | mb = data.index(mb_string) 90 | me = data.index(me_string) 91 | 92 | data = data[:mb + len(mb_string)] + dout + data[me:] 93 | 94 | writeFile(fileName, data) 95 | 96 | for fileName in FILES: 97 | processFile(fileName) 98 | -------------------------------------------------------------------------------- /src/BlackBone/FileProjection.cpp: -------------------------------------------------------------------------------- 1 | #include "FileProjection.h" 2 | 3 | namespace blackbone 4 | { 5 | 6 | FileProjection::FileProjection( void ) 7 | { 8 | } 9 | 10 | FileProjection::FileProjection( const std::wstring& path ) 11 | { 12 | Project(path); 13 | } 14 | 15 | 16 | FileProjection::~FileProjection(void) 17 | { 18 | Release(); 19 | } 20 | 21 | 22 | /// 23 | /// Memory-map specified file 24 | /// 25 | /// Image path 26 | /// File address in memory, nullptr if failed 27 | void* FileProjection::Project( const std::wstring& path ) 28 | { 29 | Release(); 30 | 31 | // Prepare activation context 32 | ACTCTX act = { 0 }; 33 | act.cbSize = sizeof(act); 34 | act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; 35 | act.lpSource = path.c_str(); 36 | act.lpResourceName = MAKEINTRESOURCEW( 2 ); 37 | 38 | _hctx = CreateActCtx( &act ); 39 | 40 | // Retry with another resource id 41 | if (_hctx == INVALID_HANDLE_VALUE) 42 | { 43 | act.lpResourceName = MAKEINTRESOURCEW( 1 ); 44 | 45 | if ((_hctx = CreateActCtx( &act )) != INVALID_HANDLE_VALUE) 46 | _manifestIdx = 1; 47 | } 48 | else 49 | _manifestIdx = 2; 50 | 51 | _hFile = CreateFileW( path.c_str(), FILE_GENERIC_READ, 52 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 53 | NULL, OPEN_EXISTING, 0, NULL ); 54 | 55 | if (_hFile != INVALID_HANDLE_VALUE) 56 | { 57 | // Try mapping as image 58 | _hMapping = CreateFileMappingW( _hFile, NULL, SEC_IMAGE | PAGE_READONLY, 0, 0, NULL ); 59 | 60 | if (_hMapping && _hMapping != INVALID_HANDLE_VALUE) 61 | { 62 | _pData = MapViewOfFile( _hMapping, FILE_MAP_READ, 0, 0, 0 ); 63 | } 64 | // Map as simple datafile 65 | else 66 | { 67 | _plainData = true; 68 | _hMapping = CreateFileMappingW( _hFile, NULL, PAGE_READONLY, 0, 0, NULL ); 69 | 70 | if (_hMapping && _hMapping != INVALID_HANDLE_VALUE) 71 | _pData = MapViewOfFile( _hMapping, FILE_MAP_READ, 0, 0, 0 ); 72 | } 73 | } 74 | 75 | return _pData; 76 | } 77 | 78 | /// 79 | /// Release mapping, if any 80 | /// 81 | void FileProjection::Release() 82 | { 83 | if (_hctx != INVALID_HANDLE_VALUE) 84 | { 85 | ReleaseActCtx( _hctx ); 86 | _hctx = INVALID_HANDLE_VALUE; 87 | } 88 | 89 | if(_pData) 90 | { 91 | UnmapViewOfFile( _pData ); 92 | _pData = nullptr; 93 | } 94 | 95 | if (_hMapping && _hMapping != INVALID_HANDLE_VALUE) 96 | { 97 | CloseHandle( _hMapping ); 98 | _hMapping = NULL; 99 | } 100 | 101 | if (_hFile != INVALID_HANDLE_VALUE) 102 | { 103 | CloseHandle( _hFile ); 104 | _hFile = INVALID_HANDLE_VALUE; 105 | } 106 | } 107 | 108 | }; -------------------------------------------------------------------------------- /src/BlackBone/AsmHelper32.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AsmHelperBase.h" 4 | 5 | namespace blackbone 6 | { 7 | 8 | /// 9 | /// 32 bit assembler helper 10 | /// 11 | class AsmHelper32 : public AsmHelperBase 12 | { 13 | public: 14 | AsmHelper32( AsmJit::Assembler& _a ); 15 | ~AsmHelper32( void ); 16 | 17 | /// 18 | /// Generate function prologue code 19 | /// 20 | /// Unused 21 | virtual void GenPrologue( bool switchMode = false ); 22 | 23 | /// 24 | /// Generate function epilogue code 25 | /// 26 | /// Unused 27 | /// Stack change value 28 | virtual void GenEpilogue( bool switchMode = false, int retSize = 4 ); 29 | 30 | /// 31 | /// Generate function call 32 | /// 33 | /// Function pointer 34 | /// Function arguments 35 | /// Calling convention 36 | virtual void GenCall( const AsmVariant& pFN, const std::vector& args, eCalligConvention cc = cc_stdcall ); 37 | 38 | /// 39 | /// Save eax value and terminate current thread 40 | /// 41 | /// Memry where eax value will be saved 42 | virtual void ExitThreadWithStatus( size_t resultPtr ); 43 | 44 | /// 45 | /// Save return value and signal thread return event 46 | /// 47 | /// Result value memory location 48 | /// Event memory location 49 | /// Error code memory location 50 | /// Return type 51 | virtual void SaveRetValAndSignalEvent( size_t ResultPtr, size_t EventPtr, size_t errPtr, eReturnType rtype = rt_int32 ); 52 | 53 | /// 54 | /// Does nothing under x86 55 | /// 56 | /// Unused 57 | virtual void EnableX64CallStack( bool ) { } 58 | 59 | /// 60 | /// Move TEB pointer into edx 61 | /// 62 | virtual void SetTebPtr() 63 | { 64 | // mov edx, fs:[0x18] 65 | a._emitDWord( 0x18158b64 ); 66 | a._emitWord( 0x00 ); 67 | a._emitByte( 0x00 ); 68 | } 69 | 70 | private: 71 | AsmHelper32( const AsmHelper32& ) = delete; 72 | AsmHelper32& operator = (const AsmHelper32&) = delete; 73 | 74 | /// 75 | /// Push function argument 76 | /// 77 | /// Argument. 78 | /// Push type(register or stack) 79 | void PushArg( const AsmVariant& arg, eArgType regidx = at_stack ); 80 | 81 | /// 82 | /// Push argument into function 83 | /// 84 | /// Argument 85 | /// Argument location 86 | template 87 | void PushArgp( _Type arg, eArgType index ); 88 | }; 89 | 90 | } 91 | 92 | -------------------------------------------------------------------------------- /src/BlackBone/Process.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ProcessCore.h" 4 | #include "ProcessMemory.h" 5 | #include "ProcessModules.h" 6 | #include "Threads.h" 7 | #include "RemoteExec.h" 8 | #include "RemoteHook.h" 9 | #include "NtLoader.h" 10 | #include "MMap.h" 11 | 12 | #include "NativeStructures.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace blackbone 18 | { 19 | 20 | #define DEFAULT_ACCESS_P PROCESS_QUERY_INFORMATION | \ 21 | PROCESS_VM_READ | \ 22 | PROCESS_VM_WRITE | \ 23 | PROCESS_VM_OPERATION | \ 24 | PROCESS_CREATE_THREAD | \ 25 | PROCESS_SET_QUOTA | \ 26 | PROCESS_TERMINATE | \ 27 | PROCESS_DUP_HANDLE 28 | class Process 29 | { 30 | public: 31 | Process(); 32 | ~Process(void); 33 | 34 | /// 35 | /// Attach to existing process 36 | /// 37 | /// Process ID 38 | /// Access mask 39 | /// Status 40 | NTSTATUS Attach( DWORD pid, DWORD access = DEFAULT_ACCESS_P ); 41 | 42 | /// 43 | /// Get process ID 44 | /// 45 | /// Process ID 46 | inline DWORD pid() const { return _core.pid(); } 47 | 48 | /// 49 | /// Checks if process still exists 50 | /// 51 | /// 52 | bool valid(); 53 | 54 | /// 55 | /// Search for process by executable name 56 | /// 57 | /// Process name. If empty - function will retrieve all existing processes 58 | /// Found processses 59 | static void EnumByName( const std::wstring& name, std::vector& found ); 60 | 61 | // 62 | // Subroutines 63 | // 64 | ProcessCore& core() { return _core; } // Core routines and native 65 | ProcessMemory& memory() { return _memory; } // Memory manipulations 66 | ProcessThreads& threads() { return _threads; } // Threads 67 | RemoteHook& hooks() { return _hooks; } // Hooking code remotely 68 | RemoteExec& remote() { return _remote; } // Remote code execution 69 | ProcessModules& modules() { return _modules; } // Module management 70 | MMap& mmap() { return _mmap; } // Manual module mapping 71 | NtLdr& nativeLdr() { return _nativeLdr; } // Native loader routines 72 | 73 | private: 74 | 75 | NTSTATUS GrantPriviledge( const std::wstring& name ); 76 | 77 | Process(const Process&) = delete; 78 | Process& operator =(const Process&) = delete; 79 | 80 | private: 81 | ProcessCore _core; // Core routines and native subsystem 82 | ProcessMemory _memory; // Memory manipulations 83 | ProcessThreads _threads; // Threads 84 | RemoteHook _hooks; // Hooking code remotely 85 | RemoteExec _remote; // Remote code execution 86 | ProcessModules _modules; // Module management 87 | MMap _mmap; // Manual module mapping 88 | NtLdr _nativeLdr; // Native loader routines 89 | }; 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/BlackBone/AsmHelper64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AsmHelperBase.h" 4 | #include "Macro.h" 5 | 6 | namespace blackbone 7 | { 8 | 9 | class AsmHelper64 : public AsmHelperBase 10 | { 11 | public: 12 | AsmHelper64( AsmJit::Assembler& _a ); 13 | ~AsmHelper64( void ); 14 | 15 | /// 16 | /// Generate function prologue code 17 | /// 18 | /// true if execution must be swithed to x64 mode 19 | virtual void GenPrologue( bool switchMode = false ); 20 | 21 | /// 22 | /// Generate function epilogue code 23 | /// 24 | /// true if execution must be swithed to x86 mode 25 | /// Stack change value 26 | virtual void GenEpilogue( bool switchMode = false, int retSize = 0 ); 27 | 28 | /// 29 | /// Generate function call 30 | /// 31 | /// Function pointer 32 | /// Function arguments 33 | /// Ignored 34 | virtual void GenCall( const AsmVariant& pFN, const std::vector& args, eCalligConvention cc = cc_stdcall ); 35 | 36 | /// 37 | /// Save rax value and terminate current thread 38 | /// 39 | /// Memry where rax value will be saved 40 | virtual void ExitThreadWithStatus( size_t resultPtr = 0 ); 41 | 42 | /// 43 | /// Save return value and signal thread return event 44 | /// 45 | /// Result value memory location 46 | /// Event memory location 47 | /// Error code memory location 48 | /// Return type 49 | virtual void SaveRetValAndSignalEvent( size_t ResultPtr, size_t EventPtr, size_t lastStatusPtr, eReturnType rtype = rt_int32 ); 50 | 51 | /// 52 | /// Set stack reservation policy on call generation 53 | /// 54 | /// 55 | /// If true - stack space will be reserved during each call generation 56 | /// If false - no automatic stack reservation, user must allocate stack by hand 57 | /// 58 | virtual void EnableX64CallStack( bool state ); 59 | 60 | /// 61 | /// Move TEB pointer into rdx 62 | /// 63 | virtual void SetTebPtr() 64 | { 65 | // mov rdx, gs:[0x30] 66 | a._emitDWord( 0x148b4865 ); 67 | a._emitDWord( 0x00003025 ); 68 | a._emitByte( 0x00 ); 69 | } 70 | 71 | private: 72 | AsmHelper64( const AsmHelper64& ) = delete; 73 | AsmHelper64& operator = (const AsmHelper64&) = delete; 74 | 75 | /// 76 | /// Push function argument 77 | /// 78 | /// Argument. 79 | /// Push type(register or stack) 80 | void PushArg( const AsmVariant& arg, size_t index ); 81 | 82 | /// 83 | /// Push function argument 84 | /// 85 | /// Argument 86 | /// Argument index 87 | /// true if argument is a floating point value 88 | template 89 | void PushArgp( const _Type& arg, size_t index, bool fpu = false ); 90 | 91 | private: 92 | bool _stackEnabled; // if true - GenCall will allocate shadow stack space 93 | }; 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Util_p.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Guard] 8 | #ifndef _ASMJIT_UTIL_P_H 9 | #define _ASMJIT_UTIL_P_H 10 | 11 | // [Dependencies] 12 | #include "Util.h" 13 | 14 | #include 15 | #include 16 | 17 | namespace AsmJit { 18 | 19 | //! @addtogroup AsmJit_Util 20 | //! @{ 21 | 22 | // ============================================================================ 23 | // [AsmJit::Util] 24 | // ============================================================================ 25 | 26 | namespace Util 27 | { 28 | // -------------------------------------------------------------------------- 29 | // [AsmJit::floatAsInt32, int32AsFloat] 30 | // -------------------------------------------------------------------------- 31 | 32 | //! @internal 33 | //! 34 | //! @brief used to cast from float to 32-bit integer and vica versa. 35 | union I32FPUnion 36 | { 37 | //! @brief 32-bit signed integer value. 38 | int32_t i; 39 | //! @brief 32-bit SP-FP value. 40 | float f; 41 | }; 42 | 43 | //! @internal 44 | //! 45 | //! @brief used to cast from double to 64-bit integer and vica versa. 46 | union I64FPUnion 47 | { 48 | //! @brief 64-bit signed integer value. 49 | int64_t i; 50 | //! @brief 64-bit DP-FP value. 51 | double f; 52 | }; 53 | 54 | //! @brief Binary cast from 32-bit integer to SP-FP value (@c float). 55 | static inline float int32AsFloat(int32_t i) ASMJIT_NOTHROW 56 | { 57 | I32FPUnion u; 58 | u.i = i; 59 | return u.f; 60 | } 61 | 62 | //! @brief Binary cast SP-FP value (@c float) to 32-bit integer. 63 | static inline int32_t floatAsInt32(float f) ASMJIT_NOTHROW 64 | { 65 | I32FPUnion u; 66 | u.f = f; 67 | return u.i; 68 | } 69 | 70 | //! @brief Binary cast from 64-bit integer to DP-FP value (@c double). 71 | static inline double int64AsDouble(int64_t i) ASMJIT_NOTHROW 72 | { 73 | I64FPUnion u; 74 | u.i = i; 75 | return u.f; 76 | } 77 | 78 | //! @brief Binary cast from DP-FP value (@c double) to 64-bit integer. 79 | static inline int64_t doubleAsInt64(double f) ASMJIT_NOTHROW 80 | { 81 | I64FPUnion u; 82 | u.f = f; 83 | return u.i; 84 | } 85 | 86 | // -------------------------------------------------------------------------- 87 | // [Str Utils] 88 | // -------------------------------------------------------------------------- 89 | 90 | ASMJIT_HIDDEN char* mycpy(char* dst, const char* src, sysuint_t len = (sysuint_t)-1) ASMJIT_NOTHROW; 91 | ASMJIT_HIDDEN char* myfill(char* dst, const int c, sysuint_t len) ASMJIT_NOTHROW; 92 | ASMJIT_HIDDEN char* myhex(char* dst, const uint8_t* src, sysuint_t len) ASMJIT_NOTHROW; 93 | ASMJIT_HIDDEN char* myutoa(char* dst, sysuint_t i, sysuint_t base = 10) ASMJIT_NOTHROW; 94 | ASMJIT_HIDDEN char* myitoa(char* dst, sysint_t i, sysuint_t base = 10) ASMJIT_NOTHROW; 95 | 96 | // -------------------------------------------------------------------------- 97 | // [Mem Utils] 98 | // -------------------------------------------------------------------------- 99 | 100 | static inline void memset32(uint32_t* p, uint32_t c, sysuint_t len) ASMJIT_NOTHROW 101 | { 102 | sysuint_t i; 103 | for (i = 0; i < len; i++) p[i] = c; 104 | } 105 | } // Util namespace 106 | 107 | //! @} 108 | 109 | } // AsmJit namespace 110 | 111 | #endif // _ASMJIT_UTIL_P_H 112 | -------------------------------------------------------------------------------- /src/BlackBone/Macro.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Architecture-dependent pointer size 4 | #define WordSize sizeof(void*) 5 | 6 | // Rebase address 7 | #define MAKE_PTR(T, pRVA, base) (T)((ptr_t)pRVA + (ptr_t)base) 8 | #define REBASE(pRVA, baseOld, baseNew) ((ptr_t)pRVA - (ptr_t)baseOld + (ptr_t)baseNew) 9 | #define REBASE2(T, rva, baseOld, baseNew) (T)((size_t)rva - (size_t)baseOld + (size_t)baseNew) 10 | 11 | // Field offset info 12 | #define FIELD_OFFSET2(type, field) ((LONG)(LONG_PTR)&(((type)0)->field)) 13 | #define GET_FIELD_PTR(entry, field) (size_t)((uint8_t*)entry + FIELD_OFFSET2(decltype(entry), field)) 14 | 15 | #define LODWORD(l) ((uint32_t)(((uint64_t)(l)) & 0xffffffff)) 16 | #define HIDWORD(l) ((uint32_t)((((uint64_t)(l)) >> 32) & 0xffffffff)) 17 | 18 | // Set or reset particular bit 19 | #define SET_BIT(v, b) v |= (1ull << b) 20 | #define RESET_BIT(v, b) v &= ~(1ull << b) 21 | 22 | // Register aliases 23 | #ifdef _M_AMD64 24 | #define NAX Rax 25 | #define NSP Rsp 26 | #define NIP Rip 27 | #else 28 | #define NAX Eax 29 | #define NSP Esp 30 | #define NIP Eip 31 | #endif 32 | 33 | // Type-unsafe cast. 34 | template 35 | inline _Tgt brutal_cast( const _Src& src ) 36 | { 37 | static_assert(sizeof(_Tgt) == sizeof(_Src), "Operand size mismatch"); 38 | union _u { _Src s; _Tgt t; } u; 39 | u.s = src; 40 | return u.t; 41 | } 42 | 43 | // Align value 44 | inline size_t Align( size_t val, size_t alignment ) 45 | { 46 | return (val % alignment == 0) ? val : (val / alignment + 1) * alignment; 47 | } 48 | 49 | // Offset of 'LastStatus' field in TEB 50 | #define LAST_STATUS_OFS (0x598 + 0x197 * WordSize) 51 | 52 | /// 53 | /// Get last NT status 54 | /// 55 | /// 56 | inline NTSTATUS LastNtStatus() 57 | { 58 | return *(NTSTATUS*)((unsigned char*)NtCurrentTeb() + LAST_STATUS_OFS); 59 | } 60 | 61 | /// 62 | /// Set last NT status 63 | /// 64 | /// The status. 65 | /// 66 | inline NTSTATUS LastNtStatus( NTSTATUS status ) 67 | { 68 | return *(NTSTATUS*)((unsigned char*)NtCurrentTeb() + LAST_STATUS_OFS) = status; 69 | } 70 | 71 | #define EMIT(a) __asm __emit (a) 72 | 73 | // Switch processor to long mode 74 | #define X64_Start_with_CS(_cs) \ 75 | { \ 76 | EMIT(0x6A) EMIT(_cs) /* push _cs */ \ 77 | EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \ 78 | EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(5) /* add dword [esp], 5 */ \ 79 | EMIT(0xCB) /* retf */ \ 80 | } 81 | 82 | // Switch processor to WOW64 mode 83 | #define X64_End_with_CS(_cs) \ 84 | { \ 85 | EMIT(0xE8) EMIT(0) EMIT(0) EMIT(0) EMIT(0) /* call $+5 */ \ 86 | EMIT(0xC7) EMIT(0x44) EMIT(0x24) EMIT(4) EMIT(_cs) EMIT(0) EMIT(0) EMIT(0) /* mov dword [rsp + 4], _cs */ \ 87 | EMIT(0x83) EMIT(4) EMIT(0x24) EMIT(0xD) /* add dword [rsp], 0xD */ \ 88 | EMIT(0xCB) /* retf */ \ 89 | } 90 | 91 | // 92 | // 64bit assembly helpers 93 | // 94 | #define X64_Start() X64_Start_with_CS(0x33) 95 | #define X64_End() X64_End_with_CS(0x23) 96 | 97 | #define _RAX 0 98 | #define _RCX 1 99 | #define _RDX 2 100 | #define _RBX 3 101 | #define _RSP 4 102 | #define _RBP 5 103 | #define _RSI 6 104 | #define _RDI 7 105 | #define _R8 8 106 | #define _R9 9 107 | #define _R10 10 108 | #define _R11 11 109 | #define _R12 12 110 | #define _R13 13 111 | #define _R14 14 112 | #define _R15 15 113 | 114 | #define X64_Push(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x50 | ((r) & 7)) 115 | #define X64_Pop(r) EMIT(0x48 | ((r) >> 3)) EMIT(0x58 | ((r) & 7)) 116 | -------------------------------------------------------------------------------- /src/BlackBone/ProcessMemory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "MemBlock.h" 5 | 6 | #include 7 | 8 | namespace blackbone 9 | { 10 | 11 | class ProcessMemory 12 | { 13 | public: 14 | ProcessMemory( class ProcessCore& core ); 15 | ~ProcessMemory(); 16 | 17 | /// 18 | /// Allocate new memory block 19 | /// 20 | /// Block size 21 | /// Memory protection 22 | /// Desired base address of new block 23 | /// Memory block. If failed - returned block will be invalid 24 | MemBlock Allocate( size_t size, DWORD protection = PAGE_EXECUTE_READWRITE, ptr_t desired = 0 ); 25 | 26 | /// 27 | /// Free memory 28 | /// 29 | /// Memory address to release. 30 | /// Region size 31 | /// Status 32 | NTSTATUS Free( ptr_t pAddr, size_t size = 0 ); 33 | 34 | /// 35 | /// Get memory region info 36 | /// 37 | /// Memory address 38 | /// Retrieved info 39 | /// Status 40 | NTSTATUS Query( ptr_t pAddr, PMEMORY_BASIC_INFORMATION64 pInfo ); 41 | 42 | /// 43 | /// Change memory protection 44 | /// 45 | /// Memory address 46 | /// Region size 47 | /// New memory protection flags 48 | /// Old protection flags 49 | /// Status 50 | NTSTATUS Protect( ptr_t pAddr, size_t size, DWORD flProtect, DWORD *pOld = NULL ); 51 | 52 | /// 53 | /// Read data 54 | /// 55 | /// Memoey address to read from 56 | /// Size of data to read 57 | /// Output buffer 58 | /// 59 | /// If true, function will try to read all committed pages in range ignoring uncommitted ones. 60 | /// Otherwise function will fail if there is at least one non-committed page in region. 61 | /// 62 | /// Status 63 | NTSTATUS Read( ptr_t dwAddress, size_t dwSize, PVOID pResult, bool handleHoles = false ); 64 | 65 | /// 66 | /// Write data 67 | /// 68 | /// Memory address to write to 69 | /// Size of data to write 70 | /// Buffer to write 71 | /// Status 72 | NTSTATUS Write( ptr_t pAddress, size_t dwSize, const void* pData ); 73 | 74 | /// 75 | /// Read data 76 | /// 77 | /// Address to read from 78 | /// Read data 79 | template 80 | inline T Read( ptr_t dwAddress ) 81 | { 82 | T res; 83 | Read( dwAddress, sizeof(T), &res ); 84 | return res; 85 | }; 86 | 87 | /// 88 | /// Write data 89 | /// 90 | /// Size of data to write 91 | /// Data to write 92 | /// Status 93 | template 94 | inline NTSTATUS Write( ptr_t dwAddress, T data ) 95 | { 96 | return Write( dwAddress, sizeof(T), &data ); 97 | } 98 | 99 | inline class ProcessCore& core() { return _core; } 100 | 101 | private: 102 | ProcessMemory( const ProcessMemory& ) = delete; 103 | ProcessMemory& operator =(const ProcessMemory&) = delete; 104 | 105 | private: 106 | class ProcessCore& _core; // Core routines 107 | }; 108 | 109 | } -------------------------------------------------------------------------------- /src/BlackBone/Threads.cpp: -------------------------------------------------------------------------------- 1 | #include "Threads.h" 2 | #include "ProcessCore.h" 3 | 4 | #include 5 | #include 6 | 7 | namespace blackbone 8 | { 9 | 10 | ProcessThreads::ProcessThreads( ProcessCore& core ) 11 | : _core( core ) 12 | { 13 | } 14 | 15 | ProcessThreads::~ProcessThreads() 16 | { 17 | } 18 | 19 | /// 20 | /// Create the thread. 21 | /// 22 | /// Thread enty point 23 | /// Thread argument. 24 | /// Thread creation flags 25 | /// New thread object 26 | Thread ProcessThreads::CreateNew( ptr_t threadProc, ptr_t arg, DWORD flags /*= 0*/ ) 27 | { 28 | HANDLE hThd = NULL; 29 | _core.native()->CreateRemoteThreadT( hThd, threadProc, arg, flags ); 30 | 31 | return Thread( hThd, &_core ); 32 | } 33 | 34 | /// 35 | /// Gets all process threads 36 | /// 37 | /// Return already existing thread list 38 | /// Threads collection 39 | std::vector& ProcessThreads::getAll( bool dontUpdate /*= false*/ ) 40 | { 41 | if (dontUpdate) 42 | return _threads; 43 | 44 | HANDLE hThreadSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 45 | 46 | _threads.clear(); 47 | 48 | if (hThreadSnapshot != INVALID_HANDLE_VALUE) 49 | { 50 | THREADENTRY32 tEntry = { 0 }; 51 | tEntry.dwSize = sizeof(THREADENTRY32); 52 | 53 | // Iterate threads 54 | for (BOOL success = Thread32First( hThreadSnapshot, &tEntry ); 55 | success == TRUE; 56 | success = Thread32Next( hThreadSnapshot, &tEntry )) 57 | { 58 | if (tEntry.th32OwnerProcessID != _core.pid()) 59 | continue; 60 | 61 | _threads.emplace_back( Thread( tEntry.th32ThreadID, &_core ) ); 62 | } 63 | 64 | CloseHandle( hThreadSnapshot ); 65 | } 66 | 67 | return _threads; 68 | } 69 | 70 | /// 71 | /// Get main process thread 72 | /// 73 | /// Pointer to thread object, nullptr if failed 74 | Thread* ProcessThreads::getMain() 75 | { 76 | uint64_t mintime = MAXULONG64; 77 | Thread* pMain = nullptr; 78 | 79 | for (auto& thread : getAll()) 80 | { 81 | uint64_t time = thread.startTime(); 82 | 83 | if (time < mintime) 84 | { 85 | mintime = time; 86 | pMain = &thread; 87 | } 88 | } 89 | 90 | return pMain; 91 | } 92 | 93 | /// 94 | /// Get least executed thread 95 | /// 96 | /// Pointer to thread object, nullptr if failed 97 | Thread* ProcessThreads::getLeastExecuted() 98 | { 99 | uint64_t mintime = MAXULONG64; 100 | Thread* pThread = nullptr; 101 | 102 | for (auto& thread : getAll()) 103 | { 104 | uint64_t time = thread.execTime(); 105 | 106 | if (time < mintime) 107 | { 108 | mintime = time; 109 | pThread = &thread; 110 | } 111 | } 112 | 113 | return pThread; 114 | } 115 | 116 | /// 117 | /// Get random thread 118 | /// 119 | /// Pointer to thread object, nullptr if failed 120 | Thread* ProcessThreads::getRandom() 121 | { 122 | getAll(); 123 | 124 | if (_threads.empty()) 125 | return nullptr; 126 | 127 | static std::random_device rd; 128 | std::uniform_int_distribution dist( 0, _threads.size() - 1 ); 129 | 130 | return &_threads[dist(rd)]; 131 | } 132 | 133 | /// 134 | /// Get thread by ID 135 | /// 136 | /// Thread ID 137 | /// Pointer to thread object, nullptr if failed 138 | Thread* ProcessThreads::get( DWORD id ) 139 | { 140 | for(auto& thd : getAll()) 141 | if (thd.id() == id) 142 | return &thd; 143 | 144 | return nullptr; 145 | } 146 | 147 | } -------------------------------------------------------------------------------- /src/BlackBone/Process.cpp: -------------------------------------------------------------------------------- 1 | #include "Process.h" 2 | #include "NameResolve.h" 3 | 4 | #include 5 | 6 | namespace blackbone 7 | { 8 | 9 | Process::Process() 10 | : _core() 11 | , _memory( _core ) 12 | , _threads( _core ) 13 | , _hooks( _memory ) 14 | , _modules( *this ) 15 | , _remote( *this ) 16 | , _nativeLdr( *this ) 17 | , _mmap( *this ) 18 | { 19 | GrantPriviledge( SE_DEBUG_NAME ); 20 | GrantPriviledge( SE_LOAD_DRIVER_NAME ); 21 | GrantPriviledge( SE_LOCK_MEMORY_NAME ); 22 | 23 | NameResolve::Instance().Initialize(); 24 | } 25 | 26 | Process::~Process(void) 27 | { 28 | } 29 | 30 | /// 31 | /// Attach to existing process 32 | /// 33 | /// Process ID 34 | /// Access mask 35 | /// Status 36 | NTSTATUS Process::Attach( DWORD pid, DWORD access /*= DEFAULT_ACCESS_P*/ ) 37 | { 38 | // Reset data 39 | _modules.reset(); 40 | _remote.reset(); 41 | _mmap.reset(); 42 | _hooks.reset(); 43 | 44 | auto res = _core.Open( pid, access ); 45 | 46 | if (res == STATUS_SUCCESS) 47 | { 48 | _nativeLdr.Init(); 49 | _remote.CreateRPCEnvironment( true ); 50 | } 51 | 52 | return res; 53 | } 54 | 55 | /// 56 | /// Checks if process still exists 57 | /// 58 | /// 59 | bool Process::valid() 60 | { 61 | DWORD dwExitCode = 0; 62 | 63 | if (!GetExitCodeProcess( _core.handle(), &dwExitCode )) 64 | return false; 65 | 66 | return (dwExitCode == STILL_ACTIVE); 67 | } 68 | 69 | /// 70 | /// Grant current process arbitrary privilege 71 | /// 72 | /// Privilege name 73 | /// Status 74 | NTSTATUS Process::GrantPriviledge( const std::wstring& name ) 75 | { 76 | TOKEN_PRIVILEGES Priv, PrivOld; 77 | DWORD cbPriv = sizeof(PrivOld); 78 | HANDLE hToken; 79 | 80 | if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken )) 81 | { 82 | if (GetLastError() != ERROR_NO_TOKEN) 83 | return LastNtStatus(); 84 | 85 | if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken )) 86 | return LastNtStatus(); 87 | } 88 | 89 | Priv.PrivilegeCount = 1; 90 | Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 91 | LookupPrivilegeValue( NULL, name.c_str(), &Priv.Privileges[0].Luid ); 92 | 93 | if (!AdjustTokenPrivileges( hToken, FALSE, &Priv, sizeof(Priv), &PrivOld, &cbPriv )) 94 | { 95 | CloseHandle( hToken ); 96 | return LastNtStatus(); 97 | } 98 | 99 | if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) 100 | { 101 | CloseHandle( hToken ); 102 | return LastNtStatus(); 103 | } 104 | 105 | return STATUS_SUCCESS; 106 | } 107 | 108 | /// 109 | /// Search for process by executable name 110 | /// 111 | /// Process name. If empty - function will retrieve all existing processes 112 | /// Found processses 113 | void Process::EnumByName( const std::wstring& name, std::vector& found ) 114 | { 115 | HANDLE hProcSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); 116 | 117 | if (hProcSnap != INVALID_HANDLE_VALUE) 118 | { 119 | PROCESSENTRY32W tEntry = { 0 }; 120 | tEntry.dwSize = sizeof(PROCESSENTRY32W); 121 | 122 | // Iterate threads 123 | for (BOOL success = Process32FirstW( hProcSnap, &tEntry ); 124 | success == TRUE; 125 | success = Process32NextW( hProcSnap, &tEntry )) 126 | { 127 | if (name.empty() || _wcsicmp( tEntry.szExeFile, name.c_str() ) == 0) 128 | found.emplace_back( tEntry.th32ProcessID ); 129 | } 130 | 131 | CloseHandle( hProcSnap ); 132 | } 133 | } 134 | 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/BlackBone/ProcessMemory.cpp: -------------------------------------------------------------------------------- 1 | #include "ProcessMemory.h" 2 | #include "ProcessCore.h" 3 | 4 | namespace blackbone 5 | { 6 | 7 | ProcessMemory::ProcessMemory( class ProcessCore& core ) 8 | : _core( core ) 9 | { 10 | } 11 | 12 | ProcessMemory::~ProcessMemory() 13 | { 14 | } 15 | 16 | /// 17 | /// Allocate new memory block 18 | /// 19 | /// Block size 20 | /// Memory protection 21 | /// Desired base address of new block 22 | /// Memory block. If failed - returned block will be invalid 23 | MemBlock ProcessMemory::Allocate( size_t size, DWORD protection /*= PAGE_EXECUTE_READWRITE*/, ptr_t desired /*= 0*/ ) 24 | { 25 | return MemBlock::Allocate( *this, size, desired, protection ); 26 | } 27 | 28 | /// 29 | /// Free memory 30 | /// 31 | /// Memory address to release. 32 | /// Region size 33 | /// Status 34 | NTSTATUS ProcessMemory::Free( ptr_t pAddr, size_t size /*= 0*/ ) 35 | { 36 | return _core.native()->VirualFreeExT( pAddr, size, MEM_RELEASE ); 37 | } 38 | 39 | /// 40 | /// Get memory region info 41 | /// 42 | /// Memory address 43 | /// Retrieved info 44 | /// Status 45 | NTSTATUS ProcessMemory::Query( ptr_t pAddr, PMEMORY_BASIC_INFORMATION64 pInfo ) 46 | { 47 | return _core.native()->VirtualQueryExT( pAddr, pInfo ); 48 | } 49 | 50 | /// 51 | /// Change memory protection 52 | /// 53 | /// Memory address 54 | /// Region size 55 | /// New memory protection flags 56 | /// Old protection flags 57 | /// Status 58 | NTSTATUS ProcessMemory::Protect( ptr_t pAddr, size_t size, DWORD flProtect, DWORD *pOld /*= NULL*/ ) 59 | { 60 | DWORD junk = 0; 61 | if (pOld == nullptr) 62 | pOld = &junk; 63 | 64 | return _core.native()->VirtualProtectExT( pAddr, size, CastProtection( flProtect, _core.DEP() ), pOld ); 65 | } 66 | 67 | /// 68 | /// Read data 69 | /// 70 | /// Memoey address to read from 71 | /// Size of data to read 72 | /// Output buffer 73 | /// 74 | /// If true, function will try to read all committed pages in range ignoring uncommitted ones. 75 | /// Otherwise function will fail if there is at least one non-committed page in region. 76 | /// 77 | /// Status 78 | NTSTATUS ProcessMemory::Read( ptr_t dwAddress, size_t dwSize, PVOID pResult, bool handleHoles /*= false*/ ) 79 | { 80 | DWORD64 dwRead = 0; 81 | 82 | if (dwAddress == 0) 83 | return LastNtStatus( STATUS_INVALID_ADDRESS ); 84 | 85 | LastNtStatus( STATUS_SUCCESS ); 86 | 87 | // Simple read 88 | if (!handleHoles) 89 | { 90 | return _core.native()->ReadProcessMemoryT( dwAddress, pResult, dwSize, &dwRead ); 91 | } 92 | // Read all committed memory regions 93 | else 94 | { 95 | MEMORY_BASIC_INFORMATION64 mbi = { 0 }; 96 | 97 | for (ptr_t memptr = dwAddress; memptr < dwAddress + dwSize; memptr = mbi.BaseAddress + mbi.RegionSize) 98 | { 99 | if (_core.native()->VirtualQueryExT( memptr, &mbi ) != STATUS_SUCCESS) 100 | continue; 101 | 102 | // Filter empty regions 103 | if (mbi.State != MEM_COMMIT || mbi.Protect == PAGE_NOACCESS) 104 | continue; 105 | 106 | uint64_t region_ptr = memptr - dwAddress; 107 | 108 | if (_core.native()->ReadProcessMemoryT( mbi.BaseAddress, 109 | reinterpret_cast(pResult) + region_ptr, 110 | static_cast(mbi.RegionSize), 111 | &dwRead ) != STATUS_SUCCESS) 112 | { 113 | return LastNtStatus(); 114 | } 115 | } 116 | } 117 | 118 | return STATUS_SUCCESS; 119 | } 120 | 121 | /// 122 | /// Write data 123 | /// 124 | /// Memory address to write to 125 | /// Size of data to write 126 | /// Buffer to write 127 | /// Status 128 | NTSTATUS ProcessMemory::Write( ptr_t pAddress, size_t dwSize, const void* pData ) 129 | { 130 | return _core.native()->WriteProcessMemoryT( pAddress, pData, dwSize ); 131 | } 132 | 133 | } -------------------------------------------------------------------------------- /src/BlackBone/x86Subsystem.cpp: -------------------------------------------------------------------------------- 1 | #include "x86Subsystem.h" 2 | #include "DynImport.h" 3 | #include "Macro.h" 4 | 5 | namespace blackbone 6 | { 7 | 8 | x86Native::x86Native( HANDLE hProcess ) 9 | : Native( hProcess, true ) 10 | { 11 | } 12 | 13 | x86Native::~x86Native() 14 | { 15 | } 16 | 17 | /// 18 | /// Query virtual memory 19 | /// 20 | /// Address to query 21 | /// Retrieved memory info 22 | /// Status code 23 | NTSTATUS x86Native::VirtualQueryExT( ptr_t lpAddress, PMEMORY_BASIC_INFORMATION64 lpBuffer ) 24 | { 25 | MEMORY_BASIC_INFORMATION tmp = { 0 }; 26 | 27 | NTSTATUS status = GET_IMPORT( NtQueryVirtualMemory )( _hProcess, reinterpret_cast(lpAddress), 28 | MemoryBasicInformation, &tmp, sizeof(tmp), nullptr); 29 | if (status != STATUS_SUCCESS) 30 | return status; 31 | 32 | // Map values 33 | lpBuffer->AllocationBase = reinterpret_cast(tmp.AllocationBase); 34 | lpBuffer->AllocationProtect = tmp.AllocationProtect; 35 | lpBuffer->BaseAddress = reinterpret_cast(tmp.BaseAddress); 36 | lpBuffer->Protect = tmp.Protect; 37 | lpBuffer->RegionSize = tmp.RegionSize; 38 | lpBuffer->State = tmp.State; 39 | lpBuffer->Type = tmp.Type; 40 | 41 | return status; 42 | } 43 | 44 | /// 45 | /// Get WOW64 thread context 46 | /// 47 | /// Thread handle. 48 | /// Thread context 49 | /// Status code 50 | NTSTATUS x86Native::GetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ) 51 | { 52 | LastNtStatus( STATUS_SUCCESS ); 53 | GetThreadContext( hThread, reinterpret_cast(&ctx) ); 54 | return LastNtStatus(); 55 | } 56 | 57 | /// 58 | /// Get native thread context 59 | /// 60 | /// Thread handle. 61 | /// Thread context 62 | /// Status code 63 | NTSTATUS x86Native::GetThreadContextT( HANDLE /*hThread*/, _CONTEXT64& /*ctx*/ ) 64 | { 65 | // There is no x64 context under x86 OS 66 | return STATUS_NOT_SUPPORTED; 67 | } 68 | 69 | /// 70 | /// Set WOW64 thread context 71 | /// 72 | /// Thread handle. 73 | /// Thread context 74 | /// Status code 75 | NTSTATUS x86Native::SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ) 76 | { 77 | LastNtStatus( STATUS_SUCCESS ); 78 | SetThreadContext( hThread, reinterpret_cast(&ctx) ); 79 | return LastNtStatus(); 80 | } 81 | 82 | /// 83 | /// Set native thread context 84 | /// 85 | /// Thread handle. 86 | /// Thread context 87 | /// Status code 88 | NTSTATUS x86Native::SetThreadContextT( HANDLE /*hThread*/, _CONTEXT64& /*ctx*/ ) 89 | { 90 | // There is no x64 context under x86 OS 91 | return STATUS_NOT_SUPPORTED; 92 | } 93 | 94 | /// 95 | /// Gets WOW64 PEB 96 | /// 97 | /// Retrieved PEB 98 | /// PEB pointer 99 | ptr_t x86Native::getPEB( _PEB32* ppeb ) 100 | { 101 | PROCESS_BASIC_INFORMATION pbi = { 0 }; 102 | ULONG bytes = 0; 103 | 104 | if (GET_IMPORT( NtQueryInformationProcess )(_hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), &bytes) == STATUS_SUCCESS) 105 | if (ppeb) 106 | ReadProcessMemory( _hProcess, pbi.PebBaseAddress, ppeb, sizeof(_PEB32), NULL ); 107 | 108 | return reinterpret_cast(pbi.PebBaseAddress); 109 | } 110 | 111 | /// 112 | /// Get native PEB 113 | /// 114 | /// Retrieved PEB 115 | /// PEB pointer 116 | ptr_t x86Native::getPEB( _PEB64* /*ppeb*/ ) 117 | { 118 | // There is no x64 PEB under x86 OS 119 | LastNtStatus( STATUS_NOT_SUPPORTED ); 120 | return 0; 121 | } 122 | 123 | /// 124 | /// Get WOW64 TEB 125 | /// 126 | /// Retrieved TEB 127 | /// TEB pointer 128 | ptr_t x86Native::getTEB( HANDLE hThread, _TEB32* pteb ) 129 | { 130 | _THREAD_BASIC_INFORMATION_T tbi = { 0 }; 131 | ULONG bytes = 0; 132 | 133 | if (GET_IMPORT( NtQueryInformationThread )( hThread, (THREADINFOCLASS)0, &tbi, sizeof(tbi), &bytes ) == STATUS_SUCCESS) 134 | if (pteb) 135 | ReadProcessMemory( _hProcess, reinterpret_cast(tbi.TebBaseAddress), pteb, sizeof(_TEB32), NULL ); 136 | 137 | return tbi.TebBaseAddress; 138 | } 139 | 140 | /// 141 | /// Get native TEB 142 | /// 143 | /// Retrieved TEB 144 | /// TEB pointer 145 | ptr_t x86Native::getTEB( HANDLE /*hThread*/, _TEB64* /*pteb*/ ) 146 | { 147 | // There is no x64 TEB under x86 OS 148 | LastNtStatus( STATUS_NOT_SUPPORTED ); 149 | return 0; 150 | } 151 | 152 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/CodeGenerator.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Guard] 8 | #ifndef _ASMJIT_CODEGENERATOR_H 9 | #define _ASMJIT_CODEGENERATOR_H 10 | 11 | // [Dependencies] 12 | #include "Build.h" 13 | 14 | namespace AsmJit { 15 | 16 | // ============================================================================ 17 | // [Forward Declarations] 18 | // ============================================================================ 19 | 20 | struct Assembler; 21 | struct JitCodeGenerator; 22 | struct MemoryManager; 23 | struct MemoryMarker; 24 | 25 | // ============================================================================ 26 | // [AsmJit::CodeGenerator] 27 | // ============================================================================ 28 | 29 | //! @brief Code generator is core class for changing behavior of code generated 30 | //! by @c Assembler or @c Compiler. 31 | struct ASMJIT_API CodeGenerator 32 | { 33 | // -------------------------------------------------------------------------- 34 | // [Construction / Destruction] 35 | // -------------------------------------------------------------------------- 36 | 37 | //! @brief Create a @c CodeGenerator instance. 38 | CodeGenerator(); 39 | //! @brief Destroy the @c CodeGenerator instance. 40 | virtual ~CodeGenerator(); 41 | 42 | // -------------------------------------------------------------------------- 43 | // [Interface] 44 | // -------------------------------------------------------------------------- 45 | 46 | //! @brief Allocate memory for code generated in @a assembler and reloc it 47 | //! to target location. 48 | //! 49 | //! This method is universal allowing any pre-process / post-process work 50 | //! with code generated by @c Assembler or @c Compiler. Because @c Compiler 51 | //! always uses @c Assembler it's allowed to access only the @c Assembler 52 | //! instance. 53 | //! 54 | //! This method is always last step when using code generation. You can use 55 | //! it to allocate memory for JIT code, saving code to remote process or a 56 | //! shared library. 57 | //! 58 | //! @retrurn Error value, see @c ERROR_CODE. 59 | virtual uint32_t generate(void** dest, Assembler* assembler) = 0; 60 | 61 | // -------------------------------------------------------------------------- 62 | // [Statics] 63 | // -------------------------------------------------------------------------- 64 | 65 | static JitCodeGenerator* getGlobal(); 66 | 67 | private: 68 | ASMJIT_DISABLE_COPY(CodeGenerator) 69 | }; 70 | 71 | // ============================================================================ 72 | // [AsmJit::JitCodeGenerator] 73 | // ============================================================================ 74 | 75 | struct JitCodeGenerator : public CodeGenerator 76 | { 77 | // -------------------------------------------------------------------------- 78 | // [Construction / Destruction] 79 | // -------------------------------------------------------------------------- 80 | 81 | //! @brief Create a @c JitCodeGenerator instance. 82 | JitCodeGenerator(); 83 | //! @brief Destroy the @c JitCodeGenerator instance. 84 | virtual ~JitCodeGenerator(); 85 | 86 | // -------------------------------------------------------------------------- 87 | // [Memory Manager and Alloc Type] 88 | // -------------------------------------------------------------------------- 89 | 90 | // Note: These members can be ignored by all derived classes. They are here 91 | // only to privide default implementation. All other implementations (remote 92 | // code patching or making dynamic loadable libraries/executables) ignore 93 | // members accessed by these accessors. 94 | 95 | //! @brief Get the @c MemoryManager instance. 96 | inline MemoryManager* getMemoryManager() const { return _memoryManager; } 97 | //! @brief Set the @c MemoryManager instance. 98 | inline void setMemoryManager(MemoryManager* memoryManager) { _memoryManager = memoryManager; } 99 | 100 | //! @brief Get the type of allocation. 101 | inline uint32_t getAllocType() const { return _allocType; } 102 | //! @brief Set the type of allocation. 103 | inline void setAllocType(uint32_t allocType) { _allocType = allocType; } 104 | 105 | // -------------------------------------------------------------------------- 106 | // [Memory Marker] 107 | // -------------------------------------------------------------------------- 108 | 109 | //! @brief Get the @c MemoryMarker instance. 110 | inline MemoryMarker* getMemoryMarker() const { return _memoryMarker; } 111 | //! @brief Set the @c MemoryMarker instance. 112 | inline void setMemoryMarker(MemoryMarker* memoryMarker) { _memoryMarker = memoryMarker; } 113 | 114 | // -------------------------------------------------------------------------- 115 | // [Interface] 116 | // -------------------------------------------------------------------------- 117 | 118 | virtual uint32_t generate(void** dest, Assembler* assembler); 119 | 120 | // -------------------------------------------------------------------------- 121 | // [Members] 122 | // -------------------------------------------------------------------------- 123 | 124 | protected: 125 | //! @brief Memory manager. 126 | MemoryManager* _memoryManager; 127 | //! @brief Memory marker. 128 | MemoryMarker* _memoryMarker; 129 | 130 | //! @brief Type of allocation. 131 | uint32_t _allocType; 132 | 133 | private: 134 | ASMJIT_DISABLE_COPY(JitCodeGenerator) 135 | }; 136 | 137 | } // AsmJit namespace 138 | 139 | // [Guard] 140 | #endif // _ASMJIT_CODEGENERATOR_H 141 | -------------------------------------------------------------------------------- /src/BlackBone/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Utils.h" 2 | #include "DynImport.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace blackbone 10 | { 11 | 12 | /// 13 | /// Convert UTF-8 string to wide char one 14 | /// 15 | /// UTF-8 string 16 | /// wide char string 17 | std::wstring Utils::UTF8ToWstring( const std::string& str ) 18 | { 19 | std::wstring_convert, wchar_t> conv; 20 | return conv.from_bytes( str ); 21 | } 22 | 23 | /// 24 | /// Convert ANSI string to wide char one 25 | /// 26 | /// ANSI string. 27 | /// String locale 28 | /// wide char string 29 | std::wstring Utils::AnsiToWstring( const std::string& input, DWORD locale /*= CP_ACP*/ ) 30 | { 31 | wchar_t buf[8192] = { 0 }; 32 | MultiByteToWideChar( locale, 0, input.c_str(), (int)input.length(), buf, ARRAYSIZE( buf ) ); 33 | return buf; 34 | } 35 | 36 | /// 37 | /// Get filename from full-qualified path 38 | /// 39 | /// File path 40 | /// Filename 41 | std::wstring Utils::StripPath( const std::wstring& path ) 42 | { 43 | if (path.empty()) 44 | return path; 45 | 46 | auto idx = path.rfind( L'\\' ); 47 | if(idx == path.npos) 48 | idx = path.rfind( L'/' ); 49 | 50 | if (idx != path.npos) 51 | return path.substr( idx + 1 ); 52 | else 53 | return path; 54 | } 55 | 56 | /// 57 | /// Get parent directory 58 | /// 59 | /// File path 60 | /// Parent directory 61 | std::wstring Utils::GetParent( const std::wstring& path ) 62 | { 63 | if (path.empty()) 64 | return path; 65 | 66 | auto idx = path.rfind( L'\\' ); 67 | if (idx == path.npos) 68 | idx = path.rfind( L'/' ); 69 | 70 | if (idx != path.npos) 71 | return path.substr( 0, idx ); 72 | else 73 | return path; 74 | } 75 | 76 | /// 77 | /// Get current process exe file directory 78 | /// 79 | /// Exe directory 80 | std::wstring Utils::GetExeDirectory() 81 | { 82 | wchar_t imgName[MAX_PATH] = { 0 }; 83 | DWORD len = ARRAYSIZE(imgName); 84 | 85 | QueryFullProcessImageNameW( GetCurrentProcess(), 0, imgName, &len ); 86 | 87 | return GetParent( imgName ); 88 | } 89 | 90 | /// 91 | /// Cast string characters to lower case 92 | /// 93 | /// Source string. 94 | /// Result string 95 | std::wstring Utils::ToLower( const std::wstring& str ) 96 | { 97 | std::wstring str2( str ); 98 | std::transform( str2.begin(), str2.end(), str2.begin(), ::tolower ); 99 | 100 | return str2; 101 | } 102 | 103 | /// 104 | /// Get system error description 105 | /// 106 | /// The code. 107 | /// Error message 108 | std::wstring Utils::GetErrorDescription( NTSTATUS code ) 109 | { 110 | LPWSTR lpMsgBuf = nullptr; 111 | 112 | if (FormatMessageW( 113 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 114 | FORMAT_MESSAGE_FROM_SYSTEM | 115 | FORMAT_MESSAGE_FROM_HMODULE, 116 | GetModuleHandleW( L"ntdll.dll" ), 117 | code, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), 118 | (LPWSTR)&lpMsgBuf, 0, NULL ) != 0) 119 | { 120 | std::wstring ret( lpMsgBuf ); 121 | 122 | LocalFree( lpMsgBuf ); 123 | return ret; 124 | } 125 | 126 | return L""; 127 | } 128 | 129 | /// 130 | /// Check if file exists 131 | /// 132 | /// Full-qualified file path 133 | /// true if exists 134 | bool Utils::FileExists( const std::wstring& path ) 135 | { 136 | return (GetFileAttributesW( path.c_str() ) != 0xFFFFFFFF ); 137 | } 138 | 139 | /// 140 | /// Load arbitrary driver 141 | /// 142 | /// Driver service name 143 | /// Driver file path 144 | /// Status 145 | NTSTATUS Utils::LoadDriver( const std::wstring& svcName, const std::wstring& path ) 146 | { 147 | HKEY key1, key2; 148 | BYTE dwType = 1; 149 | UNICODE_STRING Ustr; 150 | LSTATUS status = 0; 151 | WCHAR wszLocalPath[MAX_PATH] = { 0 }; 152 | 153 | swprintf_s( wszLocalPath, ARRAYSIZE( wszLocalPath ), L"\\??\\%s", path.c_str() ); 154 | 155 | status = RegOpenKey( HKEY_LOCAL_MACHINE, L"system\\CurrentControlSet\\Services", &key1 ); 156 | 157 | if (status) 158 | return status; 159 | 160 | status = RegCreateKeyW( key1, svcName.c_str(), &key2 ); 161 | 162 | if (status) 163 | { 164 | RegCloseKey( key1 ); 165 | return status; 166 | } 167 | 168 | status = RegSetValueEx( key2, L"ImagePath", 0, REG_SZ, reinterpret_cast(wszLocalPath), 169 | static_cast(sizeof(WCHAR)* (wcslen( wszLocalPath ) + 1)) ); 170 | 171 | if (status) 172 | { 173 | RegCloseKey( key2 ); 174 | RegCloseKey( key1 ); 175 | return status; 176 | } 177 | 178 | status = RegSetValueEx( key2, L"Type", 0, REG_DWORD, &dwType, sizeof(DWORD) ); 179 | 180 | if (status) 181 | { 182 | RegCloseKey( key2 ); 183 | RegCloseKey( key1 ); 184 | return status; 185 | } 186 | 187 | RegCloseKey( key2 ); 188 | RegCloseKey( key1 ); 189 | 190 | std::wstring regPath = L"\\registry\\machine\\SYSTEM\\CurrentControlSet\\Services\\" + svcName; 191 | GET_IMPORT( RtlInitUnicodeString )(&Ustr, regPath.c_str()); 192 | 193 | DynImport::load( "NtUnloadDriver", GetModuleHandleW( L"ntdll.dll" ) ); 194 | DynImport::load( "NtLoadDriver", GetModuleHandleW( L"ntdll.dll" ) ); 195 | 196 | // Remove previously loaded instance 197 | GET_IMPORT( NtUnloadDriver )(&Ustr); 198 | 199 | return GET_IMPORT( NtLoadDriver )(&Ustr); 200 | } 201 | 202 | } -------------------------------------------------------------------------------- /src/BlackBone/MemBlock.cpp: -------------------------------------------------------------------------------- 1 | #include "MemBlock.h" 2 | #include "ProcessMemory.h" 3 | #include "ProcessCore.h" 4 | #include "NativeSubsystem.h" 5 | 6 | namespace blackbone 7 | { 8 | 9 | MemBlock::MemBlock() 10 | : _memory( nullptr ) 11 | { 12 | } 13 | 14 | /// 15 | /// MemBlock ctor 16 | /// 17 | /// Process memory routines 18 | /// Memory address 19 | /// Block size 20 | /// Memory protection 21 | /// true if caller will be responsible for block deallocation 22 | MemBlock::MemBlock( ProcessMemory* mem, ptr_t ptr, size_t size, DWORD prot, bool own /*= true*/ ) 23 | : _ptr( ptr ) 24 | , _memory( mem ) 25 | , _size( size ) 26 | , _protection( prot ) 27 | , _own( own ) 28 | { 29 | } 30 | 31 | /// 32 | /// MemBlock ctor 33 | /// 34 | /// Process memory routines 35 | /// Memory address 36 | /// true if caller will be responsible for block deallocation 37 | MemBlock::MemBlock( ProcessMemory* mem, ptr_t ptr, bool own /*= true*/ ) 38 | : _ptr( ptr ) 39 | , _memory( mem ) 40 | , _own( own ) 41 | { 42 | MEMORY_BASIC_INFORMATION64 mbi = { 0 }; 43 | mem->Query( _ptr, &mbi ); 44 | 45 | _protection = mbi.Protect; 46 | _size = (size_t)mbi.RegionSize; 47 | } 48 | 49 | MemBlock::~MemBlock() 50 | { 51 | if (_own) 52 | Free(); 53 | } 54 | 55 | /// 56 | /// Allocate new memory block 57 | /// 58 | /// Process memory routines 59 | /// Block size 60 | /// Desired base address of new block 61 | /// Memory protection 62 | /// Memory block. If failed - returned block will be invalid 63 | MemBlock MemBlock::Allocate( ProcessMemory& process, size_t size, ptr_t desired /*= 0*/, DWORD protection /*= PAGE_EXECUTE_READWRITE */ ) 64 | { 65 | ptr_t desired64 = desired; 66 | DWORD newProt = CastProtection( protection, process.core().DEP() ); 67 | 68 | if (process.core().native()->VirualAllocExT( desired64, size, MEM_COMMIT, newProt ) != STATUS_SUCCESS) 69 | { 70 | desired64 = 0; 71 | if (process.core().native()->VirualAllocExT( desired64, size, MEM_COMMIT, newProt ) == STATUS_SUCCESS) 72 | LastNtStatus( STATUS_IMAGE_NOT_AT_BASE ); 73 | else 74 | desired64 = 0; 75 | } 76 | 77 | return MemBlock( &process, desired64, size, protection ); 78 | } 79 | 80 | /// 81 | /// Reallocate existing block for new size 82 | /// 83 | /// New block size 84 | /// Desired base address of new block 85 | /// Memory protection 86 | /// New block address 87 | ptr_t MemBlock::Realloc( size_t size, ptr_t desired /*= 0*/, DWORD protection /*= PAGE_EXECUTE_READWRITE*/ ) 88 | { 89 | ptr_t desired64 = desired; 90 | _memory->core().native()->VirualAllocExT( desired64, size, MEM_COMMIT, protection ); 91 | 92 | if (!desired64) 93 | { 94 | desired64 = 0; 95 | _memory->core( ).native( )->VirualAllocExT( desired64, size, MEM_COMMIT, protection ); 96 | 97 | if (desired64) 98 | LastNtStatus( STATUS_IMAGE_NOT_AT_BASE ); 99 | } 100 | 101 | // Replace current instance 102 | if (desired64) 103 | { 104 | Free(); 105 | 106 | _ptr = desired64; 107 | _size = size; 108 | _protection = protection; 109 | } 110 | 111 | return desired64; 112 | } 113 | 114 | /// 115 | /// Change memory protection 116 | /// 117 | /// New protection flags 118 | /// Memory offset in block 119 | /// Block size 120 | /// Old protection flags 121 | /// Status 122 | NTSTATUS MemBlock::Protect( DWORD protection, size_t offset /*= 0*/, size_t size /*= 0*/, DWORD* pOld /*= nullptr */ ) 123 | { 124 | if (size == 0) 125 | size = _size; 126 | 127 | return _memory->Protect( _ptr + offset, size, CastProtection( protection, _memory->core().DEP() ), pOld ); 128 | } 129 | 130 | /// 131 | /// Free memory 132 | /// 133 | /// Size of memory chunk to free. If 0 - whole block is freed 134 | void MemBlock::Free( size_t size /*=0 */ ) 135 | { 136 | if (_ptr != 0) 137 | { 138 | _memory->Free( _ptr, size ); 139 | 140 | if(size == 0) 141 | { 142 | _ptr = 0; 143 | _size = 0; 144 | } 145 | else 146 | { 147 | _ptr += size; 148 | _size -= size; 149 | } 150 | 151 | _protection = 0; 152 | } 153 | } 154 | 155 | /// 156 | /// Read data 157 | /// 158 | /// Data offset in block 159 | /// Size of data to read 160 | /// Output buffer 161 | /// 162 | /// If true, function will try to read all committed pages in range ignoring uncommitted. 163 | /// Otherwise function will fail if there is at least one non-committed page in region. 164 | /// 165 | /// Status 166 | NTSTATUS MemBlock::Read( size_t offset, size_t size, PVOID pResult, bool handleHoles /*= false*/ ) 167 | { 168 | return _memory->Read( _ptr + offset, size, pResult, handleHoles ); 169 | } 170 | 171 | 172 | /// 173 | /// Write data 174 | /// 175 | /// Data offset in block 176 | /// Size of data to write 177 | /// Buffer to write 178 | /// Status 179 | NTSTATUS MemBlock::Write( size_t offset, size_t size, const void* pData ) 180 | { 181 | return _memory->Write( _ptr + offset, size, pData ); 182 | } 183 | 184 | } -------------------------------------------------------------------------------- /src/BlackBone/Wow64Subsystem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NativeSubsystem.h" 4 | #include "Wow64Local.h" 5 | 6 | namespace blackbone 7 | { 8 | 9 | class NativeWow64 : public Native 10 | { 11 | public: 12 | NativeWow64( HANDLE hProcess ); 13 | ~NativeWow64(); 14 | 15 | /// 16 | /// Allocate virtual memory 17 | /// 18 | /// Allocation address 19 | /// Region size 20 | /// Allocation type 21 | /// Memory protection 22 | /// Status code 23 | virtual NTSTATUS VirualAllocExT( ptr_t& lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect ); 24 | 25 | /// 26 | /// Free virtual memory 27 | /// 28 | /// Memory address 29 | /// Region size 30 | /// Memory release type. 31 | /// Status code 32 | virtual NTSTATUS VirualFreeExT( ptr_t lpAddress, size_t dwSize, DWORD dwFreeType ); 33 | 34 | /// 35 | /// Change memory protection 36 | /// 37 | /// Memory address. 38 | /// Region size 39 | /// New protection. 40 | /// Old protection 41 | /// Status code 42 | virtual NTSTATUS VirtualProtectExT( ptr_t lpAddress, DWORD64 dwSize, DWORD flProtect, DWORD* flOld ); 43 | 44 | /// 45 | /// Read virtual memory 46 | /// 47 | /// Memory address 48 | /// Output buffer 49 | /// Number of bytes to read 50 | /// Mumber of bytes read 51 | /// Status code 52 | virtual NTSTATUS ReadProcessMemoryT( ptr_t lpBaseAddress, LPVOID lpBuffer, size_t nSize, DWORD64 *lpBytes = nullptr ); 53 | 54 | /// 55 | /// Write virtual memory 56 | /// 57 | /// Memory address 58 | /// Buffer to write 59 | /// Number of bytes to read 60 | /// Mumber of bytes read 61 | /// Status code 62 | virtual NTSTATUS WriteProcessMemoryT( ptr_t lpBaseAddress, LPCVOID lpBuffer, size_t nSize, DWORD64 *lpBytes = nullptr ); 63 | 64 | /// 65 | /// Query virtual memory 66 | /// 67 | /// Address to query 68 | /// Retrieved memory info 69 | /// Status code 70 | virtual NTSTATUS VirtualQueryExT( ptr_t lpAddress, PMEMORY_BASIC_INFORMATION64 lpBuffer ); 71 | 72 | /// 73 | /// Query virtual memory 74 | /// 75 | /// Address to query 76 | /// Retrieved memory info 77 | /// Status code 78 | virtual NTSTATUS VirtualQueryExT( ptr_t lpAddress, MEMORY_INFORMATION_CLASS infoClass, LPVOID lpBuffer, size_t bufSize ); 79 | 80 | /// 81 | /// Creates new thread in the remote process 82 | /// 83 | /// Created thread handle 84 | /// Thread entry point 85 | /// Thread argument 86 | /// Creation flags 87 | /// Status code 88 | virtual NTSTATUS CreateRemoteThreadT( HANDLE& hThread, ptr_t entry, ptr_t arg, DWORD flags ); 89 | 90 | /// 91 | /// Get native thread context 92 | /// 93 | /// Thread handle. 94 | /// Thread context 95 | /// Status code 96 | virtual NTSTATUS GetThreadContextT( HANDLE hThread, _CONTEXT64& ctx ); 97 | 98 | /// 99 | /// Get WOW64 thread context 100 | /// 101 | /// Thread handle. 102 | /// Thread context 103 | /// Status code 104 | virtual NTSTATUS GetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ); 105 | 106 | /// 107 | /// Set native thread context 108 | /// 109 | /// Thread handle. 110 | /// Thread context 111 | /// Status code 112 | virtual NTSTATUS SetThreadContextT( HANDLE hThread, _CONTEXT64& ctx ); 113 | 114 | /// 115 | /// Set WOW64 thread context 116 | /// 117 | /// Thread handle. 118 | /// Thread context 119 | /// Status code 120 | virtual NTSTATUS SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ); 121 | 122 | /// 123 | /// Get WOW64 PEB 124 | /// 125 | /// Retrieved PEB 126 | /// PEB pointer 127 | virtual ptr_t getPEB( _PEB32* ppeb ); 128 | 129 | /// 130 | /// Get native PEB 131 | /// 132 | /// Retrieved PEB 133 | /// PEB pointer 134 | virtual ptr_t getPEB( _PEB64* ppeb ); 135 | 136 | /// 137 | /// Get WOW64 TEB 138 | /// 139 | /// Retrieved TEB 140 | /// TEB pointer 141 | virtual ptr_t getTEB( HANDLE hThread, _TEB32* pteb ); 142 | 143 | /// 144 | /// Get native TEB 145 | /// 146 | /// Retrieved TEB 147 | /// TEB pointer 148 | virtual ptr_t getTEB( HANDLE hThread, _TEB64* pteb ); 149 | 150 | private: 151 | Wow64Local _local; // WOW64 helpers 152 | }; 153 | 154 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Util.cpp: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Dependencies] 8 | #include "Build.h" 9 | #include "Util_p.h" 10 | 11 | // [Api-Begin] 12 | #include "ApiBegin.h" 13 | 14 | namespace AsmJit { 15 | 16 | // ============================================================================ 17 | // [AsmJit::Util] 18 | // ============================================================================ 19 | 20 | static const char letters[] = "0123456789ABCDEF"; 21 | 22 | char* Util::mycpy(char* dst, const char* src, sysuint_t len) ASMJIT_NOTHROW 23 | { 24 | if (src == NULL) return dst; 25 | 26 | if (len == (sysuint_t)-1) 27 | { 28 | while (*src) *dst++ = *src++; 29 | } 30 | else 31 | { 32 | memcpy(dst, src, len); 33 | dst += len; 34 | } 35 | 36 | return dst; 37 | } 38 | 39 | char* Util::myfill(char* dst, const int c, sysuint_t len) ASMJIT_NOTHROW 40 | { 41 | memset(dst, c, len); 42 | return dst + len; 43 | } 44 | 45 | char* Util::myhex(char* dst, const uint8_t* src, sysuint_t len) ASMJIT_NOTHROW 46 | { 47 | for (sysuint_t i = len; i; i--, dst += 2, src += 1) 48 | { 49 | dst[0] = letters[(src[0] >> 4) & 0xF]; 50 | dst[1] = letters[(src[0] ) & 0xF]; 51 | } 52 | 53 | return dst; 54 | } 55 | 56 | // Not too efficient, but this is mainly for debugging:) 57 | char* Util::myutoa(char* dst, sysuint_t i, sysuint_t base) ASMJIT_NOTHROW 58 | { 59 | ASMJIT_ASSERT(base <= 16); 60 | 61 | char buf[128]; 62 | char* p = buf + 128; 63 | 64 | do { 65 | sysint_t b = i % base; 66 | *--p = letters[b]; 67 | i /= base; 68 | } while (i); 69 | 70 | return Util::mycpy(dst, p, (sysuint_t)(buf + 128 - p)); 71 | } 72 | 73 | char* Util::myitoa(char* dst, sysint_t i, sysuint_t base) ASMJIT_NOTHROW 74 | { 75 | if (i < 0) 76 | { 77 | *dst++ = '-'; 78 | i = -i; 79 | } 80 | 81 | return Util::myutoa(dst, (sysuint_t)i, base); 82 | } 83 | 84 | // ============================================================================ 85 | // [AsmJit::Buffer] 86 | // ============================================================================ 87 | 88 | void Buffer::emitData(const void* dataPtr, sysuint_t dataLen) ASMJIT_NOTHROW 89 | { 90 | sysint_t max = getCapacity() - getOffset(); 91 | if ((sysuint_t)max < dataLen) 92 | { 93 | if (!realloc(getOffset() + dataLen)) return; 94 | } 95 | 96 | memcpy(_cur, dataPtr, dataLen); 97 | _cur += dataLen; 98 | } 99 | 100 | bool Buffer::realloc(sysint_t to) ASMJIT_NOTHROW 101 | { 102 | if (getCapacity() < to) 103 | { 104 | sysint_t len = getOffset(); 105 | 106 | uint8_t *newdata; 107 | if (_data) 108 | newdata = (uint8_t*)ASMJIT_REALLOC(_data, to); 109 | else 110 | newdata = (uint8_t*)ASMJIT_MALLOC(to); 111 | if (!newdata) return false; 112 | 113 | _data = newdata; 114 | _cur = newdata + len; 115 | _max = newdata + to; 116 | _max -= (to >= _growThreshold) ? _growThreshold : to; 117 | 118 | _capacity = to; 119 | } 120 | 121 | return true; 122 | } 123 | 124 | bool Buffer::grow() ASMJIT_NOTHROW 125 | { 126 | sysint_t to = _capacity; 127 | 128 | if (to < 512) 129 | to = 1024; 130 | else if (to > 65536) 131 | to += 65536; 132 | else 133 | to <<= 1; 134 | 135 | return realloc(to); 136 | } 137 | 138 | void Buffer::clear() ASMJIT_NOTHROW 139 | { 140 | _cur = _data; 141 | } 142 | 143 | void Buffer::free() ASMJIT_NOTHROW 144 | { 145 | if (!_data) return; 146 | ASMJIT_FREE(_data); 147 | 148 | _data = NULL; 149 | _cur = NULL; 150 | _max = NULL; 151 | _capacity = 0; 152 | } 153 | 154 | uint8_t* Buffer::take() ASMJIT_NOTHROW 155 | { 156 | uint8_t* data = _data; 157 | 158 | _data = NULL; 159 | _cur = NULL; 160 | _max = NULL; 161 | _capacity = 0; 162 | 163 | return data; 164 | } 165 | 166 | // ============================================================================ 167 | // [AsmJit::Zone] 168 | // ============================================================================ 169 | 170 | Zone::Zone(sysuint_t chunkSize) ASMJIT_NOTHROW 171 | { 172 | _chunks = NULL; 173 | _total = 0; 174 | _chunkSize = chunkSize; 175 | } 176 | 177 | Zone::~Zone() ASMJIT_NOTHROW 178 | { 179 | freeAll(); 180 | } 181 | 182 | void* Zone::zalloc(sysuint_t size) ASMJIT_NOTHROW 183 | { 184 | // Align to 4 or 8 bytes. 185 | size = (size + sizeof(sysint_t)-1) & ~(sizeof(sysint_t)-1); 186 | 187 | Chunk* cur = _chunks; 188 | 189 | if (!cur || cur->getRemainingBytes() < size) 190 | { 191 | sysuint_t chSize = _chunkSize; 192 | if (chSize < size) chSize = size; 193 | 194 | cur = (Chunk*)ASMJIT_MALLOC(sizeof(Chunk) - sizeof(void*) + chSize); 195 | if (!cur) return NULL; 196 | 197 | cur->prev = _chunks; 198 | cur->pos = 0; 199 | cur->size = _chunkSize; 200 | _chunks = cur; 201 | } 202 | 203 | uint8_t* p = cur->data + cur->pos; 204 | cur->pos += size; 205 | _total += size; 206 | return (void*)p; 207 | } 208 | 209 | char* Zone::zstrdup(const char* str) ASMJIT_NOTHROW 210 | { 211 | if (str == NULL) return NULL; 212 | 213 | sysuint_t len = strlen(str); 214 | if (len == 0) return NULL; 215 | 216 | // Include NULL terminator. 217 | len++; 218 | 219 | // Limit string length. 220 | if (len > 256) len = 256; 221 | 222 | char* m = reinterpret_cast(zalloc((len + 15) & ~15)); 223 | if (!m) return NULL; 224 | 225 | memcpy(m, str, len); 226 | m[len-1] = '\0'; 227 | return m; 228 | } 229 | 230 | void Zone::clear() ASMJIT_NOTHROW 231 | { 232 | Chunk* cur = _chunks; 233 | if (!cur) return; 234 | 235 | _chunks->pos = 0; 236 | _chunks->prev = NULL; 237 | _total = 0; 238 | 239 | cur = cur->prev; 240 | while (cur) 241 | { 242 | Chunk* prev = cur->prev; 243 | ASMJIT_FREE(cur); 244 | cur = prev; 245 | } 246 | } 247 | 248 | void Zone::freeAll() ASMJIT_NOTHROW 249 | { 250 | Chunk* cur = _chunks; 251 | 252 | _chunks = NULL; 253 | _total = 0; 254 | 255 | while (cur) 256 | { 257 | Chunk* prev = cur->prev; 258 | ASMJIT_FREE(cur); 259 | cur = prev; 260 | } 261 | } 262 | 263 | } // AsmJit namespace 264 | 265 | // [Api-End] 266 | #include "ApiEnd.h" 267 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Platform.cpp: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Dependencies] 8 | #include 9 | 10 | #include "Platform.h" 11 | 12 | // [Api-Begin] 13 | #include "ApiBegin.h" 14 | 15 | // helpers 16 | namespace AsmJit { 17 | 18 | // ============================================================================ 19 | // [AsmJit::Assert] 20 | // ============================================================================ 21 | 22 | void assertionFailure(const char* file, int line, const char* exp) 23 | { 24 | fprintf(stderr, 25 | "*** ASSERTION FAILURE at %s (line %d)\n" 26 | "*** %s\n", file, line, exp); 27 | 28 | exit(1); 29 | } 30 | 31 | // ============================================================================ 32 | // [AsmJit::Helpers] 33 | // ============================================================================ 34 | 35 | static bool isAligned(sysuint_t base, sysuint_t alignment) 36 | { 37 | return base % alignment == 0; 38 | } 39 | 40 | static sysuint_t roundUp(sysuint_t base, sysuint_t pageSize) 41 | { 42 | sysuint_t over = base % pageSize; 43 | return base + (over > 0 ? pageSize - over : 0); 44 | } 45 | 46 | // Implementation is from "Hacker's Delight" by Henry S. Warren, Jr., 47 | // figure 3-3, page 48, where the function is called clp2. 48 | static sysuint_t roundUpToPowerOf2(sysuint_t base) 49 | { 50 | base -= 1; 51 | 52 | base = base | (base >> 1); 53 | base = base | (base >> 2); 54 | base = base | (base >> 4); 55 | base = base | (base >> 8); 56 | base = base | (base >> 16); 57 | 58 | // I'm trying to make this portable and MSVC strikes me the warning C4293: 59 | // "Shift count negative or too big, undefined behavior" 60 | // Fixing... 61 | #if _MSC_VER 62 | # pragma warning(disable: 4293) 63 | #endif // _MSC_VER 64 | 65 | if (sizeof(sysuint_t) >= 8) 66 | base = base | (base >> 32); 67 | 68 | return base + 1; 69 | } 70 | 71 | } // AsmJit namespace 72 | 73 | // ============================================================================ 74 | // [AsmJit::VirtualMemory::Windows] 75 | // ============================================================================ 76 | 77 | #if defined(ASMJIT_WINDOWS) 78 | 79 | #include 80 | 81 | namespace AsmJit { 82 | 83 | struct ASMJIT_HIDDEN VirtualMemoryLocal 84 | { 85 | VirtualMemoryLocal() ASMJIT_NOTHROW 86 | { 87 | SYSTEM_INFO info; 88 | GetSystemInfo(&info); 89 | 90 | alignment = info.dwAllocationGranularity; 91 | pageSize = roundUpToPowerOf2(info.dwPageSize); 92 | } 93 | 94 | sysuint_t alignment; 95 | sysuint_t pageSize; 96 | }; 97 | 98 | static VirtualMemoryLocal& vm() ASMJIT_NOTHROW 99 | { 100 | static VirtualMemoryLocal vm; 101 | return vm; 102 | }; 103 | 104 | void* VirtualMemory::alloc(sysuint_t length, sysuint_t* allocated, bool canExecute) 105 | ASMJIT_NOTHROW 106 | { 107 | return allocProcessMemory(GetCurrentProcess(), length, allocated, canExecute); 108 | } 109 | 110 | void VirtualMemory::free(void* addr, sysuint_t length) 111 | ASMJIT_NOTHROW 112 | { 113 | return freeProcessMemory(GetCurrentProcess(), addr, length); 114 | } 115 | 116 | void* VirtualMemory::allocProcessMemory(HANDLE hProcess, sysuint_t length, sysuint_t* allocated, bool canExecute) ASMJIT_NOTHROW 117 | { 118 | // VirtualAlloc rounds allocated size to page size automatically. 119 | sysuint_t msize = roundUp(length, vm().pageSize); 120 | 121 | // Windows XP SP2 / Vista allow Data Excution Prevention (DEP). 122 | WORD protect = canExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; 123 | LPVOID mbase = VirtualAllocEx(hProcess, NULL, msize, MEM_COMMIT | MEM_RESERVE, protect); 124 | if (mbase == NULL) return NULL; 125 | 126 | ASMJIT_ASSERT(isAligned(reinterpret_cast(mbase), vm().alignment)); 127 | 128 | if (allocated) *allocated = msize; 129 | return mbase; 130 | } 131 | 132 | void VirtualMemory::freeProcessMemory(HANDLE hProcess, void* addr, sysuint_t /* length */) ASMJIT_NOTHROW 133 | { 134 | VirtualFreeEx(hProcess, addr, 0, MEM_RELEASE); 135 | } 136 | 137 | sysuint_t VirtualMemory::getAlignment() 138 | ASMJIT_NOTHROW 139 | { 140 | return vm().alignment; 141 | } 142 | 143 | sysuint_t VirtualMemory::getPageSize() 144 | ASMJIT_NOTHROW 145 | { 146 | return vm().pageSize; 147 | } 148 | 149 | } // AsmJit 150 | 151 | #endif // ASMJIT_WINDOWS 152 | 153 | // ============================================================================ 154 | // [AsmJit::VirtualMemory::Posix] 155 | // ============================================================================ 156 | 157 | #if defined(ASMJIT_POSIX) 158 | 159 | #include 160 | #include 161 | #include 162 | 163 | // MacOS uses MAP_ANON instead of MAP_ANONYMOUS 164 | #ifndef MAP_ANONYMOUS 165 | # define MAP_ANONYMOUS MAP_ANON 166 | #endif 167 | 168 | namespace AsmJit { 169 | 170 | struct ASMJIT_HIDDEN VirtualMemoryLocal 171 | { 172 | VirtualMemoryLocal() ASMJIT_NOTHROW 173 | { 174 | alignment = pageSize = getpagesize(); 175 | } 176 | 177 | sysuint_t alignment; 178 | sysuint_t pageSize; 179 | }; 180 | 181 | static VirtualMemoryLocal& vm() 182 | ASMJIT_NOTHROW 183 | { 184 | static VirtualMemoryLocal vm; 185 | return vm; 186 | } 187 | 188 | void* VirtualMemory::alloc(sysuint_t length, sysuint_t* allocated, bool canExecute) 189 | ASMJIT_NOTHROW 190 | { 191 | sysuint_t msize = roundUp(length, vm().pageSize); 192 | int protection = PROT_READ | PROT_WRITE | (canExecute ? PROT_EXEC : 0); 193 | void* mbase = mmap(NULL, msize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 194 | if (mbase == MAP_FAILED) return NULL; 195 | if (allocated) *allocated = msize; 196 | return mbase; 197 | } 198 | 199 | void VirtualMemory::free(void* addr, sysuint_t length) 200 | ASMJIT_NOTHROW 201 | { 202 | munmap(addr, length); 203 | } 204 | 205 | sysuint_t VirtualMemory::getAlignment() 206 | ASMJIT_NOTHROW 207 | { 208 | return vm().alignment; 209 | } 210 | 211 | sysuint_t VirtualMemory::getPageSize() 212 | ASMJIT_NOTHROW 213 | { 214 | return vm().pageSize; 215 | } 216 | 217 | } // AsmJit 218 | 219 | #endif // ASMJIT_POSIX 220 | 221 | // [Api-End] 222 | #include "ApiEnd.h" 223 | -------------------------------------------------------------------------------- /src/BlackBone/FunctionTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NativeStructures.h" 4 | 5 | namespace blackbone 6 | { 7 | 8 | // NtCreateEvent 9 | typedef NTSTATUS( NTAPI* fnNtCreateEvent ) 10 | ( 11 | OUT PHANDLE EventHandle, 12 | IN ACCESS_MASK DesiredAccess, 13 | IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 14 | IN ULONG EventType, 15 | IN BOOLEAN InitialState 16 | ); 17 | 18 | // NtOpenEvent 19 | typedef NTSTATUS( NTAPI* fnNtOpenEvent ) 20 | ( 21 | OUT PHANDLE EventHandle, 22 | IN ACCESS_MASK DesiredAccess, 23 | IN POBJECT_ATTRIBUTES ObjectAttributes 24 | ); 25 | 26 | // NtQueryVirtualMemory 27 | typedef NTSTATUS( NTAPI* fnNtQueryVirtualMemory ) 28 | ( 29 | IN HANDLE ProcessHandle, 30 | IN PVOID BaseAddress, 31 | IN MEMORY_INFORMATION_CLASS MemoryInformationClass, 32 | OUT PVOID MemoryInformation, 33 | IN SIZE_T MemoryInformationLength, 34 | OUT PSIZE_T ReturnLength 35 | ); 36 | 37 | // NtWow64QueryInformationProcess64 38 | typedef NTSTATUS( NTAPI *fnNtWow64QueryInformationProcess64 ) 39 | ( 40 | IN HANDLE ProcessHandle, 41 | IN ULONG ProcessInformationClass, 42 | OUT PVOID ProcessInformation64, 43 | IN ULONG Length, 44 | OUT PULONG ReturnLength OPTIONAL 45 | ); 46 | 47 | // NtWow64ReadVirtualMemory64 48 | typedef NTSTATUS( NTAPI *fnNtWow64ReadVirtualMemory64 ) 49 | ( 50 | IN HANDLE ProcessHandle, 51 | IN ULONG64 BaseAddress, 52 | OUT PVOID Buffer, 53 | IN ULONG64 BufferLength, 54 | OUT PULONG64 ReturnLength OPTIONAL 55 | ); 56 | 57 | // NtWow64WriteVirtualMemory64 58 | typedef fnNtWow64ReadVirtualMemory64 fnNtWow64WriteVirtualMemory64; 59 | 60 | // NtWow64AllocateVirtualMemory64 61 | typedef NTSTATUS( NTAPI *fnNtWow64AllocateVirtualMemory64 ) 62 | ( 63 | IN HANDLE ProcessHandle, 64 | IN PULONG64 BaseAddress, 65 | IN ULONG64 ZeroBits, 66 | IN PULONG64 Size, 67 | IN ULONG AllocationType, 68 | IN ULONG Protection 69 | ); 70 | 71 | // NtWow64QueryVirtualMemory64 72 | typedef NTSTATUS( NTAPI *fnNtWow64QueryVirtualMemory64 ) 73 | ( 74 | IN HANDLE ProcessHandle, 75 | IN ULONG64 BaseAddress, 76 | IN DWORD MemoryInformationClass, 77 | OUT PVOID Buffer, 78 | IN ULONG64 Length, 79 | OUT PULONG ResultLength OPTIONAL 80 | ); 81 | 82 | // RtlDosApplyFileIsolationRedirection_Ustr 83 | typedef NTSTATUS( NTAPI *fnRtlDosApplyFileIsolationRedirection_Ustr ) 84 | ( 85 | IN ULONG Flags, 86 | IN PUNICODE_STRING OriginalName, 87 | IN PUNICODE_STRING Extension, 88 | IN OUT PUNICODE_STRING StaticString, 89 | IN OUT PUNICODE_STRING DynamicString, 90 | IN OUT PUNICODE_STRING *NewName, 91 | IN PULONG NewFlags, 92 | IN PSIZE_T FileNameSize, 93 | IN PSIZE_T RequiredLength 94 | ); 95 | 96 | // RtlHashUnicodeString 97 | typedef NTSTATUS( NTAPI *fnRtlHashUnicodeString ) 98 | ( 99 | IN PCUNICODE_STRING String, 100 | IN BOOLEAN CaseInSensitive, 101 | IN ULONG HashAlgorithm, 102 | OUT PULONG HashValue 103 | ); 104 | 105 | // RtlRemoteCall 106 | typedef NTSTATUS( NTAPI *fnRtlRemoteCall ) 107 | ( 108 | IN HANDLE Process, 109 | IN HANDLE Thread, 110 | IN PVOID CallSite, 111 | IN ULONG ArgumentCount, 112 | IN PULONG Arguments, 113 | IN BOOLEAN PassContext, 114 | IN BOOLEAN AlreadySuspended 115 | ); 116 | 117 | // NtCreateThreadEx 118 | typedef NTSTATUS( NTAPI* fnNtCreateThreadEx ) 119 | ( 120 | OUT PHANDLE hThread, 121 | IN ACCESS_MASK DesiredAccess, 122 | IN LPVOID ObjectAttributes, 123 | IN HANDLE ProcessHandle, 124 | IN LPTHREAD_START_ROUTINE lpStartAddress, 125 | IN LPVOID lpParameter, 126 | IN BOOL CreateSuspended, 127 | IN SIZE_T StackZeroBits, 128 | IN SIZE_T SizeOfStackCommit, 129 | IN SIZE_T SizeOfStackReserve, 130 | OUT LPVOID lpBytesBuffer 131 | ); 132 | 133 | // NtLockVirtualMemory 134 | typedef NTSTATUS( NTAPI* fnNtLockVirtualMemory ) 135 | ( 136 | IN HANDLE process, 137 | IN OUT PVOID* baseAddress, 138 | IN OUT ULONG* size, 139 | IN ULONG flags 140 | ); 141 | 142 | // RtlRbInsertNodeEx 143 | typedef int ( NTAPI* fnRtlRbInsertNodeEx ) 144 | ( 145 | PRTL_RB_TREE Tree, 146 | PRTL_BALANCED_NODE Parent, 147 | BOOLEAN Right, 148 | PRTL_BALANCED_NODE Node 149 | ); 150 | 151 | // NtSetInformationProcess 152 | typedef NTSTATUS ( NTAPI* fnNtSetInformationProcess) 153 | ( 154 | IN HANDLE ProcessHandle, 155 | IN PROCESS_INFORMATION_CLASS ProcessInformationClass, 156 | IN PVOID ProcessInformation, 157 | IN ULONG ProcessInformationLength 158 | ); 159 | 160 | // RtlRbRemoveNode 161 | typedef int (NTAPI* fnRtlRbRemoveNode) 162 | ( 163 | PRTL_RB_TREE Tree, 164 | PRTL_BALANCED_NODE Node 165 | ); 166 | 167 | // RtlUpcaseUnicodeChar 168 | typedef WCHAR( NTAPI *fnRtlUpcaseUnicodeChar ) 169 | ( 170 | WCHAR chr 171 | ); 172 | 173 | // RtlEncodeSystemPointer 174 | typedef PVOID( NTAPI *fnRtlEncodeSystemPointer ) 175 | ( 176 | IN PVOID Pointer 177 | ); 178 | 179 | // NtLoadDriver 180 | typedef NTSTATUS( NTAPI* fnNtLoadDriver ) 181 | ( 182 | IN PUNICODE_STRING path 183 | ); 184 | 185 | // NtUnloadDriver 186 | typedef NTSTATUS( NTAPI* fnNtUnloadDriver ) 187 | ( 188 | IN PUNICODE_STRING path 189 | ); 190 | 191 | 192 | // RtlInitUnicodeString 193 | typedef decltype(&RtlInitUnicodeString) fnRtlInitUnicodeString; 194 | 195 | // RtlFreeUnicodeString 196 | typedef decltype(&RtlFreeUnicodeString) fnRtlFreeUnicodeString; 197 | 198 | // NtQueryInformationProcess 199 | typedef decltype(&NtQueryInformationProcess) fnNtQueryInformationProcess; 200 | 201 | // NtQueryInformationThread 202 | typedef decltype(&NtQueryInformationThread) fnNtQueryInformationThread; 203 | 204 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Logger.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Guard] 8 | #ifndef _ASMJIT_LOGGER_H 9 | #define _ASMJIT_LOGGER_H 10 | 11 | // [Dependencies] 12 | #include "Defs.h" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | // [Api-Begin] 19 | #include "ApiBegin.h" 20 | 21 | namespace AsmJit { 22 | 23 | //! @addtogroup AsmJit_Logging 24 | //! @{ 25 | 26 | //! @brief Abstract logging class. 27 | //! 28 | //! This class can be inherited and reimplemented to fit into your logging 29 | //! subsystem. When reimplementing use @c AsmJit::Logger::log() method to 30 | //! log into your stream. 31 | //! 32 | //! This class also contain @c _enabled member that can be used to enable 33 | //! or disable logging. 34 | struct ASMJIT_API Logger 35 | { 36 | // -------------------------------------------------------------------------- 37 | // [Construction / Destruction] 38 | // -------------------------------------------------------------------------- 39 | 40 | //! @brief Create logger. 41 | Logger() ASMJIT_NOTHROW; 42 | //! @brief Destroy logger. 43 | virtual ~Logger() ASMJIT_NOTHROW; 44 | 45 | // -------------------------------------------------------------------------- 46 | // [Logging] 47 | // -------------------------------------------------------------------------- 48 | 49 | //! @brief Abstract method to log output. 50 | //! 51 | //! Default implementation that is in @c AsmJit::Logger is to do nothing. 52 | //! It's virtual to fit to your logging system. 53 | virtual void logString(const char* buf, sysuint_t len = (sysuint_t)-1) ASMJIT_NOTHROW = 0; 54 | 55 | //! @brief Log formatter message (like sprintf) sending output to @c logString() method. 56 | virtual void logFormat(const char* fmt, ...) ASMJIT_NOTHROW; 57 | 58 | // -------------------------------------------------------------------------- 59 | // [Enabled] 60 | // -------------------------------------------------------------------------- 61 | 62 | //! @brief Return @c true if logging is enabled. 63 | inline bool isEnabled() const ASMJIT_NOTHROW { return _enabled; } 64 | 65 | //! @brief Set logging to enabled or disabled. 66 | virtual void setEnabled(bool enabled) ASMJIT_NOTHROW; 67 | 68 | // -------------------------------------------------------------------------- 69 | // [Used] 70 | // -------------------------------------------------------------------------- 71 | 72 | //! @brief Get whether the logger should be used. 73 | inline bool isUsed() const ASMJIT_NOTHROW { return _used; } 74 | 75 | // -------------------------------------------------------------------------- 76 | // [LogBinary] 77 | // -------------------------------------------------------------------------- 78 | 79 | //! @brief Get whether logging binary output. 80 | inline bool getLogBinary() const { return _logBinary; } 81 | //! @brief Get whether to log binary output. 82 | inline void setLogBinary(bool val) { _logBinary = val; } 83 | 84 | // -------------------------------------------------------------------------- 85 | // [Members] 86 | // -------------------------------------------------------------------------- 87 | 88 | protected: 89 | 90 | //! @brief Whether logger is enabled or disabled. 91 | //! 92 | //! Default @c true. 93 | bool _enabled; 94 | 95 | //! @brief Whether logger is enabled and can be used. 96 | //! 97 | //! This value can be set by inherited classes to inform @c Logger that 98 | //! assigned stream (or something that can log output) is invalid. If 99 | //! @c _used is false it means that there is no logging output and AsmJit 100 | //! shouldn't use this logger (because all messages will be lost). 101 | //! 102 | //! This is designed only to optimize cases that logger exists, but its 103 | //! configured not to output messages. The API inside Logging and AsmJit 104 | //! should only check this value when needed. The API outside AsmJit should 105 | //! check only whether logging is @c _enabled. 106 | //! 107 | //! Default @c true. 108 | bool _used; 109 | 110 | //! @brief Whether to log instruction in binary form. 111 | bool _logBinary; 112 | 113 | private: 114 | ASMJIT_DISABLE_COPY(Logger) 115 | }; 116 | 117 | //! @brief Logger that can log to standard C @c FILE* stream. 118 | struct ASMJIT_API FileLogger : public Logger 119 | { 120 | // -------------------------------------------------------------------------- 121 | // [Construction / Destruction] 122 | // -------------------------------------------------------------------------- 123 | 124 | //! @brief Create new @c FileLogger. 125 | //! @param stream FILE stream where logging will be sent (can be @c NULL 126 | //! to disable logging). 127 | FileLogger(FILE* stream = NULL) ASMJIT_NOTHROW; 128 | 129 | // -------------------------------------------------------------------------- 130 | // [Logging] 131 | // -------------------------------------------------------------------------- 132 | 133 | virtual void logString(const char* buf, sysuint_t len = (sysuint_t)-1) ASMJIT_NOTHROW; 134 | 135 | // -------------------------------------------------------------------------- 136 | // [Enabled] 137 | // -------------------------------------------------------------------------- 138 | 139 | virtual void setEnabled(bool enabled) ASMJIT_NOTHROW; 140 | 141 | // -------------------------------------------------------------------------- 142 | // [Stream] 143 | // -------------------------------------------------------------------------- 144 | 145 | //! @brief Get @c FILE* stream. 146 | //! 147 | //! @note Return value can be @c NULL. 148 | inline FILE* getStream() const ASMJIT_NOTHROW { return _stream; } 149 | 150 | //! @brief Set @c FILE* stream. 151 | //! 152 | //! @param stream @c FILE stream where to log output (can be @c NULL to 153 | //! disable logging). 154 | void setStream(FILE* stream) ASMJIT_NOTHROW; 155 | 156 | // -------------------------------------------------------------------------- 157 | // [Members] 158 | // -------------------------------------------------------------------------- 159 | 160 | protected: 161 | //! @brief C file stream. 162 | FILE* _stream; 163 | 164 | ASMJIT_DISABLE_COPY(FileLogger) 165 | }; 166 | 167 | //! @} 168 | 169 | } // AsmJit namespace 170 | 171 | // [Api-End] 172 | #include "ApiEnd.h" 173 | 174 | // [Guard] 175 | #endif // _ASMJIT_LOGGER_H 176 | -------------------------------------------------------------------------------- /src/BlackBone/PEParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "Types.h" 5 | #include "ImageNET.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace blackbone 15 | { 16 | 17 | namespace pe 18 | { 19 | 20 | // Relocation block information 21 | struct RelocData 22 | { 23 | ULONG PageRVA; 24 | ULONG BlockSize; 25 | 26 | struct 27 | { 28 | WORD Offset : 12; 29 | WORD Type : 4; 30 | }Item[1]; 31 | }; 32 | 33 | // Import information 34 | struct ImportData 35 | { 36 | std::string importName; // Function name 37 | size_t ptrRVA; // Function pointer RVA in 38 | WORD importOrdinal; // Function ordinal 39 | bool importByOrd; // Function is imported by ordinal 40 | }; 41 | 42 | // Imports and sections related 43 | typedef std::unordered_map> mapImports; 44 | typedef std::vector vecSections; 45 | 46 | /// 47 | /// Primitive PE parsing class 48 | /// 49 | class PEParser 50 | { 51 | typedef const IMAGE_NT_HEADERS32* PCHDR32; 52 | typedef const IMAGE_NT_HEADERS64* PCHDR64; 53 | 54 | public: 55 | PEParser( void ); 56 | ~PEParser( void ); 57 | 58 | /// 59 | /// Parses PE image 60 | /// 61 | /// File memory location 62 | /// Treat file as plain datafile 63 | /// true on success 64 | bool Parse( const void* pFileBase, bool isPlainData = false ); 65 | 66 | /// 67 | /// Processes image imports 68 | /// 69 | /// Process delayed import instead 70 | /// Import data 71 | mapImports& ProcessImports( bool useDelayed = false ); 72 | 73 | /// 74 | /// Retrieve all exported functions with names 75 | /// 76 | /// Found exports 77 | void GetExportNames( std::list& names ); 78 | 79 | /// 80 | /// Retrieve image TLS callbacks 81 | /// Callbacks are rebased for target image 82 | /// 83 | /// Target image base 84 | /// Found callbacks 85 | /// Number of TLS callbacks in image 86 | int GetTLSCallbacks( module_t targetBase, std::vector& result ) const; 87 | 88 | /// 89 | /// Retrieve data directory address 90 | /// 91 | /// Directory index 92 | /// Keep address relative to image base 93 | /// Directory address 94 | size_t DirectoryAddress( int index, bool keepRelative = false ) const; 95 | 96 | /// 97 | /// Get data directory size 98 | /// 99 | /// Data directory index 100 | /// Data directory size 101 | size_t DirectorySize( int index ) const; 102 | 103 | /// 104 | /// Resolve virtual memory address to physical file offset 105 | /// 106 | /// Memory address 107 | /// Keep address relative to file start 108 | /// Resolved address 109 | size_t ResolveRVAToVA( size_t Rva, bool keepRelative = false ) const; 110 | 111 | /// 112 | /// Get image base address 113 | /// 114 | /// Image base 115 | inline module_t imageBase() const { return _imgBase; } 116 | 117 | /// 118 | /// Get image size in bytes 119 | /// 120 | /// Image size 121 | inline size_t imageSize() const { return _imgSize; } 122 | 123 | /// 124 | /// Get size of image headers 125 | /// 126 | /// Size of image headers 127 | inline size_t headersSize() const { return _hdrSize; } 128 | 129 | /// 130 | /// Get image entry point rebased to another image base 131 | /// 132 | /// New image base 133 | /// New entry point address 134 | inline ptr_t entryPoint( module_t base ) const { return _epRVA + base; }; 135 | 136 | /// 137 | /// Get image sections 138 | /// 139 | /// Image sections 140 | inline const vecSections& sections() const { return _sections; } 141 | 142 | /// 143 | /// Check if image is an executable file and not a dll 144 | /// 145 | /// true if image is an *.exe 146 | inline bool IsExe() const { return _isExe; } 147 | 148 | 149 | /// 150 | /// Check if image is pure IL image 151 | /// 152 | /// true on success 153 | inline bool IsPureManaged() const { return _isPureIL; } 154 | 155 | /// 156 | /// Get image type. 32/64 bit 157 | /// 158 | /// Image type 159 | inline eModType mType() const { return _is64 ? mt_mod64 : mt_mod32; } 160 | 161 | /// 162 | /// .NET image parser 163 | /// 164 | /// .NET image parser 165 | ImageNET& net() { return _netImage; } 166 | 167 | private: 168 | bool _isPlainData = false; // File mapped as plain data file 169 | bool _is64 = false; // Image is 64 bit 170 | bool _isExe = false; // Image is an .exe file 171 | bool _isPureIL = false; // Pure IL image 172 | const void *_pFileBase = nullptr; // File mapping base address 173 | PCHDR32 _pImageHdr32 = nullptr; // PE header info 174 | PCHDR64 _pImageHdr64 = nullptr; // PE header info 175 | ptr_t _imgBase = 0; // Image base 176 | size_t _imgSize = 0; // Image size 177 | size_t _epRVA = 0; // Entry point RVA 178 | size_t _hdrSize = 0; // Size of headers 179 | 180 | vecSections _sections; // Section info 181 | mapImports _imports; // Import functions 182 | mapImports _delayImports; // Import functions 183 | ImageNET _netImage; // .net image info 184 | }; 185 | 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Platform.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Guard] 8 | #ifndef _ASMJIT_PLATFORM_H 9 | #define _ASMJIT_PLATFORM_H 10 | 11 | // [Dependencies] 12 | #include "Build.h" 13 | 14 | #if defined(ASMJIT_WINDOWS) 15 | #include 16 | #endif // ASMJIT_WINDOWS 17 | 18 | #if defined(ASMJIT_POSIX) 19 | #include 20 | #endif // ASMJIT_POSIX 21 | 22 | // [Api-Begin] 23 | #include "ApiBegin.h" 24 | 25 | namespace AsmJit { 26 | 27 | //! @addtogroup AsmJit_Util 28 | //! @{ 29 | 30 | // ============================================================================ 31 | // [AsmJit::Assert] 32 | // ============================================================================ 33 | 34 | //! @brief Called in debug build on assertion failure. 35 | //! @param file Source file name where it happened. 36 | //! @param line Line in the source file. 37 | //! @param exp Expression what failed. 38 | //! 39 | //! If you have problems with assertions simply put a breakpoint into 40 | //! AsmJit::assertionFailure() method (see AsmJit/Platform.cpp file) and see 41 | //! call stack. 42 | ASMJIT_API void assertionFailure(const char* file, int line, const char* exp); 43 | 44 | // ============================================================================ 45 | // [AsmJit::Lock] 46 | // ============================================================================ 47 | 48 | //! @brief Lock - used in thread-safe code for locking. 49 | struct ASMJIT_HIDDEN Lock 50 | { 51 | #if defined(ASMJIT_WINDOWS) 52 | typedef CRITICAL_SECTION Handle; 53 | #endif // ASMJIT_WINDOWS 54 | #if defined(ASMJIT_POSIX) 55 | typedef pthread_mutex_t Handle; 56 | #endif // ASMJIT_POSIX 57 | 58 | //! @brief Create a new @ref Lock instance. 59 | inline Lock() ASMJIT_NOTHROW 60 | { 61 | #if defined(ASMJIT_WINDOWS) 62 | InitializeCriticalSection(&_handle); 63 | // InitializeLockAndSpinCount(&_handle, 2000); 64 | #endif // ASMJIT_WINDOWS 65 | #if defined(ASMJIT_POSIX) 66 | pthread_mutex_init(&_handle, NULL); 67 | #endif // ASMJIT_POSIX 68 | } 69 | 70 | //! @brief Destroy the @ref Lock instance. 71 | inline ~Lock() ASMJIT_NOTHROW 72 | { 73 | #if defined(ASMJIT_WINDOWS) 74 | DeleteCriticalSection(&_handle); 75 | #endif // ASMJIT_WINDOWS 76 | #if defined(ASMJIT_POSIX) 77 | pthread_mutex_destroy(&_handle); 78 | #endif // ASMJIT_POSIX 79 | } 80 | 81 | //! @brief Get handle. 82 | inline Handle& getHandle() ASMJIT_NOTHROW 83 | { 84 | return _handle; 85 | } 86 | 87 | //! @overload 88 | inline const Handle& getHandle() const ASMJIT_NOTHROW 89 | { 90 | return _handle; 91 | } 92 | 93 | //! @brief Lock. 94 | inline void lock() ASMJIT_NOTHROW 95 | { 96 | #if defined(ASMJIT_WINDOWS) 97 | EnterCriticalSection(&_handle); 98 | #endif // ASMJIT_WINDOWS 99 | #if defined(ASMJIT_POSIX) 100 | pthread_mutex_lock(&_handle); 101 | #endif // ASMJIT_POSIX 102 | } 103 | 104 | //! @brief Unlock. 105 | inline void unlock() ASMJIT_NOTHROW 106 | { 107 | #if defined(ASMJIT_WINDOWS) 108 | LeaveCriticalSection(&_handle); 109 | #endif // ASMJIT_WINDOWS 110 | #if defined(ASMJIT_POSIX) 111 | pthread_mutex_unlock(&_handle); 112 | #endif // ASMJIT_POSIX 113 | } 114 | 115 | private: 116 | //! @brief Handle. 117 | Handle _handle; 118 | 119 | // Disable copy. 120 | ASMJIT_DISABLE_COPY(Lock) 121 | }; 122 | 123 | // ============================================================================ 124 | // [AsmJit::AutoLock] 125 | // ============================================================================ 126 | 127 | //! @brief Scope auto locker. 128 | struct ASMJIT_HIDDEN AutoLock 129 | { 130 | //! @brief Locks @a target. 131 | inline AutoLock(Lock& target) ASMJIT_NOTHROW : _target(target) 132 | { 133 | _target.lock(); 134 | } 135 | 136 | //! @brief Unlocks target. 137 | inline ~AutoLock() ASMJIT_NOTHROW 138 | { 139 | _target.unlock(); 140 | } 141 | 142 | private: 143 | //! @brief Pointer to target (lock). 144 | Lock& _target; 145 | 146 | // Disable copy. 147 | ASMJIT_DISABLE_COPY(AutoLock) 148 | }; 149 | 150 | // ============================================================================ 151 | // [AsmJit::VirtualMemory] 152 | // ============================================================================ 153 | 154 | //! @brief Class that helps with allocating memory for executing code 155 | //! generated by JIT compiler. 156 | //! 157 | //! There are defined functions that provides facility to allocate and free 158 | //! memory where can be executed code. If processor and operating system 159 | //! supports execution protection then you can't run code from normally 160 | //! malloc()'ed memory. 161 | //! 162 | //! Functions are internally implemented by operating system dependent way. 163 | //! VirtualAlloc() function is used for Windows operating system and mmap() 164 | //! for posix ones. If you want to study or create your own functions, look 165 | //! at VirtualAlloc() or mmap() documentation (depends on you target OS). 166 | //! 167 | //! Under posix operating systems is also useable mprotect() function, that 168 | //! can enable execution protection to malloc()'ed memory block. 169 | struct ASMJIT_API VirtualMemory 170 | { 171 | //! @brief Allocate virtual memory. 172 | //! 173 | //! Pages are readable/writeable, but they are not guaranteed to be 174 | //! executable unless 'canExecute' is true. Returns the address of 175 | //! allocated memory, or NULL if failed. 176 | static void* alloc(sysuint_t length, sysuint_t* allocated, bool canExecute) ASMJIT_NOTHROW; 177 | 178 | //! @brief Free memory allocated by @c alloc() 179 | static void free(void* addr, sysuint_t length) ASMJIT_NOTHROW; 180 | 181 | #if defined(ASMJIT_WINDOWS) 182 | //! @brief Allocate virtual memory of @a hProcess. 183 | //! 184 | //! @note This function is windows specific and unportable. 185 | static void* allocProcessMemory(HANDLE hProcess, sysuint_t length, sysuint_t* allocated, bool canExecute) ASMJIT_NOTHROW; 186 | 187 | //! @brief Free virtual memory of @a hProcess. 188 | //! 189 | //! @note This function is windows specific and unportable. 190 | static void freeProcessMemory(HANDLE hProcess, void* addr, sysuint_t length) ASMJIT_NOTHROW; 191 | #endif // ASMJIT_WINDOWS 192 | 193 | //! @brief Get the alignment guaranteed by alloc(). 194 | static sysuint_t getAlignment() ASMJIT_NOTHROW; 195 | 196 | //! @brief Get size of single page. 197 | static sysuint_t getPageSize() ASMJIT_NOTHROW; 198 | }; 199 | 200 | //! @} 201 | 202 | } // AsmJit namespace 203 | 204 | // [Api-End] 205 | #include "ApiEnd.h" 206 | 207 | // [Guard] 208 | #endif // _ASMJIT_PLATFORM_H 209 | -------------------------------------------------------------------------------- /src/BlackBone/ProcessModules.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "PEParser.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | template <> 13 | struct std::hash< std::pair > 14 | { 15 | private: 16 | 17 | public: 18 | size_t operator()( const std::pair& value ) const 19 | { 20 | const hash ah; 21 | return ah( value.first ) ^ value.second; 22 | } 23 | }; 24 | 25 | 26 | namespace blackbone 27 | { 28 | 29 | 30 | struct exportData 31 | { 32 | ptr_t procAddress = 0; // Function address 33 | 34 | std::wstring forwardModule; // Name of forward module 35 | std::string forwardName; // Forwarded function name 36 | WORD forwardOrdinal = 0; // Forwarded function ordinal 37 | 38 | bool isForwarded = false; // Function is forwarded to another module 39 | bool forwardByOrd = false; // Forward is done by ordinal 40 | }; 41 | 42 | class ProcessModules 43 | { 44 | public: 45 | typedef std::unordered_map, ModuleData> mapModules; 46 | 47 | public: 48 | ProcessModules( class Process& proc ); 49 | ~ProcessModules(); 50 | 51 | /// 52 | /// Get module by name 53 | /// 54 | /// Module name 55 | /// Module type. 32 bit or 64 bit 56 | /// Saerch type. 57 | /// Module data. nullptr if not found 58 | const ModuleData* GetModule( const std::wstring& name, 59 | eModSeachType search = LdrList, 60 | eModType type = mt_default ); 61 | 62 | /// 63 | /// Get module by name 64 | /// 65 | /// TModule name. 66 | /// Module type. 32 bit or 64 bit 67 | /// Import module name. Used only to resolve ApiSchema during manual map 68 | /// Module data. nullptr if not found 69 | const ModuleData* GetModule( std::wstring& name, 70 | eModSeachType search = LdrList, 71 | eModType type = mt_default, 72 | const wchar_t* baseModule = L"" ); 73 | 74 | /// 75 | /// Get process main module 76 | /// 77 | /// Module data. nullptr if not found 78 | const ModuleData* GetMainModule(); 79 | 80 | /// 81 | /// Enumerate all process modules 82 | /// 83 | /// Search method 84 | /// Module list 85 | const ProcessModules::mapModules& GetAllModules( eModSeachType search = LdrList); 86 | 87 | /// 88 | /// Get export address. Forwarded exports will be automatically resolved if forward module is present 89 | /// 90 | /// Module to search in 91 | /// Function name or ordinal 92 | /// Import module name. Only used to resolve ApiSchema during manual map. 93 | /// Export info. If failed procAddress field is 0 94 | exportData GetExport( const ModuleData* hMod, const char* name_ord, const wchar_t* baseModule = L"" ); 95 | 96 | /// 97 | /// Inject image into target process 98 | /// 99 | /// Full-qualified image path 100 | /// Module info. nullptr if failed 101 | const ModuleData* Inject( const std::wstring& path ); 102 | 103 | /// 104 | /// Inject pure IL image. 105 | /// 106 | /// NET runtime version to use 107 | /// Path to image 108 | /// Method to call 109 | /// Arguments passed into method 110 | /// Return code 111 | /// true on success 112 | bool InjectPureIL( const std::wstring& netVersion, 113 | const std::wstring& netAssemblyPath, 114 | const std::wstring& netAssemblyMethod, 115 | const std::wstring& netAssemblyArgs, 116 | DWORD& returnCode ); 117 | 118 | /// 119 | /// Unload specific module from target process. Can't be used to unload manually mapped modules 120 | /// 121 | /// Module to unload 122 | /// true on success 123 | bool Unload( const ModuleData* hMod ); 124 | 125 | /// 126 | /// Unlink module from most loader structures 127 | /// 128 | /// Module to unlink 129 | /// true on success 130 | bool Unlink( const ModuleData* mod ); 131 | 132 | /// 133 | /// Store manually mapped module in module list 134 | /// 135 | /// Full qualified module path 136 | /// Base address 137 | /// Module size 138 | /// Module type. 32 bit or 64 bit 139 | /// Module info 140 | const ModuleData* AddManualModule( const std::wstring& FilePath, module_t base, size_t size, eModType mt ); 141 | 142 | /// 143 | /// Remove module from module list 144 | /// 145 | /// Module file name 146 | /// Module type. 32 bit or 64 bit 147 | void RemoveManualModule( const std::wstring& filename, eModType mt ); 148 | 149 | /// 150 | /// Ensure module is a valid PE image 151 | /// 152 | /// Module base address 153 | /// true on success 154 | bool ValidateModule( module_t base ); 155 | 156 | /// 157 | /// Reset local data 158 | /// 159 | void reset(); 160 | 161 | private: 162 | ProcessModules( const ProcessModules& ) = delete; 163 | ProcessModules operator =(const ProcessModules&) = delete; 164 | 165 | private: 166 | class Process& _proc; 167 | class ProcessMemory& _memory; 168 | class ProcessCore& _core; 169 | 170 | mapModules _modules; // Fast lookup cache 171 | std::mutex _modGuard; // Module guard 172 | bool _ldrPatched; // Win7 loader patch flag 173 | }; 174 | 175 | }; 176 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/MemoryManager.h: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // [Guard] 8 | #ifndef _ASMJIT_MEMORYMANAGER_H 9 | #define _ASMJIT_MEMORYMANAGER_H 10 | 11 | // [Dependencies] 12 | #include "Build.h" 13 | #include "Defs.h" 14 | 15 | // [Api-Begin] 16 | #include "ApiBegin.h" 17 | 18 | // [Debug] 19 | // #define ASMJIT_MEMORY_MANAGER_DUMP 20 | 21 | namespace AsmJit { 22 | 23 | //! @addtogroup AsmJit_MemoryManagement 24 | //! @{ 25 | 26 | // ============================================================================ 27 | // [AsmJit::MemoryManager] 28 | // ============================================================================ 29 | 30 | //! @brief Virtual memory manager interface. 31 | //! 32 | //! This class is pure virtual. You can get default virtual memory manager using 33 | //! @c getGlobal() method. If you want to create more memory managers with same 34 | //! functionality as global memory manager use @c VirtualMemoryManager class. 35 | struct ASMJIT_API MemoryManager 36 | { 37 | // -------------------------------------------------------------------------- 38 | // [Construction / Destruction] 39 | // -------------------------------------------------------------------------- 40 | 41 | //! @brief Create memory manager instance. 42 | MemoryManager() ASMJIT_NOTHROW; 43 | //! @brief Destroy memory manager instance, this means also to free all memory 44 | //! blocks. 45 | virtual ~MemoryManager() ASMJIT_NOTHROW; 46 | 47 | // -------------------------------------------------------------------------- 48 | // [Interface] 49 | // -------------------------------------------------------------------------- 50 | 51 | //! @brief Allocate a @a size bytes of virtual memory. 52 | //! 53 | //! Note that if you are implementing your own virtual memory manager then you 54 | //! can quitly ignore type of allocation. This is mainly for AsmJit to memory 55 | //! manager that allocated memory will be never freed. 56 | virtual void* alloc(sysuint_t size, uint32_t type = MEMORY_ALLOC_FREEABLE) ASMJIT_NOTHROW = 0; 57 | //! @brief Free previously allocated memory at a given @a address. 58 | virtual bool free(void* address) ASMJIT_NOTHROW = 0; 59 | //! @brief Free some tail memory. 60 | virtual bool shrink(void* address, sysuint_t used) ASMJIT_NOTHROW = 0; 61 | //! @brief Free all allocated memory. 62 | virtual void freeAll() ASMJIT_NOTHROW = 0; 63 | 64 | //! @brief Get how many bytes are currently used. 65 | virtual sysuint_t getUsedBytes() ASMJIT_NOTHROW = 0; 66 | //! @brief Get how many bytes are currently allocated. 67 | virtual sysuint_t getAllocatedBytes() ASMJIT_NOTHROW = 0; 68 | 69 | //! @brief Get global memory manager instance. 70 | //! 71 | //! Global instance is instance of @c VirtualMemoryManager class. Global memory 72 | //! manager is used by default by @ref Assembler::make() and @ref Compiler::make() 73 | //! methods. 74 | static MemoryManager* getGlobal() ASMJIT_NOTHROW; 75 | }; 76 | 77 | //! @brief Reference implementation of memory manager that uses 78 | //! @ref AsmJit::VirtualMemory class to allocate chunks of virtual memory 79 | //! and bit arrays to manage it. 80 | struct ASMJIT_API VirtualMemoryManager : public MemoryManager 81 | { 82 | // -------------------------------------------------------------------------- 83 | // [Construction / Destruction] 84 | // -------------------------------------------------------------------------- 85 | 86 | //! @brief Create a @c VirtualMemoryManager instance. 87 | VirtualMemoryManager() ASMJIT_NOTHROW; 88 | 89 | #if defined(ASMJIT_WINDOWS) 90 | //! @brief Create a @c VirtualMemoryManager instance for process @a hProcess. 91 | //! 92 | //! This is specialized version of constructor available only for windows and 93 | //! usable to alloc/free memory of different process. 94 | VirtualMemoryManager(HANDLE hProcess) ASMJIT_NOTHROW; 95 | #endif // ASMJIT_WINDOWS 96 | 97 | //! @brief Destroy the @c VirtualMemoryManager instance, this means also to 98 | //! free all blocks. 99 | virtual ~VirtualMemoryManager() ASMJIT_NOTHROW; 100 | 101 | // -------------------------------------------------------------------------- 102 | // [Interface] 103 | // -------------------------------------------------------------------------- 104 | 105 | virtual void* alloc(sysuint_t size, uint32_t type = MEMORY_ALLOC_FREEABLE) ASMJIT_NOTHROW; 106 | virtual bool free(void* address) ASMJIT_NOTHROW; 107 | virtual bool shrink(void* address, sysuint_t used) ASMJIT_NOTHROW; 108 | virtual void freeAll() ASMJIT_NOTHROW; 109 | 110 | virtual sysuint_t getUsedBytes() ASMJIT_NOTHROW; 111 | virtual sysuint_t getAllocatedBytes() ASMJIT_NOTHROW; 112 | 113 | // -------------------------------------------------------------------------- 114 | // [Virtual Memory Manager Specific] 115 | // -------------------------------------------------------------------------- 116 | 117 | //! @brief Get whether to keep allocated memory after memory manager is 118 | //! destroyed. 119 | //! 120 | //! @sa @c setKeepVirtualMemory(). 121 | bool getKeepVirtualMemory() const ASMJIT_NOTHROW; 122 | 123 | //! @brief Set whether to keep allocated memory after memory manager is 124 | //! destroyed. 125 | //! 126 | //! This method is usable when patching code of remote process. You need to 127 | //! allocate process memory, store generated assembler into it and patch the 128 | //! method you want to redirect (into your code). This method affects only 129 | //! VirtualMemoryManager destructor. After destruction all internal 130 | //! structures are freed, only the process virtual memory remains. 131 | //! 132 | //! @note Memory allocated with MEMORY_ALLOC_PERMANENT is always kept. 133 | //! 134 | //! @sa @c getKeepVirtualMemory(). 135 | void setKeepVirtualMemory(bool keepVirtualMemory) ASMJIT_NOTHROW; 136 | 137 | // -------------------------------------------------------------------------- 138 | // [Debug] 139 | // -------------------------------------------------------------------------- 140 | 141 | #if defined(ASMJIT_MEMORY_MANAGER_DUMP) 142 | //! @brief Dump memory manager tree into file. 143 | //! 144 | //! Generated output is using DOT language (from graphviz package). 145 | void dump(const char* fileName); 146 | #endif // ASMJIT_MEMORY_MANAGER_DUMP 147 | 148 | // -------------------------------------------------------------------------- 149 | // [Members] 150 | // -------------------------------------------------------------------------- 151 | 152 | protected: 153 | //! @brief Pointer to private data hidden from the public API. 154 | void* _d; 155 | }; 156 | 157 | //! @} 158 | 159 | } // AsmJit namespace 160 | 161 | // [Api-End] 162 | #include "ApiEnd.h" 163 | 164 | // [Guard] 165 | #endif // _ASMJIT_MEMORYMANAGER_H 166 | -------------------------------------------------------------------------------- /src/BlackBone/AsmJit/Compiler.cpp: -------------------------------------------------------------------------------- 1 | // [AsmJit] 2 | // Complete JIT Assembler for C++ Language. 3 | // 4 | // [License] 5 | // Zlib - See COPYING file in this package. 6 | 7 | // We are using sprintf() here. 8 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 9 | #define _CRT_SECURE_NO_WARNINGS 10 | #endif // _MSC_VER 11 | 12 | // [Dependencies] 13 | #include "Assembler.h" 14 | #include "Compiler.h" 15 | #include "CpuInfo.h" 16 | #include "Logger.h" 17 | #include "Util.h" 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | // [Api-Begin] 24 | #include "ApiBegin.h" 25 | 26 | namespace AsmJit { 27 | 28 | #pragma warning(disable : 4127 4100) 29 | 30 | 31 | // ============================================================================ 32 | // [AsmJit::Emittable] 33 | // ============================================================================ 34 | 35 | Emittable::Emittable(Compiler* c, uint32_t type) ASMJIT_NOTHROW : 36 | _compiler(c), 37 | _next(NULL), 38 | _prev(NULL), 39 | _comment(NULL), 40 | _type((uint8_t)type), 41 | _translated(false), 42 | _reserved0(0), 43 | _reserved1(0), 44 | _offset(INVALID_VALUE) 45 | { 46 | } 47 | 48 | Emittable::~Emittable() ASMJIT_NOTHROW 49 | { 50 | } 51 | 52 | void Emittable::prepare(CompilerContext& cc) ASMJIT_NOTHROW 53 | { 54 | _offset = cc._currentOffset; 55 | } 56 | 57 | Emittable* Emittable::translate(CompilerContext& cc) ASMJIT_NOTHROW 58 | { 59 | return translated(); 60 | } 61 | 62 | void Emittable::emit(Assembler& a) ASMJIT_NOTHROW 63 | { 64 | } 65 | 66 | void Emittable::post(Assembler& a) ASMJIT_NOTHROW 67 | { 68 | } 69 | 70 | int Emittable::getMaxSize() const ASMJIT_NOTHROW 71 | { 72 | // Default maximum size is -1 which means that it's not known. 73 | return -1; 74 | } 75 | 76 | bool Emittable::_tryUnuseVar(VarData* v) ASMJIT_NOTHROW 77 | { 78 | return false; 79 | } 80 | 81 | void Emittable::setComment(const char* str) ASMJIT_NOTHROW 82 | { 83 | _comment = _compiler->getZone().zstrdup(str); 84 | } 85 | 86 | void Emittable::setCommentF(const char* fmt, ...) ASMJIT_NOTHROW 87 | { 88 | // I'm really not expecting larger inline comments:) 89 | char buf[256]; 90 | 91 | va_list ap; 92 | va_start(ap, fmt); 93 | vsnprintf(buf, 255, fmt, ap); 94 | va_end(ap); 95 | 96 | // I don't know if vsnprintf can produce non-null terminated string, in case 97 | // it can, we terminate it here. 98 | buf[255] = '\0'; 99 | 100 | setComment(buf); 101 | } 102 | 103 | // ============================================================================ 104 | // [AsmJit::EDummy] 105 | // ============================================================================ 106 | 107 | EDummy::EDummy(Compiler* c) ASMJIT_NOTHROW : 108 | Emittable(c, EMITTABLE_DUMMY) 109 | { 110 | } 111 | 112 | EDummy::~EDummy() ASMJIT_NOTHROW 113 | { 114 | } 115 | 116 | int EDummy::getMaxSize() const ASMJIT_NOTHROW 117 | { 118 | return 0; 119 | } 120 | 121 | // ============================================================================ 122 | // [AsmJit::EFunctionEnd] 123 | // ============================================================================ 124 | 125 | EFunctionEnd::EFunctionEnd(Compiler* c) ASMJIT_NOTHROW : 126 | EDummy(c) 127 | { 128 | _type = EMITTABLE_FUNCTION_END; 129 | } 130 | 131 | EFunctionEnd::~EFunctionEnd() ASMJIT_NOTHROW 132 | { 133 | } 134 | 135 | Emittable* EFunctionEnd::translate(CompilerContext& cc) ASMJIT_NOTHROW 136 | { 137 | _translated = true; 138 | return NULL; 139 | } 140 | 141 | // ============================================================================ 142 | // [AsmJit::EComment] 143 | // ============================================================================ 144 | 145 | EComment::EComment(Compiler* c, const char* str) ASMJIT_NOTHROW : 146 | Emittable(c, EMITTABLE_COMMENT) 147 | { 148 | setComment(str); 149 | } 150 | 151 | EComment::~EComment() ASMJIT_NOTHROW 152 | { 153 | } 154 | 155 | void EComment::emit(Assembler& a) ASMJIT_NOTHROW 156 | { 157 | if (a.getLogger()) 158 | { 159 | a.getLogger()->logString(getComment()); 160 | } 161 | } 162 | 163 | int EComment::getMaxSize() const ASMJIT_NOTHROW 164 | { 165 | return 0; 166 | } 167 | 168 | // ============================================================================ 169 | // [AsmJit::EData] 170 | // ============================================================================ 171 | 172 | EData::EData(Compiler* c, const void* data, sysuint_t length) ASMJIT_NOTHROW : 173 | Emittable(c, EMITTABLE_EMBEDDED_DATA) 174 | { 175 | _length = length; 176 | memcpy(_data, data, length); 177 | } 178 | 179 | EData::~EData() ASMJIT_NOTHROW 180 | { 181 | } 182 | 183 | void EData::emit(Assembler& a) ASMJIT_NOTHROW 184 | { 185 | a.embed(_data, _length); 186 | } 187 | 188 | int EData::getMaxSize() const ASMJIT_NOTHROW 189 | { 190 | return (int)_length;; 191 | } 192 | 193 | // ============================================================================ 194 | // [AsmJit::EAlign] 195 | // ============================================================================ 196 | 197 | EAlign::EAlign(Compiler* c, uint32_t size) ASMJIT_NOTHROW : 198 | Emittable(c, EMITTABLE_ALIGN), _size(size) 199 | { 200 | } 201 | 202 | EAlign::~EAlign() ASMJIT_NOTHROW 203 | { 204 | } 205 | 206 | void EAlign::emit(Assembler& a) ASMJIT_NOTHROW 207 | { 208 | a.align(_size); 209 | } 210 | 211 | int EAlign::getMaxSize() const ASMJIT_NOTHROW 212 | { 213 | return (_size > 0) ? (int)_size - 1 : 0; 214 | } 215 | 216 | // ============================================================================ 217 | // [AsmJit::ETarget] 218 | // ============================================================================ 219 | 220 | ETarget::ETarget(Compiler* c, const Label& label) ASMJIT_NOTHROW : 221 | Emittable(c, EMITTABLE_TARGET), 222 | _label(label), 223 | _from(NULL), 224 | _state(NULL), 225 | _jumpsCount(0) 226 | { 227 | } 228 | 229 | ETarget::~ETarget() ASMJIT_NOTHROW 230 | { 231 | } 232 | 233 | void ETarget::prepare(CompilerContext& cc) ASMJIT_NOTHROW 234 | { 235 | _offset = cc._currentOffset++; 236 | } 237 | 238 | Emittable* ETarget::translate(CompilerContext& cc) ASMJIT_NOTHROW 239 | { 240 | // If this ETarget was already translated, it's needed to change the current 241 | // state and return NULL to tell CompilerContext to process next untranslated 242 | // emittable. 243 | if (_translated) 244 | { 245 | cc._restoreState(_state); 246 | return NULL; 247 | } 248 | 249 | if (cc._unreachable) 250 | { 251 | cc._unreachable = 0; 252 | 253 | // Assign state to the compiler context. 254 | ASMJIT_ASSERT(_state != NULL); 255 | cc._assignState(_state); 256 | } 257 | else 258 | { 259 | _state = cc._saveState(); 260 | } 261 | 262 | return translated(); 263 | } 264 | 265 | void ETarget::emit(Assembler& a) ASMJIT_NOTHROW 266 | { 267 | a.bind(_label); 268 | } 269 | 270 | int ETarget::getMaxSize() const ASMJIT_NOTHROW 271 | { 272 | return 0; 273 | } 274 | 275 | #pragma warning(default : 4127 4100) 276 | 277 | } // AsmJit namespace 278 | -------------------------------------------------------------------------------- /src/BlackBone/ImageNET.cpp: -------------------------------------------------------------------------------- 1 | #include "ImageNET.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace blackbone 9 | { 10 | 11 | ImageNET::ImageNET( void ) 12 | { 13 | } 14 | 15 | ImageNET::~ImageNET(void) 16 | { 17 | if (!_path.empty()) 18 | CoUninitialize(); 19 | } 20 | 21 | /// 22 | /// Initialize COM classes 23 | /// 24 | /// Image file path 25 | /// true on success 26 | bool ImageNET::Init( const std::wstring& path ) 27 | { 28 | HRESULT hr; 29 | VARIANT value; 30 | 31 | _path = path; 32 | 33 | if (FAILED( CoInitialize( 0 ) )) 34 | return false; 35 | 36 | hr = CoCreateInstance( CLSID_CorMetaDataDispenser, NULL, CLSCTX_INPROC_SERVER, 37 | IID_IMetaDataDispenserEx, reinterpret_cast(&_pMetaDisp) ); 38 | if (FAILED( hr )) 39 | return false; 40 | 41 | // 42 | // query required interfaces 43 | // 44 | hr = _pMetaDisp->OpenScope( _path.c_str(), 0, IID_IMetaDataImport, reinterpret_cast(&_pMetaImport) ); 45 | if (hr == CLDB_E_BADUPDATEMODE) 46 | { 47 | V_VT(&value) = VT_UI4; 48 | V_UI4(&value) = MDUpdateIncremental; 49 | 50 | if (FAILED( hr = _pMetaDisp->SetOption( MetaDataSetUpdate, &value ) )) 51 | return false; 52 | 53 | hr = _pMetaDisp->OpenScope( _path.c_str(), 0, IID_IMetaDataImport, reinterpret_cast(&_pMetaImport) ); 54 | } 55 | 56 | if (FAILED( hr )) 57 | return false; 58 | 59 | hr = _pMetaImport->QueryInterface( IID_IMetaDataAssemblyImport, reinterpret_cast(&_pAssemblyImport) ); 60 | if (FAILED( hr )) 61 | return false; 62 | 63 | return true; 64 | } 65 | 66 | /// 67 | /// Extract methods from image 68 | /// 69 | /// Found Methods 70 | /// true on success 71 | bool ImageNET::Parse( mapMethodRVA& methods ) 72 | { 73 | DWORD dwcTypeDefs, dwTypeDefFlags, dwcTokens, dwSigBlobSize; 74 | 75 | HCORENUM hceTypeDefs = 0; 76 | mdToken tExtends = 0; 77 | HCORENUM hceMethods = 0; 78 | mdTypeRef rTypeDefs[10] = { 0 }; 79 | WCHAR wcName[1024] = { 0 }; 80 | mdToken rTokens[10] = { 0 }; 81 | 82 | while (SUCCEEDED( _pMetaImport->EnumTypeDefs( &hceTypeDefs, rTypeDefs, ARRAYSIZE( rTypeDefs ), &dwcTypeDefs )) 83 | && dwcTypeDefs > 0) 84 | { 85 | for (UINT i = 0; i < dwcTypeDefs; i++) 86 | { 87 | HRESULT hr = _pMetaImport->GetTypeDefProps( rTypeDefs[i], wcName, ARRAYSIZE( wcName ), NULL, &dwTypeDefFlags, &tExtends ); 88 | if ( FAILED(hr) ) 89 | continue; 90 | 91 | while (SUCCEEDED( _pMetaImport->EnumMethods( &hceMethods, rTypeDefs[i], rTokens, ARRAYSIZE( rTokens ), &dwcTokens ) ) 92 | && dwcTokens > 0) 93 | { 94 | DWORD dwCodeRVA, dwAttr; 95 | WCHAR wmName[1024] = { 0 }; 96 | PCCOR_SIGNATURE pbySigBlob = nullptr; 97 | 98 | for (UINT j = 0; j < dwcTokens; j++) 99 | { 100 | // get method information 101 | HRESULT hr = _pMetaImport->GetMemberProps( 102 | rTokens[j], NULL, wmName, 103 | ARRAYSIZE( wmName ), NULL, 104 | &dwAttr, &pbySigBlob, &dwSigBlobSize, 105 | &dwCodeRVA, NULL, NULL, NULL, NULL ); 106 | 107 | if (FAILED( hr )) 108 | continue; 109 | 110 | _methods.emplace( std::make_pair( wcName, wmName ), dwCodeRVA ); 111 | } 112 | } 113 | } 114 | } 115 | 116 | methods = _methods; 117 | 118 | return true; 119 | } 120 | 121 | typedef decltype(&GetRequestedRuntimeVersion) fnGetRequestedRuntimeVersion; 122 | typedef decltype(&CLRCreateInstance) fnCLRCreateInstancen; 123 | 124 | /// 125 | /// Get image .NET runtime version 126 | /// 127 | /// runtime version, "n/a" if nothing found 128 | std::wstring ImageNET::GetImageRuntimeVer( const wchar_t* ImagePath ) 129 | { 130 | std::wstring LatestVersion = L"n/a"; 131 | 132 | CComPtr MetaHost; 133 | 134 | // Check if .NET 4 or higher is present 135 | auto clrCreate = reinterpret_cast( 136 | GetProcAddress( LoadLibraryW( L"mscoree.dll" ), "CLRCreateInstance" )); 137 | 138 | // Legacy runtime. Get exact required version 139 | if(!clrCreate) 140 | { 141 | wchar_t ver[64] = { 0 }; 142 | DWORD bytes = 0; 143 | 144 | auto clrGetVer = reinterpret_cast( 145 | GetProcAddress( GetModuleHandleW( L"mscoree.dll" ), "GetRequestedRuntimeVersion" )); 146 | 147 | clrGetVer( const_cast(ImagePath), ver, 64, &bytes ); 148 | 149 | FreeLibrary( GetModuleHandleW( L"mscoree.dll" ) ); 150 | return ver; 151 | } 152 | // Get highest available 153 | else 154 | { 155 | if (FAILED( clrCreate( CLSID_CLRMetaHost, IID_ICLRMetaHost, reinterpret_cast(&MetaHost) ) )) 156 | return LatestVersion; 157 | 158 | CComPtr Runtimes; 159 | if (FAILED( MetaHost->EnumerateInstalledRuntimes( &Runtimes ) )) 160 | return LatestVersion; 161 | 162 | CComPtr Runtime; 163 | CComPtr Latest; 164 | 165 | while (Runtimes->Next( 1, &Runtime, NULL ) == S_OK) 166 | { 167 | CComPtr Current; 168 | wchar_t tmpString[MAX_PATH]; 169 | DWORD tmp = MAX_PATH * sizeof(wchar_t); 170 | 171 | if (SUCCEEDED( Runtime->QueryInterface( IID_PPV_ARGS( &Current ) ) )) 172 | { 173 | if (!Latest) 174 | { 175 | if (SUCCEEDED( Current->QueryInterface( IID_PPV_ARGS( &Latest ) ) )) 176 | { 177 | Latest->GetVersionString( tmpString, &tmp ); 178 | LatestVersion = tmpString; 179 | } 180 | } 181 | else 182 | { 183 | if (SUCCEEDED( Current->GetVersionString( tmpString, &tmp ) )) 184 | { 185 | std::wstring CurrentVersion = tmpString; 186 | if (CurrentVersion.compare( LatestVersion ) > 0) 187 | { 188 | LatestVersion = CurrentVersion; 189 | Latest.Release(); 190 | Current->QueryInterface( IID_PPV_ARGS( &Latest ) ); 191 | } 192 | } 193 | } 194 | } 195 | 196 | Runtime.Release(); 197 | } 198 | 199 | return LatestVersion; 200 | } 201 | 202 | } 203 | 204 | } -------------------------------------------------------------------------------- /src/BlackBone/Thread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "NativeStructures.h" 5 | #include "Types.h" 6 | 7 | #include 8 | 9 | namespace blackbone 10 | { 11 | 12 | #define DEFAULT_ACCESS_T THREAD_SUSPEND_RESUME | \ 13 | THREAD_GET_CONTEXT | \ 14 | THREAD_SET_CONTEXT | \ 15 | THREAD_QUERY_INFORMATION | \ 16 | THREAD_TERMINATE | \ 17 | SYNCHRONIZE 18 | 19 | // Breakpoint type 20 | enum HWBPType 21 | { 22 | hwbp_access = 3, // Read or write 23 | hwbp_write = 1, // Write only 24 | hwbp_execute = 0, // Execute only 25 | }; 26 | 27 | enum HWBPLength 28 | { 29 | hwbp_1 = 0, // 1 byte 30 | hwbp_2 = 1, // 2 bytes 31 | hwbp_4 = 3, // 4 bytes 32 | hwbp_8 = 2, // 8 bytes 33 | }; 34 | 35 | 36 | /// 37 | /// Thread management 38 | /// 39 | class Thread 40 | { 41 | public: 42 | Thread( DWORD id, class ProcessCore* hProcess, DWORD access = DEFAULT_ACCESS_T ); 43 | Thread( HANDLE handle, class ProcessCore* hProcess ); 44 | Thread( const Thread& other ); 45 | ~Thread(); 46 | 47 | /// 48 | /// Get thread ID 49 | /// 50 | /// Thread ID 51 | inline DWORD id() const { return _id; } 52 | 53 | /// 54 | /// Get thread handle 55 | /// 56 | /// Thread hande 57 | inline HANDLE handle() const { return _handle; } 58 | 59 | /// 60 | /// Check if thread exists 61 | /// 62 | /// true if thread exists 63 | inline bool valid() const { return (_handle != NULL && ExitCode() == STILL_ACTIVE); } 64 | 65 | /// 66 | /// Get WOW64 TEB 67 | /// 68 | /// Process TEB 69 | /// TEB pointer 70 | ptr_t teb( _TEB32* pteb = nullptr ) const; 71 | 72 | /// 73 | /// Get Native TEB 74 | /// 75 | /// Process TEB 76 | /// TEB pointer 77 | ptr_t teb( _TEB64* pteb = nullptr ) const; 78 | 79 | /// 80 | /// Get TEB 81 | /// 82 | /// TEB pointer 83 | inline ptr_t teb() const { return teb( (TEB_T*)nullptr ); } 84 | 85 | /// 86 | /// Get thread creation time 87 | /// 88 | /// Thread creation time 89 | uint64_t startTime(); 90 | 91 | /// 92 | /// Get total execution time(user mode and kernel mode) 93 | /// 94 | /// Total execution time 95 | uint64_t execTime(); 96 | 97 | /// 98 | /// Suspend thread 99 | /// 100 | /// true on success 101 | bool Suspend(); 102 | 103 | /// 104 | /// Resumes thread. 105 | /// 106 | /// true on success 107 | bool Resume(); 108 | 109 | /// 110 | /// Get WOW64 thread context 111 | /// 112 | /// Returned context 113 | /// Context flags. 114 | /// true if thread shouldn't be suspended before retrieving context 115 | /// true on success 116 | bool GetContext( _CONTEXT32& ctx, DWORD flags = CONTEXT_ALL, bool dontSuspend = false ); 117 | 118 | /// 119 | /// Get native thread context 120 | /// 121 | /// Returned context 122 | /// Context flags. 123 | /// true if thread shouldn't be suspended before retrieving context 124 | /// true on success 125 | bool GetContext( _CONTEXT64& ctx, DWORD flags = CONTEXT64_ALL, bool dontSuspend = false ); 126 | 127 | /// 128 | /// Set WOW64 thread context 129 | /// 130 | /// Context to set 131 | /// true if thread shouldn't be suspended before retrieving context 132 | /// true on success 133 | bool SetContext( _CONTEXT32& ctx, bool dontSuspend = false ); 134 | 135 | /// 136 | /// Set native thread context 137 | /// 138 | /// Context to set 139 | /// true if thread shouldn't be suspended before retrieving context 140 | /// true on success 141 | bool SetContext( _CONTEXT64& ctx, bool dontSuspend = false ); 142 | 143 | /// 144 | /// Terminate thread 145 | /// 146 | /// Exit code 147 | /// true on success 148 | bool Terminate( DWORD code = 0 ); 149 | 150 | /// 151 | /// Join thread 152 | /// 153 | /// Join timeout 154 | /// true on success 155 | bool Join( int timeout = INFINITE ); 156 | 157 | /// 158 | /// Get thread exit code 159 | /// 160 | /// Thread exit code 161 | DWORD ExitCode() const; 162 | 163 | /// 164 | /// Add hardware breakpoint to thread 165 | /// 166 | /// Breakpoint address 167 | /// Breakpoint type(read/write/execute) 168 | /// Number of bytes to include into breakpoint 169 | /// Index of used breakpoint; -1 if failed 170 | int AddHWBP( ptr_t addr, HWBPType type, HWBPLength length ); 171 | 172 | /// 173 | /// Remove existing hardware breakpoint 174 | /// 175 | /// Breakpoint index 176 | /// true on success 177 | bool RemoveHWBP( int idx ); 178 | 179 | /// 180 | /// Remove existing hardware breakpoint 181 | /// 182 | /// Breakpoint address 183 | /// true on success 184 | bool RemoveHWBP( ptr_t ptr ); 185 | 186 | inline bool operator ==(const Thread& other) { return (_id == other._id); } 187 | 188 | Thread& operator =(const Thread& other) 189 | { 190 | _id = other._id; 191 | _core = other._core; 192 | _handle = other._handle; 193 | 194 | // Transfer handle ownership 195 | other.ReleaseHandle(); 196 | 197 | return *this; 198 | } 199 | 200 | private: 201 | 202 | /// 203 | /// Release thread handle 204 | /// 205 | inline void ReleaseHandle() const { _handle = NULL; } 206 | 207 | private: 208 | class ProcessCore* _core; // Core routines 209 | 210 | DWORD _id = 0; // Thread ID 211 | mutable HANDLE _handle = NULL; // Thread handle 212 | }; 213 | 214 | } -------------------------------------------------------------------------------- /src/BlackBone/MemBlock.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Winheaders.h" 4 | #include "Macro.h" 5 | #include "Types.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace blackbone 12 | { 13 | 14 | /// 15 | /// Get rid of EXECUTABLE flag if DEP isn't enabled 16 | /// 17 | /// Memry protection flags 18 | /// DEP flag 19 | /// New protection flags 20 | inline DWORD CastProtection( DWORD prot, bool bDEP ) 21 | { 22 | if (bDEP == true) 23 | { 24 | return prot; 25 | } 26 | else 27 | { 28 | if (prot == PAGE_EXECUTE_READ) 29 | return PAGE_READONLY; 30 | else if (prot == PAGE_EXECUTE_READWRITE) 31 | return PAGE_READWRITE; 32 | else if (prot == PAGE_EXECUTE_WRITECOPY) 33 | return PAGE_WRITECOPY; 34 | else 35 | return prot; 36 | } 37 | } 38 | 39 | class MemBlock 40 | { 41 | public: 42 | 43 | MemBlock(); 44 | 45 | /// 46 | /// MemBlock ctor 47 | /// 48 | /// Process memory routines 49 | /// Memory address 50 | /// true if caller will be responsible for block deallocation 51 | MemBlock( class ProcessMemory* mem, ptr_t ptr, bool own = true ); 52 | 53 | /// 54 | /// MemBlock ctor 55 | /// 56 | /// Process memory routines 57 | /// Memory address 58 | /// Block size 59 | /// Memory protection 60 | /// true if caller will be responsible for block deallocation 61 | MemBlock( class ProcessMemory* mem, ptr_t ptr, size_t size, DWORD prot, bool own = true ); 62 | 63 | ~MemBlock(); 64 | 65 | /// 66 | /// Allocate new memory block 67 | /// 68 | /// Process memory routines 69 | /// Block size 70 | /// Desired base address of new block 71 | /// Win32 Memory protection flags 72 | /// Memory block. If failed - returned block will be invalid 73 | static MemBlock Allocate( class ProcessMemory& process, size_t size, ptr_t desired = 0, DWORD protection = PAGE_EXECUTE_READWRITE ); 74 | 75 | /// 76 | /// Reallocate existing block for new size 77 | /// 78 | /// New block size 79 | /// Desired base address of new block 80 | /// Memory protection 81 | /// New block address 82 | ptr_t Realloc( size_t size, ptr_t desired = 0, DWORD protection = PAGE_EXECUTE_READWRITE ); 83 | 84 | /// 85 | /// Change memory protection 86 | /// 87 | /// New protection flags 88 | /// Memory offset in block 89 | /// Block size 90 | /// Old protection flags 91 | /// Status 92 | NTSTATUS Protect( DWORD protection, size_t offset = 0, size_t size = 0, DWORD* pOld = nullptr ); 93 | 94 | /// 95 | /// Free memory 96 | /// 97 | /// Size of memory chunk to free. If 0 - whole block is freed 98 | void Free( size_t size = 0 ); 99 | 100 | /// 101 | /// Read data 102 | /// 103 | /// Data offset in block 104 | /// Size of data to read 105 | /// Output buffer 106 | /// 107 | /// If true, function will try to read all committed pages in range ignoring uncommitted. 108 | /// Otherwise function will fail if there is at least one non-committed page in region. 109 | /// 110 | /// Status 111 | NTSTATUS Read( size_t offset, size_t size, PVOID pResult, bool handleHoles = false ); 112 | 113 | /// 114 | /// Write data 115 | /// 116 | /// Data offset in block 117 | /// Size of data to write 118 | /// Buffer to write 119 | /// Status 120 | NTSTATUS Write( size_t offset, size_t size, const void* pData ); 121 | 122 | /// 123 | /// Read data 124 | /// 125 | /// Data offset in block 126 | /// Defult return value if read has failed 127 | /// Read data 128 | template 129 | T Read( size_t offset, T def_val ) 130 | { 131 | T res = def_val; 132 | Read( offset, sizeof(T), &res ); 133 | return res; 134 | }; 135 | 136 | /// 137 | /// Write data 138 | /// 139 | /// Offset in block 140 | /// Data to write 141 | /// Status 142 | template 143 | NTSTATUS Write( size_t offset, T data ) 144 | { 145 | return Write( offset, sizeof(T), &data ); 146 | } 147 | 148 | /// 149 | /// Memory will not be deallocated upon object destruction 150 | /// 151 | inline void Release() const { _own = false; } 152 | 153 | /// 154 | /// Get memory pointer 155 | /// 156 | /// Memory pointer 157 | template< typename T = ptr_t > 158 | inline T ptr() const { return (T)_ptr; } 159 | 160 | /// 161 | /// Get block size 162 | /// 163 | /// Block size 164 | inline size_t size() const { return _size; } 165 | 166 | /// 167 | /// Get block memory protection 168 | /// 169 | /// Memory protection flags 170 | inline DWORD protection() const { return _protection; } 171 | 172 | /// 173 | /// Validate memory block 174 | /// true if memory pointer isn't 0 175 | inline bool valid() const { return (_memory != nullptr && _ptr != 0); } 176 | 177 | /// 178 | /// Get memory pointer 179 | /// 180 | /// Memory pointer 181 | operator ptr_t() const { return _ptr; } 182 | 183 | MemBlock& operator =(const MemBlock& other) 184 | { 185 | _memory = other._memory; 186 | _ptr = other._ptr; 187 | _size = other._size; 188 | _protection = other._protection; 189 | _own = true; 190 | 191 | // Transfer memory ownership 192 | other.Release(); 193 | 194 | return *this; 195 | } 196 | 197 | private: 198 | ptr_t _ptr = 0; // Raw memory pointer 199 | size_t _size = 0; // Region size 200 | DWORD _protection = 0; // Region protection 201 | mutable bool _own = true; // Memory will be freed in destructor 202 | class ProcessMemory* _memory; // Target process routines 203 | }; 204 | 205 | } -------------------------------------------------------------------------------- /src/BlackBone/AsmVariant.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AsmJit/Assembler.h" 4 | #include "AsmJit/MemoryManager.h" 5 | 6 | namespace blackbone 7 | { 8 | /// 9 | /// General purpose assembly variable 10 | /// 11 | class AsmVariant 12 | { 13 | public: 14 | enum eType 15 | { 16 | reg, // register 17 | imm, // immediate value (e.g. address) 18 | imm_double, // double or long double 19 | imm_float, // float 20 | dataPtr, // pointer to local data (e.g. string or pointer to structure) 21 | dataStruct, // structure passed by value 22 | structRet, // pointer to space into which return value is copied (used when returning structures by value) 23 | mem, // stack variable 24 | mem_ptr // pointer to stack variable 25 | }; 26 | 27 | public: 28 | AsmVariant( int _imm ) 29 | : AsmVariant( imm, sizeof(size_t), _imm ) { } 30 | 31 | AsmVariant( long _imm ) 32 | : AsmVariant( imm, sizeof(size_t), _imm ) { } 33 | 34 | AsmVariant( unsigned long _imm ) 35 | : AsmVariant( imm, sizeof(size_t), _imm ) { } 36 | 37 | AsmVariant( size_t _imm ) 38 | : AsmVariant( imm, sizeof(size_t), _imm ) { } 39 | 40 | AsmVariant( char* ptr ) 41 | : AsmVariant( dataPtr, strlen( ptr ) + 1, reinterpret_cast(ptr) ) { } 42 | 43 | AsmVariant( const char* ptr ) 44 | : AsmVariant( const_cast(ptr) ) { } 45 | 46 | AsmVariant( wchar_t* ptr ) 47 | : AsmVariant( dataPtr, (wcslen( ptr ) + 1) * sizeof(wchar_t), reinterpret_cast(ptr) ) { } 48 | 49 | AsmVariant( const wchar_t* ptr ) 50 | : AsmVariant( const_cast(ptr) ) { } 51 | 52 | AsmVariant( void* _imm ) 53 | : AsmVariant( imm, sizeof(void*), reinterpret_cast(_imm) ) { } 54 | 55 | AsmVariant( const void* _imm ) 56 | : AsmVariant( imm, sizeof(void*), reinterpret_cast(_imm) ) { } 57 | 58 | // In MSVS compiler 'long double' and 'double' are both 8 bytes long 59 | AsmVariant( long double _imm_fpu ) 60 | : AsmVariant( (double)_imm_fpu ) { } 61 | 62 | AsmVariant( double _imm_fpu ) 63 | : type( imm_double ) 64 | , size( sizeof(double) ) 65 | , imm_double_val( _imm_fpu ) 66 | , new_imm_val( 0 ) { } 67 | 68 | AsmVariant( float _imm_fpu ) 69 | : type( imm_float ) 70 | , size( sizeof(float) ) 71 | , imm_float_val( _imm_fpu ) 72 | , new_imm_val( 0 ) { } 73 | 74 | AsmVariant( AsmJit::GPReg _reg ) 75 | : type( reg ) 76 | , size( sizeof(size_t) ) 77 | , reg_val( _reg ) 78 | , imm_double_val( -1.0 ) 79 | , new_imm_val( 0 ) { } 80 | 81 | // Stack variable 82 | AsmVariant( AsmJit::Mem _mem ) 83 | : type( mem ) 84 | , size( sizeof(size_t) ) 85 | , mem_val( _mem ) 86 | , imm_double_val( -1.0 ) { } 87 | 88 | // Pointer to stack address 89 | AsmVariant( AsmJit::Mem* _mem ) 90 | : type( mem_ptr ) 91 | , size( sizeof(size_t) ) 92 | , mem_val( *_mem ) 93 | , imm_double_val( -1.0 ) 94 | , new_imm_val( 0 ) { } 95 | 96 | AsmVariant( const AsmJit::Mem* _mem ) 97 | : AsmVariant( const_cast(_mem) ) { } 98 | 99 | template 100 | AsmVariant( T* ptr ) 101 | : AsmVariant( dataPtr, sizeof(T), reinterpret_cast(ptr) ) { } 102 | 103 | template 104 | AsmVariant( const T* ptr ) 105 | { 106 | // 107 | // Treat function pointer as void* 108 | // 109 | const bool isFunction = std::is_function::type>::value; 110 | typedef typename std::conditional::type Type; 111 | 112 | type = isFunction ? imm : dataPtr; 113 | size = sizeof(Type); 114 | imm_val = reinterpret_cast(ptr); 115 | new_imm_val = 0; 116 | } 117 | 118 | template 119 | AsmVariant( const T* ptr, size_t size ) 120 | : AsmVariant( dataPtr, size, reinterpret_cast(ptr) ) { } 121 | 122 | template 123 | AsmVariant( T& val ) 124 | : AsmVariant( dataPtr, sizeof(T), reinterpret_cast(&val) ) { } 125 | 126 | template 127 | AsmVariant( const T& val ) 128 | : AsmVariant( dataPtr, sizeof(T), reinterpret_cast(&val) ) {} 129 | 130 | // Pass argument by value case 131 | #pragma warning(disable : 4127) 132 | template 133 | AsmVariant( T&& val ) 134 | : AsmVariant( dataStruct, sizeof(T), reinterpret_cast(&val) ) 135 | { 136 | // Check if argument fits into register 137 | if (sizeof(T) <= sizeof(void*) && !std::is_class::value) 138 | { 139 | type = imm; 140 | imm_val = 0; 141 | memcpy( &imm_val, &val, sizeof(T) ); 142 | } 143 | } 144 | #pragma warning(default : 4127) 145 | 146 | // 147 | // Get floating point value as raw data 148 | // 149 | inline uint32_t getImm_float() const { return *(reinterpret_cast(&imm_float_val)); } 150 | inline uint64_t getImm_double() const { return *(reinterpret_cast(&imm_double_val)); } 151 | 152 | /// 153 | /// Check if argument can be passed in x86 register 154 | /// 155 | /// true if can 156 | inline bool reg86Compatible() const 157 | { 158 | if (type == dataStruct || type == imm_float || type == imm_double || type == structRet) 159 | return false; 160 | else 161 | return true; 162 | } 163 | 164 | private: 165 | // 166 | /// 167 | /// Generic ctor for major data types 168 | /// 169 | /// Argument type 170 | /// Argument size 171 | /// Immediate value 172 | AsmVariant( eType _type, size_t _size, size_t val ) 173 | : type( _type ) 174 | , size( _size ) 175 | , imm_val( val ) 176 | , new_imm_val( 0 ) { } 177 | 178 | public: 179 | eType type; // Variable type 180 | size_t size; // Variable size 181 | 182 | AsmJit::GPReg reg_val; // General purpose register 183 | AsmJit::Mem mem_val; // Memory pointer 184 | 185 | // Immediate values 186 | union 187 | { 188 | size_t imm_val; 189 | double imm_double_val; 190 | float imm_float_val; 191 | }; 192 | 193 | size_t new_imm_val; // Replaced immediate value for dataPtr type 194 | }; 195 | 196 | } -------------------------------------------------------------------------------- /src/BlackBone/RemoteFunction.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "AsmHelperBase.h" 4 | #include "Process.h" 5 | 6 | // TODO: Find more elegant way to deduce calling convention 7 | // than defining each one manually 8 | 9 | namespace blackbone 10 | { 11 | 12 | /// 13 | /// Base class for remote function pointer 14 | /// 15 | template< typename Fn > 16 | class RemoteFuncBase 17 | { 18 | protected: 19 | typedef Fn type; // Function pointer type 20 | 21 | protected: 22 | 23 | RemoteFuncBase( Process& proc, eCalligConvention conv ) 24 | : _callConv( conv ) 25 | , _process( proc ) 26 | , _pfn( nullptr ) { } 27 | 28 | RemoteFuncBase( Process& proc, type ptr, eCalligConvention conv ) 29 | : _callConv( conv ) 30 | , _process( proc ) 31 | , _pfn( ptr ) { } 32 | 33 | // conditional expression is constant 34 | #pragma warning(disable : 4127) 35 | 36 | /// 37 | /// Perform remote function call 38 | /// 39 | /// Function result 40 | /// Function arguments 41 | /// Execution thread 42 | /// Call status 43 | template 44 | NTSTATUS Call( T& result, std::vector& args, Thread* contextThread = nullptr ) 45 | { 46 | uint64_t result2 = 0; 47 | AsmJit::Assembler a; 48 | 49 | // Ensure RPC environment exists 50 | if (_process.remote().CreateRPCEnvironment() != STATUS_SUCCESS) 51 | return LastNtStatus(); 52 | 53 | // FPU check 54 | bool isFloat = std::is_same::value; 55 | bool isDouble = std::is_same::value || std::is_same::value; 56 | 57 | // Deduce return type 58 | eReturnType retType = rt_int32; 59 | 60 | if (isFloat) 61 | retType = rt_float; 62 | else if (isDouble) 63 | retType = rt_double; 64 | else if (sizeof(T) == sizeof(uint64_t)) 65 | retType = rt_int64; 66 | else if (!std::is_reference::value && sizeof(T) > sizeof(uint64_t)) 67 | retType = rt_struct; 68 | 69 | auto pfnNew = brutal_cast(_pfn); 70 | 71 | _process.remote().PrepareCallAssembly( a, pfnNew, args, _callConv, retType ); 72 | 73 | // Choose execution thread 74 | if (contextThread == nullptr) 75 | _process.remote().ExecInNewThread( a.make(), a.getCodeSize(), result2 ); 76 | else if (*contextThread == _process.remote()._hWorkThd) 77 | _process.remote().ExecInWorkerThread( a.make(), a.getCodeSize(), result2 ); 78 | else 79 | _process.remote().ExecInAnyThread( a.make(), a.getCodeSize(), result2, *contextThread ); 80 | 81 | // Get function return value 82 | _process.remote().GetCallResult( result ); 83 | 84 | return STATUS_SUCCESS; 85 | } 86 | 87 | #pragma warning(default : 4127) 88 | 89 | inline type ptr() const { return _pfn; } 90 | 91 | private: 92 | RemoteFuncBase( const RemoteFuncBase& ) = delete; 93 | RemoteFuncBase& operator =(const RemoteFuncBase&) = delete; 94 | 95 | private: 96 | eCalligConvention _callConv; // Calling convention 97 | type _pfn; // Function pointer 98 | Process& _process; // Underlying process 99 | }; 100 | 101 | // Function arguments 102 | template 103 | class FuncArguments 104 | { 105 | static const size_t arg_count = sizeof...(Args); 106 | 107 | public: 108 | 109 | // Get arguments. Either in variant form, or as declared type 110 | inline std::vector& getArgsRaw() const { return _args; } 111 | inline std::tuple& getArgs() const { return _targs; } 112 | 113 | // Get argument by index 114 | // Index is zero-based 115 | template 116 | auto getArg() -> decltype(std::get( _targs )) 117 | { 118 | return std::get( _targs ); 119 | } 120 | 121 | // Update any changes to arguments passed by reference or pointer 122 | void updateArgs() const 123 | { 124 | for (auto& arg : _args) 125 | if (arg.type == AsmVariant::dataPtr) 126 | _process.memory().Read( arg.new_imm_val, arg.size, (void*)arg.imm_val ); 127 | } 128 | 129 | // Manually set argument to custom value 130 | void setArg( int pos, const AsmVariant& newVal ) 131 | { 132 | if (_args.size() > (size_t)pos) 133 | _args[pos] = newVal; 134 | } 135 | 136 | protected: 137 | template 138 | FuncArguments( Process& proc, TArgs&&... args ) 139 | : _process( proc ) 140 | , _targs(args...) 141 | , _args( { static_cast(args)... } ) { } 142 | 143 | private: 144 | FuncArguments( const FuncArguments& ) = delete; 145 | FuncArguments& operator =(const FuncArguments&) = delete; 146 | 147 | private: 148 | mutable std::vector _args; // Generic arguments 149 | mutable std::tuple _targs; // Real arguments 150 | Process& _process; // Process routines 151 | }; 152 | 153 | // Remote function pointer 154 | template< typename Fn > 155 | class RemoteFunction; 156 | 157 | #define DECLPFN(CALL_OPT, CALL_DEF, ...) \ 158 | template<__VA_ARGS__ typename R, typename... Args > \ 159 | class RemoteFunction< R( CALL_OPT* )(Args...) > : public RemoteFuncBase, public FuncArguments \ 160 | { \ 161 | public: \ 162 | typedef typename std::conditional::value, int, R>::type ReturnType; \ 163 | \ 164 | public: \ 165 | template \ 166 | RemoteFunction( Process& proc, typename RemoteFuncBase::type ptr, TArgs&&... args ) \ 167 | : RemoteFuncBase( proc, ptr, CALL_DEF ) \ 168 | , FuncArguments( proc, static_cast(args)... ) { } \ 169 | \ 170 | inline DWORD Call( ReturnType& result, Thread* contextThread = nullptr ) \ 171 | { \ 172 | NTSTATUS status = RemoteFuncBase::Call( result, getArgsRaw(), contextThread ); \ 173 | FuncArguments::updateArgs( ); \ 174 | return status; \ 175 | } \ 176 | } 177 | 178 | // 179 | // Calling convention specialization 180 | // 181 | DECLPFN( __cdecl, cc_cdecl ); 182 | 183 | // Under AMD64 these will be same declarations as __cdecl, so compilation will fail. 184 | #ifdef _M_IX86 185 | DECLPFN( __stdcall, cc_stdcall ); 186 | DECLPFN( __thiscall, cc_thiscall ); 187 | DECLPFN( __fastcall, cc_fastcall ); 188 | #endif 189 | 190 | // Class member function 191 | template< class C, typename R, typename... Args > 192 | class RemoteFunction< R( C::* )(Args...) > : public RemoteFuncBase, public FuncArguments 193 | { 194 | public: 195 | typedef typename std::conditional::value, int, R>::type ReturnType; 196 | typedef typename ReturnType( C::*type )(Args...); 197 | 198 | public: 199 | RemoteFunction( Process& proc, type ptr ) 200 | : RemoteFuncBase( proc, ptr, cc_thiscall ) 201 | , FuncArguments( proc ) { } 202 | 203 | RemoteFunction( Process& proc, type ptr, const C* pClass, const Args&... args ) 204 | : RemoteFuncBase( proc, (typename RemoteFuncBase::type)ptr, cc_thiscall ) 205 | , FuncArguments( proc, pClass, args... ) { } 206 | 207 | inline DWORD Call( R& result, Thread* contextThread = nullptr ) 208 | { 209 | NTSTATUS status = RemoteFuncBase::Call( result, getArgsRaw(), contextThread ); 210 | FuncArguments::updateArgs(); 211 | return status; 212 | } 213 | }; 214 | 215 | } --------------------------------------------------------------------------------