Skip to content

Commit 73e2986

Browse files
committed
updated to RS6; added test for private symbols
1 parent 25d5d49 commit 73e2986

File tree

11 files changed

+188
-45
lines changed

11 files changed

+188
-45
lines changed

src/3rd_party/VersionApi.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ enum eBuildThreshold
2626
Build_RS3 = 16299,
2727
Build_RS4 = 17134,
2828
Build_RS5 = 17763,
29+
Build_RS6 = 18362,
2930
Build_RS_MAX = 99999,
3031
};
3132

@@ -42,6 +43,7 @@ enum eVerShort
4243
Win10_RS3, // Windows 10 Fall Creators update
4344
Win10_RS4, // Windows 10 Spring Creators update
4445
Win10_RS5, // Windows 10 October 2018 update
46+
Win10_RS6, // Windows 10 May 2019 update
4547
};
4648

4749
struct WinVersion
@@ -103,7 +105,9 @@ BLACKBONE_API inline void InitVersion()
103105
switch (fullver)
104106
{
105107
case _WIN32_WINNT_WIN10:
106-
if (g_WinVer.native.dwBuildNumber >= Build_RS5)
108+
if (g_WinVer.native.dwBuildNumber >= Build_RS6)
109+
g_WinVer.ver = Win10_RS6;
110+
else if (g_WinVer.native.dwBuildNumber >= Build_RS5)
107111
g_WinVer.ver = Win10_RS5;
108112
else if (g_WinVer.native.dwBuildNumber >= Build_RS4)
109113
g_WinVer.ver = Win10_RS4;
@@ -273,6 +277,12 @@ IsWindows10RS5OrGreater()
273277
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_RS5 );
274278
}
275279

280+
VERSIONHELPERAPI
281+
IsWindows10RS6OrGreater()
282+
{
283+
return IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN10 ), LOBYTE( _WIN32_WINNT_WIN10 ), 0, Build_RS6 );
284+
}
285+
276286
VERSIONHELPERAPI
277287
IsWindowsServer()
278288
{

src/BlackBone/Include/HandleGuard.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44
namespace blackbone
55
{
66

7+
template<typename T>
8+
struct non_zero
9+
{
10+
static bool call( T handle ) noexcept
11+
{
12+
return intptr_t( handle ) != 0;
13+
}
14+
};
15+
716
template<typename T>
817
struct non_negative
918
{
@@ -119,5 +128,6 @@ using Handle = HandleGuard<HANDLE, &CloseHandle>;
119128
using ProcessHandle = HandleGuard<HANDLE, &CloseHandle, with_pseudo<non_negative>::type>;
120129
using ACtxHandle = HandleGuard<HANDLE, &ReleaseActCtx>;
121130
using RegHandle = HandleGuard<HKEY, &RegCloseKey>;
131+
using Mapping = HandleGuard<void*, & UnmapViewOfFile, non_zero>;
122132

123133
}

src/BlackBone/PE/PEImage.cpp

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ NTSTATUS PEImage::Load( const std::wstring& path, bool skipActx /*= false*/ )
5050
if (_hMapping)
5151
{
5252
_isPlainData = false;
53-
_pFileBase = MapViewOfFile( _hMapping, FILE_MAP_READ, 0, 0, 0 );
53+
_pFileBase = Mapping( MapViewOfFile( _hMapping, FILE_MAP_READ, 0, 0, 0 ) );
5454
}
5555
// Map as simple datafile
5656
else
@@ -59,7 +59,7 @@ NTSTATUS PEImage::Load( const std::wstring& path, bool skipActx /*= false*/ )
5959
_hMapping = CreateFileMappingW( _hFile, NULL, PAGE_READONLY, 0, 0, NULL );
6060

6161
if (_hMapping)
62-
_pFileBase = MapViewOfFile( _hMapping, FILE_MAP_READ, 0, 0, 0 );
62+
_pFileBase = Mapping( MapViewOfFile( _hMapping, FILE_MAP_READ, 0, 0, 0 ) );
6363
}
6464

6565
// Mapping failed
@@ -113,12 +113,7 @@ NTSTATUS PEImage::Reload()
113113
/// <param name="temporary">Preserve file paths for file reopening</param>
114114
void PEImage::Release( bool temporary /*= false*/ )
115115
{
116-
if (_pFileBase)
117-
{
118-
UnmapViewOfFile( _pFileBase );
119-
_pFileBase = nullptr;
120-
}
121-
116+
_pFileBase.reset();
122117
_hMapping.reset();
123118
_hFile.reset();
124119
_hctx.reset();
@@ -156,7 +151,7 @@ NTSTATUS PEImage::Parse( void* pImageBase /*= nullptr*/ )
156151
return STATUS_INVALID_ADDRESS;
157152

158153
// Get DOS header
159-
pDosHdr = reinterpret_cast<const IMAGE_DOS_HEADER*>(_pFileBase);
154+
pDosHdr = reinterpret_cast<const IMAGE_DOS_HEADER*>(_pFileBase.get());
160155

161156
// File not a valid PE file
162157
if (pDosHdr->e_magic != IMAGE_DOS_SIGNATURE)
@@ -206,7 +201,7 @@ NTSTATUS PEImage::Parse( void* pImageBase /*= nullptr*/ )
206201
{
207202
_ILFlagOffset = static_cast<int32_t>(
208203
reinterpret_cast<uint8_t*>(pCorHdr)
209-
- reinterpret_cast<uint8_t*>(_pFileBase)
204+
- reinterpret_cast<uint8_t*>(_pFileBase.get())
210205
+ static_cast<int32_t>(offsetof( IMAGE_COR20_HEADER, Flags )));
211206

212207
#ifdef COMPILER_MSVC
@@ -322,7 +317,7 @@ mapImports& PEImage::GetImports( bool useDelayed /*= false*/ )
322317
data.ptrRVA = pImportTbl->FirstThunk + IAT_Index;
323318
// Save address to OrigianlFirstThunk
324319
else
325-
data.ptrRVA = static_cast<uintptr_t>(AddressOfData) - reinterpret_cast<uintptr_t>(_pFileBase);
320+
data.ptrRVA = static_cast<uintptr_t>(AddressOfData) - reinterpret_cast<uintptr_t>(_pFileBase.get());
326321

327322
_imports[dllStr].emplace_back( data );
328323

@@ -350,12 +345,12 @@ void PEImage::GetExports( vecExports& exports )
350345
if (pExport == 0)
351346
return;
352347

353-
DWORD *pAddressOfNames = reinterpret_cast<DWORD*>(pExport->AddressOfNames + reinterpret_cast<uintptr_t>(_pFileBase));
354-
DWORD *pAddressOfFuncs = reinterpret_cast<DWORD*>(pExport->AddressOfFunctions + reinterpret_cast<uintptr_t>(_pFileBase));
355-
WORD *pAddressOfOrds = reinterpret_cast<WORD*> (pExport->AddressOfNameOrdinals + reinterpret_cast<size_t>(_pFileBase));
348+
DWORD *pAddressOfNames = reinterpret_cast<DWORD*>(pExport->AddressOfNames + reinterpret_cast<uintptr_t>(_pFileBase.get()));
349+
DWORD *pAddressOfFuncs = reinterpret_cast<DWORD*>(pExport->AddressOfFunctions + reinterpret_cast<uintptr_t>(_pFileBase.get()));
350+
WORD *pAddressOfOrds = reinterpret_cast<WORD*> (pExport->AddressOfNameOrdinals + reinterpret_cast<size_t>(_pFileBase.get()));
356351

357352
for (DWORD i = 0; i < pExport->NumberOfNames; ++i)
358-
exports.push_back( ExportData( reinterpret_cast<const char*>(_pFileBase)+pAddressOfNames[i], pAddressOfFuncs[pAddressOfOrds[i]] ) );
353+
exports.push_back( ExportData( reinterpret_cast<const char*>(_pFileBase.get())+pAddressOfNames[i], pAddressOfFuncs[pAddressOfOrds[i]] ) );
359354

360355
std::sort( exports.begin(), exports.end() );
361356
return Release( true );
@@ -414,15 +409,15 @@ uintptr_t PEImage::ResolveRVAToVA( uintptr_t Rva, AddressType type /*= VA*/ ) co
414409
{
415410
if (Rva >= sec.VirtualAddress && Rva < sec.VirtualAddress + sec.Misc.VirtualSize)
416411
if (type == VA)
417-
return reinterpret_cast<uintptr_t>(_pFileBase) + Rva - sec.VirtualAddress + sec.PointerToRawData;
412+
return reinterpret_cast<uintptr_t>(_pFileBase.get()) + Rva - sec.VirtualAddress + sec.PointerToRawData;
418413
else
419414
return Rva - sec.VirtualAddress + sec.PointerToRawData;
420415
}
421416

422417
return 0;
423418
}
424419
else
425-
return (type == VA) ? (reinterpret_cast<uintptr_t>(_pFileBase) + Rva) : Rva;
420+
return (type == VA) ? (reinterpret_cast<uintptr_t>(_pFileBase.get()) + Rva) : Rva;
426421

427422
default:
428423
return 0;
@@ -449,7 +444,7 @@ int PEImage::GetTLSCallbacks( module_t targetBase, std::vector<ptr_t>& result )
449444
return 0;
450445

451446
// Not at base
452-
if (imageBase() != reinterpret_cast<module_t>(_pFileBase))
447+
if (imageBase() != reinterpret_cast<module_t>(_pFileBase.get()))
453448
pCallback = reinterpret_cast<uint64_t*>(ResolveRVAToVA( static_cast<size_t>(offset - imageBase()) ));
454449
else
455450
pCallback = reinterpret_cast<uint64_t*>(offset);

src/BlackBone/PE/PEImage.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ class PEImage
9595
BLACKBONE_API PEImage( void );
9696
BLACKBONE_API ~PEImage( void );
9797

98+
BLACKBONE_API PEImage( PEImage&& other ) = default;
99+
98100
/// <summary>
99101
/// Load image from file
100102
/// </summary>
@@ -312,7 +314,7 @@ class PEImage
312314
private:
313315
Handle _hFile; // Target file HANDLE
314316
Handle _hMapping; // Memory mapping object
315-
void* _pFileBase = nullptr; // Mapping base
317+
Mapping _pFileBase; // Mapping base
316318
bool _isPlainData = false; // File mapped as plain data file
317319
bool _is64 = false; // Image is 64 bit
318320
bool _isExe = false; // Image is an .exe file

src/BlackBone/Symbols/PatternLoader.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ void OSFillPatterns( std::unordered_map<ptr_t*, OffsetData>& patterns, SymbolDat
7373
{
7474
// LdrpHandleTlsData
7575
// 74 33 44 8D 43 09
76-
auto offset = IsWindows10RS4OrGreater() ? 0x44 : 0x43;
76+
auto offset = 0x43;
77+
if(IsWindows10RS6OrGreater())
78+
offset = 0x46;
79+
else if (IsWindows10RS4OrGreater())
80+
offset = 0x44;
81+
7782
patterns.emplace( &result.LdrpHandleTlsData64, OffsetData{ "\x74\x33\x44\x8d\x43\x09", true, offset } );
7883

7984
// RtlInsertInvertedFunctionTable
@@ -95,9 +100,19 @@ void OSFillPatterns( std::unordered_map<ptr_t*, OffsetData>& patterns, SymbolDat
95100
// LdrpHandleTlsData
96101
// 33 F6 85 C0 79 03 - RS5+
97102
// 8B C1 8D 4D AC/BC 51 - RS3-RS4
98-
const auto pattern = IsWindows10RS4OrGreater() ? "\x8b\xc1\x8d\x4d\xac\x51" : "\x8b\xc1\x8d\x4d\xbc\x51";
99-
const auto data = IsWindows10RS5OrGreater() ? OffsetData{ "\x33\xf6\x85\xc0\x79\x03", false, 0x2C } : OffsetData{ pattern, false, 0x18 };
100-
patterns.emplace( &result.LdrpHandleTlsData32, data );
103+
auto pattern = "\x8b\xc1\x8d\x4d\xbc\x51";
104+
if (IsWindows10RS5OrGreater())
105+
pattern = "\x33\xf6\x85\xc0\x79\x03";
106+
else if (IsWindows10RS4OrGreater())
107+
pattern = "\x8b\xc1\x8d\x4d\xac\x51";
108+
109+
offset = 0x18;
110+
if (IsWindows10RS6OrGreater())
111+
offset = 0x2E;
112+
else if (IsWindows10RS5OrGreater())
113+
offset = 0x2C;
114+
115+
patterns.emplace( &result.LdrpHandleTlsData32, OffsetData{ pattern, false, offset } );
101116

102117
// LdrProtectMrdata
103118
// 75 24 85 F6 75 08

src/BlackBone/Symbols/SymbolLoader.cpp

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,34 +32,32 @@ SymbolLoader::SymbolLoader()
3232
/// <returns>Status code</returns>
3333
NTSTATUS SymbolLoader::Load( SymbolData& result )
3434
{
35-
pe::PEImage ntdll32, ntdll64;
36-
PDBHelper sym32, sym64;
37-
38-
wchar_t buf[MAX_PATH] = { 0 };
39-
GetWindowsDirectoryW( buf, MAX_PATH );
40-
41-
std::wstring windir( buf );
42-
43-
if (_x86OS)
44-
{
45-
ntdll32.Load( std::wstring( windir + L"\\System32\\ntdll.dll" ), true );
46-
}
47-
else
48-
{
49-
FsRedirector fsr( _wow64Process );
35+
auto [ntdll32, ntdll64] = LoadImages();
5036

51-
ntdll64.Load( std::wstring( windir + L"\\System32\\ntdll.dll" ), true );
52-
ntdll32.Load( std::wstring( windir + L"\\SysWOW64\\ntdll.dll" ), true );
53-
}
37+
// Get addresses from pdb
38+
LoadFromSymbols( ntdll32, ntdll64, result );
39+
40+
// Fill missing symbols from patterns
41+
return LoadFromPatterns( ntdll32, ntdll64, result );
42+
}
5443

44+
/// <summary>
45+
/// Load symbol addresses from PDBs
46+
/// </summary>
47+
/// <param name="ntdll32">Loaded x86 ntdll image</param>
48+
/// <param name="ntdll64">Loaded x64 ntdll image</param>
49+
/// <param name="result">Found symbols</param>
50+
/// <returns>Status code</returns>
51+
NTSTATUS SymbolLoader::LoadFromSymbols( const pe::PEImage& ntdll32, const pe::PEImage& ntdll64, SymbolData& result )
52+
{
53+
PDBHelper sym32, sym64;
5554
HRESULT hr = sym32.Init( ntdll32.path(), ntdll32.imageBase() );
5655
if (!_x86OS && SUCCEEDED( hr ))
5756
{
5857
FsRedirector fsr( _wow64Process );
5958
hr = sym64.Init( ntdll64.path(), ntdll64.imageBase() );
6059
}
6160

62-
// Get addresses from pdb
6361
if (SUCCEEDED( hr ))
6462
{
6563
sym32.GetSymAddress( L"LdrpHandleTlsData", result.LdrpHandleTlsData32 );
@@ -75,10 +73,50 @@ NTSTATUS SymbolLoader::Load( SymbolData& result )
7573
sym64.GetSymAddress( L"LdrpReleaseTlsEntry", result.LdrpReleaseTlsEntry64 );
7674

7775
sym32.GetSymAddress( L"LdrProtectMrdata", result.LdrProtectMrdata );
76+
77+
return STATUS_SUCCESS;
7878
}
79-
80-
// Fill missing symbols from patterns
79+
80+
return STATUS_UNSUCCESSFUL;
81+
}
82+
83+
/// <summary>
84+
/// Load symbol addresses from pattern scans
85+
/// </summary>
86+
/// <param name="ntdll32">Loaded x86 ntdll image</param>
87+
/// <param name="ntdll64">Loaded x64 ntdll image</param>
88+
/// <param name="result">Found symbols</param>
89+
/// <returns>Status code</returns>
90+
NTSTATUS SymbolLoader::LoadFromPatterns( const pe::PEImage& ntdll32, const pe::PEImage& ntdll64, SymbolData& result )
91+
{
8192
return ScanSymbolPatterns( ntdll32, ntdll64, result );
8293
}
8394

95+
/// <summary>
96+
/// Load ntdll images from the disk
97+
/// </summary>
98+
/// <returns>Loaded x86 and x64 ntdll</returns>
99+
std::pair<pe::PEImage, pe::PEImage> SymbolLoader::LoadImages()
100+
{
101+
pe::PEImage ntdll32, ntdll64;
102+
103+
wchar_t buf[MAX_PATH] = { 0 };
104+
GetWindowsDirectoryW( buf, MAX_PATH );
105+
std::wstring windir( buf );
106+
107+
if (_x86OS)
108+
{
109+
ntdll32.Load( std::wstring( windir + L"\\System32\\ntdll.dll" ), true );
110+
}
111+
else
112+
{
113+
FsRedirector fsr( _wow64Process );
114+
115+
ntdll64.Load( std::wstring( windir + L"\\System32\\ntdll.dll" ), true );
116+
ntdll32.Load( std::wstring( windir + L"\\SysWOW64\\ntdll.dll" ), true );
117+
}
118+
119+
return std::make_pair( std::move( ntdll32 ), std::move( ntdll64 ) );
120+
}
121+
84122
}

src/BlackBone/Symbols/SymbolLoader.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
namespace blackbone
55
{
66

7+
namespace pe
8+
{
9+
class PEImage;
10+
}
11+
712
class SymbolLoader
813
{
914
public:
@@ -16,6 +21,30 @@ class SymbolLoader
1621
/// <returns>Status code</returns>
1722
NTSTATUS Load( SymbolData& result );
1823

24+
/// <summary>
25+
/// Load symbol addresses from PDBs
26+
/// </summary>
27+
/// <param name="ntdll32">Loaded x86 ntdll image</param>
28+
/// <param name="ntdll64">Loaded x64 ntdll image</param>
29+
/// <param name="result">Found symbols</param>
30+
/// <returns>Status code</returns>
31+
NTSTATUS LoadFromSymbols( const pe::PEImage& ntdll32, const pe::PEImage& ntdll64, SymbolData& result );
32+
33+
/// <summary>
34+
/// Load symbol addresses from pattern scans
35+
/// </summary>
36+
/// <param name="ntdll32">Loaded x86 ntdll image</param>
37+
/// <param name="ntdll64">Loaded x64 ntdll image</param>
38+
/// <param name="result">Found symbols</param>
39+
/// <returns>Status code</returns>
40+
NTSTATUS LoadFromPatterns( const pe::PEImage& ntdll32, const pe::PEImage& ntdll64, SymbolData& result );
41+
42+
/// <summary>
43+
/// Load ntdll images from the disk
44+
/// </summary>
45+
/// <returns>Loaded x86 and x64 ntdll</returns>
46+
std::pair<pe::PEImage, pe::PEImage> LoadImages();
47+
1948
private:
2049
bool _x86OS; // x86 OS
2150
bool _wow64Process; // Current process is wow64 process

src/BlackBoneTest/BlackBoneTest.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@
315315
<ClInclude Include="Common.h" />
316316
</ItemGroup>
317317
<ItemGroup>
318+
<ClCompile Include="TestSymbols.cpp" />
318319
<ClCompile Include="TestAsmJit.cpp" />
319320
<ClCompile Include="TestAsmVariant.cpp" />
320321
<ClCompile Include="TestDriver.cpp" />

src/BlackBoneTest/BlackBoneTest.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
<ClCompile Include="TestGuard.cpp">
4141
<Filter>Tests</Filter>
4242
</ClCompile>
43+
<ClCompile Include="TestSymbols.cpp">
44+
<Filter>Tests</Filter>
45+
</ClCompile>
4346
</ItemGroup>
4447
<ItemGroup>
4548
<ClInclude Include="Common.h" />

src/BlackBoneTest/Common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <BlackBone/Patterns/PatternSearch.h>
1111
#include <BlackBone/Asm/LDasm.h>
1212
#include <BlackBone/localHook/VTableHook.hpp>
13+
#include <BlackBone/Symbols/SymbolLoader.h>
1314

1415
#include <iostream>
1516
#include <CppUnitTest.h>

0 commit comments

Comments
 (0)