ntdll pattern scan separation

This commit is contained in:
DarthTon
2017-04-10 03:28:39 +03:00
parent 199d66df12
commit dba8049ae9
12 changed files with 432 additions and 352 deletions
+2 -1
View File
@@ -618,9 +618,9 @@
<ClCompile Include="ManualMap\MExcept.cpp" />
<ClCompile Include="ManualMap\MMap.cpp" />
<ClCompile Include="ManualMap\Native\NtLoader.cpp" />
<ClCompile Include="Misc\DynImport.cpp" />
<ClCompile Include="Misc\InitOnce.cpp" />
<ClCompile Include="Misc\NameResolve.cpp" />
<ClCompile Include="Misc\PattrernLoader.cpp" />
<ClCompile Include="Misc\Utils.cpp" />
<ClCompile Include="Patterns\PatternSearch.cpp" />
<ClCompile Include="PE\ImageNET.cpp" />
@@ -717,6 +717,7 @@
<ClInclude Include="Misc\DynImport.h" />
<ClInclude Include="Misc\InitOnce.h" />
<ClInclude Include="Misc\NameResolve.h" />
<ClInclude Include="Misc\PattrernLoader.h" />
<ClInclude Include="Misc\Thunk.hpp" />
<ClInclude Include="Misc\Trace.hpp" />
<ClInclude Include="Misc\Utils.h" />
+6 -3
View File
@@ -90,9 +90,6 @@
<ClCompile Include="Patterns\PatternSearch.cpp">
<Filter>Patterns</Filter>
</ClCompile>
<ClCompile Include="Misc\DynImport.cpp">
<Filter>Misc</Filter>
</ClCompile>
<ClCompile Include="Misc\NameResolve.cpp">
<Filter>Misc</Filter>
</ClCompile>
@@ -195,6 +192,9 @@
<ClCompile Include="..\..\contrib\rewolf-wow64ext\src\wow64ext.cpp">
<Filter>Subsystem</Filter>
</ClCompile>
<ClCompile Include="Misc\PattrernLoader.cpp">
<Filter>Misc</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Config.h" />
@@ -450,5 +450,8 @@
<ClInclude Include="Asm\AsmFactory.h">
<Filter>AsmJit\Helpers</Filter>
</ClInclude>
<ClInclude Include="Misc\PattrernLoader.h">
<Filter>Misc</Filter>
</ClInclude>
</ItemGroup>
</Project>
+24 -303
View File
@@ -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
/// </summary>
/// <returns>true on success</returns>
bool NtLdr::FindLdrpHashTable( )
bool NtLdr::FindLdrpHashTable()
{
PEB_LDR_DATA_T *Ldr =
reinterpret_cast<PEB_LDR_DATA_T*>(
reinterpret_cast<PEB_T*>(
reinterpret_cast<TEB_T*>(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<wchar_t*>(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<PLIST_ENTRY>(Ntdll->HashLinks.Flink);
e != reinterpret_cast<PLIST_ENTRY>(&Ntdll->HashLinks);
e = e->Flink)
for (auto e = reinterpret_cast<PLIST_ENTRY>(Ntdll->HashLinks.Flink); e != reinterpret_cast<PLIST_ENTRY>(&Ntdll->HashLinks); e = e->Flink)
{
if (reinterpret_cast<ULONG_PTR>(e) >= NtdllBase &&
reinterpret_cast<ULONG_PTR>(e) < NtdllEndAddress)
if (reinterpret_cast<ULONG_PTR>(e) >= NtdllBase && reinterpret_cast<ULONG_PTR>(e) < NtdllEndAddress)
{
bHeadFound = true;
pNtdllHashHead = e;
break;
}
}
if (bHeadFound)
if (pNtdllHashHead != nullptr)
_LdrpHashTable = reinterpret_cast<uintptr_t>(pNtdllHashHead - NtdllHashIndex);
return bHeadFound;
return _LdrpHashTable != 0;
}
@@ -795,16 +769,15 @@ bool NtLdr::FindLdrpHashTable( )
/// Find LdrpModuleIndex variable under win8
/// </summary>
/// <returns>true on success</returns>
bool NtLdr::FindLdrpModuleIndexBase( )
bool NtLdr::FindLdrpModuleIndexBase()
{
PEB_T* pPeb = reinterpret_cast<PEB_T*>(reinterpret_cast<TEB_T*>(NtCurrentTeb())->ProcessEnvironmentBlock);
if(pPeb)
{
PRTL_BALANCED_NODE lastNode = 0;
PEB_LDR_DATA_T* Ldr = reinterpret_cast<PEB_LDR_DATA_T*>(pPeb->Ldr);
_LDR_DATA_TABLE_ENTRY_W8 *Ntdll = CONTAINING_RECORD( Ldr->InInitializationOrderModuleList.Flink,
_LDR_DATA_TABLE_ENTRY_W8, InInitializationOrderLinks );
auto Ldr = reinterpret_cast<PEB_LDR_DATA_T*>(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( )
/// <returns>true on success</returns>
bool NtLdr::ScanPatterns( )
{
std::vector<ptr_t> 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<uintptr_t>(data.LdrKernel32PatchAddress);
_APC64PatchAddress = static_cast<uintptr_t>(data.APC64PatchAddress);
_LdrProtectMrdata = static_cast<uintptr_t>(data.LdrProtectMrdata);
// Find ntdll code section
for (auto& section : ntdll.sections())
if (_process.core().isWow64())
{
if (_stricmp( reinterpret_cast<LPCSTR>(section.Name), ".text" ) == 0)
{
pStart = reinterpret_cast<void*>(reinterpret_cast<size_t>(hNtdll) + section.VirtualAddress);
scanSize = section.Misc.VirtualSize;
break;
}
_LdrpHandleTlsData = static_cast<uintptr_t>(data.LdrpHandleTlsData32);
_LdrpInvertedFunctionTable = static_cast<uintptr_t>(data.LdrpInvertedFunctionTable32);
_RtlInsertInvertedFunctionTable = static_cast<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<int32_t*>(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<size_t>(foundData.front() - 0xB);
_LdrpInvertedFunctionTable = *reinterpret_cast<uintptr_t*>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(foundData.front() - 0x84);
if (IsWindows10OrGreater())
_LdrpInvertedFunctionTable = *reinterpret_cast<int32_t*>(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<size_t>(foundData.front() - 0xB);
if (IsWindows10OrGreater())
_LdrpInvertedFunctionTable = *reinterpret_cast<uintptr_t*>(foundData.front() + 0x22);
else
_LdrpInvertedFunctionTable = *reinterpret_cast<uintptr_t*>(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<uintptr_t>(foundData.front() - 0xB);
_LdrpInvertedFunctionTable = *reinterpret_cast<uintptr_t*>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(foundData.front());
_LdrpInvertedFunctionTable = *reinterpret_cast<uintptr_t*>(_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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<size_t>(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<uintptr_t*>(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<uintptr_t>(foundData.front() - 0x14);
#endif
_LdrpHandleTlsData = static_cast<uintptr_t>(data.LdrpHandleTlsData64);
_LdrpInvertedFunctionTable = static_cast<uintptr_t>(data.LdrpInvertedFunctionTable64);
_RtlInsertInvertedFunctionTable = static_cast<uintptr_t>(data.RtlInsertInvertedFunctionTable64);
}
return true;
-38
View File
@@ -1,38 +0,0 @@
#include "DynImport.h"
namespace blackbone
{
/// <summary>
/// Load function into database
/// </summary>
/// <param name="name">Function name</param>
/// <param name="module">Module name</param>
/// <returns>true on success</returns>
FARPROC DynImport::load( const std::string& name, const std::wstring& module )
{
auto mod = GetModuleHandleW( module.c_str() );
return load( name, mod );
}
/// <summary>
/// Load function into database
/// </summary>
/// <param name="name">Function name</param>
/// <param name="hMod">Module base</param>
/// <returns>true on success</returns>
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;
}
}
+18 -2
View File
@@ -72,7 +72,11 @@ public:
/// <param name="name">Function name</param>
/// <param name="module">Module name</param>
/// <returns>true on success</returns>
BLACKBONE_API FARPROC load( const std::string& name, const std::wstring& module );
BLACKBONE_API FARPROC load( const std::string& name, const std::wstring& module )
{
auto mod = GetModuleHandleW( module.c_str() );
return load( name, mod );
}
/// <summary>
/// Load function into database
@@ -80,7 +84,19 @@ public:
/// <param name="name">Function name</param>
/// <param name="hMod">Module base</param>
/// <returns>true on success</returns>
BLACKBONE_API FARPROC load( const std::string& name, HMODULE hMod );
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;
+7 -1
View File
@@ -2,6 +2,7 @@
#include "../Include/Winheaders.h"
#include "../Include/Macro.h"
#include "DynImport.h"
#include "PattrernLoader.h"
#include <string>
#include <cassert>
@@ -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<PatternLoader> g_PatternLoader;
bool InitOnce::_done = false;
const bool g_Initialized = InitOnce::Exec();
}
+296
View File
@@ -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
{
/// <summary>
/// System32 helper
/// </summary>
class FsRedirector
{
public:
FsRedirector( bool wow64 )
: _wow64( wow64 )
{
if (wow64)
Wow64DisableWow64FsRedirection( &_fsRedirection );
}
~FsRedirector()
{
if (_wow64)
Wow64RevertWow64FsRedirection( _fsRedirection );
}
private:
PVOID _fsRedirection = nullptr;
bool _wow64;
};
/// <summary>
/// Scan ntdll for internal loader data
/// </summary>
/// <returns>Found data</returns>
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<int64_t>(ntdll32.imageBase()) - reinterpret_cast<int64_t>(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<int64_t>(ntdll32.imageBase()) - reinterpret_cast<int64_t>(ntdll32.base());
diff64 = static_cast<int64_t>(ntdll64.imageBase()) - reinterpret_cast<int64_t>(ntdll64.base());
}
auto fillRanges = []( const pe::PEImage& file, ptr_t& start, ptr_t& size )
{
for (auto& sec : file.sections())
if (_stricmp( reinterpret_cast<const char*>(sec.Name), ".text" ) == 0)
{
start = reinterpret_cast<ptr_t>(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<ptr_t> found;
if (rule.bit64)
{
scanStart = scanStart64;
scanSize = scanSize64;
diff = diff64;
}
else
{
scanStart = scanStart32;
scanSize = scanSize32;
diff = diff32;
}
rule.pattern.Search( reinterpret_cast<void*>(scanStart), static_cast<size_t>(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<int32_t*>(found.front() + (rule.dataStartOffset + rule.dataOperandOffset)) +
(found.front() + rule.dataStartOffset + rule.dataInstructionSize) + diff;
}
else
result = *reinterpret_cast<int32_t*>(found.front() + rule.dataStartOffset);
}
}
};
std::unordered_map<ptr_t*, OffsetData> 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;
}
/// <summary>
/// Detect process and OS architecture
/// </summary>
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;
}
}
/// <summary>
/// Fill OS-dependent patterns
/// </summary>
/// <param name="patterns">Pattern collection</param>
void PatternLoader::OSFillPatterns( std::unordered_map<ptr_t*, OffsetData>& 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 } );
}
}
}
+74
View File
@@ -0,0 +1,74 @@
#pragma once
#include "../Include/Types.h"
#include "../Patterns/PatternSearch.h"
#include <memory>
#include <unordered_map>
namespace blackbone
{
/// <summary>
/// Ntdll internal pointers
/// </summary>
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
};
/// <summary>
/// Ntdll scanner
/// </summary>
class PatternLoader
{
struct OffsetData
{
PatternSearch pattern;
bool bit64;
int32_t functionOffset;
int32_t dataStartOffset;
int32_t dataOperandOffset;
int32_t dataInstructionSize;
};
public:
/// <summary>
/// Scan ntdll for internal loader data
/// </summary>
/// <returns>Found data</returns>
const PatternData& DoSearch();
/// <summary>
/// Get internal loader data
/// </summary>
/// <returns>Internal loader data</returns>
inline const PatternData& data() const { return _data; }
private:
/// <summary>
/// Detect process and OS architecture
/// </summary>
void CheckSystem();
/// <summary>
/// Fill OS-dependent patterns
/// </summary>
/// <param name="patterns">Pattern collection</param>
void OSFillPatterns( std::unordered_map<ptr_t*, OffsetData>& 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<PatternLoader> g_PatternLoader;
}
+1
View File
@@ -5,6 +5,7 @@
#include "../../Include/NativeStructures.h"
#include "../../Include/CallResult.h"
#include "../../Include/Types.h"
#include "../../Misc/Utils.h"
#include <memory>
+2 -2
View File
@@ -43,7 +43,7 @@ call_result_t<ThreadPtr> ProcessThreads::CreateNew( ptr_t threadProc, ptr_t arg,
if (!NT_SUCCESS( status ))
return status;
std::lock_guard<std::mutex> lg( _lock );
CSLock lg( _lock );
_threads.emplace_back( new Thread( hThd, &_core ) );
return _threads.back();
}
@@ -75,7 +75,7 @@ std::vector<ThreadPtr>& ProcessThreads::getAll( bool dontUpdate /*= false*/ )
if (tEntry.th32OwnerProcessID != _core.pid())
continue;
std::lock_guard<std::mutex> lg( _lock );
CSLock lg( _lock );
_threads.emplace_back( new Thread( tEntry.th32ThreadID, &_core ) );
}
+1 -1
View File
@@ -74,7 +74,7 @@ private:
private:
class ProcessCore& _core; // Core process functions
std::vector<ThreadPtr> _threads; // Process thread snapshot
std::mutex _lock; // Update lock
CriticalSection _lock; // Update lock
};
}
+1 -1
View File
@@ -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];