#include "utils.h" #include "pdb.h" #include "win_funcs.h" // ======================= // ====== windows.h ====== // ======================= // // Debug APIs // #define EXCEPTION_DEBUG_EVENT 1 #define CREATE_THREAD_DEBUG_EVENT 2 #define CREATE_PROCESS_DEBUG_EVENT 3 #define EXIT_THREAD_DEBUG_EVENT 4 #define EXIT_PROCESS_DEBUG_EVENT 5 #define LOAD_DLL_DEBUG_EVENT 6 #define UNLOAD_DLL_DEBUG_EVENT 7 #define OUTPUT_DEBUG_STRING_EVENT 8 #define RIP_EVENT 9 typedef u32 (*PTHREAD_START_ROUTINE)(void* lpThreadParameter); typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE; #define EXCEPTION_MAXIMUM_PARAMETERS 15 // maximum number of exception parameters #define FILE_NAME_NORMALIZED 0x0 //default #define FILE_NAME_OPENED 0x8 #define STATUS_WAIT_0 ((u32 )0x00000000L) #define STATUS_ABANDONED_WAIT_0 ((u32 )0x00000080L) #define STATUS_USER_APC ((u32 )0x000000C0L) #define STATUS_TIMEOUT ((u32 )0x00000102L) #define STATUS_PENDING ((u32 )0x00000103L) #define DBG_EXCEPTION_HANDLED ((u32 )0x00010001L) #define DBG_CONTINUE ((u32 )0x00010002L) #define STATUS_SEGMENT_NOTIFICATION ((u32 )0x40000005L) #define STATUS_FATAL_APP_EXIT ((u32 )0x40000015L) #define DBG_REPLY_LATER ((u32 )0x40010001L) #define DBG_TERMINATE_THREAD ((u32 )0x40010003L) #define DBG_TERMINATE_PROCESS ((u32 )0x40010004L) #define DBG_CONTROL_C ((u32 )0x40010005L) #define DBG_PRINTEXCEPTION_C ((u32 )0x40010006L) #define DBG_RIPEXCEPTION ((u32 )0x40010007L) #define DBG_CONTROL_BREAK ((u32 )0x40010008L) #define DBG_COMMAND_EXCEPTION ((u32 )0x40010009L) #define DBG_PRINTEXCEPTION_WIDE_C ((u32 )0x4001000AL) #define STATUS_GUARD_PAGE_VIOLATION ((u32 )0x80000001L) #define STATUS_DATATYPE_MISALIGNMENT ((u32 )0x80000002L) #define STATUS_BREAKPOINT ((u32 )0x80000003L) #define STATUS_SINGLE_STEP ((u32 )0x80000004L) #define STATUS_LONGJUMP ((u32 )0x80000026L) #define STATUS_UNWIND_CONSOLIDATE ((u32 )0x80000029L) #define DBG_EXCEPTION_NOT_HANDLED ((u32 )0x80010001L) #define STATUS_ACCESS_VIOLATION ((u32 )0xC0000005L) #define STATUS_IN_PAGE_ERROR ((u32 )0xC0000006L) #define STATUS_INVALID_HANDLE ((u32 )0xC0000008L) #define STATUS_INVALID_PARAMETER ((u32 )0xC000000DL) #define STATUS_NO_MEMORY ((u32 )0xC0000017L) #define STATUS_ILLEGAL_INSTRUCTION ((u32 )0xC000001DL) #define STATUS_NONCONTINUABLE_EXCEPTION ((u32 )0xC0000025L) #define STATUS_INVALID_DISPOSITION ((u32 )0xC0000026L) #define STATUS_ARRAY_BOUNDS_EXCEEDED ((u32 )0xC000008CL) #define STATUS_FLOAT_DENORMAL_OPERAND ((u32 )0xC000008DL) #define STATUS_FLOAT_DIVIDE_BY_ZERO ((u32 )0xC000008EL) #define STATUS_FLOAT_INEXACT_RESULT ((u32 )0xC000008FL) #define STATUS_FLOAT_INVALID_OPERATION ((u32 )0xC0000090L) #define STATUS_FLOAT_OVERFLOW ((u32 )0xC0000091L) #define STATUS_FLOAT_STACK_CHECK ((u32 )0xC0000092L) #define STATUS_FLOAT_UNDERFLOW ((u32 )0xC0000093L) #define STATUS_INTEGER_DIVIDE_BY_ZERO ((u32 )0xC0000094L) #define STATUS_INTEGER_OVERFLOW ((u32 )0xC0000095L) #define STATUS_PRIVILEGED_INSTRUCTION ((u32 )0xC0000096L) #define STATUS_STACK_OVERFLOW ((u32 )0xC00000FDL) #define STATUS_DLL_NOT_FOUND ((u32 )0xC0000135L) #define STATUS_ORDINAL_NOT_FOUND ((u32 )0xC0000138L) #define STATUS_ENTRYPOINT_NOT_FOUND ((u32 )0xC0000139L) #define STATUS_CONTROL_C_EXIT ((u32 )0xC000013AL) #define STATUS_DLL_INIT_FAILED ((u32 )0xC0000142L) #define STATUS_CONTROL_STACK_VIOLATION ((u32 )0xC00001B2L) #define STATUS_FLOAT_MULTIPLE_FAULTS ((u32 )0xC00002B4L) #define STATUS_FLOAT_MULTIPLE_TRAPS ((u32 )0xC00002B5L) #define STATUS_REG_NAT_CONSUMPTION ((u32 )0xC00002C9L) #define STATUS_HEAP_CORRUPTION ((u32 )0xC0000374L) #define STATUS_STACK_BUFFER_OVERRUN ((u32 )0xC0000409L) #define STATUS_INVALID_CRUNTIME_PARAMETER ((u32 )0xC0000417L) #define STATUS_ASSERTION_FAILURE ((u32 )0xC0000420L) #define STATUS_ENCLAVE_VIOLATION ((u32 )0xC00004A2L) #define STATUS_INTERRUPTED ((u32 )0xC0000515L) #define STATUS_THREAD_NOT_RUNNING ((u32 )0xC0000516L) #define STATUS_ALREADY_REGISTERED ((u32 )0xC0000718L) /* compatibility macros */ #define STILL_ACTIVE STATUS_PENDING #define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION #define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT #define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT #define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP #define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED #define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND #define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO #define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT #define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION #define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW #define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK #define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW #define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO #define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW #define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION #define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR #define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION #define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION #define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW #define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION #define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION #define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE #define EXCEPTION_POSSIBLE_DEADLOCK STATUS_POSSIBLE_DEADLOCK #define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY { u32 BeginAddress; u32 EndAddress; union { u32 UnwindInfoAddress; u32 UnwindData; }; } _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY; typedef struct _IMAGE_EXPORT_DIRECTORY { u32 Characteristics; u32 TimeDateStamp; u16 MajorVersion; u16 MinorVersion; u32 Name; u32 Base; u32 NumberOfFunctions; u32 NumberOfNames; u32 AddressOfFunctions; // RVA from base of image u32 AddressOfNames; // RVA from base of image u32 AddressOfNameOrdinals; // RVA from base of image } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; typedef struct _IMAGE_DEBUG_DIRECTORY { u32 Characteristics; u32 TimeDateStamp; u16 MajorVersion; u16 MinorVersion; u32 Type; u32 SizeOfData; u32 AddressOfRawData; u32 PointerToRawData; } IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY; #define IMAGE_DEBUG_TYPE_UNKNOWN 0 #define IMAGE_DEBUG_TYPE_COFF 1 #define IMAGE_DEBUG_TYPE_CODEVIEW 2 #define IMAGE_DEBUG_TYPE_FPO 3 #define IMAGE_DEBUG_TYPE_MISC 4 #define IMAGE_DEBUG_TYPE_EXCEPTION 5 #define IMAGE_DEBUG_TYPE_FIXUP 6 #define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 #define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 #define IMAGE_DEBUG_TYPE_BORLAND 9 #define IMAGE_DEBUG_TYPE_RESERVED10 10 #define IMAGE_DEBUG_TYPE_BBT IMAGE_DEBUG_TYPE_RESERVED10 #define IMAGE_DEBUG_TYPE_CLSID 11 #define IMAGE_DEBUG_TYPE_VC_FEATURE 12 #define IMAGE_DEBUG_TYPE_POGO 13 #define IMAGE_DEBUG_TYPE_ILTCG 14 #define IMAGE_DEBUG_TYPE_MPX 15 #define IMAGE_DEBUG_TYPE_REPRO 16 #define IMAGE_DEBUG_TYPE_SPGO 18 #define IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS 20 typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY RUNTIME_FUNCTION, *PRUNTIME_FUNCTION; // // Code Page Default Values. // Please Use Unicode, either UTF-16 (as in WCHAR) or UTF-8 (code page CP_ACP) // #define CP_ACP 0 // default to ANSI code page #define CP_OEMCP 1 // default to OEM code page #define CP_MACCP 2 // default to MAC code page #define CP_THREAD_ACP 3 // current thread's ANSI code page #define CP_SYMBOL 42 // SYMBOL translations #define CP_UTF7 65000 // UTF-7 translation #define CP_UTF8 65001 // UTF-8 translation #define PAGE_NOACCESS 0x01 #define PAGE_READONLY 0x02 #define PAGE_READWRITE 0x04 #define PAGE_WRITECOPY 0x08 #define PAGE_EXECUTE 0x10 #define PAGE_EXECUTE_READ 0x20 #define PAGE_EXECUTE_READWRITE 0x40 #define PAGE_EXECUTE_WRITECOPY 0x80 #define PAGE_GUARD 0x100 #define PAGE_NOCACHE 0x200 #define PAGE_WRITECOMBINE 0x400 #define PAGE_GRAPHICS_NOACCESS 0x0800 #define PAGE_GRAPHICS_READONLY 0x1000 #define PAGE_GRAPHICS_READWRITE 0x2000 #define PAGE_GRAPHICS_EXECUTE 0x4000 #define PAGE_GRAPHICS_EXECUTE_READ 0x8000 #define PAGE_GRAPHICS_EXECUTE_READWRITE 0x10000 #define PAGE_GRAPHICS_COHERENT 0x20000 #define PAGE_GRAPHICS_NOCACHE 0x40000 #define PAGE_ENCLAVE_THREAD_CONTROL 0x80000000 #define PAGE_REVERT_TO_FILE_MAP 0x80000000 #define PAGE_TARGETS_NO_UPDATE 0x40000000 #define PAGE_TARGETS_INVALID 0x40000000 #define PAGE_ENCLAVE_UNVALIDATED 0x20000000 #define PAGE_ENCLAVE_MASK 0x10000000 #define PAGE_ENCLAVE_DECOMMIT (PAGE_ENCLAVE_MASK | 0) #define PAGE_ENCLAVE_SS_FIRST (PAGE_ENCLAVE_MASK | 1) #define PAGE_ENCLAVE_SS_REST (PAGE_ENCLAVE_MASK | 2) #define MEM_COMMIT 0x00001000 #define MEM_RESERVE 0x00002000 #define MEM_REPLACE_PLACEHOLDER 0x00004000 #define MEM_RESERVE_PLACEHOLDER 0x00040000 #define MEM_RESET 0x00080000 #define MEM_TOP_DOWN 0x00100000 #define MEM_WRITE_WATCH 0x00200000 #define MEM_PHYSICAL 0x00400000 #define MEM_ROTATE 0x00800000 #define MEM_DIFFERENT_IMAGE_BASE_OK 0x00800000 #define MEM_RESET_UNDO 0x01000000 #define MEM_LARGE_PAGES 0x20000000 #define MEM_4MB_PAGES 0x80000000 #define MEM_64K_PAGES (MEM_LARGE_PAGES | MEM_PHYSICAL) #define MEM_UNMAP_WITH_TRANSIENT_BOOST 0x00000001 #define MEM_COALESCE_PLACEHOLDERS 0x00000001 #define MEM_PRESERVE_PLACEHOLDER 0x00000002 #define MEM_DECOMMIT 0x00004000 #define MEM_RELEASE 0x00008000 #define MEM_FREE 0x00010000 #define MEM_EXTENDED_PARAMETER_GRAPHICS 0x00000001 #define MEM_EXTENDED_PARAMETER_NONPAGED 0x00000002 #define MEM_EXTENDED_PARAMETER_ZERO_PAGES_OPTIONAL 0x00000004 #define MEM_EXTENDED_PARAMETER_NONPAGED_LARGE 0x00000008 #define MEM_EXTENDED_PARAMETER_NONPAGED_HUGE 0x00000010 #define MEM_EXTENDED_PARAMETER_SOFT_FAULT_PAGES 0x00000020 #define MEM_EXTENDED_PARAMETER_EC_CODE 0x00000040 #define MEM_EXTENDED_PARAMETER_NUMA_NODE_MANDATORY MINLONG64 #define PROCESS_TERMINATE (0x0001) #define PROCESS_CREATE_THREAD (0x0002) #define PROCESS_SET_SESSIONID (0x0004) #define PROCESS_VM_OPERATION (0x0008) #define PROCESS_VM_READ (0x0010) #define PROCESS_VM_WRITE (0x0020) #define PROCESS_DUP_HANDLE (0x0040) #define PROCESS_CREATE_PROCESS (0x0080) #define PROCESS_SET_QUOTA (0x0100) #define PROCESS_SET_INFORMATION (0x0200) #define PROCESS_QUERY_INFORMATION (0x0400) #define PROCESS_SUSPEND_RESUME (0x0800) #define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) #define PROCESS_SET_LIMITED_INFORMATION (0x2000) // ======================== // ====== !windows.h ====== // ======================== u8 expect_single_step = FALSE; extern DEBUG_EVENT dbg_event; extern u8* string_stack_base; extern u8* string_stack_current; const char* dummy_name = "Function_dummy_name"; void read_name_uni(const void* name_addr, i8* name, size_t name_size) { u8* addr = NULL; if (!read_memory(name_addr, (void*)&addr, 8U)) { print("%s %u\n", "Loading DLL : error reading dll name : ", GetLastError()); return; } u16 name_uni[256U] = { 0U }; if (!read_memory((const void*)addr, name_uni, sizeof(name_uni))) { print("Cannot read dll name from proc memory %u\n", GetLastError()); return; } WideCharToMultiByte( CP_ACP, 0, name_uni, -1, 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, struct module* module) { if (!read_memory(base_addr, (void*)&module->dos_header, sizeof(module->dos_header))) { print("Cannot read DOS header for module %s at address %x\n", (char*)module->name, base_addr); return; } if (!read_memory((const void*)((u64)base_addr + module->dos_header.e_lfanew), (void*)&module->nt_header, sizeof(module->nt_header))) { print("Cannot read NT header for module %s at address %x\n", (char*)module->name, base_addr); return; } print("Module Base Address %x\n", base_addr); print("Module Size %x\n", module->nt_header.OptionalHeader.SizeOfImage); #ifndef HASHMAP // Exception directory IMAGE_DATA_DIRECTORY exception_entry = module->nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; if (exception_entry.Size == 0U) { print("Exception directory is empty in module %s\n", module->name); } RUNTIME_FUNCTION* exception_table = VirtualAlloc(NULL, exception_entry.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!read_memory((const void*)((u64)base_addr + (u64)exception_entry.VirtualAddress), (void*)exception_table, exception_entry.Size)) { print("Cannot read exception table for module %s at address %x\n", (char*)module->name, base_addr); return; } u32 pdata_entries = exception_entry.Size / sizeof(exception_table[0U]); module->functions_name = VirtualAlloc(NULL, pdata_entries * sizeof(module->functions_name[0U]), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); module->functions_start = VirtualAlloc(NULL, pdata_entries * sizeof(module->functions_start[0U]), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); module->functions_end = VirtualAlloc(NULL, pdata_entries * sizeof(module->functions_end[0U]), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); module->functions_unwind = VirtualAlloc(NULL, pdata_entries * sizeof(module->functions_unwind[0U]), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); module->functions_count = pdata_entries; for (u32 index = 0U; index < pdata_entries; index++) { RUNTIME_FUNCTION cur_entry = exception_table[index]; module->functions_start[index] = cur_entry.BeginAddress; module->functions_end[index] = cur_entry.EndAddress; module->functions_unwind[index] = cur_entry.UnwindData; module->functions_name[index] = (u8*)dummy_name; } #endif // Export table IMAGE_DATA_DIRECTORY export_table = module->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(export_dir_start, (void*)&export_dir, sizeof(export_dir))) { print("Cannot read export dir for module %s at address %x\n", (char*)module->name, base_addr); return; } size_t ordinals_size = export_dir.NumberOfNames * sizeof(u16); u16* ordinals = VirtualAlloc(NULL, ordinals_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!read_memory((const void*)((u64)base_addr + (u64)export_dir.AddressOfNameOrdinals), (void*)ordinals, ordinals_size)) { print("Cannot read name ordinals from export directory for module %s at address %x\n", (char*)module->name, base_addr); return; } size_t names_size = export_dir.NumberOfNames * sizeof(u32); u32* names_address = VirtualAlloc(NULL, names_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!read_memory((const void*)((u64)base_addr + (u64)export_dir.AddressOfNames), (void*)names_address, names_size)) { print("Cannot read names from export directory for module %s at address %x\n", (char*)module->name, base_addr); return; } size_t addresses_size = export_dir.NumberOfFunctions * sizeof(u32); u32* addresses = VirtualAlloc(NULL, addresses_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (!read_memory((const void*)((u64)base_addr + (u64)export_dir.AddressOfFunctions), (void*)addresses, addresses_size)) { print("Cannot read functions addresses from export directory for module %s at address %x\n", (char*)module->name, base_addr); return; } #ifndef HASHMAP // u32 global_functions_index = 0U; for (u32 i = 0U; i < export_dir.NumberOfFunctions; i++) { u64 address = (u64)base_addr + addresses[i]; u32 name_index = 0U; u8* name = string_stack_current; size_t length = 0U; for (; name_index < export_dir.NumberOfNames; name_index++) { if (ordinals[name_index] == i) { // TODO: Add string management code assert(string_stack_current - 16U * 4096U < string_stack_base); void* name_address = (void*)((u64)module->base_addr + names_address[name_index]); read_memory(name_address, name, 256U); length = str_len((const char*)name); break; } } if (name_index == export_dir.NumberOfNames) { print("%u : Function has no name, function address %x\n", i, addresses[i]); continue; } if (export_dir_start < (void*)address && (void*)address < export_dir_end) { print("%u : Fowarded function : %s\n", i, name); continue; } u32 global_functions_index = 0U; for(; global_functions_index < module->functions_count; global_functions_index++) { if (module->functions_start[global_functions_index] == addresses[i]) { string_stack_current[length] = '\0'; module->functions_name[global_functions_index] = name; string_stack_current += length + 1U; print("%u : Function name : %s, function address %x\n", i, name, addresses[i]); break; } } if (global_functions_index == module->functions_count) { print("Function not found : %s!\n", string_stack_current); } } #endif #ifdef HASHMAP print("Found %u functions\n", export_dir.NumberOfFunctions); for (u32 i = 0U; i < export_dir.NumberOfFunctions; i++) { char func_name[256U] = { 0 }; u64 func_address = (u64)base_addr + addresses[i]; u32 name_index = 0U; for (; name_index < export_dir.NumberOfNames; name_index++) { if (ordinals[name_index] == i) { break; } } u64 name_address = (u64)base_addr + names_address[name_index]; read_memory((void*)name_address, func_name, sizeof(func_name)); if (export_dir_start < (void*)func_address && (void*)func_address < export_dir_end) { print("%u : Fowarded function : %s\n", i, func_name); } else if (name_index && name_index < export_dir.NumberOfNames) { print("%u : Function name : %s, function address %x\n", i, func_name, addresses[i]); insert_elem(&module->symbols, addresses[i], 0U, name_address); } else { print("%u : Function has no name, function address %x\n", i, addresses[i]); insert_elem(&module->symbols, addresses[i], 0U, (u64)dummy_name); } } #endif VirtualFree(names_address, names_size, MEM_RELEASE); VirtualFree(ordinals, ordinals_size, MEM_RELEASE); VirtualFree(addresses, addresses_size, MEM_RELEASE); } // Private symbols IMAGE_DATA_DIRECTORY debug_table = module->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", module->name, base_addr); return; } 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 { u32 signature; u32 guid[4U]; u32 age; i8 path; } 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*)module->name, base_addr); } print("PDB path : %s\n", &header.path); open_pdb(&header.path, module); } #ifdef HASHMAP // Exception directory IMAGE_DATA_DIRECTORY exception_entry = module->nt_header.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; if (exception_entry.Size == 0U) { print("Exception directory is empty in module %s\n", module->name); } RUNTIME_FUNCTION* exception_table = VirtualAlloc(NULL, exception_entry.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!read_memory((const void*)((u64)base_addr + (u64)exception_entry.VirtualAddress), (void*)exception_table, exception_entry.Size)) { print("Cannot read exception table for module %s at address %x\n", (char*)module->name, base_addr); return; } // Find unwind info offset u32 pdata_entries = exception_entry.Size / sizeof(exception_table[0U]); for (u32 index = 0U; index < pdata_entries; index++) { RUNTIME_FUNCTION cur_entry = exception_table[index]; struct element* elem = find_elem(&module->symbols, cur_entry.BeginAddress); if (elem == NULL) { elem = insert_elem(&module->symbols, cur_entry.BeginAddress, cur_entry.EndAddress, 0ULL); } else { if (elem->name == 0U) { print("function name %s\n", elem->name); } elem->end = cur_entry.EndAddress; } elem->unwind_offset = cur_entry.UnwindData; // if (!read_memory((const void*)((u64)base_addr + (u64)cur_entry.UnwindData), (void*)u_info, 4096U)) { // print("Cannot read unwind info in for function %s\n", elem->name); // continue; // } // size_t total_size = sizeof(*u_info) + (u_info->count_of_unwind_codes - 1U) * sizeof(struct UNWIND_CODE); // assert(total_size < 4096U); // for (u32 code_index = 0U; code_index < u_info->count_of_unwind_codes; code_index++) { // struct UNWIND_CODE* cur_code = &u_info->unwind_code[code_index]; // switch (cur_code->unwind_operation_code) { // case UWOP_PUSH_NONVOL: // print("push non volatile\n"); // print("push "); // print_reg(cur_code->op_info); // break; // case UWOP_ALLOC_LARGE: // print("alloc large\n"); // if (cur_code->op_info == 0U) { // u16 size = *(u16*)&u_info->unwind_code[code_index + 1U]; // if (u_info->frame_register) { // print("sub rbp %x\n", size); // } else { // print("sub rsp %x\n", size); // } // code_index++; // } else { // u32 size = *(u32*)&u_info->unwind_code[code_index + 1U]; // if (u_info->frame_register) { // print("sub rbp %x\n", size); // } else { // print("sub rsp %x\n", size); // } // code_index += 2U; // } // break; // case UWOP_ALLOC_SMALL: // print("alloc small\n"); // u32 size = cur_code->op_info * 8U + 8U; // if (u_info->frame_register) { // print("sub rbp %x\n", size); // } else { // print("sub rsp %u\n", size); // } // break; // case UWOP_SET_FPREG: // print("set frame point reg\n"); // print("mov rbp rsp - %u\n", u_info->frame_register_offset * 16U); // break; // case UWOP_SAVE_NONVOL: // print("save non volatile\n"); // if (u_info->frame_register) { // print("mov rbp "); // } else { // print("mov rsp "); // } // print_reg(cur_code->op_info); // code_index++; // break; // case UWOP_SAVE_NONVOL_FAR: // print("save non volatile far\n"); // code_index += 2U; // break; // case UWOP_SAVE_XMM128: // print("save xmm128\n"); // code_index++; // break; // case UWOP_SAVE_XMM128_FAR: // print("save xmm128 far\n"); // code_index += 2U; // break; // case UWOP_PUSH_MACHFRAME: // print("push mach frame\n"); // break; // default: // print("bad operation code\n"); // } // } } #endif // VirtualFree(u_info, 4096U, MEM_RELEASE); VirtualFree(exception_table, exception_entry.Size, MEM_RELEASE); } void handle_create_process(void) { print("%s\n", "CreateProcessDebugEvent"); CREATE_PROCESS_DEBUG_INFO proc_dbg_info = dbg_event.u.CreateProcessInfo; void* hproc = OpenProcess(PROCESS_VM_READ, FALSE, dbg_event.dwProcessId); (void)hproc; struct module* module = &modules[add_module()]; // https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-create_process_debug_info // Debuggers must be prepared to handle the case where lpImageName is NULL or *lpImageName (in the address space of the process being debugged) is NULL. // Specifically, the system does not provide an image name for a create process event // module->base_addr = proc_dbg_info.lpBaseOfImage; // read_name_uni(proc_dbg_info.lpImageName, (const char*)module->name, sizeof(module->name)); module->base_addr = proc_dbg_info.lpBaseOfImage; GetFinalPathNameByHandleA(proc_dbg_info.hFile, module->name, sizeof(module->name), FILE_NAME_NORMALIZED); print("%s%s\n", "Loading Process : ", (char*)module->name); load_symbols((const void*)proc_dbg_info.lpBaseOfImage, module); } void handle_create_thread(void) { print("%s\n", "CreateThreadDebugEvent"); } void handle_exception(void) { extern u32 continue_status; print("%s : ", "ExceptionDebugEvent"); if (dbg_event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP && expect_single_step) { print("%s\n", "Single Step"); continue_status = DBG_CONTINUE; expect_single_step = FALSE; } else if (dbg_event.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { print("%s\n", "Breakpoint"); continue_status = DBG_CONTINUE; } else { print("%u\n", dbg_event.u.Exception.ExceptionRecord.ExceptionCode); } } void handle_exit_process(void) { print("%s\n", "ExitProcessDebugEvent"); TerminateProcess(NULL, 0U); } void handle_exit_thread(void) { print("%s\n", "ExitThreadDebugEvent"); } void handle_load_dll(void) { LOAD_DLL_DEBUG_INFO dll_info = dbg_event.u.LoadDll; const void* dll_name_addr = dll_info.lpImageName; void* dll_base_addr = dll_info.lpBaseOfDll; if (dll_name_addr == NULL) { print("%s\n", "Loading DLL : error reading dll name"); return; } struct module* module = &modules[add_module()]; module->base_addr = dll_base_addr; read_name_uni(dll_name_addr, module->name, sizeof(module->name)); print("%s%s\n", "Loading DLL : ", (char*)module->name); load_symbols(dll_base_addr, module); } void handle_unload_dll(void) { print("%s\n", "UnloadDLLDebugEvent"); } void handle_output_debug_string(void) { OUTPUT_DEBUG_STRING_INFO dbg_str_event = dbg_event.u.DebugString; char* str_addr = dbg_str_event.lpDebugStringData; size_t str_size = (size_t)dbg_str_event.nDebugStringLength; // assert(str_size > 1024U); u16 dbg_str[1024U] = { 0U }; if (!read_memory(str_addr, dbg_str, str_size)) { print("%s %u\n", "OutputDebugStringDebugEvent : error reading debug string : ", GetLastError()); return; } if (dbg_str_event.fUnicode) { i8 ansi_str[1024U] = { 0U }; WideCharToMultiByte( CP_ACP, 0, dbg_str, -1, ansi_str, sizeof(ansi_str), NULL, NULL ); print("%s%s\n", "OutputDebugStringDebugEvent : ", ansi_str); } else { print("%s%s\n", "OutputDebugStringDebugEvent : ", dbg_str); } } void handle_rip(void) { print("%s\n", "RIPEvent"); }