mirror of
https://github.com/wavestone-cdt/EDRSandblast.git
synced 2026-06-10 09:27:19 +00:00
Implements a check on PDB files to avoid using an invalid one and crash the machine
When loading a PDB that was already on disk (not downloaded) for a specific PE, verifies that the PDB file is indeed for the current version of the target PE. (Did I just started to write a PDB file parser ?)
This commit is contained in:
@@ -178,6 +178,7 @@
|
|||||||
<ClCompile Include="LSASSProtectionBypass\CredGuard.c" />
|
<ClCompile Include="LSASSProtectionBypass\CredGuard.c" />
|
||||||
<ClCompile Include="LSASSProtectionBypass\RunAsPPL.c" />
|
<ClCompile Include="LSASSProtectionBypass\RunAsPPL.c" />
|
||||||
<ClCompile Include="Utils\ListUtils.c" />
|
<ClCompile Include="Utils\ListUtils.c" />
|
||||||
|
<ClCompile Include="Utils\PdbParser.c" />
|
||||||
<ClCompile Include="Utils\RemotePEBBrowser.c" />
|
<ClCompile Include="Utils\RemotePEBBrowser.c" />
|
||||||
<ClCompile Include="Utils\PdbSymbols.c" />
|
<ClCompile Include="Utils\PdbSymbols.c" />
|
||||||
<ClCompile Include="UserlandBypass\Firewalling.c" />
|
<ClCompile Include="UserlandBypass\Firewalling.c" />
|
||||||
@@ -208,6 +209,7 @@
|
|||||||
<ClInclude Include="Includes\DriverRTCore.h" />
|
<ClInclude Include="Includes\DriverRTCore.h" />
|
||||||
<ClInclude Include="Includes\KernelDSE.h" />
|
<ClInclude Include="Includes\KernelDSE.h" />
|
||||||
<ClInclude Include="Includes\PrintFunctions.h" />
|
<ClInclude Include="Includes\PrintFunctions.h" />
|
||||||
|
<ClInclude Include="Includes\PdbParser.h" />
|
||||||
<ClInclude Include="Includes\ProcessDumpDirectSyscalls.h" />
|
<ClInclude Include="Includes\ProcessDumpDirectSyscalls.h" />
|
||||||
<ClInclude Include="Includes\FileUtils.h" />
|
<ClInclude Include="Includes\FileUtils.h" />
|
||||||
<ClInclude Include="Includes\HttpClient.h" />
|
<ClInclude Include="Includes\HttpClient.h" />
|
||||||
|
|||||||
@@ -126,6 +126,9 @@
|
|||||||
<ClCompile Include="KernellandBypass\KernelDSE.c">
|
<ClCompile Include="KernellandBypass\KernelDSE.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Utils\PdbParser.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Includes\CredGuard.h">
|
<ClInclude Include="Includes\CredGuard.h">
|
||||||
@@ -248,6 +251,9 @@
|
|||||||
<ClInclude Include="Includes\PrintFunctions.h">
|
<ClInclude Include="Includes\PrintFunctions.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Includes\PdbParser.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<MASM Include="Utils\SW2_Syscalls_stubs.x64.asm">
|
<MASM Include="Utils\SW2_Syscalls_stubs.x64.asm">
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
PVOID extractGuidFromPdb(LPWSTR filepath);
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "PEParser.h"
|
||||||
|
|
||||||
typedef struct symbol_ctx_t {
|
typedef struct symbol_ctx_t {
|
||||||
LPWSTR pdb_name_w;
|
LPWSTR pdb_name_w;
|
||||||
@@ -6,6 +7,7 @@ typedef struct symbol_ctx_t {
|
|||||||
HANDLE sym_handle;
|
HANDLE sym_handle;
|
||||||
} symbol_ctx;
|
} symbol_ctx;
|
||||||
|
|
||||||
|
symbol_ctx* LoadSymbolsFromPE(PE* pe);
|
||||||
symbol_ctx* LoadSymbolsFromImageFile(LPCWSTR image_file_path);
|
symbol_ctx* LoadSymbolsFromImageFile(LPCWSTR image_file_path);
|
||||||
DWORD64 GetSymbolOffset(symbol_ctx* ctx, LPCSTR symbol_name);
|
DWORD64 GetSymbolOffset(symbol_ctx* ctx, LPCSTR symbol_name);
|
||||||
DWORD GetFieldOffset(symbol_ctx* ctx, LPCSTR struct_name, LPCWSTR field_name);
|
DWORD GetFieldOffset(symbol_ctx* ctx, LPCSTR struct_name, LPCWSTR field_name);
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
typedef DWORD ulittle32_t;
|
||||||
|
|
||||||
|
typedef struct SuperBlock_t {
|
||||||
|
char FileMagic[0x20];
|
||||||
|
ulittle32_t BlockSize;
|
||||||
|
ulittle32_t FreeBlockMapBlock;
|
||||||
|
ulittle32_t NumBlocks;
|
||||||
|
ulittle32_t NumDirectoryBytes;
|
||||||
|
ulittle32_t Unknown;
|
||||||
|
ulittle32_t BlockMapAddr;
|
||||||
|
}SuperBlock;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct StreamDirectory {
|
||||||
|
ulittle32_t NumStreams;
|
||||||
|
ulittle32_t StreamSizes[NumStreams];
|
||||||
|
ulittle32_t StreamBlocks[NumStreams][];
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct PdbInfoStreamHeader_t {
|
||||||
|
DWORD Version;
|
||||||
|
DWORD Signature;
|
||||||
|
DWORD Age;
|
||||||
|
GUID UniqueId;
|
||||||
|
} PdbInfoStreamHeader;
|
||||||
|
|
||||||
|
PVOID extractGuidFromPdb(LPWSTR filepath) {
|
||||||
|
GUID* guid = NULL;
|
||||||
|
HANDLE hFile = CreateFileW(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
HANDLE hMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||||
|
if (hMapping == NULL) {
|
||||||
|
goto clean_file;
|
||||||
|
}
|
||||||
|
PBYTE filemap = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
|
||||||
|
if (filemap == NULL) {
|
||||||
|
goto clean_mapping;
|
||||||
|
}
|
||||||
|
SuperBlock* superblock = (SuperBlock*)filemap;
|
||||||
|
DWORD blockSize = superblock->BlockSize;
|
||||||
|
DWORD* StreamDirectoryBlockMap = (DWORD*)(filemap + (ULONG_PTR)superblock->BlockMapAddr * blockSize);
|
||||||
|
DWORD* StreamDirectory = calloc(superblock->NumDirectoryBytes, 1);
|
||||||
|
if (StreamDirectory == NULL) {
|
||||||
|
goto clean_viewoffile;
|
||||||
|
}
|
||||||
|
DWORD StreamDirectoryBlockIndex = 0;
|
||||||
|
DWORD StreamDirectoryRemainingSize = superblock->NumDirectoryBytes;
|
||||||
|
while (StreamDirectoryRemainingSize) {
|
||||||
|
DWORD SizeToCopy = min(StreamDirectoryRemainingSize, blockSize);
|
||||||
|
memcpy(
|
||||||
|
((PBYTE)StreamDirectory) + (ULONG_PTR)StreamDirectoryBlockIndex * blockSize,
|
||||||
|
((PBYTE)filemap) + (ULONG_PTR)blockSize * StreamDirectoryBlockMap[StreamDirectoryBlockIndex],
|
||||||
|
SizeToCopy);
|
||||||
|
StreamDirectoryBlockIndex++;
|
||||||
|
StreamDirectoryRemainingSize -= SizeToCopy;
|
||||||
|
}
|
||||||
|
DWORD NumStreams = StreamDirectory[0];
|
||||||
|
if (NumStreams < 2) {
|
||||||
|
goto clean_StreamDirectory;
|
||||||
|
}
|
||||||
|
DWORD** StreamBlocks = calloc(NumStreams, sizeof(DWORD*));
|
||||||
|
if (StreamBlocks == NULL) {
|
||||||
|
goto clean_StreamDirectory;
|
||||||
|
}
|
||||||
|
DWORD* StreamBlocksFlat = &StreamDirectory[1 + NumStreams];
|
||||||
|
DWORD i = 0;
|
||||||
|
if ((1 + NumStreams) >= superblock->NumDirectoryBytes / 4) {
|
||||||
|
goto clean_StreamBlocks;
|
||||||
|
}
|
||||||
|
for (DWORD stream_i = 0; stream_i < NumStreams; stream_i++) {
|
||||||
|
DWORD StreamSize = StreamDirectory[1 + stream_i];
|
||||||
|
DWORD StreamBlockCount = 0;
|
||||||
|
while (StreamBlockCount * blockSize < StreamSize) {
|
||||||
|
PVOID tmp = realloc(StreamBlocks[stream_i], ((SIZE_T)StreamBlockCount + 1) * sizeof(DWORD));
|
||||||
|
if (tmp == NULL) {
|
||||||
|
goto clean_StreamBlocks;
|
||||||
|
}
|
||||||
|
StreamBlocks[stream_i] = tmp;
|
||||||
|
StreamBlocks[stream_i][StreamBlockCount] = StreamBlocksFlat[i];
|
||||||
|
i++;
|
||||||
|
StreamBlockCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DWORD PdbInfoStreamSize = StreamDirectory[1 + 1];
|
||||||
|
if (PdbInfoStreamSize == 0) {
|
||||||
|
goto clean_StreamBlocks;
|
||||||
|
}
|
||||||
|
PdbInfoStreamHeader* PdbInfoStream = (PdbInfoStreamHeader*)(filemap + (ULONG_PTR)StreamBlocks[1][0] * blockSize);
|
||||||
|
guid = calloc(1, sizeof(GUID));
|
||||||
|
if (guid == NULL) {
|
||||||
|
goto clean_StreamBlocks;
|
||||||
|
}
|
||||||
|
memcpy(guid, &PdbInfoStream->UniqueId, sizeof(GUID));
|
||||||
|
clean_StreamBlocks:
|
||||||
|
for (DWORD stream_i = 0; stream_i < NumStreams; stream_i++) {
|
||||||
|
free(StreamBlocks[stream_i]);
|
||||||
|
}
|
||||||
|
free(StreamBlocks);
|
||||||
|
clean_StreamDirectory:
|
||||||
|
free(StreamDirectory);
|
||||||
|
clean_viewoffile:
|
||||||
|
UnmapViewOfFile(filemap);
|
||||||
|
clean_mapping:
|
||||||
|
CloseHandle(hMapping);
|
||||||
|
clean_file:
|
||||||
|
CloseHandle(hFile);
|
||||||
|
return guid;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "HttpClient.h"
|
#include "HttpClient.h"
|
||||||
#include "PEParser.h"
|
#include "PEParser.h"
|
||||||
#include "PrintFunctions.h"
|
#include "PrintFunctions.h"
|
||||||
|
#include "PdbParser.h"
|
||||||
|
|
||||||
#include "PdbSymbols.h"
|
#include "PdbSymbols.h"
|
||||||
|
|
||||||
@@ -59,10 +60,26 @@ symbol_ctx* LoadSymbolsFromPE(PE* pe) {
|
|||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (strchr(pe->codeviewDebugInfo->pdbName, '\\')) {
|
||||||
|
// path is strange, PDB file won't be found on Microsoft Symbol Server, better give up...
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
int size_needed = MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, NULL, 0);
|
int size_needed = MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, NULL, 0);
|
||||||
ctx->pdb_name_w = calloc(size_needed, sizeof(WCHAR));
|
ctx->pdb_name_w = calloc(size_needed, sizeof(WCHAR));
|
||||||
MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, ctx->pdb_name_w, size_needed);
|
MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, ctx->pdb_name_w, size_needed);
|
||||||
|
BOOL needPdbDownload = FALSE;
|
||||||
if (!FileExistsW(ctx->pdb_name_w)) {
|
if (!FileExistsW(ctx->pdb_name_w)) {
|
||||||
|
needPdbDownload = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// PDB file exists, but is it the right version ?
|
||||||
|
GUID* guid = extractGuidFromPdb(ctx->pdb_name_w);
|
||||||
|
if (!guid || memcmp(guid, &pe->codeviewDebugInfo->guid, sizeof(GUID))) {
|
||||||
|
needPdbDownload = TRUE;
|
||||||
|
}
|
||||||
|
free(guid);
|
||||||
|
}
|
||||||
|
if (needPdbDownload){
|
||||||
PBYTE file;
|
PBYTE file;
|
||||||
SIZE_T file_size;
|
SIZE_T file_size;
|
||||||
BOOL res = DownloadPDBFromPE(pe, &file, &file_size);
|
BOOL res = DownloadPDBFromPE(pe, &file, &file_size);
|
||||||
@@ -73,9 +90,6 @@ symbol_ctx* LoadSymbolsFromPE(PE* pe) {
|
|||||||
WriteFullFileW(ctx->pdb_name_w, file, file_size);
|
WriteFullFileW(ctx->pdb_name_w, file, file_size);
|
||||||
free(file);
|
free(file);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
//TODO : check if exisiting PDB corresponds to the file version
|
|
||||||
}
|
|
||||||
DWORD64 asked_pdb_base_addr = 0x1337000;
|
DWORD64 asked_pdb_base_addr = 0x1337000;
|
||||||
DWORD pdb_image_size = MAXDWORD;
|
DWORD pdb_image_size = MAXDWORD;
|
||||||
HANDLE cp = GetCurrentProcess();
|
HANDLE cp = GetCurrentProcess();
|
||||||
|
|||||||
Reference in New Issue
Block a user