#include #include #include #include #include "../EDRSandblast.h" #include "FileUtils.h" #include "HttpClient.h" #include "PEParser.h" #include "PdbSymbols.h" BOOL DownloadPDB(GUID guid, DWORD age, LPCWSTR pdb_name_w, PBYTE* file, SIZE_T* file_size) { WCHAR full_pdb_uri[MAX_PATH] = { 0 }; swprintf_s(full_pdb_uri, _countof(full_pdb_uri), L"/download/symbols/%s/%08X%04hX%04hX%016llX%X/%s", pdb_name_w, guid.Data1, guid.Data2, guid.Data3, _byteswap_uint64(*((DWORD64*)guid.Data4)), age, pdb_name_w); return HttpsDownloadFullFile(L"msdl.microsoft.com", full_pdb_uri, file, file_size); } BOOL DownloadPDBFromPE(PE* image_pe, PBYTE* file, SIZE_T* file_size) { WCHAR pdb_name_w[MAX_PATH] = { 0 }; GUID guid = image_pe->codeviewDebugInfo->guid; DWORD age = image_pe->codeviewDebugInfo->age; MultiByteToWideChar(CP_UTF8, 0, image_pe->codeviewDebugInfo->pdbName, -1, pdb_name_w, _countof(pdb_name_w)); return DownloadPDB(guid, age, pdb_name_w, file, file_size); } BOOL DownloadOriginalFileW(DWORD image_timestamp, DWORD image_size, LPCWSTR image_name, PBYTE* file, SIZE_T* file_size) { WCHAR full_pdb_uri[MAX_PATH] = { 0 }; swprintf_s(full_pdb_uri, _countof(full_pdb_uri), L"/download/symbols/%s/%08X%X/%s", image_name, image_timestamp, image_size, image_name); return HttpsDownloadFullFile(L"msdl.microsoft.com", full_pdb_uri, file, file_size); } BOOL DownloadOriginalFileFromPE(PE* image_pe, _In_opt_ LPCWSTR image_name, PBYTE* file, SIZE_T* file_size) { DWORD image_size = image_pe->optHeader->SizeOfImage; //useless check if (image_size & 0xFFF) { image_size &= ~0xFFF; image_size += 0x1000; } DWORD image_timestamp = image_pe->ntHeader->FileHeader.TimeDateStamp; WCHAR image_name_w[MAX_PATH] = { 0 }; if (image_name == NULL) { if (image_pe->exportDirectory != NULL) { LPCSTR image_name_a = (LPCSTR)PE_RVA_to_Addr(image_pe, image_pe->exportDirectory->Name); MultiByteToWideChar(CP_UTF8, 0, image_name_a, -1, image_name_w, _countof(image_name_w)); image_name = image_name_w; } else { return FALSE; } } return DownloadOriginalFileW(image_timestamp, image_size, image_name, file, file_size); } symbol_ctx* LoadSymbolsFromPE(PE* pe) { symbol_ctx* ctx = calloc(1, sizeof(symbol_ctx)); if (ctx == NULL) { 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); if (!FileExistsW(ctx->pdb_name_w)) { PBYTE file; SIZE_T file_size; BOOL res = DownloadPDBFromPE(pe, &file, &file_size); if (!res) { free(ctx); return NULL; } 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(); if (!SymInitialize(cp, NULL, FALSE)) { free(ctx); return NULL; } ctx->sym_handle = cp; DWORD64 pdb_base_addr = SymLoadModuleExW(cp, NULL, ctx->pdb_name_w, NULL, asked_pdb_base_addr, pdb_image_size, NULL, 0); while (pdb_base_addr == 0) { DWORD err = GetLastError(); if (err == ERROR_SUCCESS) break; if (err == ERROR_FILE_NOT_FOUND) { printf_or_not("PDB file not found\n"); SymUnloadModule(cp, asked_pdb_base_addr);//TODO : fix handle leak SymCleanup(cp); free(ctx); return NULL; } printf_or_not("SymLoadModuleExW, error 0x%x\n", GetLastError()); asked_pdb_base_addr += 0x1000000; pdb_base_addr = SymLoadModuleExW(cp, NULL, ctx->pdb_name_w, NULL, asked_pdb_base_addr, pdb_image_size, NULL, 0); } ctx->pdb_base_addr = pdb_base_addr; return ctx; } symbol_ctx* LoadSymbolsFromImageFile(LPCWSTR image_file_path) { PVOID image_content = ReadFullFileW(image_file_path); PE* pe = PE_create(image_content, FALSE); symbol_ctx* ctx = LoadSymbolsFromPE(pe); PE_destroy(pe); free(image_content); return ctx; } DWORD64 GetSymbolOffset(symbol_ctx* ctx, LPCSTR symbol_name) { SYMBOL_INFO_PACKAGE si = { 0 }; si.si.SizeOfStruct = sizeof(SYMBOL_INFO); si.si.MaxNameLen = sizeof(si.name); BOOL res = SymGetTypeFromName(ctx->sym_handle, ctx->pdb_base_addr, symbol_name, &si.si); if (res) { return si.si.Address - ctx->pdb_base_addr; } else { return 0; } } DWORD GetFieldOffset(symbol_ctx* ctx, LPCSTR struct_name, LPCWSTR field_name) { SYMBOL_INFO_PACKAGE si = {0}; si.si.SizeOfStruct = sizeof(SYMBOL_INFO); si.si.MaxNameLen = sizeof(si.name); BOOL res = SymGetTypeFromName(ctx->sym_handle, ctx->pdb_base_addr, struct_name, &si.si); if (!res) { return 0; } TI_FINDCHILDREN_PARAMS* childrenParam = calloc(1, sizeof(TI_FINDCHILDREN_PARAMS)); if (childrenParam == NULL) { return 0; } res = SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, si.si.TypeIndex, TI_GET_CHILDRENCOUNT, &childrenParam->Count); if (!res){ return 0; } TI_FINDCHILDREN_PARAMS* ptr = realloc(childrenParam, sizeof(TI_FINDCHILDREN_PARAMS) + childrenParam->Count * sizeof(ULONG)); if (ptr == NULL) { free(childrenParam); return 0; } childrenParam = ptr; res = SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, si.si.TypeIndex, TI_FINDCHILDREN, childrenParam); DWORD offset = 0; for (ULONG i = 0; i < childrenParam->Count; i++) { ULONG childID = childrenParam->ChildId[i]; WCHAR* name = NULL; SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, childID, TI_GET_SYMNAME, &name); if (wcscmp(field_name, name)) { continue; } SymGetTypeInfo(ctx->sym_handle, ctx->pdb_base_addr, childID, TI_GET_OFFSET, &offset); break; } free(childrenParam); return offset; } void UnloadSymbols(symbol_ctx* ctx, BOOL delete_pdb) { SymUnloadModule(ctx->sym_handle, ctx->pdb_base_addr); SymCleanup(ctx->sym_handle); if (delete_pdb) { DeleteFileW(ctx->pdb_name_w); } free(ctx->pdb_name_w); ctx->pdb_name_w = NULL; free(ctx); }