diff --git a/src/BlackBone/Asm/AsmHelper32.cpp b/src/BlackBone/Asm/AsmHelper32.cpp index df8be49..3663dfc 100644 --- a/src/BlackBone/Asm/AsmHelper32.cpp +++ b/src/BlackBone/Asm/AsmHelper32.cpp @@ -170,7 +170,7 @@ void AsmHelper32::SaveRetValAndSignalEvent( // Save last NT status _assembler.mov( asmjit::host::edx, asmjit::host::dword_ptr_abs( 0x18 ).setSegment( asmjit::host::fs ) ); - _assembler.add( asmjit::host::edx, LAST_STATUS_OFS ); + _assembler.add( asmjit::host::edx, 0x598 + 0x197 * sizeof( uint32_t ) ); _assembler.mov( asmjit::host::edx, asmjit::host::dword_ptr( asmjit::host::edx ) ); _assembler.mov( asmjit::host::eax, errPtr ); _assembler.mov( asmjit::host::dword_ptr( asmjit::host::eax ), asmjit::host::edx ); diff --git a/src/BlackBone/Asm/AsmHelper64.cpp b/src/BlackBone/Asm/AsmHelper64.cpp index 603f491..7d73a8b 100644 --- a/src/BlackBone/Asm/AsmHelper64.cpp +++ b/src/BlackBone/Asm/AsmHelper64.cpp @@ -146,7 +146,7 @@ void AsmHelper64::SaveRetValAndSignalEvent( // Save last NT status _assembler.mov( asmjit::host::rdx, asmjit::host::dword_ptr_abs( 0x30 ).setSegment( asmjit::host::gs ) ); // TEB ptr - _assembler.add( asmjit::host::rdx, LAST_STATUS_OFS ); + _assembler.add( asmjit::host::rdx, 0x598 + 0x197 * sizeof( uint64_t ) ); _assembler.mov( asmjit::host::rdx, asmjit::host::dword_ptr( asmjit::host::rdx ) ); _assembler.mov( asmjit::host::rax, lastStatusPtr ); _assembler.mov( asmjit::host::dword_ptr( asmjit::host::rax ), asmjit::host::rdx ); diff --git a/src/BlackBone/Include/Macro.h b/src/BlackBone/Include/Macro.h index 6dae4a6..1d4fc12 100644 --- a/src/BlackBone/Include/Macro.h +++ b/src/BlackBone/Include/Macro.h @@ -1,5 +1,6 @@ #pragma once #include "../Config.h" +#include // Architecture-dependent pointer size #define WordSize sizeof(void*) @@ -71,6 +72,18 @@ template struct CompileTimeSizeOf; +template +constexpr size_t offsetOf( U T::*member ) +{ + return (size_t)&((T*)nullptr->*member); +} + +template +constexpr uint64_t fieldPtr( uint64_t base, U T::*member ) +{ + return base + offsetOf( member ); +} + // Type-unsafe cast. template inline _Tgt brutal_cast( const _Src& src ) @@ -110,3 +123,5 @@ inline NTSTATUS SetLastNtStatus( NTSTATUS status ) { return *(NTSTATUS*)((unsigned char*)NtCurrentTeb() + LAST_STATUS_OFS) = status; } + +#define SharedUserData32 ((KUSER_SHARED_DATA* const)0x7FFE0000) diff --git a/src/BlackBone/Include/NativeStructures.h b/src/BlackBone/Include/NativeStructures.h index 8a633d4..60591bf 100644 --- a/src/BlackBone/Include/NativeStructures.h +++ b/src/BlackBone/Include/NativeStructures.h @@ -445,6 +445,17 @@ namespace blackbone ULONG NonPagedPoolUsage; }; + template + struct _OBJECT_ATTRIBUTES_T + { + ULONG Length; + T RootDirectory; + T ObjectName; + ULONG Attributes; + T SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR + T SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE + }; + struct _XSAVE_FORMAT64 { WORD ControlWord; @@ -679,37 +690,47 @@ namespace blackbone T PatchInformation; }; - typedef struct _RTL_INVERTED_FUNCTION_TABLE_ENTRY + template + struct _RTL_INVERTED_FUNCTION_TABLE_ENTRY { - PIMAGE_RUNTIME_FUNCTION_ENTRY ExceptionDirectory; - PVOID ImageBase; + T ExceptionDirectory; // PIMAGE_RUNTIME_FUNCTION_ENTRY + T ImageBase; ULONG ImageSize; ULONG SizeOfTable; - } RTL_INVERTED_FUNCTION_TABLE_ENTRY, *PRTL_INVERTED_FUNCTION_TABLE_ENTRY; + }; + typedef _UNICODE_STRING_T _UNICODE_STRING32; + typedef _UNICODE_STRING_T _UNICODE_STRING64; + typedef _UNICODE_STRING_T UNICODE_STRING_T; - typedef _PEB_T _PEB32; - typedef _PEB_T _PEB64; + typedef _PEB_T _PEB32; + typedef _PEB_T _PEB64; - typedef _TEB_T _TEB32; - typedef _TEB_T _TEB64; - typedef _TEB_T TEB_T; +#ifdef USE64 + typedef _PEB64 PEB_T; +#else + typedef _PEB32 PEB_T; +#endif - typedef _PEB_LDR_DATA2 _PEB_LDR_DATA232; - typedef _PEB_LDR_DATA2 _PEB_LDR_DATA264; - typedef _PEB_LDR_DATA2 PEB_LDR_DATA_T; + typedef _TEB_T _TEB32; + typedef _TEB_T _TEB64; + typedef _TEB_T TEB_T; - typedef _LDR_DATA_TABLE_ENTRY_BASE _LDR_DATA_TABLE_ENTRY_BASE32; - typedef _LDR_DATA_TABLE_ENTRY_BASE _LDR_DATA_TABLE_ENTRY_BASE64; - typedef _LDR_DATA_TABLE_ENTRY_BASE LDR_DATA_TABLE_ENTRY_BASE_T; + typedef _PEB_LDR_DATA2 _PEB_LDR_DATA232; + typedef _PEB_LDR_DATA2 _PEB_LDR_DATA264; + typedef _PEB_LDR_DATA2 PEB_LDR_DATA_T; - typedef _CONTEXT_T _CONTEXT32; - typedef _CONTEXT_T _CONTEXT64; - typedef _CONTEXT_T CONTEXT_T; + typedef _LDR_DATA_TABLE_ENTRY_BASE _LDR_DATA_TABLE_ENTRY_BASE32; + typedef _LDR_DATA_TABLE_ENTRY_BASE _LDR_DATA_TABLE_ENTRY_BASE64; + typedef _LDR_DATA_TABLE_ENTRY_BASE LDR_DATA_TABLE_ENTRY_BASE_T; + + typedef _CONTEXT_T _CONTEXT32; + typedef _CONTEXT_T _CONTEXT64; + typedef _CONTEXT_T CONTEXT_T; typedef _SECTION_BASIC_INFORMATION_T _SECTION_BASIC_INFORMATION32; typedef _SECTION_BASIC_INFORMATION_T _SECTION_BASIC_INFORMATION64; - typedef _SECTION_BASIC_INFORMATION_T SECTION_BASIC_INFORMATION_T; + typedef _SECTION_BASIC_INFORMATION_T SECTION_BASIC_INFORMATION_T; typedef _SYSTEM_HANDLE_INFORMATION_T _SYSTEM_HANDLE_INFORMATION32; typedef _SYSTEM_HANDLE_INFORMATION_T _SYSTEM_HANDLE_INFORMATION64; @@ -719,11 +740,13 @@ namespace blackbone typedef _OBJECT_TYPE_INFORMATION_T _OBJECT_TYPE_INFORMATION64; typedef _OBJECT_TYPE_INFORMATION_T OBJECT_TYPE_INFORMATION_T; -#ifdef USE64 - typedef _PEB64 PEB_T; -#else - typedef _PEB32 PEB_T; -#endif + typedef _OBJECT_ATTRIBUTES_T _OBJECT_ATTRIBUTES32; + typedef _OBJECT_ATTRIBUTES_T _OBJECT_ATTRIBUTES64; + typedef _OBJECT_ATTRIBUTES_T OBJECT_ATTRIBUTES_T; + + typedef _ACTCTXW_T _ACTCTXW32; + typedef _ACTCTXW_T _ACTCTXW64; + typedef _ACTCTXW_T ACTCTXW_T; } #include "ApiSet.h" diff --git a/src/BlackBone/Include/Win7Specific.h b/src/BlackBone/Include/Win7Specific.h index 549d658..1b35813 100644 --- a/src/BlackBone/Include/Win7Specific.h +++ b/src/BlackBone/Include/Win7Specific.h @@ -16,14 +16,14 @@ namespace blackbone _LARGE_INTEGER LoadTime; }; - typedef struct _RTL_INVERTED_FUNCTION_TABLE7 + template + struct _RTL_INVERTED_FUNCTION_TABLE7 { ULONG Count; ULONG MaxCount; ULONG Epoch; - RTL_INVERTED_FUNCTION_TABLE_ENTRY Entries[0x200]; - - } RTL_INVERTED_FUNCTION_TABLE7, *PRTL_INVERTED_FUNCTION_TABLE7; + _RTL_INVERTED_FUNCTION_TABLE_ENTRY Entries[0x200]; + }; #pragma warning(default : 4201) } \ No newline at end of file diff --git a/src/BlackBone/Include/Win8Specific.h b/src/BlackBone/Include/Win8Specific.h index 23efbe3..a5f41ea 100644 --- a/src/BlackBone/Include/Win8Specific.h +++ b/src/BlackBone/Include/Win8Specific.h @@ -72,15 +72,15 @@ namespace blackbone unsigned long ImplicitPathOptions; }; - typedef struct _RTL_INVERTED_FUNCTION_TABLE8 + template + struct _RTL_INVERTED_FUNCTION_TABLE8 { ULONG Count; ULONG MaxCount; ULONG Epoch; UCHAR Overflow; - RTL_INVERTED_FUNCTION_TABLE_ENTRY Entries[0x200]; - - } RTL_INVERTED_FUNCTION_TABLE8, *PRTL_INVERTED_FUNCTION_TABLE8; + _RTL_INVERTED_FUNCTION_TABLE_ENTRY Entries[0x200]; + }; #pragma warning(default : 4201) } \ No newline at end of file diff --git a/src/BlackBone/ManualMap/MExcept.cpp b/src/BlackBone/ManualMap/MExcept.cpp index 0cbe314..051b1b1 100644 --- a/src/BlackBone/ManualMap/MExcept.cpp +++ b/src/BlackBone/ManualMap/MExcept.cpp @@ -2,6 +2,7 @@ #include "../Process/Process.h" #include "../Include/Macro.h" #include "../Misc/Trace.hpp" +#include "../Misc/PattrernLoader.h" #include "../Asm/LDasm.h" namespace blackbone @@ -217,7 +218,7 @@ MExcept::~MExcept() /// Mosule type /// Partial exception support /// Error code -NTSTATUS MExcept::CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType mt, bool partial ) +NTSTATUS MExcept::CreateVEH( ptr_t pTargetBase, size_t imageSize, eModType mt, bool partial ) { auto a = AsmFactory::GetAssembler( mt ); uint64_t result = 0; @@ -304,7 +305,7 @@ NTSTATUS MExcept::CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType m // LdrpInvertedFunctionTable if (*(uint32_t*)pData == 0xDEADDA7A) { - *(uint32_t*)pData = static_cast(_proc.nativeLdr().LdrpInvertedFunctionTable()); + *(uint32_t*)pData = static_cast(g_PatternLoader->data().LdrpInvertedFunctionTable32); continue; } @@ -318,7 +319,7 @@ NTSTATUS MExcept::CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType m // LdrProtectMrdata address if (*(uint32_t*)pData == 0xDEADC0D2) { - *(uint32_t*)pData = static_cast(_proc.nativeLdr().LdrProtectMrdata()); + *(uint32_t*)pData = static_cast(g_PatternLoader->data().LdrProtectMrdata); continue; } } @@ -344,10 +345,17 @@ NTSTATUS MExcept::CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType m _proc.remote().AddReturnWithEvent( *a, mt ); a->GenEpilogue(); - _proc.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result ); - _hVEH = result; - - return (_hVEH == 0 ? STATUS_NOT_FOUND : STATUS_SUCCESS); + NTSTATUS status = _proc.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result ); + if (result != 0) + { + _hVEH = result; + return STATUS_SUCCESS; + } + else + { + status = _proc.remote().GetLastStatus(); + return status; + } } /// diff --git a/src/BlackBone/ManualMap/MExcept.h b/src/BlackBone/ManualMap/MExcept.h index a3cfd4d..3f688f7 100644 --- a/src/BlackBone/ManualMap/MExcept.h +++ b/src/BlackBone/ManualMap/MExcept.h @@ -43,7 +43,7 @@ protected: /// Mosule type /// Partial exception support /// Error code - BLACKBONE_API NTSTATUS CreateVEH( uintptr_t pTargetBase, size_t imageSize, eModType mt, bool partial ); + BLACKBONE_API NTSTATUS CreateVEH( ptr_t pTargetBase, size_t imageSize, eModType mt, bool partial ); /// /// Removes VEH from target process diff --git a/src/BlackBone/ManualMap/MMap.cpp b/src/BlackBone/ManualMap/MMap.cpp index f29d608..713007d 100644 --- a/src/BlackBone/ManualMap/MMap.cpp +++ b/src/BlackBone/ManualMap/MMap.cpp @@ -362,7 +362,7 @@ call_result_t MMap::FindOrMapModule( ldrEntry.baseAddress = pImage->imgMem.ptr(); ldrEntry.size = pImage->peImage.imageSize(); - BLACKBONE_TRACE( L"ManualMap: Image base allocated at 0x%p", pImage->imgMem.ptr() ); + BLACKBONE_TRACE( L"ManualMap: Image base allocated at 0x%016x", pImage->imgMem.ptr() ); // Create Activation context for SxS if (pImage->peImage.manifestID() == 0) @@ -661,7 +661,7 @@ NTSTATUS MMap::RelocateImage( ImageContext* pImage ) BLACKBONE_TRACE( L"ManualMap: Relocating image '%ls'", pImage->ldrEntry.fullPath.c_str() ); // Reloc delta - uintptr_t Delta = pImage->imgMem.ptr() - static_cast(pImage->peImage.imageBase()); + ptr_t Delta = pImage->imgMem.ptr() - pImage->peImage.imageBase(); // No need to relocate if (Delta == 0) @@ -681,6 +681,10 @@ NTSTATUS MMap::RelocateImage( ImageContext* pImage ) return STATUS_INVALID_IMAGE_FORMAT; } + size_t size = sizeof( ptr_t ); + if (pImage->ldrEntry.type == mt_mod32) + size = sizeof( uint32_t ); + while ((uintptr_t)fixrec < end && fixrec->BlockSize) { DWORD count = (fixrec->BlockSize - 8) >> 1; // records count @@ -698,14 +702,15 @@ NTSTATUS MMap::RelocateImage( ImageContext* pImage ) if (fixtype == IMAGE_REL_BASED_HIGHLOW || fixtype == IMAGE_REL_BASED_DIR64) { uintptr_t fixRVA = fixoffset + fixrec->PageRVA; - uintptr_t val = *reinterpret_cast(pImage->peImage.ResolveRVAToVA( fixoffset + fixrec->PageRVA )) + Delta; + ptr_t val = pImage->peImage.ResolveRVAToVA( fixoffset + fixrec->PageRVA ); + val = pImage->ldrEntry.type == mt_mod64 ? *reinterpret_cast(val) : *reinterpret_cast(val); + val += Delta; auto status = STATUS_SUCCESS; - if (pImage->flags & HideVAD) - status = Driver().WriteMem( _process.pid(), pImage->imgMem.ptr() + fixRVA, sizeof( val ), &val ); + status = Driver().WriteMem( _process.pid(), pImage->imgMem.ptr() + fixRVA, size, &val ); else - status = pImage->imgMem.Write( fixRVA, val ); + status = pImage->imgMem.Write( fixRVA, size, &val ); // Apply relocation if (!NT_SUCCESS( status )) @@ -744,11 +749,17 @@ call_result_t MMap::FindOrMapDependency( ImageContext* pImage, st BLACKBONE_TRACE( L"ManualMap: Loading new dependency '%ls'", path.c_str() ); + auto flags = NameResolve::EnsureFullPath; + + // Wow64 fs redirection + if (pImage->ldrEntry.type == mt_mod32 && !_process.barrier().sourceWow64) + flags = static_cast(static_cast(flags) | NameResolve::Wow64); + auto basedir = pImage->peImage.noPhysFile() ? Utils::GetExeDirectory() : Utils::GetParent( pImage->ldrEntry.fullPath ); auto status = NameResolve::Instance().ResolvePath( - path, pImage->ldrEntry.name, - basedir, - NameResolve::EnsureFullPath, + path, + pImage->ldrEntry.name, + basedir, flags, _process.pid(), pImage->peImage.actx() ); @@ -803,6 +814,10 @@ NTSTATUS MMap::ResolveImport( ImageContext* pImage, bool useDelayed /*= false */ if (imports.empty()) return STATUS_SUCCESS; + auto entrySize = sizeof( uint32_t ); + if (pImage->ldrEntry.type == mt_mod64) + entrySize = sizeof( uint64_t ); + // Traverse entries for (auto& importMod : imports) { @@ -864,12 +879,9 @@ NTSTATUS MMap::ResolveImport( ImageContext* pImage, bool useDelayed /*= false */ auto status = STATUS_SUCCESS; if (pImage->flags & HideVAD) - { - uintptr_t address = static_cast(expData->procAddress); - status = Driver().WriteMem( _process.pid(), pImage->imgMem.ptr() + importFn.ptrRVA, sizeof( address ), &address ); - } + status = Driver().WriteMem( _process.pid(), pImage->imgMem.ptr() + importFn.ptrRVA, entrySize, &expData->procAddress ); else - status = pImage->imgMem.Write( importFn.ptrRVA, static_cast(expData->procAddress) ); + status = pImage->imgMem.Write( importFn.ptrRVA, entrySize, &expData->procAddress ); // Write function address if (!NT_SUCCESS( status )) @@ -1012,44 +1024,54 @@ NTSTATUS MMap::InitStaticTLS( ImageContext* pImage ) /// Status code NTSTATUS MMap::InitializeCookie( ImageContext* pImage ) { - auto pLoadConfig = reinterpret_cast(pImage->peImage.DirectoryAddress( IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG )); + auto pLoadConfig32 = reinterpret_cast(pImage->peImage.DirectoryAddress( IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG )); + auto pLoadConfig64 = reinterpret_cast(pLoadConfig32); + + ptr_t pCookie = pLoadConfig32->SecurityCookie; + if (pImage->ldrEntry.type == mt_mod64) + pCookie = pLoadConfig64->SecurityCookie; // // Cookie generation based on MSVC++ compiler // - if (pLoadConfig && pLoadConfig->SecurityCookie) + if (pLoadConfig32 && pCookie) { BLACKBONE_TRACE( L"ManualMap: Performing security cookie initializtion for image '%ls'", pImage->ldrEntry.name.c_str() ); FILETIME systime = { 0 }; LARGE_INTEGER PerformanceCount = { { 0 } }; - uintptr_t cookie = 0; + size_t size = sizeof( uint32_t ); GetSystemTimeAsFileTime( &systime ); QueryPerformanceCounter( &PerformanceCount ); - cookie = _process.pid() ^ _process.remote().getWorker()->id() ^ reinterpret_cast(&cookie); + ptr_t cookie = _process.pid() ^ _process.remote().getWorker()->id() ^ reinterpret_cast(&cookie); - #ifdef USE64 - cookie ^= *reinterpret_cast(&systime); - cookie ^= (PerformanceCount.QuadPart << 32) ^ PerformanceCount.QuadPart; - cookie &= 0xFFFFFFFFFFFF; + if (pImage->ldrEntry.type == mt_mod64) + { + size = sizeof( uint64_t ); - if (cookie == 0x2B992DDFA232) - cookie++; - #else + cookie ^= *reinterpret_cast(&systime); + cookie ^= (PerformanceCount.QuadPart << 32) ^ PerformanceCount.QuadPart; + cookie &= 0xFFFFFFFFFFFF; - cookie ^= systime.dwHighDateTime ^ systime.dwLowDateTime; - cookie ^= PerformanceCount.LowPart; - cookie ^= PerformanceCount.HighPart; + if (cookie == 0x2B992DDFA232) + cookie++; + } + else + { + cookie &= 0xFFFFFFFF; + cookie ^= systime.dwHighDateTime ^ systime.dwLowDateTime; + cookie ^= PerformanceCount.LowPart; + cookie ^= PerformanceCount.HighPart; - if (cookie == 0xBB40E64E) - cookie++; - else if (!(cookie & 0xFFFF0000)) - cookie |= (cookie | 0x4711) << 16; - #endif + if (cookie == 0xBB40E64E) + cookie++; + else if (!(cookie & 0xFFFF0000)) + cookie |= (cookie | 0x4711) << 16; + } - return _process.memory().Write( REBASE( pLoadConfig->SecurityCookie, pImage->peImage.imageBase(), pImage->imgMem.ptr() ), cookie ); + return _process.memory().Write( REBASE( pCookie, pImage->peImage.imageBase(), pImage->imgMem.ptr() ), size, &cookie ); } return STATUS_SUCCESS; @@ -1106,7 +1128,7 @@ call_result_t MMap::RunModuleInitializers( ImageContext* pImage, DWORD if (!( pImage->flags & NoTLS )) for (auto& pCallback : pImage->tlsCallbacks) { - BLACKBONE_TRACE( L"ManualMap: Calling TLS callback at 0x%p for '%ls', Reason: %d", + BLACKBONE_TRACE( L"ManualMap: Calling TLS callback at 0x%016llx for '%ls', Reason: %d", pCallback, pImage->ldrEntry.name.c_str(), dwReason ); a->GenCall( pCallback, { pImage->imgMem.ptr(), dwReason, customArgumentsAddress } ); @@ -1134,7 +1156,7 @@ call_result_t MMap::RunModuleInitializers( ImageContext* pImage, DWORD if (!( pImage->flags & NoTLS )) for (auto& pCallback : pImage->tlsCallbacks) { - BLACKBONE_TRACE( L"ManualMap: Calling TLS callback at 0x%p for '%ls', Reason: %d", + BLACKBONE_TRACE( L"ManualMap: Calling TLS callback at 0x%016llx for '%ls', Reason: %d", pCallback, pImage->ldrEntry.name.c_str(), dwReason ); a->GenCall( pCallback, { pImage->imgMem.ptr(), dwReason, customArgumentsAddress } ); @@ -1180,7 +1202,6 @@ NTSTATUS MMap::CreateActx( const pe::PEImage& image ) NTSTATUS status = STATUS_SUCCESS; uint64_t result = 0; - ACTCTXW act = { 0 }; auto mem = _process.memory().Allocate( 512, PAGE_READWRITE ); if (!mem) @@ -1188,16 +1209,6 @@ NTSTATUS MMap::CreateActx( const pe::PEImage& image ) _pAContext = std::move( mem.result() ); - act.cbSize = sizeof( act ); - act.lpSource = reinterpret_cast(_pAContext.ptr() + sizeof( ptr_t ) + sizeof( act )); - - // Ignore some fields for pure manifest file - if (!image.noPhysFile()) - { - act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; - act.lpResourceName = MAKEINTRESOURCEW( image.manifestID() ); - } - bool switchMode = image.mType() == mt_mod64 && _process.core().isWow64(); auto pCreateActx = _process.modules().GetExport( _process.modules().GetModule( L"kernel32.dll" ), "CreateActCtxW" ); if (!pCreateActx) @@ -1251,8 +1262,37 @@ NTSTATUS MMap::CreateActx( const pe::PEImage& image ) // Native way else { - a->GenPrologue(); + auto fillACTX = [this, &image]( auto&& act ) + { + memset( &act, 0, sizeof( act ) ); + act.cbSize = sizeof( act ); + act.lpSource = static_cast(this->_pAContext.ptr() + sizeof( ptr_t ) + sizeof( act )); + + // Ignore some fields for pure manifest file + if (!image.noPhysFile()) + { + act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; + act.lpResourceName = static_cast(image.manifestID()); + } + + // Write path to file + NTSTATUS status = this->_pAContext.Write( sizeof( ptr_t ), act ); + status |= this->_pAContext.Write( + sizeof( ptr_t ) + sizeof( act ), + (image.manifestFile().length() + 1) * sizeof( wchar_t ), + image.manifestFile().c_str() + ); + + return status; + }; + + if (_process.core().isWow64()) + status = fillACTX( _ACTCTXW32() ); + else + status = fillACTX( _ACTCTXW64() ); + + a->GenPrologue(); a->GenCall( pCreateActx->procAddress, { _pAContext.ptr() + sizeof( ptr_t ) } ); (*a)->mov( (*a)->zdx, _pAContext.ptr() ); @@ -1261,14 +1301,6 @@ NTSTATUS MMap::CreateActx( const pe::PEImage& image ) _process.remote().AddReturnWithEvent( *a ); a->GenEpilogue(); - // Write path to file - _pAContext.Write( sizeof( ptr_t ), act ); - _pAContext.Write( - sizeof( ptr_t ) + sizeof(act), - (image.manifestFile().length() + 1) * sizeof(wchar_t), - image.manifestFile().c_str() - ); - status = _process.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result ); if (!NT_SUCCESS( status )) return status; diff --git a/src/BlackBone/ManualMap/Native/NtLoader.cpp b/src/BlackBone/ManualMap/Native/NtLoader.cpp index b455507..3e8fd60 100644 --- a/src/BlackBone/ManualMap/Native/NtLoader.cpp +++ b/src/BlackBone/ManualMap/Native/NtLoader.cpp @@ -32,7 +32,6 @@ bool NtLdr::Init() if (IsWindows8OrGreater()) FindLdrpModuleIndexBase(); - ScanPatterns(); _nodeMap.clear(); // Report errors @@ -64,41 +63,42 @@ bool NtLdr::CreateNTReference( NtLdrEntry& mod ) // Win 8 and higher if (IsWindows8OrGreater()) { - ULONG hash = 0; - _LDR_DATA_TABLE_ENTRY_W8 *pEntry = InitW8Node( mod ); - _nodeMap.emplace( std::make_pair( mod.baseAddress, pEntry ) ); + ptr_t entry = InitW8Node( mod ); + _nodeMap.emplace( std::make_pair( mod.baseAddress, entry ) ); // Insert into LdrpHashTable if (mod.flags & Ldr_HashTable) - InsertHashNode( GET_FIELD_PTR( pEntry, HashLinks ), hash ); + InsertHashNode( fieldPtr( entry, &_LDR_DATA_TABLE_ENTRY_W8::HashLinks ), mod.hash ); // Insert into module graph if (mod.flags & Ldr_ModList) - InsertTreeNode( pEntry, mod ); + InsertTreeNode( entry, mod ); if (mod.flags & Ldr_ThdCall) { - _process.memory().Write( GET_FIELD_PTR( pEntry, Flags ), 0x80004 ); - InsertMemModuleNode( 0, GET_FIELD_PTR( pEntry, InLoadOrderLinks ), - GET_FIELD_PTR( pEntry, InInitializationOrderLinks ) ); + _process.memory().Write( fieldPtr( entry, &_LDR_DATA_TABLE_ENTRY_W8::Flags ), 0x80004 ); + InsertMemModuleNode( + 0, + fieldPtr( entry, &_LDR_DATA_TABLE_ENTRY_W8::InLoadOrderLinks ), + fieldPtr( entry, &_LDR_DATA_TABLE_ENTRY_W8::InInitializationOrderLinks ) + ); } } // Windows 7 and earlier else { - ULONG hash = 0; _LDR_DATA_TABLE_ENTRY_W7 *pEntry = InitW7Node( mod ); - _nodeMap.emplace( std::make_pair( mod.baseAddress, pEntry ) ); + _nodeMap.emplace( std::make_pair( mod.baseAddress, reinterpret_cast(pEntry) ) ); // Insert into LdrpHashTable if (mod.flags & Ldr_HashTable) - InsertHashNode( GET_FIELD_PTR( pEntry, HashLinks ), hash ); + InsertHashNode( GET_FIELD_PTR( pEntry, HashLinks ), mod.hash ); // Insert into LDR list if (mod.flags & (Ldr_ModList | Ldr_ThdCall)) { _process.memory().Write( GET_FIELD_PTR( pEntry, Flags ), 0x80004 ); - InsertMemModuleNode( 0, GET_FIELD_PTR( pEntry, InLoadOrderLinks ), 0 ); + InsertMemModuleNode( 0, GET_FIELD_PTR( pEntry, InLoadOrderLinks ), 0 ); } } @@ -111,16 +111,16 @@ bool NtLdr::CreateNTReference( NtLdrEntry& mod ) /// node pointer (if nullptr - new dummy node is allocated) /// Module base address /// Node address -template -T* NtLdr::SetNode( T* ptr, void* pModule ) +template +ptr_t NtLdr::SetNode( ptr_t ptr, T2 pModule ) { - if(ptr == nullptr) + if(ptr == 0) { auto mem = _process.memory().Allocate( sizeof( T ), PAGE_READWRITE, 0, false ); if (!mem) - return nullptr; + return 0; - ptr = mem->ptr(); + ptr = mem->ptr(); mem->Write( FIELD_OFFSET2( T*, DllBase ), pModule ); } @@ -136,20 +136,29 @@ T* NtLdr::SetNode( T* ptr, void* pModule ) NTSTATUS NtLdr::AddStaticTLSEntry( NtLdrEntry& mod, IMAGE_TLS_DIRECTORY *pTls ) { bool wxp = IsWindowsXPOrGreater() && !IsWindowsVistaOrGreater(); - void* pNode = _nodeMap.count( mod.baseAddress ) ? _nodeMap[mod.baseAddress] : nullptr; + ptr_t pNode = _nodeMap.count( mod.baseAddress ) ? _nodeMap[mod.baseAddress] : 0; // Allocate appropriate structure - if ((pNode = SetNode( reinterpret_cast(pNode), reinterpret_cast(mod.baseAddress) )) == nullptr) + ptr_t LdrpHandleTlsData = 0; + if (mod.type == mt_mod64) + { + LdrpHandleTlsData = g_PatternLoader->data().LdrpHandleTlsData64; + pNode = SetNode<_LDR_DATA_TABLE_ENTRY_BASE64>( pNode, mod.baseAddress ); + } + else + { + LdrpHandleTlsData = g_PatternLoader->data().LdrpHandleTlsData32; + pNode = SetNode<_LDR_DATA_TABLE_ENTRY_BASE32>( pNode, mod.baseAddress ); + } + + if (pNode == 0) return STATUS_NO_MEMORY; // Manually add TLS table - if ((wxp || _process.barrier().type == wow_64_32) && pTls != nullptr) + if (wxp && pTls != nullptr) { ptr_t pTeb = 0; - if (wxp) - pTeb = _process.remote().getWorker()->teb( static_cast<_TEB32*>(nullptr) ); - else - pTeb = _process.remote().getWorker()->teb( static_cast<_TEB64*>(nullptr) ); + pTeb = _process.remote().getWorker()->teb( static_cast<_TEB32*>(nullptr) ); auto mem = _process.memory().Allocate( 0x1000, PAGE_READWRITE, 0, false ); if (!mem) @@ -168,22 +177,17 @@ NTSTATUS NtLdr::AddStaticTLSEntry( NtLdrEntry& mod, IMAGE_TLS_DIRECTORY *pTls ) tlsStore.Write( 0, tlsStore.ptr() + 0x800 ); tlsStore.Write( 0x800, size, buf.get() ); - if (wxp) - _process.memory().Write( pTeb + FIELD_OFFSET( _TEB32, ThreadLocalStoragePointer ), tlsStore.ptr() ); - else - _process.memory().Write( pTeb + FIELD_OFFSET( _TEB64, ThreadLocalStoragePointer ), tlsStore.ptr() ); - - return STATUS_SUCCESS; + return _process.memory().Write( pTeb + FIELD_OFFSET( _TEB32, ThreadLocalStoragePointer ), tlsStore.ptr() ); } // Use native method - if (_LdrpHandleTlsData) + if (LdrpHandleTlsData) { auto a = AsmFactory::GetAssembler( mod.type ); uint64_t result = 0; a->GenPrologue(); - a->GenCall( _LdrpHandleTlsData, { reinterpret_cast(pNode) }, IsWindows8Point1OrGreater() ? cc_thiscall : cc_stdcall ); + a->GenCall( LdrpHandleTlsData, { pNode }, IsWindows8Point1OrGreater() ? cc_thiscall : cc_stdcall ); _process.remote().AddReturnWithEvent( *a ); a->GenEpilogue(); @@ -197,6 +201,7 @@ NTSTATUS NtLdr::AddStaticTLSEntry( NtLdrEntry& mod, IMAGE_TLS_DIRECTORY *pTls ) return STATUS_ORDINAL_NOT_FOUND; } + /// /// Create module record in LdrpInvertedFunctionTable /// Used to create fake SAFESEH entries @@ -205,84 +210,109 @@ NTSTATUS NtLdr::AddStaticTLSEntry( NtLdrEntry& mod, IMAGE_TLS_DIRECTORY *pTls ) /// true on success bool NtLdr::InsertInvertedFunctionTable( NtLdrEntry& mod ) { - RTL_INVERTED_FUNCTION_TABLE7 table = { 0 }; - PRTL_INVERTED_FUNCTION_TABLE_ENTRY Entries = nullptr; - uint64_t result = 0; - auto a = AsmFactory::GetAssembler( mod.type ); - auto& memory = _process.memory(); - - // Invalid addresses. Probably pattern scan has failed - if (_RtlInsertInvertedFunctionTable == 0 || _LdrpInvertedFunctionTable == 0) - return false; - - if (IsWindows8OrGreater()) - Entries = reinterpret_cast(GET_FIELD_PTR( reinterpret_cast(&table), Entries )); - else - Entries = reinterpret_cast(GET_FIELD_PTR( &table, Entries )); - - // - // Try to find module address in table. - // If found - no additional work is required. - // - memory.Read( _LdrpInvertedFunctionTable, sizeof( table ), &table ); - for (ULONG i = 0; i < table.Count; i++) - if (reinterpret_cast(Entries[i].ImageBase) == mod.baseAddress) - return true; - - a->GenPrologue(); - - if (IsWindows8Point1OrGreater()) - a->GenCall( _RtlInsertInvertedFunctionTable, { mod.baseAddress, mod.size }, cc_fastcall ); - else if (IsWindows8OrGreater()) - a->GenCall( _RtlInsertInvertedFunctionTable, { mod.baseAddress, mod.size } ); - else - a->GenCall( _RtlInsertInvertedFunctionTable, { _LdrpInvertedFunctionTable, mod.baseAddress, mod.size } ); - - _process.remote().AddReturnWithEvent( *a ); - a->GenEpilogue(); - - _process.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result ); - memory.Read( _LdrpInvertedFunctionTable, sizeof( table ), &table ); - - for(DWORD i = 0; i < table.Count; i++) + ptr_t RtlInsertInvertedFunctionTable = g_PatternLoader->data().RtlInsertInvertedFunctionTable64; + ptr_t LdrpInvertedFunctionTable = g_PatternLoader->data().LdrpInvertedFunctionTable64; + if (mod.type == mt_mod32) { - if (reinterpret_cast(Entries[i].ImageBase) != mod.baseAddress) - continue; - - // If Image has SAFESEH, RtlInsertInvertedFunctionTable is enough - if (Entries[i].SizeOfTable != 0) - return mod.safeSEH = true; - - // - // Create fake Exception directory - // Directory will be filled later, during exception handling - // - PIMAGE_RUNTIME_FUNCTION_ENTRY pImgEntry = nullptr; - - // Allocate memory for 512 possible handlers - auto mem = memory.Allocate( sizeof( DWORD ) * 0x200, PAGE_READWRITE, 0, false ); - if (!mem) - return false; - - pImgEntry = mem->ptr(); - auto pEncoded = EncodeSystemPointer( pImgEntry ); - - // m_LdrpInvertedFunctionTable->Entries[i].ExceptionDirectory - uintptr_t field_ofst = reinterpret_cast(&Entries[i].ExceptionDirectory) - - reinterpret_cast(&table); - - // In Win10 _LdrpInvertedFunctionTable is located in mrdata section - // mrdata is read-only by default - // LdrProtectMrdata is used to make it writable when needed - DWORD flOld = 0; - memory.Protect( _LdrpInvertedFunctionTable + field_ofst, sizeof( uintptr_t ), PAGE_EXECUTE_READWRITE, &flOld ); - auto status = memory.Write( _LdrpInvertedFunctionTable + field_ofst, pEncoded ); - memory.Protect( _LdrpInvertedFunctionTable + field_ofst, sizeof( uintptr_t ), flOld, &flOld ); - - return NT_SUCCESS( status ); + RtlInsertInvertedFunctionTable = g_PatternLoader->data().RtlInsertInvertedFunctionTable32; + LdrpInvertedFunctionTable = g_PatternLoader->data().LdrpInvertedFunctionTable32; } - return false; + // Invalid addresses. Probably pattern scan has failed + if (RtlInsertInvertedFunctionTable == 0 || LdrpInvertedFunctionTable == 0) + return false; + + auto InsertP = [&]( auto&& table ) + { + uint64_t result = 0; + auto a = AsmFactory::GetAssembler( mod.type ); + auto& memory = _process.memory(); + + memory.Read( LdrpInvertedFunctionTable, sizeof( table ), &table ); + for (ULONG i = 0; i < table.Count; i++) + if (table.Entries[i].ImageBase == mod.baseAddress) + return true; + + a->GenPrologue(); + + if (IsWindows8Point1OrGreater()) + a->GenCall( RtlInsertInvertedFunctionTable, { mod.baseAddress, mod.size }, cc_fastcall ); + else if (IsWindows8OrGreater()) + a->GenCall( RtlInsertInvertedFunctionTable, { mod.baseAddress, mod.size } ); + else + a->GenCall( RtlInsertInvertedFunctionTable, { LdrpInvertedFunctionTable, mod.baseAddress, mod.size } ); + + _process.remote().AddReturnWithEvent( *a ); + a->GenEpilogue(); + + _process.remote().ExecInWorkerThread( (*a)->make(), (*a)->getCodeSize(), result ); + memory.Read( LdrpInvertedFunctionTable, sizeof( table ), &table ); + + for (DWORD i = 0; i < table.Count; i++) + { + if (table.Entries[i].ImageBase != mod.baseAddress) + continue; + + // If Image has SAFESEH, RtlInsertInvertedFunctionTable is enough + if (table.Entries[i].SizeOfTable != 0) + return mod.safeSEH = true; + + // + // Create fake Exception directory + // Directory will be filled later, during exception handling + // + + // Allocate memory for 2048 possible handlers + auto mem = memory.Allocate( sizeof( DWORD ) * 0x800, PAGE_READWRITE, 0, false ); + if (!mem) + return false; + + uint32_t size = 0; + ptr_t pEncoded = 0; + auto cookie = *reinterpret_cast(0x7FFE0330); + if (mod.type == mt_mod64) + { + size = sizeof( uint64_t ); + pEncoded = _rotr64( cookie ^ mem->ptr(), cookie & 0x3F ); + } + else + { + size = sizeof( uint32_t ); + pEncoded = _rotr( cookie ^ mem->ptr(), cookie & 0x1F ); + } + + // m_LdrpInvertedFunctionTable->Entries[i].ExceptionDirectory + uintptr_t field_ofst = reinterpret_cast(&table.Entries[i].ExceptionDirectory) + - reinterpret_cast(&table); + + // In Win10 LdrpInvertedFunctionTable is located in mrdata section + // mrdata is read-only by default + // LdrProtectMrdata is used to make it writable when needed + DWORD flOld = 0; + memory.Protect( LdrpInvertedFunctionTable + field_ofst, sizeof( ptr_t ), PAGE_EXECUTE_READWRITE, &flOld ); + auto status = memory.Write( LdrpInvertedFunctionTable + field_ofst, size, &pEncoded ); + memory.Protect( LdrpInvertedFunctionTable + field_ofst, sizeof( ptr_t ), flOld, &flOld ); + + return NT_SUCCESS( status ); + } + + return false; + }; + + if (IsWindows8OrGreater()) + { + if(mod.type == mt_mod64) + return InsertP( _RTL_INVERTED_FUNCTION_TABLE8() ); + else + return InsertP( _RTL_INVERTED_FUNCTION_TABLE8() ); + } + else + { + if (mod.type == mt_mod64) + return InsertP( _RTL_INVERTED_FUNCTION_TABLE7() ); + else + return InsertP( _RTL_INVERTED_FUNCTION_TABLE7() ); + } } /// @@ -290,82 +320,71 @@ bool NtLdr::InsertInvertedFunctionTable( NtLdrEntry& mod ) /// /// Module data /// Pointer to created entry -_LDR_DATA_TABLE_ENTRY_W8* NtLdr::InitW8Node( NtLdrEntry& mod ) +ptr_t NtLdr::InitW8Node( NtLdrEntry& mod ) { - UNICODE_STRING strLocal = { 0 }; + typedef _LDR_DATA_TABLE_ENTRY_W8 EntryType; + + ptr_t entry = AllocateInHeap( mod.type, sizeof( EntryType ) ).result( 0 ); + ptr_t pDdagNode = AllocateInHeap( mod.type, sizeof( _LDR_DDAG_NODE ) ).result( 0 ); + if (!entry || !pDdagNode) + return 0; // Allocate space for Unicode string + UNICODE_STRING strLocal = { 0 }; auto mem = _process.memory().Allocate( 0x1000, PAGE_READWRITE, 0, false ); if (!mem) - return nullptr; + return 0; auto StringBuf = std::move( mem.result() ); - _LDR_DATA_TABLE_ENTRY_W8* pEntry = reinterpret_cast(AllocateInHeap( - mod.type, sizeof( *pEntry ) - ).result( 0 )); - if(pEntry) - { - _LDR_DDAG_NODE* pDdagNode = reinterpret_cast(AllocateInHeap( - mod.type, sizeof( *pDdagNode ) - ).result(0)); + // pEntry->DllBase = ModuleBase; + _process.memory().Write( fieldPtr( entry, &EntryType::DllBase ), static_cast(mod.baseAddress) ); - if(pDdagNode) - { - // pEntry->DllBase = ModuleBase; - _process.memory().Write( GET_FIELD_PTR( pEntry, DllBase ), static_cast(mod.baseAddress) ); + // pEntry->SizeOfImage = ImageSize; + _process.memory().Write( fieldPtr( entry, &EntryType::SizeOfImage ), mod.size ); - // pEntry->SizeOfImage = ImageSize; - _process.memory().Write( GET_FIELD_PTR( pEntry, SizeOfImage ), mod.size ); + // pEntry->EntryPoint = entryPoint; + _process.memory().Write( fieldPtr( entry, &EntryType::EntryPoint ), static_cast(mod.entryPoint) ); - // pEntry->EntryPoint = entryPoint; - _process.memory().Write( GET_FIELD_PTR( pEntry, EntryPoint ), static_cast(mod.entryPoint) ); + // Dll name and name hash + SAFE_CALL( RtlInitUnicodeString, &strLocal, mod.name.c_str() ); + mod.hash = HashString( mod.name ); - // Dll name and name hash - SAFE_CALL( RtlInitUnicodeString, &strLocal, mod.name.c_str() ); - mod.hash = HashString( mod.name ); + // Write into buffer + strLocal.Buffer = StringBuf.ptr(); + StringBuf.Write( 0, mod.name.length() * sizeof( wchar_t ) + 2, mod.name.c_str() ); - // Write into buffer - strLocal.Buffer = StringBuf.ptr(); - StringBuf.Write( 0, mod.name.length() * sizeof(wchar_t) + 2, mod.name.c_str() ); + // pEntry->BaseDllName = strLocal; + _process.memory().Write( fieldPtr( entry, &EntryType::BaseDllName ), strLocal ); - // pEntry->BaseDllName = strLocal; - _process.memory().Write( GET_FIELD_PTR( pEntry, BaseDllName ), strLocal ); + // Dll full path + SAFE_CALL( RtlInitUnicodeString, &strLocal, mod.fullPath.c_str() ); + strLocal.Buffer = reinterpret_cast(StringBuf.ptr() + 0x800); + StringBuf.Write( 0x800, mod.fullPath.length() * sizeof( wchar_t ) + 2, mod.fullPath.c_str() ); - // Dll full path - SAFE_CALL( RtlInitUnicodeString, &strLocal, mod.fullPath.c_str() ); - strLocal.Buffer = reinterpret_cast(StringBuf.ptr() + 0x800); - StringBuf.Write( 0x800, mod.fullPath.length() * sizeof(wchar_t) + 2, mod.fullPath.c_str() ); - - // pEntry->FullDllName = strLocal; - _process.memory().Write( GET_FIELD_PTR( pEntry, FullDllName ), strLocal ); + // pEntry->FullDllName = strLocal; + _process.memory().Write( fieldPtr( entry, &EntryType::FullDllName ), strLocal ); - // pEntry->BaseNameHashValue = hash; - _process.memory().Write( GET_FIELD_PTR( pEntry, BaseNameHashValue ), mod.hash ); + // pEntry->BaseNameHashValue = hash; + _process.memory().Write( fieldPtr( entry, &EntryType::BaseNameHashValue ), mod.hash ); - // - // Ddag node - // + // + // Ddag node + // - // pEntry->DdagNode = pDdagNode; - _process.memory().Write( GET_FIELD_PTR( pEntry, DdagNode ), pDdagNode ); + // pEntry->DdagNode = pDdagNode; + _process.memory().Write( fieldPtr( entry, &EntryType::DdagNode ), pDdagNode ); - // pDdagNode->State = LdrModulesReadyToRun; - _process.memory().Write( GET_FIELD_PTR( pDdagNode, State ), LdrModulesReadyToRun ); + // pDdagNode->State = LdrModulesReadyToRun; + _process.memory().Write( fieldPtr( pDdagNode, &_LDR_DDAG_NODE::State ), LdrModulesReadyToRun ); - // pDdagNode->ReferenceCount = 1; - _process.memory().Write( GET_FIELD_PTR( pDdagNode, ReferenceCount ), 1 ); + // pDdagNode->ReferenceCount = 1; + _process.memory().Write( fieldPtr( pDdagNode, &_LDR_DDAG_NODE::ReferenceCount ), 1 ); - // pDdagNode->LoadCount = -1; - _process.memory().Write( GET_FIELD_PTR( pDdagNode, LoadCount ), -1 ); + // pDdagNode->LoadCount = -1; + _process.memory().Write( fieldPtr( pDdagNode, &_LDR_DDAG_NODE::LoadCount ), -1 ); - return pEntry; - } - - return nullptr; - } - - return nullptr; + return entry; } /// @@ -438,7 +457,7 @@ _LDR_DATA_TABLE_ENTRY_W7* NtLdr::InitW7Node( NtLdrEntry& mod ) /// /// Node to insert /// Module data -void NtLdr::InsertTreeNode( _LDR_DATA_TABLE_ENTRY_W8* pNode, const NtLdrEntry& mod ) +void NtLdr::InsertTreeNode( ptr_t pNode, const NtLdrEntry& mod ) { // // Win8 module tree @@ -503,9 +522,9 @@ void NtLdr::InsertTreeNode( _LDR_DATA_TABLE_ENTRY_W8* pNode, const NtLdrEntry& m a->GenCall( static_cast(RtlRbInsertNodeEx->procAddress), { _LdrpModuleIndexBase, - GET_FIELD_PTR( pLdrNode, BaseAddressIndexNode ), + fieldPtr( (ptr_t)pLdrNode, &_LDR_DATA_TABLE_ENTRY_W8::BaseAddressIndexNode ), static_cast(bRight), - GET_FIELD_PTR( pNode, BaseAddressIndexNode ) + fieldPtr( (ptr_t)pNode, &_LDR_DATA_TABLE_ENTRY_W8::BaseAddressIndexNode ) } ); _process.remote().AddReturnWithEvent( *a, mod.type ); @@ -519,27 +538,28 @@ void NtLdr::InsertTreeNode( _LDR_DATA_TABLE_ENTRY_W8* pNode, const NtLdrEntry& m /// /// InMemoryOrderModuleList link of entry to be inserted /// InLoadOrderModuleList link of entry to be inserted -void NtLdr::InsertMemModuleNode( uintptr_t pNodeMemoryOrderLink, uintptr_t pNodeLoadOrderLink, uintptr_t pNodeInitOrderLink ) +template +void NtLdr::InsertMemModuleNode( ptr_t pNodeMemoryOrderLink, ptr_t pNodeLoadOrderLink, ptr_t pNodeInitOrderLink ) { - PEB_T* pPeb = reinterpret_cast(_process.core().peb()); - PEB_LDR_DATA_T* pLdr = nullptr; + ptr_t pPeb = _process.core().peb( (_PEB_T2::type*)nullptr ); + ptr_t pLdr = 0; if (pPeb) - pLdr = _process.memory().Read( GET_FIELD_PTR( pPeb, Ldr ) ).result( nullptr ); + pLdr = _process.memory().Read( fieldPtr( pPeb, &PEB_T::Ldr ) ).result( 0 ); if (pLdr) { // pLdr->InMemoryOrderModuleList if (pNodeMemoryOrderLink) - InsertTailList( GET_FIELD_PTR( pLdr, InMemoryOrderModuleList ), pNodeMemoryOrderLink ); + InsertTailList( fieldPtr( pLdr, &_PEB_LDR_DATA2::InMemoryOrderModuleList ), pNodeMemoryOrderLink ); // pLdr->InLoadOrderModuleList if (pNodeLoadOrderLink) - InsertTailList( GET_FIELD_PTR( pLdr, InLoadOrderModuleList ), pNodeLoadOrderLink ); + InsertTailList( fieldPtr( pLdr, &_PEB_LDR_DATA2::InLoadOrderModuleList ), pNodeLoadOrderLink ); // pLdr->InInitializationOrderModuleList if (pNodeInitOrderLink) - InsertTailList( GET_FIELD_PTR( pLdr, InInitializationOrderModuleList ), pNodeInitOrderLink ); + InsertTailList( fieldPtr( pLdr, &_PEB_LDR_DATA2::InInitializationOrderModuleList ), pNodeInitOrderLink ); } } @@ -548,14 +568,14 @@ void NtLdr::InsertMemModuleNode( uintptr_t pNodeMemoryOrderLink, uintptr_t pNode /// /// Link of entry to be inserted /// Module hash -void NtLdr::InsertHashNode( uintptr_t pNodeLink, ULONG hash ) +void NtLdr::InsertHashNode( ptr_t pNodeLink, ULONG hash ) { if(pNodeLink) { // LrpHashTable record auto pHashList = _process.memory().Read( _LdrpHashTable + sizeof(LIST_ENTRY)*(hash & 0x1F) ); if(pHashList) - InsertTailList( pHashList.result(), pNodeLink ); + InsertTailList( pHashList.result(), pNodeLink ); } } @@ -564,20 +584,21 @@ void NtLdr::InsertHashNode( uintptr_t pNodeLink, ULONG hash ) /// /// List head pointer /// Entry list link to be inserted -void NtLdr::InsertTailList( uintptr_t ListHead, uintptr_t Entry ) +template +void NtLdr::InsertTailList( ptr_t ListHead, ptr_t Entry ) { // PrevEntry = ListHead->Blink; - auto PrevEntry = _process.memory().Read( GET_FIELD_PTR( reinterpret_cast(ListHead), Blink ) ).result( 0 ); + auto PrevEntry = _process.memory().Read( fieldPtr( ListHead, &_LIST_ENTRY_T::Blink ) ).result( 0 ); // Entry->Flink = ListHead; // Entry->Blink = PrevEntry; - _process.memory().Write( GET_FIELD_PTR( reinterpret_cast(Entry), Flink ), ListHead ); - _process.memory().Write( GET_FIELD_PTR( reinterpret_cast(Entry), Blink ), PrevEntry ); + _process.memory().Write( fieldPtr( Entry, &_LIST_ENTRY_T::Flink ), sizeof(T), &ListHead ); + _process.memory().Write( fieldPtr( Entry, &_LIST_ENTRY_T::Blink ), sizeof( T ), &PrevEntry ); // PrevEntry->Flink = Entry; // ListHead->Blink = Entry; - _process.memory().Write( GET_FIELD_PTR( reinterpret_cast(PrevEntry), Flink ), Entry ); - _process.memory().Write( GET_FIELD_PTR( reinterpret_cast(ListHead), Blink ), Entry ); + _process.memory().Write( fieldPtr( PrevEntry, &_LIST_ENTRY_T::Flink ), sizeof( T ), &Entry ); + _process.memory().Write( fieldPtr( ListHead, &_LIST_ENTRY_T::Blink ), sizeof( T ), &Entry ); } /// @@ -735,36 +756,6 @@ bool NtLdr::FindLdrpModuleIndexBase() return false; } - -/// -/// Search for RtlInsertInvertedFunctionTable, LdrpInvertedFunctionTable, LdrpHandleTlsData. -/// -/// true on success -bool NtLdr::ScanPatterns( ) -{ - auto& data = g_PatternLoader->data(); - - _LdrKernel32PatchAddress = static_cast(data.LdrKernel32PatchAddress); - _APC64PatchAddress = static_cast(data.APC64PatchAddress); - _LdrProtectMrdata = static_cast(data.LdrProtectMrdata); - - if (_process.core().isWow64()) - { - _LdrpHandleTlsData = static_cast(data.LdrpHandleTlsData32); - _LdrpInvertedFunctionTable = static_cast(data.LdrpInvertedFunctionTable32); - _RtlInsertInvertedFunctionTable = static_cast(data.RtlInsertInvertedFunctionTable32); - } - else - { - _LdrpHandleTlsData = static_cast(data.LdrpHandleTlsData64); - _LdrpInvertedFunctionTable = static_cast(data.LdrpInvertedFunctionTable64); - _RtlInsertInvertedFunctionTable = static_cast(data.RtlInsertInvertedFunctionTable64); - } - - return true; -} - - /// /// Find Loader heap base /// diff --git a/src/BlackBone/ManualMap/Native/NtLoader.h b/src/BlackBone/ManualMap/Native/NtLoader.h index 2d1f274..6144622 100644 --- a/src/BlackBone/ManualMap/Native/NtLoader.h +++ b/src/BlackBone/ManualMap/Native/NtLoader.h @@ -70,16 +70,7 @@ public: /// /// Module data /// true on success - BLACKBONE_API bool Unlink( const ModuleData& mod ); - - // - // Get some not exported values - // - BLACKBONE_API inline uintptr_t LdrpInvertedFunctionTable( ) const { return _LdrpInvertedFunctionTable; } - BLACKBONE_API inline uintptr_t LdrKernel32PatchAddress() const { return _LdrKernel32PatchAddress; } - BLACKBONE_API inline uintptr_t APC64PatchAddress() const { return _APC64PatchAddress; } - BLACKBONE_API inline uintptr_t LdrProtectMrdata() const { return _LdrProtectMrdata; } - + BLACKBONE_API bool Unlink( const ModuleData& mod ); private: /// @@ -94,12 +85,6 @@ private: /// true on success bool FindLdrpModuleIndexBase(); - /// - /// Search for RtlInsertInvertedFunctionTable, LdrpInvertedFunctionTable, LdrpHandleTlsDatas. - /// - /// true on success - bool ScanPatterns(); - /// /// Find Loader heap base /// @@ -111,7 +96,7 @@ private: /// /// Module data /// Pointer to created entry - _LDR_DATA_TABLE_ENTRY_W8* InitW8Node( NtLdrEntry& mod ); + ptr_t InitW8Node( NtLdrEntry& mod ); /// /// Initialize OS-specific module entry @@ -125,28 +110,30 @@ private: /// /// Node to insert /// Module data - void InsertTreeNode( _LDR_DATA_TABLE_ENTRY_W8* pNode, const NtLdrEntry& mod ); + void InsertTreeNode( ptr_t pNode, const NtLdrEntry& mod ); /// /// Insert entry into LdrpHashTable[] /// /// Link of entry to be inserted /// Module hash - void InsertHashNode( uintptr_t pNodeLink, ULONG hash ); + void InsertHashNode( ptr_t pNodeLink, ULONG hash ); /// /// Insert entry into InLoadOrderModuleList and InMemoryOrderModuleList /// /// InMemoryOrderModuleList link of entry to be inserted /// InLoadOrderModuleList link of entry to be inserted - void InsertMemModuleNode( uintptr_t pNodeMemoryOrderLink, uintptr_t pNodeLoadOrderLink, uintptr_t pNodeInitOrderLink ); + template + void InsertMemModuleNode( ptr_t pNodeMemoryOrderLink, ptr_t pNodeLoadOrderLink, ptr_t pNodeInitOrderLink ); /// /// Insert entry into standard double linked list /// /// List head pointer /// Entry list link to be inserted - void InsertTailList( uintptr_t ListHead, uintptr_t Entry ); + template + void InsertTailList( ptr_t ListHead, ptr_t Entry ); /// /// Hash image name @@ -169,8 +156,8 @@ private: /// node pointer (if nullptr - new dummy node is allocated) /// Module base address /// Node address - template - T* SetNode( T* ptr, void* pModule ); + template + ptr_t SetNode( ptr_t ptr, T2 pModule ); /// /// Unlink module from PEB_LDR_DATA @@ -206,19 +193,13 @@ private: NtLdr& operator =(const NtLdr&) = delete; private: - class Process& _process; // Process memory routines + class Process& _process; // Process memory routines - uintptr_t _LdrpHashTable = 0; // LdrpHashTable address - uintptr_t _LdrpModuleIndexBase = 0; // LdrpModuleIndex address - uintptr_t _LdrHeapBase = 0; // Loader heap base address - uintptr_t _LdrKernel32PatchAddress = 0; // Address to patch to enable kernel32 loading under win7 - uintptr_t _APC64PatchAddress = 0; // Address to patch for x64->WOW64 APC dispatching under win7 - uintptr_t _LdrpHandleTlsData = 0; // LdrpHandleTlsData address - uintptr_t _LdrpInvertedFunctionTable = 0; // LdrpInvertedFunctionTable address - uintptr_t _RtlInsertInvertedFunctionTable = 0; // RtlInsertInvertedFunctionTable address - uintptr_t _LdrProtectMrdata = 0; // LdrProtectMrdata address + uintptr_t _LdrpHashTable = 0; // LdrpHashTable address + uintptr_t _LdrpModuleIndexBase = 0; // LdrpModuleIndex address + uintptr_t _LdrHeapBase = 0; // Loader heap base address - std::map _nodeMap; // Allocated native structures + std::map _nodeMap; // Allocated native structures }; } diff --git a/src/BlackBone/Misc/DynImport.h b/src/BlackBone/Misc/DynImport.h index 835e68f..268aae9 100644 --- a/src/BlackBone/Misc/DynImport.h +++ b/src/BlackBone/Misc/DynImport.h @@ -60,7 +60,7 @@ public: /// Function args /// Function result or 0 if import not found template - inline auto safeCall( const std::string& name, Args&&... args ) -> typename std::result_of::type + inline auto safeCall( const std::string& name, Args&&... args ) { auto pfn = DynImport::get( name ); return pfn ? pfn( std::forward( args )... ) : (std::result_of::type)(0); diff --git a/src/BlackBone/Misc/NameResolve.cpp b/src/BlackBone/Misc/NameResolve.cpp index 5ea6ae4..ec488b0 100644 --- a/src/BlackBone/Misc/NameResolve.cpp +++ b/src/BlackBone/Misc/NameResolve.cpp @@ -189,7 +189,10 @@ NTSTATUS NameResolve::ResolvePath( dwSize = 255; // In Win10 DllDirectory value got screwed, so less reliable method is used - GetSystemDirectoryW( sys_path, dwSize ); + if (flags & Wow64) + GetSystemWow64DirectoryW( sys_path, dwSize ); + else + GetSystemDirectoryW( sys_path, dwSize ); if (res == ERROR_SUCCESS) { @@ -232,7 +235,10 @@ NTSTATUS NameResolve::ResolvePath( // // 4. The system directory // - GetSystemDirectoryW( tmpPath, ARRAYSIZE( tmpPath ) ); + if (flags & Wow64) + GetSystemWow64DirectoryW( tmpPath, ARRAYSIZE( tmpPath ) ); + else + GetSystemDirectoryW( tmpPath, ARRAYSIZE( tmpPath ) ); completePath = std::wstring( tmpPath ) + L"\\" + filename; diff --git a/src/BlackBone/PE/PEImage.cpp b/src/BlackBone/PE/PEImage.cpp index 52cc93a..cfb102b 100644 --- a/src/BlackBone/PE/PEImage.cpp +++ b/src/BlackBone/PE/PEImage.cpp @@ -22,6 +22,7 @@ PEImage::PEImage( void ) PEImage::~PEImage( void ) { + Release(); } /// diff --git a/src/BlackBone/Process/ProcessModules.cpp b/src/BlackBone/Process/ProcessModules.cpp index 57c4267..38f3d14 100644 --- a/src/BlackBone/Process/ProcessModules.cpp +++ b/src/BlackBone/Process/ProcessModules.cpp @@ -4,6 +4,7 @@ #include "RPC/RemoteExec.h" #include "../Misc/NameResolve.h" #include "../Misc/Utils.h" +#include "../Misc/PattrernLoader.h" #include "../Asm/AsmFactory.h" #include @@ -18,10 +19,6 @@ namespace blackbone { - -typedef std::unique_ptr::type, decltype(&CloseHandle)> handlePtr; - - ProcessModules::ProcessModules( class Process& proc ) : _proc( proc ) , _memory( _proc.memory() ) @@ -437,7 +434,7 @@ call_result_t ProcessModules::Inject( const std::wstring& path ) if (switchMode == ForceSwitch && !_ldrPatched && IsWindows7OrGreater() && !IsWindows8OrGreater()) { uint8_t patch[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 }; - auto patchBase = _proc.nativeLdr().LdrKernel32PatchAddress(); + auto patchBase = g_PatternLoader->data().LdrKernel32PatchAddress; if (patchBase != 0) { @@ -870,7 +867,7 @@ bool ProcessModules::InjectPureIL( // write JIT code to target size_t codeSize = a->getCodeSize(); - uintptr_t codeAddress = address.ptr() + offset; + ptr_t codeAddress = address.ptr() + offset; std::vector codeBuffer( codeSize ); diff --git a/src/BlackBone/Process/RPC/RemoteExec.cpp b/src/BlackBone/Process/RPC/RemoteExec.cpp index 42640ef..30f9832 100644 --- a/src/BlackBone/Process/RPC/RemoteExec.cpp +++ b/src/BlackBone/Process/RPC/RemoteExec.cpp @@ -1,6 +1,7 @@ #include "RemoteExec.h" #include "../Process.h" #include "../../Misc/DynImport.h" +#include "../../Misc/PattrernLoader.h" #include #include @@ -113,6 +114,9 @@ NTSTATUS RemoteExec::ExecInWorkerThread( PVOID pCode, size_t size, uint64_t& cal { NTSTATUS dwResult = STATUS_SUCCESS; + if (_proc.barrier().type == wow_64_32) + return ExecInAnyThread( pCode, size, callResult, _hWorkThd ); + // Create thread if needed CreateRPCEnvironment(); @@ -130,7 +134,7 @@ NTSTATUS RemoteExec::ExecInWorkerThread( PVOID pCode, size_t size, uint64_t& cal { if (_proc.barrier().type == wow_64_32) { - auto patchBase = _proc.nativeLdr().APC64PatchAddress(); + auto patchBase = g_PatternLoader->data().APC64PatchAddress; if (patchBase != 0) { @@ -150,8 +154,8 @@ NTSTATUS RemoteExec::ExecInWorkerThread( PVOID pCode, size_t size, uint64_t& cal // Execute code in thread context // TODO: Find out why am I passing pRemoteCode as an argument??? - auto pRemoteCode = _userCode.ptr(); - if (NT_SUCCESS( SAFE_NATIVE_CALL( NtQueueApcThread, _hWorkThd->handle(), pRemoteCode, pRemoteCode, nullptr, nullptr ) )) + auto pRemoteCode = _userCode.ptr(); + if (NT_SUCCESS( _proc.core().native()->NtQueueApcThreadT( _hWorkThd->handle(), pRemoteCode, pRemoteCode ) )) { dwResult = WaitForSingleObject( _hWaitEvent, 30 * 1000 /*wait 30s*/ ); callResult = _userData.Read( RET_OFFSET, 0 ); @@ -275,7 +279,7 @@ NTSTATUS RemoteExec::ExecInAnyThread( PVOID pCode, size_t size, uint64_t& callRe if (NT_SUCCESS( status )) { WaitForSingleObject( _hWaitEvent, INFINITE ); - status = _userData.Read( INTRET_OFFSET, callResult ); + status = _userData.Read( RET_OFFSET, callResult ); } return status; @@ -358,16 +362,7 @@ NTSTATUS RemoteExec::CreateRPCEnvironment( bool bThread /*= true*/, bool bEvent // Create RPC sync event if (bEvent) - { - if (_proc.barrier().type != wow_32_64) - { - status = CreateAPCEvent( thdID ); - } - else - { - status = STATUS_NOT_SUPPORTED; - } - } + status = CreateAPCEvent( thdID ); return status; } @@ -386,8 +381,7 @@ call_result_t RemoteExec::CreateWorkerThread() // if(!_hWorkThd->valid()) { - eModType mt = mt_default; - if (_proc.barrier().type == wow_64_32) + /*if (_proc.barrier().type == wow_64_32) { a->SwitchTo64(); @@ -405,9 +399,9 @@ call_result_t RemoteExec::CreateWorkerThread() (*a)->mov( (*a)->zdx, asmjit::host::dword_ptr_abs( 0x18 ).setSegment( asmjit::host::fs ) ); (*a)->mov( (*a)->intptr_ptr( (*a)->zdx, 0x2c8 ), (*a)->zax ); } - } + }*/ - auto ntdll = _mods.GetModule( L"ntdll.dll", Sections, mt ); + auto ntdll = _mods.GetModule( L"ntdll.dll", Sections ); auto proc = _mods.GetExport( ntdll, "NtDelayExecution" ); auto pExitThread = _mods.GetExport( ntdll, "NtTerminateThread" ); if (!proc || !pExitThread) @@ -462,11 +456,6 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID ) OBJECT_ATTRIBUTES obAttr = { 0 }; UNICODE_STRING ustr = { 0 }; - // Detect ntdll type - eModType mt = mt_default; - if (_proc.barrier().type == wow_64_32) - mt = mt_mod64; - // Event name swprintf_s( pEventName, ARRAYSIZE( pEventName ), L"\\BaseNamedObjects\\_MMapEvent_0x%x_0x%x", threadID, GetTickCount() ); @@ -476,14 +465,14 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID ) // Prepare Arguments ustr.Length = static_cast(wcslen( pEventName ) * sizeof(wchar_t)); - ustr.MaximumLength = static_cast(sizeof(pEventName)); + ustr.MaximumLength = static_cast(len); ustr.Buffer = pEventName; obAttr.ObjectName = &ustr; obAttr.Length = sizeof(obAttr); obAttr.SecurityDescriptor = pDescriptor; - auto pOpenEvent = _mods.GetNtdllExport( "NtOpenEvent", mt, Sections ); + auto pOpenEvent = _mods.GetNtdllExport( "NtOpenEvent", mt_default, Sections ); if (!pOpenEvent) return pOpenEvent.status; @@ -494,9 +483,36 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID ) if (!NT_SUCCESS( status )) return status; - ustr.Buffer = reinterpret_cast(_userData.ptr() + ARGS_OFFSET + sizeof( obAttr ) + sizeof( ustr )); - obAttr.ObjectName = reinterpret_cast(_userData.ptr() + ARGS_OFFSET + sizeof(obAttr)); - obAttr.SecurityDescriptor = nullptr; + auto fillAttributes = [this, len, pEventName]( auto& obAttr, auto& ustr ) + { + ustr.Buffer = static_cast(this->_userData.ptr() + ARGS_OFFSET + sizeof( obAttr ) + sizeof( ustr )); + ustr.Length = static_cast(wcslen( pEventName ) * sizeof( wchar_t )); + ustr.MaximumLength = static_cast(len); + + obAttr.Length = sizeof( obAttr ); + obAttr.ObjectName = static_cast(this->_userData.ptr() + ARGS_OFFSET + sizeof( obAttr )); + + NTSTATUS status = this->_userData.Write( ARGS_OFFSET, obAttr ); + status |= this->_userData.Write( ARGS_OFFSET + sizeof( obAttr ), ustr ); + status |= this->_userData.Write( ARGS_OFFSET + sizeof( obAttr ) + sizeof( ustr ), len, pEventName ); + return status; + }; + + if (_proc.core().isWow64()) + { + _OBJECT_ATTRIBUTES32 obAttr32 = { 0 }; + _UNICODE_STRING32 ustr32 = { 0 }; + status = fillAttributes( obAttr32, ustr32 ); + } + else + { + _OBJECT_ATTRIBUTES64 obAttr64 = { 0 }; + _UNICODE_STRING64 ustr64 = { 0 }; + status = fillAttributes( obAttr64, ustr64 ); + } + + if (!NT_SUCCESS( status )) + return status; a->GenCall( pOpenEvent->procAddress, { _userData.ptr() + EVENT_OFFSET, @@ -507,17 +523,11 @@ NTSTATUS RemoteExec::CreateAPCEvent( DWORD threadID ) // Save status (*a)->mov( (*a)->zdx, _userData.ptr() + ERR_OFFSET ); (*a)->mov( asmjit::host::dword_ptr( (*a)->zdx ), asmjit::host::eax ); - (*a)->ret(); - status = _userData.Write( ARGS_OFFSET, obAttr ); - status |= _userData.Write( ARGS_OFFSET + sizeof(obAttr), ustr ); - status |= _userData.Write( ARGS_OFFSET + sizeof(obAttr) + sizeof(ustr), len, pEventName ); - if (!NT_SUCCESS( status )) - return status; - - ExecInNewThread( (*a)->make(), (*a)->getCodeSize(), dwResult ); - status = _userData.Read( ERR_OFFSET, -1 ); + status = ExecInNewThread( (*a)->make(), (*a)->getCodeSize(), dwResult, NoSwitch ); + if (NT_SUCCESS( status )) + status = _userData.Read( ERR_OFFSET, -1 ); } return status; diff --git a/src/BlackBone/Process/RPC/RemoteExec.h b/src/BlackBone/Process/RPC/RemoteExec.h index 18f004a..d26c785 100644 --- a/src/BlackBone/Process/RPC/RemoteExec.h +++ b/src/BlackBone/Process/RPC/RemoteExec.h @@ -118,7 +118,7 @@ public: /// Target assembly helper BLACKBONE_API inline void SaveCallResult( IAsmHelper& a, uint32_t retOffset = RET_OFFSET ) { - a->mov( a->zdx, _userData.ptr() + retOffset ); + a->mov( a->zdx, _userData.ptr() + retOffset ); a->mov( asmjit::host::dword_ptr( a->zdx ), a->zax ); } diff --git a/src/BlackBone/Subsystem/NativeSubsystem.cpp b/src/BlackBone/Subsystem/NativeSubsystem.cpp index bfc53a0..c6c226b 100644 --- a/src/BlackBone/Subsystem/NativeSubsystem.cpp +++ b/src/BlackBone/Subsystem/NativeSubsystem.cpp @@ -303,6 +303,18 @@ NTSTATUS Native::SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ) } } +/// +/// NtQueueApcThread +/// +/// Thread handle. +/// APC function +/// APC argument +/// Status code +NTSTATUS Native::NtQueueApcThreadT( HANDLE hThread, ptr_t func, ptr_t arg ) +{ + return SAFE_NATIVE_CALL( NtQueueApcThread, hThread, reinterpret_cast(func), reinterpret_cast(arg), nullptr, nullptr ); +} + /// /// Get WOW64 PEB /// diff --git a/src/BlackBone/Subsystem/NativeSubsystem.h b/src/BlackBone/Subsystem/NativeSubsystem.h index 1059d03..645aa8f 100644 --- a/src/BlackBone/Subsystem/NativeSubsystem.h +++ b/src/BlackBone/Subsystem/NativeSubsystem.h @@ -158,6 +158,15 @@ public: /// Status code virtual NTSTATUS SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ); + /// + /// NtQueueApcThread + /// + /// Thread handle. + /// APC function + /// APC argument + /// Status code + virtual NTSTATUS NtQueueApcThreadT( HANDLE hThread, ptr_t func, ptr_t arg ); + /// /// Get WOW64 PEB /// diff --git a/src/BlackBone/Subsystem/Wow64Subsystem.cpp b/src/BlackBone/Subsystem/Wow64Subsystem.cpp index 1703548..44d04ae 100644 --- a/src/BlackBone/Subsystem/Wow64Subsystem.cpp +++ b/src/BlackBone/Subsystem/Wow64Subsystem.cpp @@ -272,6 +272,25 @@ NTSTATUS NativeWow64::SetThreadContextT( HANDLE hThread, _CONTEXT64& ctx ) return static_cast(X64Call( stc, 2, (DWORD64)hThread, (DWORD64)&ctx )); } +/// +/// NtQueueApcThread +/// +/// Thread handle. +/// APC function +/// APC argument +/// Status code +NTSTATUS NativeWow64::NtQueueApcThreadT( HANDLE hThread, ptr_t func, ptr_t arg ) +{ + if (_wowBarrier.targetWow64) + return Native::NtQueueApcThreadT( hThread, func, arg ); + + static ptr_t qat = GetProcAddress64( getNTDLL64(), "NtQueueApcThread" ); + if (qat == 0) + return STATUS_ORDINAL_NOT_FOUND; + + return static_cast(X64Call( qat, 5, (DWORD64)hThread, func, arg, 0ull, 0ull )); +} + /// /// Gets WOW64 PEB /// diff --git a/src/BlackBone/Subsystem/Wow64Subsystem.h b/src/BlackBone/Subsystem/Wow64Subsystem.h index d2114b7..3ca5c06 100644 --- a/src/BlackBone/Subsystem/Wow64Subsystem.h +++ b/src/BlackBone/Subsystem/Wow64Subsystem.h @@ -136,6 +136,15 @@ public: /// Status code virtual NTSTATUS SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx ); + /// + /// NtQueueApcThread + /// + /// Thread handle. + /// APC function + /// APC argument + /// Status code + virtual NTSTATUS NtQueueApcThreadT( HANDLE hThread, ptr_t func, ptr_t arg ); + /// /// Get WOW64 PEB ///