From dba8049ae91fb0cd2f8add8bcd6f12dfd4292f5d Mon Sep 17 00:00:00 2001 From: DarthTon Date: Sat, 8 Apr 2017 19:28:09 +0300 Subject: [PATCH] ntdll pattern scan separation --- src/BlackBone/BlackBone.vcxproj | 3 +- src/BlackBone/BlackBone.vcxproj.filters | 9 +- src/BlackBone/ManualMap/Native/NtLoader.cpp | 327 ++------------------ src/BlackBone/Misc/DynImport.cpp | 38 --- src/BlackBone/Misc/DynImport.h | 20 +- src/BlackBone/Misc/InitOnce.cpp | 8 +- src/BlackBone/Misc/PattrernLoader.cpp | 296 ++++++++++++++++++ src/BlackBone/Misc/PattrernLoader.h | 74 +++++ src/BlackBone/Process/Threads/Thread.h | 1 + src/BlackBone/Process/Threads/Threads.cpp | 4 +- src/BlackBone/Process/Threads/Threads.h | 2 +- src/TestApp/LocalHookTest.cpp | 2 +- 12 files changed, 432 insertions(+), 352 deletions(-) delete mode 100644 src/BlackBone/Misc/DynImport.cpp create mode 100644 src/BlackBone/Misc/PattrernLoader.cpp create mode 100644 src/BlackBone/Misc/PattrernLoader.h diff --git a/src/BlackBone/BlackBone.vcxproj b/src/BlackBone/BlackBone.vcxproj index abf04ba..a98db9e 100644 --- a/src/BlackBone/BlackBone.vcxproj +++ b/src/BlackBone/BlackBone.vcxproj @@ -618,9 +618,9 @@ - + @@ -717,6 +717,7 @@ + diff --git a/src/BlackBone/BlackBone.vcxproj.filters b/src/BlackBone/BlackBone.vcxproj.filters index 4b9c5d8..0675d19 100644 --- a/src/BlackBone/BlackBone.vcxproj.filters +++ b/src/BlackBone/BlackBone.vcxproj.filters @@ -90,9 +90,6 @@ Patterns - - Misc - Misc @@ -195,6 +192,9 @@ Subsystem + + Misc + @@ -450,5 +450,8 @@ AsmJit\Helpers + + Misc + \ No newline at end of file diff --git a/src/BlackBone/ManualMap/Native/NtLoader.cpp b/src/BlackBone/ManualMap/Native/NtLoader.cpp index 615c3de..2df700a 100644 --- a/src/BlackBone/ManualMap/Native/NtLoader.cpp +++ b/src/BlackBone/ManualMap/Native/NtLoader.cpp @@ -1,10 +1,10 @@ #include "NtLoader.h" #include "../../Process/Process.h" -#include "../../Patterns/PatternSearch.h" -#include "../../Misc/Utils.h" #include "../../Include/Macro.h" +#include "../../Misc/Utils.h" #include "../../Misc/DynImport.h" #include "../../Misc/trace.hpp" +#include "../../Misc/PattrernLoader.h" #include "../contrib/VersionHelpers.h" @@ -35,9 +35,7 @@ bool NtLdr::Init() ScanPatterns(); _nodeMap.clear(); - // // Report errors - // #ifndef BLACBONE_NO_TRACE auto barrier = _process.barrier().type; if (_LdrpHashTable == 0) @@ -46,24 +44,6 @@ bool NtLdr::Init() BLACKBONE_TRACE( "NativeLdr: LdrpModuleIndexBase not found" ); if (_LdrHeapBase == 0 && (barrier == wow_32_32 || barrier == wow_64_64)) BLACKBONE_TRACE( "NativeLdr: LdrHeapBase not found" ); - if (_LdrpHandleTlsData == 0) - BLACKBONE_TRACE( "NativeLdr: LdrpHandleTlsData not found" ); -#ifdef USE64 - if (IsWindows7OrGreater() && !IsWindows8OrGreater()) - { - if (_LdrKernel32PatchAddress == 0) - BLACKBONE_TRACE( "NativeLdr: LdrKernel32PatchAddress not found" ); - if (_APC64PatchAddress == 0) - BLACKBONE_TRACE( "NativeLdr: APC64PatchAddress not found" ); - } -#else - if (_LdrpInvertedFunctionTable == 0) - BLACKBONE_TRACE( "NativeLdr: LdrpInvertedFunctionTable not found" ); - if (_RtlInsertInvertedFunctionTable == 0) - BLACKBONE_TRACE( "NativeLdr: RtlInsertInvertedFunctionTable not found" ); - if (IsWindows8Point1OrGreater() && _LdrProtectMrdata == 0) - BLACKBONE_TRACE( "NativeLdr: LdrProtectMrdata not found" ); -#endif #endif return true; @@ -752,15 +732,14 @@ ULONG NtLdr::HashString( const std::wstring& str ) /// Find LdrpHashTable[] variable /// /// true on success -bool NtLdr::FindLdrpHashTable( ) +bool NtLdr::FindLdrpHashTable() { PEB_LDR_DATA_T *Ldr = reinterpret_cast( reinterpret_cast( reinterpret_cast(NtCurrentTeb())->ProcessEnvironmentBlock)->Ldr); - LDR_DATA_TABLE_ENTRY_BASE_T *Ntdll = CONTAINING_RECORD( Ldr->InInitializationOrderModuleList.Flink, - LDR_DATA_TABLE_ENTRY_BASE_T, InInitializationOrderLinks ); + auto Ntdll = CONTAINING_RECORD( Ldr->InInitializationOrderModuleList.Flink, LDR_DATA_TABLE_ENTRY_BASE_T, InInitializationOrderLinks ); ULONG NtdllHashIndex = HashString( reinterpret_cast(Ntdll->BaseDllName.Buffer) ) & 0x1F; @@ -768,26 +747,21 @@ bool NtLdr::FindLdrpHashTable( ) ULONG_PTR NtdllEndAddress = NtdllBase + Ntdll->SizeOfImage - 1; // scan hash list to the head (head is located within ntdll) - bool bHeadFound = false; - PLIST_ENTRY pNtdllHashHead = NULL; + PLIST_ENTRY pNtdllHashHead = nullptr; - for (PLIST_ENTRY e = reinterpret_cast(Ntdll->HashLinks.Flink); - e != reinterpret_cast(&Ntdll->HashLinks); - e = e->Flink) + for (auto e = reinterpret_cast(Ntdll->HashLinks.Flink); e != reinterpret_cast(&Ntdll->HashLinks); e = e->Flink) { - if (reinterpret_cast(e) >= NtdllBase && - reinterpret_cast(e) < NtdllEndAddress) + if (reinterpret_cast(e) >= NtdllBase && reinterpret_cast(e) < NtdllEndAddress) { - bHeadFound = true; pNtdllHashHead = e; break; } } - if (bHeadFound) + if (pNtdllHashHead != nullptr) _LdrpHashTable = reinterpret_cast(pNtdllHashHead - NtdllHashIndex); - return bHeadFound; + return _LdrpHashTable != 0; } @@ -795,16 +769,15 @@ bool NtLdr::FindLdrpHashTable( ) /// Find LdrpModuleIndex variable under win8 /// /// true on success -bool NtLdr::FindLdrpModuleIndexBase( ) +bool NtLdr::FindLdrpModuleIndexBase() { PEB_T* pPeb = reinterpret_cast(reinterpret_cast(NtCurrentTeb())->ProcessEnvironmentBlock); if(pPeb) { PRTL_BALANCED_NODE lastNode = 0; - PEB_LDR_DATA_T* Ldr = reinterpret_cast(pPeb->Ldr); - _LDR_DATA_TABLE_ENTRY_W8 *Ntdll = CONTAINING_RECORD( Ldr->InInitializationOrderModuleList.Flink, - _LDR_DATA_TABLE_ENTRY_W8, InInitializationOrderLinks ); + auto Ldr = reinterpret_cast(pPeb->Ldr); + auto Ntdll = CONTAINING_RECORD( Ldr->InInitializationOrderModuleList.Flink, _LDR_DATA_TABLE_ENTRY_W8, InInitializationOrderLinks ); PRTL_BALANCED_NODE pNode = &Ntdll->BaseAddressIndexNode; @@ -851,275 +824,23 @@ bool NtLdr::FindLdrpModuleIndexBase( ) /// true on success bool NtLdr::ScanPatterns( ) { - std::vector foundData; - pe::PEImage ntdll; - void* pStart = nullptr; - size_t scanSize = 0; + auto& data = g_PatternLoader->data(); - HMODULE hNtdll = GetModuleHandleW( L"ntdll.dll" ); - ntdll.Parse( hNtdll ); + _LdrKernel32PatchAddress = static_cast(data.LdrKernel32PatchAddress); + _APC64PatchAddress = static_cast(data.APC64PatchAddress); + _LdrProtectMrdata = static_cast(data.LdrProtectMrdata); - // Find ntdll code section - for (auto& section : ntdll.sections()) + if (_process.core().isWow64()) { - if (_stricmp( reinterpret_cast(section.Name), ".text" ) == 0) - { - pStart = reinterpret_cast(reinterpret_cast(hNtdll) + section.VirtualAddress); - scanSize = section.Misc.VirtualSize; - - break; - } + _LdrpHandleTlsData = static_cast(data.LdrpHandleTlsData32); + _LdrpInvertedFunctionTable = static_cast(data.LdrpInvertedFunctionTable32); + _RtlInsertInvertedFunctionTable = static_cast(data.RtlInsertInvertedFunctionTable32); } - - // Code section not found - if(pStart == nullptr) - return false; - - // Win10 update 2 - if (IsWindows10CreatorsOrGreater()) + else { -#ifdef USE64 - // LdrpHandleTlsData - // 74 33 44 8D 43 09 - PatternSearch ps( "\x74\x33\x44\x8d\x43\x09" ); - ps.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _LdrpHandleTlsData = static_cast(foundData.front() - 0x43); - foundData.clear(); - } - - // RtlInsertInvertedFunctionTable - // 8B FA 49 8D 43 20 - PatternSearch ps2( "\x8b\xfa\x49\x8d\x43\x20" ); - ps2.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _RtlInsertInvertedFunctionTable = static_cast(foundData.front() - 0x10); - foundData.clear(); - } - - // RtlpInsertInvertedFunctionTableEntry - // 49 8B E8 48 8B FA 0F 84 - PatternSearch ps3( "\x49\x8b\xe8\x48\x8b\xfa\x0f\x84" ); - ps3.Search( pStart, scanSize, foundData ); - if (!foundData.empty()) - _LdrpInvertedFunctionTable = *reinterpret_cast(foundData.front() - 0xF + 2) + (foundData.front() - 0xF + 6); -#else - // RtlInsertInvertedFunctionTable - // 8D 45 F0 89 55 F8 50 8D 55 F4 - PatternSearch ps1( "\x8d\x45\xf0\x89\x55\xf8\x50\x8d\x55\xf4" ); - ps1.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _RtlInsertInvertedFunctionTable = static_cast(foundData.front() - 0xB); - _LdrpInvertedFunctionTable = *reinterpret_cast(foundData.front() + 0x4C); - foundData.clear(); - } - - // LdrpHandleTlsData - // 8B C1 8D 4D BC 51 - PatternSearch ps2( "\x8b\xc1\x8d\x4d\xbc\x51" ); - ps2.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _LdrpHandleTlsData = static_cast(foundData.front() - 0x18); - foundData.clear(); - } - - // LdrProtectMrdata - // 75 24 85 F6 75 08 - PatternSearch ps3( "\x75\x24\x85\xf6\x75\x08" ); - ps3.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - _LdrProtectMrdata = static_cast(foundData.front() - 0x1C); -#endif - } - // Win 8.1 and later - else if (IsWindows8Point1OrGreater()) - { - #ifdef USE64 - // LdrpHandleTlsData - // 44 8D 43 09 4C 8D 4C 24 38 - PatternSearch ps( "\x44\x8d\x43\x09\x4c\x8d\x4c\x24\x38" ); - ps.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _LdrpHandleTlsData = static_cast(foundData.front() - 0x43); - foundData.clear(); - } - - // RtlInsertInvertedFunctionTable - // 8B C3 2B D3 48 8D 48 01 - PatternSearch ps2( "\x8B\xC3\x2B\xD3\x48\x8D\x48\x01" ); - ps2.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _RtlInsertInvertedFunctionTable = static_cast(foundData.front() - 0x84); - if (IsWindows10OrGreater()) - _LdrpInvertedFunctionTable = *reinterpret_cast(foundData.front() - 0x27 + 3) + (foundData.front() - 0x27 + 7); - } - #else - // RtlInsertInvertedFunctionTable - // 53 56 57 8B DA 8B F9 50 - PatternSearch ps1( "\x53\x56\x57\x8b\xda\x8b\xf9\x50" ); - ps1.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _RtlInsertInvertedFunctionTable = static_cast(foundData.front() - 0xB); - - if (IsWindows10OrGreater()) - _LdrpInvertedFunctionTable = *reinterpret_cast(foundData.front() + 0x22); - else - _LdrpInvertedFunctionTable = *reinterpret_cast(foundData.front() + 0x23); - - foundData.clear(); - } - // Rescan using old pattern - else - { - // RtlInsertInvertedFunctionTable - // 8D 45 F4 89 55 F8 50 8D 55 FC - PatternSearch ps12( "\x8d\x45\xf4\x89\x55\xf8\x50\x8d\x55\xfc" ); - ps12.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _RtlInsertInvertedFunctionTable = static_cast(foundData.front() - 0xB); - _LdrpInvertedFunctionTable = *reinterpret_cast(foundData.front() + 0x1D); - foundData.clear(); - } - } - - // LdrpHandleTlsData - // 8D 45 ?? 50 6A 09 6A 01 8B C1 - PatternSearch ps2( "\x8d\x45\xcc\x50\x6a\x09\x6a\x01\x8b\xc1" ); - ps2.Search( 0xCC, pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _LdrpHandleTlsData = static_cast(foundData.front() - 0x18); - foundData.clear(); - } - - // LdrProtectMrdata - // 83 7D 08 00 8B 35 - PatternSearch ps3( "\x83\x7d\x08\x00\x8b\x35", 6 ); - ps3.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - _LdrProtectMrdata = static_cast(foundData.front() - 0x12); - #endif - } - // Win 8 - else if (IsWindows8OrGreater()) - { - #ifdef USE64 - // LdrpHandleTlsData - // 48 8B 79 30 45 8D 66 01 - PatternSearch ps( "\x48\x8b\x79\x30\x45\x8d\x66\x01" ); - ps.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - _LdrpHandleTlsData = static_cast(foundData.front() - 0x49); - #else - // RtlInsertInvertedFunctionTable - // 8B FF 55 8B EC 51 51 53 57 8B 7D 08 8D - PatternSearch ps1( "\x8b\xff\x55\x8b\xec\x51\x51\x53\x57\x8b\x7d\x08\x8d" ); - ps1.Search( pStart, scanSize, foundData ); - - if(!foundData.empty()) - { - _RtlInsertInvertedFunctionTable = static_cast(foundData.front()); - _LdrpInvertedFunctionTable = *reinterpret_cast(_RtlInsertInvertedFunctionTable + 0x26); - foundData.clear(); - } - - // LdrpHandleTlsData - // 8B 45 08 89 45 A0 - PatternSearch ps2( "\x8b\x45\x08\x89\x45\xa0" ); - ps2.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - _LdrpHandleTlsData = static_cast(foundData.front() - 0xC); - #endif - } - // Win 7 - else if(IsWindows7OrGreater()) - { - #ifdef USE64 - // LdrpHandleTlsData - // 41 B8 09 00 00 00 48 8D 44 24 38 - PatternSearch ps1( "\x41\xb8\x09\x00\x00\x00\x48\x8d\x44\x24\x38", 11 ); - ps1.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _LdrpHandleTlsData = static_cast(foundData.front() - 0x27); - foundData.clear(); - } - - // LdrpFindOrMapDll patch address - // 48 8D 8C 24 98 00 00 00 41 b0 01 - PatternSearch ps2( "\x48\x8D\x8C\x24\x98\x00\x00\x00\x41\xb0\x01", 11 ); - ps2.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _LdrKernel32PatchAddress = static_cast(foundData.front() + 0x12); - foundData.clear(); - } - - // KiUserApcDispatcher patch address - // 48 8B 4C 24 18 48 8B C1 4C - PatternSearch ps3( "\x48\x8b\x4c\x24\x18\x48\x8b\xc1\x4c"); - ps3.Search( pStart, scanSize, foundData ); - - if (!foundData.empty()) - { - _APC64PatchAddress = static_cast(foundData.front()); - foundData.clear(); - } - #else - // RtlInsertInvertedFunctionTable - // 8B FF 55 8B EC 56 68 - PatternSearch ps1( "\x8b\xff\x55\x8b\xec\x56\x68" ); - ps1.Search( pStart, scanSize, foundData); - - if(!foundData.empty()) - { - _RtlInsertInvertedFunctionTable = static_cast(foundData.front( )); - foundData.clear(); - } - - // RtlLookupFunctionTable + 0x11 - // 89 5D E0 38 - PatternSearch ps2( "\x89\x5D\xE0\x38" ); - ps2.Search( pStart, scanSize, foundData ); - - if(!foundData.empty()) - { - _LdrpInvertedFunctionTable = *reinterpret_cast(foundData.front() + 0x1B); - foundData.clear(); - } - - // LdrpHandleTlsData - // 74 20 8D 45 D4 50 6A 09 - PatternSearch ps3( "\x74\x20\x8d\x45\xd4\x50\x6a\x09" ); - ps3.Search( pStart, scanSize, foundData ); - - if(!foundData.empty()) - _LdrpHandleTlsData = static_cast(foundData.front() - 0x14); - - #endif + _LdrpHandleTlsData = static_cast(data.LdrpHandleTlsData64); + _LdrpInvertedFunctionTable = static_cast(data.LdrpInvertedFunctionTable64); + _RtlInsertInvertedFunctionTable = static_cast(data.RtlInsertInvertedFunctionTable64); } return true; diff --git a/src/BlackBone/Misc/DynImport.cpp b/src/BlackBone/Misc/DynImport.cpp deleted file mode 100644 index c50a843..0000000 --- a/src/BlackBone/Misc/DynImport.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "DynImport.h" - -namespace blackbone -{ - -/// -/// Load function into database -/// -/// Function name -/// Module name -/// true on success -FARPROC DynImport::load( const std::string& name, const std::wstring& module ) -{ - auto mod = GetModuleHandleW( module.c_str() ); - return load( name, mod ); -} - -/// -/// Load function into database -/// -/// Function name -/// Module base -/// true on success -FARPROC blackbone::DynImport::load( const std::string& name, HMODULE hMod ) -{ - CSLock lck( _mapGuard ); - - auto proc = GetProcAddress( hMod, name.c_str() ); - if (proc) - { - _funcs.insert( std::make_pair( name, proc ) ); - return proc; - } - - return nullptr; -} - -} \ No newline at end of file diff --git a/src/BlackBone/Misc/DynImport.h b/src/BlackBone/Misc/DynImport.h index 5e91b36..835e68f 100644 --- a/src/BlackBone/Misc/DynImport.h +++ b/src/BlackBone/Misc/DynImport.h @@ -72,7 +72,11 @@ public: /// Function name /// Module name /// true on success - BLACKBONE_API FARPROC load( const std::string& name, const std::wstring& module ); + BLACKBONE_API FARPROC load( const std::string& name, const std::wstring& module ) + { + auto mod = GetModuleHandleW( module.c_str() ); + return load( name, mod ); + } /// /// Load function into database @@ -80,7 +84,19 @@ public: /// Function name /// Module base /// true on success - BLACKBONE_API FARPROC load( const std::string& name, HMODULE hMod ); + BLACKBONE_API FARPROC load( const std::string& name, HMODULE hMod ) + { + CSLock lck( _mapGuard ); + + auto proc = GetProcAddress( hMod, name.c_str() ); + if (proc) + { + _funcs.insert( std::make_pair( name, proc ) ); + return proc; + } + + return nullptr; + } private: DynImport() = default; diff --git a/src/BlackBone/Misc/InitOnce.cpp b/src/BlackBone/Misc/InitOnce.cpp index c99ad82..f34e8a3 100644 --- a/src/BlackBone/Misc/InitOnce.cpp +++ b/src/BlackBone/Misc/InitOnce.cpp @@ -2,6 +2,7 @@ #include "../Include/Winheaders.h" #include "../Include/Macro.h" #include "DynImport.h" +#include "PattrernLoader.h" #include #include @@ -19,6 +20,10 @@ public: GrantPriviledge( L"SeDebugPrivilege" ); GrantPriviledge( L"SeLoadDriverPrivilege" ); LoadFuncs(); + + g_PatternLoader.reset( new PatternLoader ); + g_PatternLoader->DoSearch(); + _done = true; } @@ -115,7 +120,8 @@ private: static bool _done; }; +std::unique_ptr g_PatternLoader; + bool InitOnce::_done = false; const bool g_Initialized = InitOnce::Exec(); - } \ No newline at end of file diff --git a/src/BlackBone/Misc/PattrernLoader.cpp b/src/BlackBone/Misc/PattrernLoader.cpp new file mode 100644 index 0000000..adbc840 --- /dev/null +++ b/src/BlackBone/Misc/PattrernLoader.cpp @@ -0,0 +1,296 @@ +#include "PattrernLoader.h" +#include "../PE/PEImage.h" +#include "../Include/Winheaders.h" +#include "../Misc/Trace.hpp" +#include "../../../contrib/VersionHelpers.h" + +namespace blackbone +{ + +/// +/// System32 helper +/// +class FsRedirector +{ +public: + FsRedirector( bool wow64 ) + : _wow64( wow64 ) + { + if (wow64) + Wow64DisableWow64FsRedirection( &_fsRedirection ); + } + + ~FsRedirector() + { + if (_wow64) + Wow64RevertWow64FsRedirection( _fsRedirection ); + } + +private: + PVOID _fsRedirection = nullptr; + bool _wow64; +}; + +/// +/// Scan ntdll for internal loader data +/// +/// Found data +const PatternData& PatternLoader::DoSearch() +{ + CheckSystem(); + + pe::PEImage ntdll32; + pe::PEImage ntdll64; + ptr_t scanStart32 = 0, scanSize32 = 0; + ptr_t scanStart64 = 0, scanSize64 = 0; + int64_t diff32 = 0, diff64 = 0; + + wchar_t buf[MAX_PATH] = { 0 }; + GetWindowsDirectoryW( buf, MAX_PATH ); + + std::wstring windir( buf ); + + // Load ntdlls + if (_x86OS) + { + ntdll32.Load( std::wstring( windir + L"\\System32\\ntdll.dll" ), true ); + diff32 = static_cast(ntdll32.imageBase()) - reinterpret_cast(ntdll32.base()); + } + else + { + FsRedirector fsr( _wow64Process ); + ntdll64.Load( std::wstring( windir + L"\\System32\\ntdll.dll" ), true ); + ntdll32.Load( std::wstring( windir + L"\\SysWOW64\\ntdll.dll" ), true ); + + diff32 = static_cast(ntdll32.imageBase()) - reinterpret_cast(ntdll32.base()); + diff64 = static_cast(ntdll64.imageBase()) - reinterpret_cast(ntdll64.base()); + } + + auto fillRanges = []( const pe::PEImage& file, ptr_t& start, ptr_t& size ) + { + for (auto& sec : file.sections()) + if (_stricmp( reinterpret_cast(sec.Name), ".text" ) == 0) + { + start = reinterpret_cast(file.base()) + sec.VirtualAddress; + size = sec.Misc.VirtualSize; + break; + } + }; + + // Get code section bounds + fillRanges( ntdll32, scanStart32, scanSize32 ); + if (!_x86OS) + fillRanges( ntdll64, scanStart64, scanSize64 ); + + auto scan = [&]( OffsetData& rule, auto& result ) + { + ptr_t scanStart = 0, scanSize = 0; + int64_t diff = 0; + std::vector found; + + if (rule.bit64) + { + scanStart = scanStart64; + scanSize = scanSize64; + diff = diff64; + } + else + { + scanStart = scanStart32; + scanSize = scanSize32; + diff = diff32; + } + + rule.pattern.Search( reinterpret_cast(scanStart), static_cast(scanSize), found ); + if (!found.empty()) + { + // Plain pointer sum + if (rule.functionOffset != -1) + { + result = found.front() - rule.functionOffset + diff; + } + // Pointer dereference inside instruction + else if (rule.dataStartOffset != 0) + { + if (rule.bit64) + { + result = *reinterpret_cast(found.front() + (rule.dataStartOffset + rule.dataOperandOffset)) + + (found.front() + rule.dataStartOffset + rule.dataInstructionSize) + diff; + } + else + result = *reinterpret_cast(found.front() + rule.dataStartOffset); + } + } + }; + + std::unordered_map patterns; + OSFillPatterns( patterns ); + + // Final search + for (auto& e : patterns) + scan( e.second, *e.first ); + + // Retry with old patterns + if (_data.RtlInsertInvertedFunctionTable32 == 0 && IsWindows8Point1OrGreater() && !IsWindows10CreatorsOrGreater()) + { + // RtlInsertInvertedFunctionTable + // 8D 45 F4 89 55 F8 50 8D 55 FC + OffsetData rule1{ "\x8d\x45\xf4\x89\x55\xf8\x50\x8d\x55\xfc", false, 0xB }; + OffsetData rule2{ "\x8d\x45\xf4\x89\x55\xf8\x50\x8d\x55\xfc", false, -1, 0x1D }; + + scan( rule1, _data.RtlInsertInvertedFunctionTable32 ); + scan( rule2, _data.LdrpInvertedFunctionTable32 ); + } + + // Report errors +#ifndef BLACBONE_NO_TRACE + if (_data.LdrpHandleTlsData64 == 0) + BLACKBONE_TRACE( "PatternData: LdrpHandleTlsData64 not found" ); + if (_data.LdrpHandleTlsData32 == 0) + BLACKBONE_TRACE( "PatternData: LdrpHandleTlsData32 not found" ); + if (_data.LdrpInvertedFunctionTable64 == 0) + BLACKBONE_TRACE( "PatternData: LdrpInvertedFunctionTable64 not found" ); + if (_data.LdrpInvertedFunctionTable32 == 0) + BLACKBONE_TRACE( "PatternData: LdrpInvertedFunctionTable32 not found" ); + if (_data.RtlInsertInvertedFunctionTable64 == 0) + BLACKBONE_TRACE( "PatternData: RtlInsertInvertedFunctionTable64 not found" ); + if (_data.RtlInsertInvertedFunctionTable32 == 0) + BLACKBONE_TRACE( "PatternData: RtlInsertInvertedFunctionTable32 not found" ); + if (IsWindows8Point1OrGreater() && _data.LdrProtectMrdata == 0) + BLACKBONE_TRACE( "PatternData: LdrProtectMrdata not found" ); + if (IsWindows7OrGreater() && !IsWindows8OrGreater()) + { + if (_data.LdrKernel32PatchAddress == 0) + BLACKBONE_TRACE( "PatternData: LdrKernel32PatchAddress not found" ); + if (_data.APC64PatchAddress == 0) + BLACKBONE_TRACE( "PatternData: APC64PatchAddress not found" ); + } +#endif + return _data; +} + +/// +/// Detect process and OS architecture +/// +void PatternLoader::CheckSystem() +{ + SYSTEM_INFO info = { { 0 } }; + GetNativeSystemInfo( &info ); + + if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) + { + _x86OS = true; + } + else + { + BOOL wowSrc = FALSE; + IsWow64Process( GetCurrentProcess(), &wowSrc ); + _wow64Process = wowSrc != 0; + } +} + +/// +/// Fill OS-dependent patterns +/// +/// Pattern collection +void PatternLoader::OSFillPatterns( std::unordered_map& patterns ) +{ + if (IsWindows10CreatorsOrGreater()) + { + // LdrpHandleTlsData + // 74 33 44 8D 43 09 + patterns.emplace( &_data.LdrpHandleTlsData64, OffsetData{ "\x74\x33\x44\x8d\x43\x09", true, 0x43 } ); + + // RtlInsertInvertedFunctionTable + // 8B FA 49 8D 43 20 + patterns.emplace( &_data.RtlInsertInvertedFunctionTable64, OffsetData{ "\x8b\xfa\x49\x8d\x43\x20", true, 0x10 } ); + + // RtlpInsertInvertedFunctionTableEntry + // 49 8B E8 48 8B FA 0F 84 + patterns.emplace( &_data.LdrpInvertedFunctionTable64, OffsetData{ "\x49\x8b\xe8\x48\x8b\xfa\x0f\x84", true, -1, -0xF, 2, 6 } ); + + // RtlInsertInvertedFunctionTable + // 8D 45 F0 89 55 F8 50 8D 55 F4 + patterns.emplace( &_data.RtlInsertInvertedFunctionTable32, OffsetData{ "\x8d\x45\xf0\x89\x55\xf8\x50\x8d\x55\xf4", false, 0xB } ); + patterns.emplace( &_data.LdrpInvertedFunctionTable32, OffsetData{ "\x8d\x45\xf0\x89\x55\xf8\x50\x8d\x55\xf4", false, -1, 0x4C } ); + + // LdrpHandleTlsData + // 8B C1 8D 4D BC 51 + patterns.emplace( &_data.LdrpHandleTlsData32, OffsetData{ "\x8b\xc1\x8d\x4d\xbc\x51", false, 0x18 } ); + + // LdrProtectMrdata + // 75 24 85 F6 75 08 + patterns.emplace( &_data.LdrProtectMrdata, OffsetData{ "\x75\x24\x85\xf6\x75\x08", false, 0x1C } ); + } + else if (IsWindows8Point1OrGreater()) + { + // LdrpHandleTlsData + // 44 8D 43 09 4C 8D 4C 24 38 + patterns.emplace( &_data.LdrpHandleTlsData64, OffsetData{ "\x44\x8d\x43\x09\x4c\x8d\x4c\x24\x38", true, 0x43 } ); + + // RtlInsertInvertedFunctionTable + // 8B C3 2B D3 48 8D 48 01 + patterns.emplace( &_data.RtlInsertInvertedFunctionTable64, OffsetData{ "\x8b\xc3\x2b\xd3\x48\x8d\x48\x01", true, 0x84 } ); + patterns.emplace( &_data.LdrpInvertedFunctionTable64, OffsetData{ "\x8b\xc3\x2b\xd3\x48\x8d\x48\x01", true, -1, -0x27, 3, 7 } ); + + // RtlInsertInvertedFunctionTable + // 53 56 57 8B DA 8B F9 50 + patterns.emplace( &_data.RtlInsertInvertedFunctionTable32, OffsetData{ "\x53\x56\x57\x8b\xda\x8b\xf9\x50", false, 0xB } ); + + if (IsWindows10OrGreater()) + patterns.emplace( &_data.LdrpInvertedFunctionTable32, OffsetData{ "\x53\x56\x57\x8b\xda\x8b\xf9\x50", false, -1, 0x22 } ); + else + patterns.emplace( &_data.LdrpInvertedFunctionTable32, OffsetData{ "\x53\x56\x57\x8b\xda\x8b\xf9\x50", false, -1, 0x23 } ); + + // LdrpHandleTlsData + // 50 6A 09 6A 01 8B C1 + patterns.emplace( &_data.LdrpHandleTlsData32, OffsetData{ "\x50\x6a\x09\x6a\x01\x8b\xc1", false, 0x1B } ); + + // LdrProtectMrdata + // 83 7D 08 00 8B 35 + patterns.emplace( &_data.LdrProtectMrdata, OffsetData{ "\x83\x7d\x08\x00\x8b\x35", false, 0x12 } ); + } + else if (IsWindows8OrGreater()) + { + // LdrpHandleTlsData + // 48 8B 79 30 45 8D 66 01 + patterns.emplace( &_data.LdrpHandleTlsData64, OffsetData{ "\x48\x8b\x79\x30\x45\x8d\x66\x01", true, 0x49 } ); + + // RtlInsertInvertedFunctionTable + // 8B FF 55 8B EC 51 51 53 57 8B 7D 08 8D + patterns.emplace( &_data.RtlInsertInvertedFunctionTable32, OffsetData{ "\x8b\xff\x55\x8b\xec\x51\x51\x53\x57\x8b\x7d\x08\x8d", false, 0 } ); + patterns.emplace( &_data.LdrpInvertedFunctionTable32, OffsetData{ "\x8b\xff\x55\x8b\xec\x51\x51\x53\x57\x8b\x7d\x08\x8d", false, -1, 0x26 } ); + + // LdrpHandleTlsData + // 8B 45 08 89 45 A0 + patterns.emplace( &_data.LdrpHandleTlsData32, OffsetData{ "\x8b\x45\x08\x89\x45\xa0", false, 0xC } ); + } + else if (IsWindows7OrGreater()) + { + // LdrpHandleTlsData + // 41 B8 09 00 00 00 48 8D 44 24 38 + patterns.emplace( &_data.LdrpHandleTlsData64, OffsetData{ PatternSearch( "\x41\xb8\x09\x00\x00\x00\x48\x8d\x44\x24\x38", 11 ), true, 0x27 } ); + + // LdrpFindOrMapDll patch address + // 48 8D 8C 24 98 00 00 00 41 b0 01 + patterns.emplace( &_data.LdrKernel32PatchAddress, OffsetData{ PatternSearch( "\x48\x8D\x8C\x24\x98\x00\x00\x00\x41\xb0\x01", 11 ), true, -0x12 } ); + + // KiUserApcDispatcher patch address + // 48 8B 4C 24 18 48 8B C1 4C + patterns.emplace( &_data.APC64PatchAddress, OffsetData{ "\x48\x8b\x4c\x24\x18\x48\x8b\xc1\x4c", true, 0 } ); + + // RtlInsertInvertedFunctionTable + // 8B FF 55 8B EC 56 68 + patterns.emplace( &_data.RtlInsertInvertedFunctionTable32, OffsetData{ "\x8b\xff\x55\x8b\xec\x56\x68", false, 0 } ); + + // RtlLookupFunctionTable + 0x11 + // 89 5D E0 38 + patterns.emplace( &_data.LdrpInvertedFunctionTable32, OffsetData{ "\x89\x5D\xE0\x38", false, -1, 0x1B } ); + + // LdrpHandleTlsData + // 74 20 8D 45 D4 50 6A 09 + patterns.emplace( &_data.LdrpHandleTlsData32, OffsetData{ "\x74\x20\x8d\x45\xd4\x50\x6a\x09", false, 0x14 } ); + } +} + +} \ No newline at end of file diff --git a/src/BlackBone/Misc/PattrernLoader.h b/src/BlackBone/Misc/PattrernLoader.h new file mode 100644 index 0000000..31fee53 --- /dev/null +++ b/src/BlackBone/Misc/PattrernLoader.h @@ -0,0 +1,74 @@ +#pragma once +#include "../Include/Types.h" +#include "../Patterns/PatternSearch.h" + +#include +#include + +namespace blackbone +{ + +/// +/// Ntdll internal pointers +/// +struct PatternData +{ + ptr_t LdrKernel32PatchAddress = 0; // Address to patch to enable kernel32 loading under win7 + ptr_t APC64PatchAddress = 0; // Address to patch for x64->WOW64 APC dispatching under win7 + ptr_t LdrpHandleTlsData32 = 0; // LdrpHandleTlsData address + ptr_t LdrpHandleTlsData64 = 0; // LdrpHandleTlsData address + ptr_t LdrpInvertedFunctionTable32 = 0; // LdrpInvertedFunctionTable address + ptr_t LdrpInvertedFunctionTable64 = 0; // LdrpInvertedFunctionTable address + ptr_t RtlInsertInvertedFunctionTable32 = 0; // RtlInsertInvertedFunctionTable address + ptr_t RtlInsertInvertedFunctionTable64 = 0; // RtlInsertInvertedFunctionTable address + ptr_t LdrProtectMrdata = 0; // LdrProtectMrdata address +}; + +/// +/// Ntdll scanner +/// +class PatternLoader +{ + struct OffsetData + { + PatternSearch pattern; + bool bit64; + int32_t functionOffset; + int32_t dataStartOffset; + int32_t dataOperandOffset; + int32_t dataInstructionSize; + }; + +public: + /// + /// Scan ntdll for internal loader data + /// + /// Found data + const PatternData& DoSearch(); + + /// + /// Get internal loader data + /// + /// Internal loader data + inline const PatternData& data() const { return _data; } +private: + /// + /// Detect process and OS architecture + /// + void CheckSystem(); + + /// + /// Fill OS-dependent patterns + /// + /// Pattern collection + void OSFillPatterns( std::unordered_map& patterns ); + +private: + bool _x86OS = false; // x86 OS + bool _wow64Process = false; // Current process is wow64 process + PatternData _data; // Ntdll internal loader data +}; + +extern std::unique_ptr g_PatternLoader; + +} \ No newline at end of file diff --git a/src/BlackBone/Process/Threads/Thread.h b/src/BlackBone/Process/Threads/Thread.h index b4a4c88..2d259eb 100644 --- a/src/BlackBone/Process/Threads/Thread.h +++ b/src/BlackBone/Process/Threads/Thread.h @@ -5,6 +5,7 @@ #include "../../Include/NativeStructures.h" #include "../../Include/CallResult.h" #include "../../Include/Types.h" +#include "../../Misc/Utils.h" #include diff --git a/src/BlackBone/Process/Threads/Threads.cpp b/src/BlackBone/Process/Threads/Threads.cpp index b4912a5..ca05887 100644 --- a/src/BlackBone/Process/Threads/Threads.cpp +++ b/src/BlackBone/Process/Threads/Threads.cpp @@ -43,7 +43,7 @@ call_result_t ProcessThreads::CreateNew( ptr_t threadProc, ptr_t arg, if (!NT_SUCCESS( status )) return status; - std::lock_guard lg( _lock ); + CSLock lg( _lock ); _threads.emplace_back( new Thread( hThd, &_core ) ); return _threads.back(); } @@ -75,7 +75,7 @@ std::vector& ProcessThreads::getAll( bool dontUpdate /*= false*/ ) if (tEntry.th32OwnerProcessID != _core.pid()) continue; - std::lock_guard lg( _lock ); + CSLock lg( _lock ); _threads.emplace_back( new Thread( tEntry.th32ThreadID, &_core ) ); } diff --git a/src/BlackBone/Process/Threads/Threads.h b/src/BlackBone/Process/Threads/Threads.h index 775d6df..985474c 100644 --- a/src/BlackBone/Process/Threads/Threads.h +++ b/src/BlackBone/Process/Threads/Threads.h @@ -74,7 +74,7 @@ private: private: class ProcessCore& _core; // Core process functions std::vector _threads; // Process thread snapshot - std::mutex _lock; // Update lock + CriticalSection _lock; // Update lock }; } \ No newline at end of file diff --git a/src/TestApp/LocalHookTest.cpp b/src/TestApp/LocalHookTest.cpp index c79e903..ab89956 100644 --- a/src/TestApp/LocalHookTest.cpp +++ b/src/TestApp/LocalHookTest.cpp @@ -131,7 +131,7 @@ TEST_CASE( "05. Local hooks" ) REQUIRE( det.Hook( &CloseHandle, &MyMook::hkCloseHandle, &mh, HookType::HWBP ) ); REQUIRE( det2.Hook( &TestFastcall, &hkTestFastcall, HookType::Inline ) ); - REQUIRE( det3.Hook( ptr, &::hkTest, HookType::Inline ) ); + REQUIRE( det3.Hook( ptr, &::hkTest, HookType::Int3 ) ); REQUIRE( det4.Hook( (void**)&testClass, 0, &MyMook::hkVFunc, &mh ) ); int a = args[0];