diff --git a/EDRSandblast/EDRSandblast.vcxproj b/EDRSandblast/EDRSandblast.vcxproj
index a982537..c40556d 100644
--- a/EDRSandblast/EDRSandblast.vcxproj
+++ b/EDRSandblast/EDRSandblast.vcxproj
@@ -178,6 +178,7 @@
+
@@ -208,6 +209,7 @@
+
diff --git a/EDRSandblast/EDRSandblast.vcxproj.filters b/EDRSandblast/EDRSandblast.vcxproj.filters
index ce385a3..ad5b31d 100644
--- a/EDRSandblast/EDRSandblast.vcxproj.filters
+++ b/EDRSandblast/EDRSandblast.vcxproj.filters
@@ -126,6 +126,9 @@
Source Files
+
+ Source Files
+
@@ -248,6 +251,9 @@
Header Files
+
+ Header Files
+
diff --git a/EDRSandblast/Includes/PdbParser.h b/EDRSandblast/Includes/PdbParser.h
new file mode 100644
index 0000000..74306b5
--- /dev/null
+++ b/EDRSandblast/Includes/PdbParser.h
@@ -0,0 +1,4 @@
+#pragma once
+#include
+
+PVOID extractGuidFromPdb(LPWSTR filepath);
\ No newline at end of file
diff --git a/EDRSandblast/Includes/PdbSymbols.h b/EDRSandblast/Includes/PdbSymbols.h
index 89819cd..bbd171a 100644
--- a/EDRSandblast/Includes/PdbSymbols.h
+++ b/EDRSandblast/Includes/PdbSymbols.h
@@ -1,4 +1,5 @@
#pragma once
+#include "PEParser.h"
typedef struct symbol_ctx_t {
LPWSTR pdb_name_w;
@@ -6,6 +7,7 @@ typedef struct symbol_ctx_t {
HANDLE sym_handle;
} symbol_ctx;
+symbol_ctx* LoadSymbolsFromPE(PE* pe);
symbol_ctx* LoadSymbolsFromImageFile(LPCWSTR image_file_path);
DWORD64 GetSymbolOffset(symbol_ctx* ctx, LPCSTR symbol_name);
DWORD GetFieldOffset(symbol_ctx* ctx, LPCSTR struct_name, LPCWSTR field_name);
diff --git a/EDRSandblast/Utils/PdbParser.c b/EDRSandblast/Utils/PdbParser.c
new file mode 100644
index 0000000..0f72ca5
--- /dev/null
+++ b/EDRSandblast/Utils/PdbParser.c
@@ -0,0 +1,115 @@
+#include
+
+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;
+}
+
diff --git a/EDRSandblast/Utils/PdbSymbols.c b/EDRSandblast/Utils/PdbSymbols.c
index e2198c7..73d5634 100644
--- a/EDRSandblast/Utils/PdbSymbols.c
+++ b/EDRSandblast/Utils/PdbSymbols.c
@@ -7,6 +7,7 @@
#include "HttpClient.h"
#include "PEParser.h"
#include "PrintFunctions.h"
+#include "PdbParser.h"
#include "PdbSymbols.h"
@@ -59,10 +60,26 @@ symbol_ctx* LoadSymbolsFromPE(PE* pe) {
if (ctx == 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);
ctx->pdb_name_w = calloc(size_needed, sizeof(WCHAR));
MultiByteToWideChar(CP_UTF8, 0, pe->codeviewDebugInfo->pdbName, -1, ctx->pdb_name_w, size_needed);
+ BOOL needPdbDownload = FALSE;
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;
SIZE_T 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);
free(file);
}
- else {
- //TODO : check if exisiting PDB corresponds to the file version
- }
DWORD64 asked_pdb_base_addr = 0x1337000;
DWORD pdb_image_size = MAXDWORD;
HANDLE cp = GetCurrentProcess();