#include "../Config.h" #include "ProcessModules.h" #include "Process.h" #include "RPC/RemoteExec.h" #include "../Misc/NameResolve.h" #include "../Misc/Utils.h" #include "../Symbols/SymbolData.h" #include "../Asm/AsmFactory.h" #include #include #ifdef COMPILER_MSVC #include #include #endif #include <3rd_party/VersionApi.h> namespace blackbone { ProcessModules::ProcessModules( class Process& proc ) : _proc( proc ) , _memory( _proc.memory() ) , _core( _proc.core() ) , _ldrPatched( false ) { } ProcessModules::~ProcessModules() { } /// /// Get module by name /// /// Module name /// Module type. 32 bit or 64 bit /// Saerch type. /// Module data. nullptr if not found ModuleDataPtr ProcessModules::GetModule( const std::wstring& name, eModSeachType search /*= LdrList*/, eModType type /*= mt_default*/ ) { std::wstring namecopy( Utils::StripPath( name ) ); return GetModule( namecopy, search, type ); } /// /// Get module by name /// /// Module name. /// Search type. /// Module type. 32 bit or 64 bit /// Import module name. Used only to resolve ApiSchema during manual map /// Module data. nullptr if not found ModuleDataPtr ProcessModules::GetModule( std::wstring& name, eModSeachType search /*= LdrList*/, eModType type /*= mt_default*/, const wchar_t* baseModule /*= L""*/ ) { NameResolve::Instance().ResolvePath( name, Utils::StripPath( baseModule ), L"", NameResolve::ApiSchemaOnly, _proc ); // Detect module type if (type == mt_default) type = _proc.barrier().targetWow64 ? mt_mod32 : mt_mod64; CSLock lck( _modGuard ); auto key = std::make_pair( name, type ); // Fast lookup if (_modules.count( key ) && (_modules[key]->manual || ValidateModule( _modules[key]->baseAddress ))) return _modules[key]; UpdateModuleCache( search, type ); if (_modules.count( key )) return _modules[key]; return nullptr; } /// /// Get module by base address /// /// Module base address /// If true modBase must exactly match module base address /// Search type. /// Module type. 32 bit or 64 bit /// Module data. nullptr if not found ModuleDataPtr ProcessModules::GetModule( module_t modBase, bool strict /*= true*/, eModSeachType search /*= LdrList*/, eModType type /*= mt_default */ ) { // Detect module type if (type == mt_default) type = _proc.barrier().targetWow64 ? mt_mod32 : mt_mod64; CSLock lck( _modGuard ); auto compFn = [modBase, strict]( const mapModules::value_type& val ) { if (strict) return (val.second->baseAddress == modBase); else return (modBase >= val.second->baseAddress && modBase < val.second->baseAddress + val.second->size); }; auto iter = std::find_if( _modules.begin(), _modules.end(), compFn ); if (iter != _modules.end()) return iter->second; UpdateModuleCache( search , type ); iter = std::find_if( _modules.begin(), _modules.end(), compFn ); if (iter != _modules.end()) return iter->second; else return nullptr; } /// /// Get process main module /// /// Module data. nullptr if not found ModuleDataPtr ProcessModules::GetMainModule() { if (_proc.barrier().x86OS) { _PEB32 peb = { 0 }; if (_proc.core().peb32( &peb ) == 0) return nullptr; return GetModule( peb.ImageBaseAddress ); } else { _PEB64 peb = { 0 }; if (_proc.core().peb64( &peb ) == 0) return nullptr; return GetModule( peb.ImageBaseAddress ); } } /// /// Enumerate all process modules /// /// Search method /// Module list const ProcessModules::mapModules& ProcessModules::GetAllModules( eModSeachType search /*= LdrList*/ ) { eModType mt = _core.isWow64() ? mt_mod32 : mt_mod64; CSLock lck( _modGuard ); // Remove non-manual modules for (auto iter = _modules.begin(); iter != _modules.end();) { if (!iter->second->manual) _modules.erase( iter++ ); else ++iter; } UpdateModuleCache( search, mt ); // Do additional search in case of loader lists // This, however won't search for 32 bit modules in native x64 process if (search == LdrList && mt == mt_mod32) UpdateModuleCache( search, mt_mod64 ); return _modules; } /// /// Get list of manually mapped modules /// /// List of modules ProcessModules::mapModules ProcessModules::GetManualModules() { ProcessModules::mapModules mods; std::copy_if( _modules.begin(), _modules.end(), std::inserter( mods, mods.end() ), []( const auto& mod ) { return mod.second->manual; } ); return mods; } /// /// Get export address. Forwarded exports will be automatically resolved if forward module is present /// /// Module to search in /// Function name or ordinal /// Import module name. Only used to resolve ApiSchema during manual map. /// Export info. If failed procAddress field is 0 call_result_t ProcessModules::GetExport( const ModuleDataPtr& hMod, const char* name_ord, const wchar_t* baseModule /*= L""*/ ) { return GetExport( *hMod, name_ord, baseModule ); } /// /// Get export address. Forwarded exports will be automatically resolved if forward module is present /// /// Module to search in /// Function name or ordinal /// Import module name. Only used to resolve ApiSchema during manual map. /// Export info. If failed procAddress field is 0 call_result_t ProcessModules::GetExport( const ModuleData& hMod, const char* name_ord, const wchar_t* baseModule /*= L"0"*/ ) { exportData data; // Invalid module if (hMod.baseAddress == 0) return STATUS_INVALID_PARAMETER_1; std::unique_ptr expData( nullptr, &free ); IMAGE_DOS_HEADER hdrDos = { 0 }; uint8_t hdrNt32[sizeof( IMAGE_NT_HEADERS64 )] = { 0 }; auto phdrNt32 = reinterpret_cast(hdrNt32); auto phdrNt64 = reinterpret_cast(hdrNt32); DWORD expSize = 0; uintptr_t expBase = 0; _memory.Read( hMod.baseAddress, sizeof( hdrDos ), &hdrDos ); if (hdrDos.e_magic != IMAGE_DOS_SIGNATURE) return STATUS_INVALID_IMAGE_NOT_MZ; _memory.Read( hMod.baseAddress + hdrDos.e_lfanew, sizeof( IMAGE_NT_HEADERS64 ), &hdrNt32 ); if (phdrNt32->Signature != IMAGE_NT_SIGNATURE) return STATUS_INVALID_IMAGE_FORMAT; if (phdrNt32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) expBase = phdrNt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; else expBase = phdrNt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; // Exports are present if (expBase) { if (phdrNt32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) expSize = phdrNt32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; else expSize = phdrNt64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; expData.reset( reinterpret_cast(malloc( expSize )) ); IMAGE_EXPORT_DIRECTORY* pExpData = expData.get(); if( auto status = _memory.Read( hMod.baseAddress + expBase, expSize, pExpData ); !NT_SUCCESS( status ) ) return status; // Fix invalid directory size if (expSize <= sizeof( IMAGE_EXPORT_DIRECTORY )) { // New size should take care of max number of present names (max name length is assumed to be 255 chars) expSize = static_cast( pExpData->AddressOfNameOrdinals - expBase + max( pExpData->NumberOfFunctions, pExpData->NumberOfNames ) * 255 ); expData.reset( reinterpret_cast(malloc( expSize )) ); pExpData = expData.get(); if (auto status = _memory.Read( hMod.baseAddress + expBase, expSize, pExpData ); !NT_SUCCESS( status )) return status; } WORD* pAddressOfOrds = reinterpret_cast( pExpData->AddressOfNameOrdinals + reinterpret_cast(pExpData) - expBase); DWORD* pAddressOfNames = reinterpret_cast( pExpData->AddressOfNames + reinterpret_cast(pExpData) - expBase); DWORD* pAddressOfFuncs = reinterpret_cast( pExpData->AddressOfFunctions + reinterpret_cast(pExpData) - expBase); for (DWORD i = 0; i < pExpData->NumberOfFunctions; ++i) { WORD OrdIndex = 0xFFFF; char *pName = nullptr; // Find by index if (reinterpret_cast(name_ord) <= 0xFFFF) { OrdIndex = static_cast(i); } // Find by name else if (reinterpret_cast(name_ord) > 0xFFFF && i < pExpData->NumberOfNames) { pName = (char*)(pAddressOfNames[i] + reinterpret_cast(pExpData) - expBase); OrdIndex = static_cast(pAddressOfOrds[i]); } else return STATUS_NOT_FOUND; if ((reinterpret_cast(name_ord) <= 0xFFFF && (WORD)((uintptr_t)name_ord) == (OrdIndex + pExpData->Base)) || (reinterpret_cast(name_ord) > 0xFFFF && strcmp( pName, name_ord ) == 0)) { data.procAddress = pAddressOfFuncs[OrdIndex] + hMod.baseAddress; // Check forwarded export if (data.procAddress >= hMod.baseAddress + expBase && data.procAddress <= hMod.baseAddress + expBase + expSize) { char forwardStr[255] = { 0 }; _memory.Read( data.procAddress, sizeof( forwardStr ), forwardStr ); std::string chainExp( forwardStr ); std::string strDll = chainExp.substr( 0, chainExp.find( "." ) ) + ".dll"; std::string strName = chainExp.substr( chainExp.find( "." ) + 1, strName.npos ); std::wstring wDll( Utils::AnsiToWstring( strDll ) ); // Fill export data info data.isForwarded = true; data.forwardModule = wDll; data.forwardByOrd = (strName.find( "#" ) == 0); if (data.forwardByOrd) data.forwardOrdinal = static_cast(atoi( strName.c_str() + 1 )); else data.forwardName = strName; // Check if forward mod is loaded auto mt = (phdrNt32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) ? mt_mod32 : mt_mod64; auto hChainMod = GetModule( wDll, LdrList, mt, baseModule ); if (hChainMod == nullptr) return call_result_t( data, STATUS_SOME_NOT_MAPPED ); // Import by ordinal if (data.forwardByOrd) return GetExport( hChainMod, reinterpret_cast(data.forwardOrdinal), wDll.c_str() ); // Import by name else return GetExport( hChainMod, strName.c_str(), wDll.c_str() ); } return data; } } } return STATUS_NOT_FOUND; } /// /// Get export address. Forwarded exports will be automatically resolved if forward module is present /// /// Module name to search in /// Function name or ordinal /// Export info. If failed procAddress field is 0 call_result_t ProcessModules::GetExport( const std::wstring& modName, const char* name_ord ) { return GetExport( GetModule( modName ), name_ord ); } /// /// Get export from ntdll /// /// Function name or ordinal /// Module type. 32 bit or 64 bit /// Search type. /// Export info. If failed procAddress field is 0 call_result_t ProcessModules::GetNtdllExport( const char* name_ord, eModType type /*= mt_default*/, eModSeachType search /*= LdrList */ ) { auto mod = GetModule( L"ntdll.dll", search, type ); if (!mod) return STATUS_NOT_FOUND; return GetExport( mod, name_ord ); } /// /// Inject image into target process /// /// Full-qualified image path /// Injection status code /// Module info. nullptr if failed call_result_t ProcessModules::Inject( const std::wstring& path, ThreadPtr pThread /*= nullptr*/ ) { NTSTATUS status = STATUS_SUCCESS; ModuleDataPtr mod; pe::PEImage img; uint32_t ustrSize = 0; ptr_t res = 0; img.Load( path, true ); img.Release(); // Already loaded if (mod = GetModule( path, LdrList, img.mType() )) return call_result_t( mod, STATUS_IMAGE_ALREADY_LOADED ); // Image path auto modName = _memory.Allocate( 0x1000, PAGE_READWRITE ); if (!modName) return modName.status; // Write dll name into target process auto fillDllName = [&modName, &path]( auto& ustr ) { ustr.Buffer = modName->ptr::type>() + sizeof( ustr ); ustr.MaximumLength = ustr.Length = static_cast(path.size() * sizeof( wchar_t )); modName->Write( 0, ustr ); modName->Write( sizeof( ustr ), path.size() * sizeof( wchar_t ), path.c_str() ); return static_cast(sizeof( ustr )); }; if (img.mType() == mt_mod32) { _UNICODE_STRING32 ustr = { 0 }; ustrSize = fillDllName( ustr ); } else if (img.mType() == mt_mod64) { _UNICODE_STRING64 ustr = { 0 }; ustrSize = fillDllName( ustr ); } else return STATUS_INVALID_IMAGE_FORMAT; // Image and process have same processor architecture bool sameArch = (img.mType() == mt_mod64 && _core.isWow64() == false) || (img.mType() == mt_mod32 && _core.isWow64() == true); auto pLoadLibrary = GetExport( GetModule( L"kernel32.dll", LdrList, img.mType() ), "LoadLibraryW" ); // Can't inject 32bit dll into native process if (!_proc.core().isWow64() && img.mType() == mt_mod32) return STATUS_INVALID_IMAGE_WIN_32; auto switchMode = NoSwitch; if (_proc.core().isWow64() && img.mType() == mt_mod64) switchMode = ForceSwitch; auto pLdrLoadDll = GetNtdllExport( "LdrLoadDll", img.mType(), Sections ); if (!pLdrLoadDll) return pLdrLoadDll.status; // Patch LdrFindOrMapDll to enable kernel32.dll loading if (switchMode == ForceSwitch && !_ldrPatched && IsWindows7OrGreater() && !IsWindows8OrGreater()) { uint8_t patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; auto patchBase = g_symbols.LdrKernel32PatchAddress; if (patchBase != 0) { DWORD flOld = 0; _memory.Protect( patchBase, sizeof( patch ), PAGE_EXECUTE_READWRITE, &flOld ); _memory.Write( patchBase, sizeof( patch ), patch ); _memory.Protect( patchBase, sizeof( patch ), flOld, nullptr ); } _ldrPatched = true; } auto a = AsmFactory::GetAssembler( img.mType() ); a->GenCall( pLdrLoadDll->procAddress, { 0, 0, modName->ptr(), modName->ptr() + 0x800 } ); (*a)->ret(); _proc.remote().CreateRPCEnvironment( Worker_None, true ); // Execute call if (pThread != nullptr) { if (pThread == _proc.remote().getWorker()) status = _proc.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), res ); else status = _proc.remote().ExecInAnyThread( (*a)->make(), (*a)->getCodeSize(), res, pThread ); if (NT_SUCCESS( status )) status = static_cast(res); } else { status = _proc.remote().ExecInNewThread( (*a)->make(), (*a)->getCodeSize(), res, switchMode ); if (NT_SUCCESS( status )) status = static_cast(res); } // Retry with LoadLibrary if possible if (!NT_SUCCESS(status) && pLoadLibrary && sameArch) { auto result = _proc.remote().ExecDirect( pLoadLibrary->procAddress, modName->ptr() + ustrSize ); if (result == 0) { return status; } } return GetModule( path, LdrList, img.mType() ); } /// /// Unload specific module from target process. Can't be used to unload manually mapped modules /// /// Module to unload /// true on success NTSTATUS ProcessModules::Unload( const ModuleDataPtr& hMod ) { // Module not present or is manually mapped if (hMod->manual || !ValidateModule( hMod->baseAddress )) return STATUS_NOT_FOUND; // Unload routine auto pUnload = GetNtdllExport( "LdrUnloadDll", hMod->type ); if (!pUnload) return pUnload.status; // Special case for unloading 64 bit modules from WOW64 process auto threadSwitch = NoSwitch; if (_proc.core().isWow64() && hMod->type == mt_mod64) threadSwitch = ForceSwitch; uint64_t res = 0; auto a = AsmFactory::GetAssembler( hMod->type ); a->GenCall( pUnload->procAddress, { hMod->baseAddress } ); (*a)->ret(); _proc.remote().ExecInNewThread( (*a)->make(), (*a)->getCodeSize(), res, threadSwitch ); // Remove module from cache _modules.erase( std::make_pair( hMod->name, hMod->type ) ); return true; } /// /// Unlink module from most loader structures /// /// Module to unlink /// true on success bool ProcessModules::Unlink( const ModuleDataPtr& mod ) { return _proc.nativeLdr().Unlink( *mod ); } bool ProcessModules::Unlink( const ModuleData& mod ) { return _proc.nativeLdr().Unlink( mod ); } /// /// Ensure module is a valid PE image /// /// Module base address /// true on success bool ProcessModules::ValidateModule( module_t base ) { IMAGE_DOS_HEADER idh = { 0 }; IMAGE_NT_HEADERS inth = { 0 }; // Validate memory and headers if (_memory.Read( base, sizeof(idh), &idh ) == STATUS_SUCCESS) if (idh.e_magic == IMAGE_DOS_SIGNATURE) if(_memory.Read( base + idh.e_lfanew, sizeof(inth), &inth ) == STATUS_SUCCESS) if (inth.Signature == IMAGE_NT_SIGNATURE) return true; return false; } /// /// Store manually mapped module in module list /// /// Module data /// Module info ModuleDataPtr ProcessModules::AddManualModule( const ModuleData& mod ) { auto canonicalized = Canonicalize( mod, true ); auto key = std::make_pair( canonicalized.name, canonicalized.type ); return _modules.emplace( key, std::make_shared( canonicalized ) ).first->second; } /// /// Canonicalize paths and set module type to manual if requested /// /// Module data /// Value to set ModuleData::manual to /// Module data ModuleData ProcessModules::Canonicalize( const ModuleData& mod, bool manual ) { ModuleData result = {}; result.baseAddress = mod.baseAddress; result.ldrPtr = mod.ldrPtr; result.size = mod.size; result.type = mod.type; result.fullPath = Utils::ToLower( mod.fullPath ); result.name = Utils::ToLower( mod.name ); result.manual = manual; return result; } /// /// Remove module from module list /// /// Module file name /// Module type. 32 bit or 64 bit void ProcessModules::RemoveManualModule( const std::wstring& filename, eModType mt ) { auto key = std::make_pair( Utils::ToLower( Utils::StripPath( filename ) ), mt ); if (_modules.count( key )) _modules.erase( key ); } void ProcessModules::UpdateModuleCache( eModSeachType search, eModType type ) { for (const auto& mod : _core.native()->EnumModules( search, type )) _modules.emplace( std::make_pair( mod->name, mod->type ), mod ); } using namespace asmjit; using namespace asmjit::host; #ifdef COMPILER_MSVC /// /// Inject pure IL image. /// /// NET runtime version to use /// Path to image /// Method to call /// Arguments passed into method /// Return code /// true on success bool ProcessModules::InjectPureIL( const std::wstring& netVersion, const std::wstring& netAssemblyPath, const std::wstring& netAssemblyMethod, const std::wstring& netAssemblyArgs, DWORD& returnCode ) { // split netAssemblyMethod string into class and method names size_t idx = netAssemblyMethod.find_last_of( '.' ); if (idx == std::wstring::npos) return false; std::wstring MethodName = netAssemblyMethod.substr( idx + 1 ); std::wstring tmp = netAssemblyMethod; tmp.erase( idx ); std::wstring ClassName = tmp; auto mem = _memory.Allocate( 0x10000 ); if (!mem) { returnCode = 7; return false; } auto address = std::move( mem.result() ); uintptr_t offset = 4; uintptr_t address_VersionString, address_netAssemblyDll, address_netAssemblyClass, address_netAssemblyMethod, address_netAssemblyArgs; const std::wstring* strArr[] = { &netVersion, &netAssemblyPath, &ClassName, &MethodName, &netAssemblyArgs }; uintptr_t* ofstArr[] = { &address_VersionString, &address_netAssemblyDll, &address_netAssemblyClass, &address_netAssemblyMethod, &address_netAssemblyArgs }; // Write strings for (int i = 0; i < ARRAYSIZE( strArr ); i++) { size_t len = strArr[i]->length(); *(ofstArr[i]) = address.ptr() + offset; // runtime version to use if (address.Write( offset, len * sizeof(wchar_t) + 2, strArr[i]->c_str( ) ) != STATUS_SUCCESS) { returnCode = 5; return false; } offset = Align( offset + len * sizeof( wchar_t ) + 2, sizeof( uint64_t ) ); } offset += 4; GUID GArray[] = { CLSID_CLRMetaHost, IID_ICLRMetaHost, IID_ICLRRuntimeInfo, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost }; // COM object GUIDs if (address.Write( offset, sizeof(GArray), GArray ) != STATUS_SUCCESS) { returnCode = 10; return false; } uintptr_t address_CLSID_CLRMetaHost = address.ptr() + offset + 0; uintptr_t address_IID_ICLRMetaHost = address.ptr() + offset + 0x10; uintptr_t address_IID_ICLRRuntimeInfo = address.ptr() + offset + 0x20; uintptr_t address_CLSID_CLRRuntimeHost = address.ptr() + offset + 0x30; uintptr_t address_IID_ICLRRuntimeHost = address.ptr() + offset + 0x40; offset += sizeof(GArray); std::wstring libName = L"mscoree.dll"; NameResolve::Instance().ResolvePath( libName, L"", L"", NameResolve::EnsureFullPath, _proc ); auto pMscoree = Inject( libName ); if(!pMscoree) { returnCode = pMscoree.status; return false; } // CLRCreateInstance address auto pfnCreateInstance = GetExport( pMscoree.result(), "CLRCreateInstance" ); if (!pfnCreateInstance) return false; // Scary assembler code incoming! auto pAsm = AsmFactory::GetAssembler( _proc.core().isWow64() ); auto& a = *pAsm; AsmStackAllocator sa( a.assembler(), 0x30 ); // 0x30 - 6 arguments of ExecuteInDefaultAppDomain // Stack will be reserved manually a.EnableX64CallStack( false ); Label L_Exit = a->newLabel(); Label L_Error1 = a->newLabel(); Label L_Error2 = a->newLabel(); Label L_Error3 = a->newLabel(); Label L_Error4 = a->newLabel(); Label L_Error5 = a->newLabel(); Label L_Error6 = a->newLabel(); Label L_SkipStart = a->newLabel(); Label L_ReleaseInterface = a->newLabel(); // stack variables for the injected code ALLOC_STACK_VAR( sa, stack_MetaHost, ICLRMetaHost* ); ALLOC_STACK_VAR( sa, stack_RuntimeInfo, ICLRRuntimeInfo* ); ALLOC_STACK_VAR( sa, stack_RuntimeHost, ICLRRuntimeHost* ); ALLOC_STACK_VAR( sa, stack_IsStarted, BOOL ); ALLOC_STACK_VAR( sa, stack_StartupFlags, DWORD ); ALLOC_STACK_VAR( sa, stack_returnCode, HRESULT ); #ifdef USE64 GpReg callReg = r13; #else GpReg callReg = edx; a->push( a->zbp ); a->mov( a->zbp, a->zsp ); #endif // function prologue a->sub( a->zsp, Align( sa.getTotalSize(), 0x10 ) + 8 ); a->xor_( a->zsi, a->zsi ); // CLRCreateInstance() a.GenCall( (uintptr_t)pfnCreateInstance->procAddress, { address_CLSID_CLRMetaHost, address_IID_ICLRMetaHost, &stack_MetaHost } ); // success? a->test( a->zax, a->zax ); a->jnz( L_Error1 ); // pMetaHost->GetRuntime() a->mov( a->zax, stack_MetaHost ); a->mov( a->zcx, a->intptr_ptr( a->zax ) ); a->mov( callReg, a->intptr_ptr( a->zcx, 3 * sizeof( void* ) ) ); a.GenCall( callReg, { a->zcx, address_VersionString, address_IID_ICLRRuntimeInfo, &stack_RuntimeInfo } ); // success? a->test( a->zax, a->zax ); a->jnz( L_Error2 ); // pRuntimeInterface->IsStarted() a->mov( a->zcx, stack_RuntimeInfo ); a->mov( a->zax, a->intptr_ptr( a->zcx ) ); a->mov( callReg, a->intptr_ptr( a->zax, 14 * sizeof( void* ) ) ); a.GenCall( callReg, { a->zcx, &stack_IsStarted, &stack_StartupFlags } ); // success? a->test( a->zax, a->zax ); a->jnz( L_Error3 ); // pRuntimeTime->GetInterface() a->mov( a->zcx, stack_RuntimeInfo ); a->mov( a->zax, a->intptr_ptr( a->zcx ) ); a->mov( callReg, a->intptr_ptr( a->zax, 9 * sizeof( void* ) ) ); a.GenCall( callReg, { a->zcx, address_CLSID_CLRRuntimeHost, address_IID_ICLRRuntimeHost, &stack_RuntimeHost } ); // success? a->test( a->zax, a->zax ); a->jnz( L_Error3 ); // jump if already started a->cmp( stack_IsStarted, a->zsi ); a->jne( L_SkipStart ); // pRuntimeHost->Start() a->mov( a->zcx, stack_RuntimeHost ); a->mov( a->zax, a->intptr_ptr( a->zcx ) ); a->mov( callReg, a->intptr_ptr( a->zax, 3 * sizeof( void* ) ) ); a.GenCall( callReg, { a->zcx } ); // success? a->test( a->zax, a->zax ); a->jnz( L_Error5 ); // pRuntimeHost->ExecuteInDefaultAppDomain() a->bind( L_SkipStart ); a->mov( a->zcx, stack_RuntimeHost ); a->mov( a->zax, a->intptr_ptr( a->zcx ) ); a->mov( callReg, a->intptr_ptr( a->zax, 11 * sizeof( void* ) ) ); a.GenCall( callReg, { a->zcx, address_netAssemblyDll, address_netAssemblyClass, address_netAssemblyMethod, address_netAssemblyArgs, &stack_returnCode } ); // success? a->test( a->zax, a->zax ); a->jnz( L_Error6 ); // Release unneeded interfaces a->mov( a->zcx, stack_RuntimeHost ); a->call( L_ReleaseInterface ); a->mov( a->zcx, stack_RuntimeInfo ); a->call( L_ReleaseInterface ); a->mov( a->zcx, stack_MetaHost ); a->call( L_ReleaseInterface ); // Write the managed code's return value to the first DWORD // in the allocated buffer a->mov( eax, stack_returnCode ); a->mov( a->zdx, address.ptr() ); a->mov( dword_ptr( a->zdx ), eax ); a->mov( a->zax, 0 ); // stack restoration a->bind( L_Exit ); #ifdef USE64 a->add( a->zsp, Align( sa.getTotalSize(), 0x10 ) + 8 ); #else a->mov( a->zsp, a->zbp ); a->pop( a->zbp ); #endif a->ret(); // CLRCreateInstance() failed a->bind( L_Error1 ); a->mov( a->zax, 1 ); a->jmp( L_Exit ); // pMetaHost->GetRuntime() failed a->bind( L_Error2 ); a->mov( a->zcx, stack_MetaHost ); a->call( L_ReleaseInterface ); a->mov( a->zax, 2 ); a->jmp( L_Exit ); // pRuntimeInterface->IsStarted() failed a->bind( L_Error3 ); a->mov( a->zcx, stack_RuntimeInfo ); a->call( L_ReleaseInterface ); a->mov( a->zcx, stack_MetaHost ); a->call( L_ReleaseInterface ); a->mov( a->zax, 3 ); a->jmp( L_Exit ); // pRuntimeTime->GetInterface() failed a->bind( L_Error4 ); a->mov( a->zcx, stack_RuntimeInfo ); a->call( L_ReleaseInterface ); a->mov( a->zcx, stack_MetaHost ); a->call( L_ReleaseInterface ); a->mov( a->zax, 4 ); a->jmp( L_Exit ); // pRuntimeHost->Start() failed a->bind( L_Error5 ); a->mov( a->zcx, stack_RuntimeHost ); a->call( L_ReleaseInterface ); a->mov( a->zcx, stack_RuntimeInfo ); a->call( L_ReleaseInterface ); a->mov( a->zcx, stack_MetaHost ); a->call( L_ReleaseInterface ); a->mov( a->zax, 5 ); a->jmp( L_Exit ); // pRuntimeHost->ExecuteInDefaultAppDomain() failed a->bind( L_Error6 ); a->push( a->zax ); a->mov( a->zcx, stack_RuntimeHost ); a->call( L_ReleaseInterface ); a->mov( a->zcx, stack_RuntimeInfo ); a->call( L_ReleaseInterface ); a->mov( a->zcx, stack_MetaHost ); a->call( L_ReleaseInterface ); a->mov( a->zax, 6 ); a->pop( a->zax ); a->jmp( L_Exit ); // void __fastcall ReleaseInterface(IUnknown* pInterface) a->bind( L_ReleaseInterface ); a->mov( a->zax, a->zcx ); a->mov( a->zcx, a->intptr_ptr( a->zax ) ); a->mov( callReg, a->intptr_ptr( a->zcx, 2 * sizeof( void* ) ) ); a.GenCall( callReg, { a->zax } ); a->ret(); // write JIT code to target size_t codeSize = a->getCodeSize(); ptr_t codeAddress = address.ptr() + offset; std::vector codeBuffer( codeSize ); a->setBaseAddress( codeAddress ); a->relocCode( codeBuffer.data() ); if (address.Write( offset, codeSize, codeBuffer.data() ) != STATUS_SUCCESS) { returnCode = 17; return false; } // run ze codez _proc.remote().ExecDirect( (ptr_t)codeAddress, 0 ); // Get the managed return value address.Read( 0, 4, &returnCode ); return true; } #endif // COMPILER_MSVC /// /// Reset local data /// void ProcessModules::reset() { CSLock lck( _modGuard ); _modules.clear(); _ldrPatched = false; } }