summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin LADEVIE <qladevie@wanadev.fr>2024-09-09 08:28:11 +0200
committerQuentin LADEVIE <qladevie@wanadev.fr>2024-09-09 08:28:11 +0200
commit09d761b30a579b0282185c1db9e91e981f2f3a27 (patch)
tree6050453c03502e0eee84c8d90b8e7da92d63d61e
parente61b27e6c699ae175d7704ddaaee0d39b6d14382 (diff)
Load public symbols for dll
Initial code for pdb loading
-rw-r--r--src/events.c166
-rw-r--r--src/main.c1
-rw-r--r--src/pdb.c96
3 files changed, 224 insertions, 39 deletions
diff --git a/src/events.c b/src/events.c
index ea80e58..8870571 100644
--- a/src/events.c
+++ b/src/events.c
@@ -1,5 +1,130 @@
+void read_name_uni(const void* name_addr, const char* name, size_t name_size) {
+ u8* addr = NULL;
+ if (!read_memory(name_addr, (void*)&addr, 8U)) {
+ print("%s\n", "Loading DLL : error reading dll name");
+ return;
+ }
+
+ wchar_t name_uni[1024U] = { 0U };
+ if (!read_memory((const void*)addr, name_uni, sizeof(name_uni))) {
+ print("Cannot read dll name from proc memory\n");
+ return;
+ }
+
+ WideCharToMultiByte(
+ CP_ACP,
+ 0,
+ name_uni,
+ -1,
+ (char*)name,
+ (int)name_size,
+ NULL,
+ NULL
+ );
+}
+void read_name_ansi(const void* name_addr, const char* name, size_t name_size) {
+ u8* addr = NULL;
+ if (!read_memory(name_addr, (void*)&addr, 8U)) {
+ print("%s\n", "Loading DLL : error reading dll name");
+ return;
+ }
+
+ if (!read_memory((const void*)addr, (char*)name, name_size)) {
+ print("Cannot read dll name from proc memory\n");
+ return;
+ }
+
+}
+void load_symbols(const void* base_addr, const char* name) {
+ IMAGE_DOS_HEADER dos_header = { 0U };
+ if (!read_memory(base_addr, (void*)&dos_header, sizeof(dos_header))) {
+ print("Cannot read DOS header for module %s at address %x\n", (char*)name, base_addr);
+ return;
+ }
+
+ IMAGE_NT_HEADERS64 nt_header = { 0U };
+ if (!read_memory((const void*)((u64)base_addr + dos_header.e_lfanew), (void*)&nt_header, sizeof(nt_header))) {
+ print("Cannot read NT header for module %s at address %x\n", (char*)name, base_addr);
+ return;
+ }
+
+ // Export table
+ IMAGE_DATA_DIRECTORY export_table = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ IMAGE_EXPORT_DIRECTORY export_dir = { 0U };
+ const void* export_dir_start = (const void*)((u64)base_addr + (u64)export_table.VirtualAddress);
+ const void* export_dir_end = (const void*)((u64)export_dir_start + export_table.Size);
+
+ if (export_table.Size != 0U) {
+ if (!read_memory((const void*)((u64)base_addr + (u64)export_table.VirtualAddress), (void*)&export_dir, sizeof(export_dir))) {
+ print("Cannot read export dir for module %s at address %x\n", (char*)name, base_addr);
+ return;
+ }
+
+ u16 name_ordinals[8192];
+ if (!read_memory((const void*)((u64)base_addr + (u64)export_dir.AddressOfNameOrdinals), (void*)&name_ordinals, export_dir.NumberOfNames * sizeof(name_ordinals[0]))) {
+ print("Cannot read name ordinals from export directory for module %s at address %x\n", (char*)name, base_addr);
+ return;
+ }
+
+ u32 names[8192];
+ if (!read_memory((const void*)((u64)base_addr + (u64)export_dir.AddressOfNames), (void*)&names, export_dir.NumberOfNames * sizeof(names[0]))) {
+ print("Cannot read names from export directory for module %s at address %x\n", (char*)name, base_addr);
+ return;
+ }
+
+ print("Found %u functions\n", export_dir.NumberOfNames);
+ for (u32 i = 0U; i < export_dir.NumberOfNames; i++) {
+ const char* func_name = (const char*)((u64)base_addr + names[name_ordinals[i]]);
+ if (export_dir_end < (void*)func_name || (void*)func_name < export_dir_start) {
+ print("%u : Fowarded function\n", i);
+ } else {
+ print("%u : Function name : %s\n", i, func_name);
+ }
+ }
+ }
+
+
+ // Private symbols
+ IMAGE_DATA_DIRECTORY debug_table = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
+ IMAGE_DEBUG_DIRECTORY debug_entries[20U] = { 0U };
+
+ if (debug_table.VirtualAddress && !read_memory((const void*)((u64)base_addr + (u64)debug_table.VirtualAddress), debug_entries, debug_table.Size)) {
+ print("Cannot read image debug infos for module %s at address %x\n", name, base_addr);
+ return;
+ }
+
+ struct codeview_header {
+ u32 signature;
+ u32 guid[4U];
+ u32 age;
+ char path;
+ };
+
+ for (u32 i = 0U; i < debug_table.Size / sizeof(debug_entries[0U]); i++) {
+ if (debug_entries[i].Type != IMAGE_DEBUG_TYPE_CODEVIEW) {
+ print("Image debug type different from CodeView\n");
+ continue;
+ }
+
+ struct codeview_header header = { 0U };
+ if (!read_memory((const void*)((u64)base_addr + (u64)debug_entries[i].AddressOfRawData), (void*)&header, debug_entries[i].SizeOfData)) {
+ print("Cannot read code view header for module %s at address %x\n", (char*)name, base_addr);
+ }
+
+ print("PDB path : %s\n", &header.path);
+ open_pdb(&header.path);
+ }
+}
+
void handle_create_process() {
print("%s\n", "CreateProcessDebugEvent");
+
+ CREATE_PROCESS_DEBUG_INFO proc_dbg_info = dbg_event.u.CreateProcessInfo;
+ u8 proc_name[1024U] = { 0U };
+ read_name_uni(proc_dbg_info.lpImageName, (const char*)proc_name, sizeof(proc_name));
+ print("%s%s\n", "Loading Process : ", (char*)proc_name);
+
+ load_symbols((const void*)proc_dbg_info.lpBaseOfImage, (const char*)proc_name);
}
void handle_create_thread() {
@@ -39,49 +164,12 @@ void handle_load_dll() {
return;
}
- u8* addr = NULL;
- if (!read_memory(dll_name_addr, (void*)&addr, 8U)) {
- print("%s\n", "Loading DLL : error reading dll name");
- return;
- }
-
u8 dll_name[1024U] = { 0U };
- if (!read_memory((const void*)addr, dll_name, sizeof(dll_name))) {
- print("Cannot read dll name from proc memory\n");
- }
+ read_name_uni(dll_name_addr, (const char*)dll_name, sizeof(dll_name));
- if (dll_info.fUnicode) {
- u8 dll_name_ansi[1024U] = { 0U };
- WideCharToMultiByte(
- CP_ACP,
- 0,
- (wchar_t*)dll_name,
- -1,
- (char*)dll_name_ansi,
- sizeof(dll_name_ansi),
- NULL,
- NULL
- );
- StringCchCopyA((char*)dll_name, sizeof(dll_name), (const char*)dll_name_ansi);
- }
print("%s%s\n", "Loading DLL : ", (char*)dll_name);
- IMAGE_DOS_HEADER dos_header = { 0U };
- if (!read_memory(dll_base_addr, (void*)&dos_header, sizeof(dos_header))) {
- print("Cannot read DOS header for module %s at address %x\n", dll_name, dll_base_addr);
- }
-
- IMAGE_NT_HEADERS64 nt_header = { 0U };
- if (!read_memory((const void*)((u64)dll_base_addr + dos_header.e_lfanew), (void*)&nt_header, sizeof(nt_header))) {
- print("Cannot read NT header for module %s at address %x\n", dll_name, dll_base_addr);
- }
-
- IMAGE_DATA_DIRECTORY export_table = nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
- IMAGE_EXPORT_DIRECTORY export_dir = { 0U };
-
- if (!read_memory((const void*)((u64)dll_base_addr + (u64)export_table.VirtualAddress), (void*)&export_dir, export_table.Size)) {
- print("Cannot read export table for module at address %x\n", dll_base_addr);
- }
+ load_symbols(dll_base_addr, (const char*)dll_name);
}
void handle_unload_dll() {
diff --git a/src/main.c b/src/main.c
index 94fdd37..5ff1e42 100644
--- a/src/main.c
+++ b/src/main.c
@@ -46,6 +46,7 @@ u8 read_memory(const void* addr, void* buffer, size_t size) {
}
#include "parser.c"
+#include "pdb.c"
#include "events.c"
void dbg_loop() {
diff --git a/src/pdb.c b/src/pdb.c
new file mode 100644
index 0000000..dfa4c74
--- /dev/null
+++ b/src/pdb.c
@@ -0,0 +1,96 @@
+void open_pdb(const char* pdb_path) {
+ HANDLE pdb_file = CreateFileA(pdb_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (pdb_file == INVALID_HANDLE_VALUE) {
+ print("Cannot open pdb file at path %s due to error %u\n", pdb_path, GetLastError());
+ }
+
+ // MSF superblock
+ struct msf_superblock {
+ u8 magic[32U];
+ u32 block_size;
+ u32 free_block_map_block;
+ u32 num_blocks;
+ u32 num_directory_bytes;
+ u32 unknown;
+ u32 block_map_addr;
+ };
+ struct msf_superblock superblock = { 0U };
+ u8 block[4096U] = { 0U };
+ u32 b_read = 0U;
+ ReadFile(pdb_file, (void*)&superblock, sizeof(superblock), (LPDWORD)&b_read, NULL);
+
+ // Stream directory
+ u32 dir_addr = (superblock.block_map_addr - 1U) * sizeof(block);
+ SetFilePointer(pdb_file, dir_addr, NULL, FILE_BEGIN);
+ ReadFile(pdb_file, (void*)block, superblock.num_directory_bytes, (LPDWORD)&b_read, NULL);
+ u32 num_streams = ((u32*)block)[0U];
+ u32* stream_sizes = &((u32*)block)[1U];
+ u32* stream_blocks = stream_sizes + num_streams;
+ u32* pdb_info_stream_blocks = NULL;
+ u32* pdb_DBI_stream_blocks = NULL;
+
+ u32 block_index = 0U;
+ for(u32 stream_id = 0u; stream_id < num_streams; stream_id++) {
+ print("PDB stream size : %u\n", stream_sizes[stream_id]);
+ if (stream_id == 1U) {
+ pdb_info_stream_blocks = &stream_blocks[block_index];
+ }
+ if (stream_id == 3U) {
+ pdb_DBI_stream_blocks = &stream_blocks[block_index];
+ }
+ if (stream_sizes[stream_id] == (u32)-1) {
+ continue;
+ }
+ for(u32 id = 0u; id < (stream_sizes[stream_id] / sizeof(block)) + 1U; id++) {
+ print("PDB stream blocks : %u\n", stream_blocks[block_index]);
+ block_index++;
+ }
+ }
+
+ // PDB Info Stream
+ struct pdb_info_stream {
+ u32 version;
+ u32 signature;
+ u32 age;
+ u32 guid[4u];
+ };
+
+ struct pdb_info_stream pdb_info_stream = { 0U };
+ SetFilePointer(pdb_file, pdb_info_stream_blocks[0U] * sizeof(block), NULL, FILE_BEGIN);
+ ReadFile(pdb_file, (void*)&pdb_info_stream, sizeof(pdb_info_stream), (LPDWORD)&b_read, NULL);
+ pdb_info_stream;
+
+ // DBI Stream
+ struct pdb_DBI_stream {
+ i32 version_signature;
+ u32 version_header;
+ u32 age;
+ u16 global_stream_index;
+ u16 build_number;
+ u16 public_stream_index;
+ u16 pdb_dll_version;
+ u16 sym_record_stream;
+ u16 pdb_dll_rbld;
+ i32 mod_info_size;
+ i32 section_contribution_size;
+ i32 section_map_size;
+ i32 source_info_size;
+ i32 type_server_map_size;
+ u32 mfc_type_server_index;
+ i32 optional_dbg_header_size;
+ i32 ec_substream_size;
+ u16 flags;
+ u16 machine;
+ u32 padding;
+ };
+ struct pdb_DBI_stream pdb_DBI_stream = { 0U };
+ SetFilePointer(pdb_file, pdb_DBI_stream_blocks[0U] * sizeof(block), NULL, FILE_BEGIN);
+ ReadFile(pdb_file, (void*)&pdb_DBI_stream, sizeof(pdb_DBI_stream), (LPDWORD)&b_read, NULL);
+ print("");
+ pdb_DBI_stream;
+
+ // Global Symbol Stream
+ SetFilePointer(pdb_file, pdb_DBI_stream.global_stream_index * sizeof(block), NULL, FILE_BEGIN);
+ ReadFile(pdb_file, (void*)&pdb_DBI_stream, sizeof(pdb_DBI_stream), (LPDWORD)&b_read, NULL);
+}