From 0d0c599e000d3b5edc50419d9bfa2a7f4a04072e Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Tue, 5 Mar 2024 16:54:57 -0800 Subject: [PATCH] begin process of moving pe unwinding info into pe layer; more demon2 work checkpoint --- src/ctrl/ctrl_core.c | 9 - src/demon2/win32/demon2_core_win32.c | 353 +++++++++++----------- src/demon2/win32/demon2_core_win32.h | 27 +- src/pe/pe.c | 96 +++--- src/pe/pe.h | 435 +++++++++++++++++---------- src/scratch/ryan_scratch.c | 8 +- 6 files changed, 518 insertions(+), 410 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index c7d7041f..90f77226 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -691,15 +691,6 @@ ctrl_halt(void) demon_halt(0, 0); } -//- rjf: entity introspection - -internal U32 -ctrl_id_from_machine_entity(CTRL_MachineID id, DEMON_Handle handle) -{ - U32 result = 0; - return result; -} - //- rjf: exe -> dbg path mapping internal String8 diff --git a/src/demon2/win32/demon2_core_win32.c b/src/demon2/win32/demon2_core_win32.c index f0a40960..2f42d85f 100644 --- a/src/demon2/win32/demon2_core_win32.c +++ b/src/demon2/win32/demon2_core_win32.c @@ -2,9 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: Helpers - -//- rjf: entity id -> hash +//~ rjf: Basic Helpers internal U64 dmn_w32_hash_from_string(String8 string) @@ -23,6 +21,9 @@ dmn_w32_hash_from_id(U64 id) return dmn_w32_hash_from_string(str8_struct(&id)); } +//////////////////////////////// +//~ rjf: Entity Helpers + //- rjf: entity <-> handle internal DMN_Handle @@ -198,7 +199,107 @@ dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id) return result; } -//- rjf: win32-level process reads/writes +//////////////////////////////// +//~ rjf: Module Info Extraction + +internal String8 +dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: extract path from module + String16 path16 = {0}; + String8 path8 = {0}; + { + // rjf: handle -> full path + if(module->handle != 0) + { + DWORD cap16 = GetFinalPathNameByHandleW(module->handle, 0, 0, VOLUME_NAME_DOS); + U16 *buffer16 = push_array_no_zero(scratch.arena, U16, cap16); + DWORD size16 = GetFinalPathNameByHandleW(module->handle, (WCHAR*)buffer16, cap16, VOLUME_NAME_DOS); + path16 = str16(buffer16, size16); + } + + // rjf: fallback (main module only): process -> full path + if(path16.size == 0 && module->module.is_main) + { + DMN_W32_Entity *process = module->parent; + DWORD size = KB(4); + U16 *buf = push_array_no_zero(scratch.arena, U16, size); + if(QueryFullProcessImageNameW(process->handle, 0, (WCHAR*)buf, &size)) + { + path16 = str16(buf, size); + } + } + + // rjf: fallback (any module - no guarantee): address_of_name -> full path + if(path16.size == 0 && module->module.address_of_name_pointer != 0) + { + DMN_W32_Entity *process = module->parent; + U64 ptr_size = bit_size_from_arch(process->arch)/8; + U64 name_pointer = 0; + if(dmn_w32_process_read(process->handle, r1u64(module->module.address_of_name_pointer, module->module.address_of_name_pointer+ptr_size), &name_pointer)) + { + if(name_pointer != 0) + { + if(module->module.name_is_unicode) + { + path16 = dmn_w32_read_memory_str16(scratch.arena, process->handle, name_pointer); + } + else + { + path8 = dmn_w32_read_memory_str(scratch.arena, process->handle, name_pointer); + } + } + } + } + } + + // rjf: produce finalized result + String8 result = {0}; + { + if(path16.size > 0) + { + // rjf: skip the extended path thing if necessary + if(path16.size >= 4 && + path16.str[0] == L'\\' && + path16.str[1] == L'\\' && + path16.str[2] == L'?' && + path16.str[3] == L'\\') + { + path16.size -= 4; + path16.str += 4; + } + + // rjf: convert to UTF-8 + result = str8_from_16(arena, path16); + } + else + { + // rjf: skip the extended path thing if necessary + if (path8.size >= 4 && + path8.str[0] == L'\\' && + path8.str[1] == L'\\' && + path8.str[2] == L'?' && + path8.str[3] == L'\\') + { + path8.size -= 4; + path8.str += 4; + } + + // rjf: copy to output arena + result = push_str8_copy(arena, path8); + } + } + + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Win32-Level Process/Thread Reads/Writes + +//- rjf: processes internal U64 dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst) @@ -346,7 +447,78 @@ dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address) return(result); } -//- rjf: win32-level thread register reads/writes +internal DMN_W32_ImageInfo +dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) +{ + // rjf: find PE offset + U32 pe_offset = 0; + { + U64 dos_magic_off = base_vaddr; + U16 dos_magic = 0; + dmn_w32_process_read_struct(process, dos_magic_off, &dos_magic); + if(dos_magic == PE_DOS_MAGIC) + { + U64 pe_offset_off = base_vaddr + OffsetOf(PE_DosHeader, coff_file_offset); + dmn_w32_process_read_struct(process, pe_offset_off, &pe_offset); + } + } + + // rjf: get COFF header + B32 got_coff_header = 0; + U64 coff_header_off = 0; + COFF_Header coff_header = {0}; + if(pe_offset > 0) + { + U64 pe_magic_off = base_vaddr + pe_offset; + U32 pe_magic = 0; + dmn_w32_process_read_struct(process, pe_magic_off, &pe_magic); + if(pe_magic == PE_MAGIC) + { + coff_header_off = pe_magic_off + sizeof(pe_magic); + if(dmn_w32_process_read_struct(process, coff_header_off, &coff_header)) + { + got_coff_header = 1; + } + } + } + + // rjf: get arch and size + DMN_W32_ImageInfo result = zero_struct; + if(got_coff_header) + { + U64 optional_size_off = 0; + Architecture arch = Architecture_Null; + switch(coff_header.machine) + { + case COFF_MachineType_X86: + { + arch = Architecture_x86; + optional_size_off = OffsetOf(PE_OptionalHeader32, sizeof_image); + }break; + case COFF_MachineType_X64: + { + arch = Architecture_x64; + optional_size_off = OffsetOf(PE_OptionalHeader32Plus, sizeof_image); + }break; + default: + {}break; + } + if(arch != Architecture_Null) + { + U64 optional_off = coff_header_off + sizeof(coff_header); + U32 size = 0; + if(dmn_w32_process_read_struct(process, optional_off+optional_size_off, &size) >= sizeof(size)) + { + result.arch = arch; + result.size = size; + } + } + } + + return result; +} + +//- rjf: threads internal U16 dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave) @@ -872,7 +1044,7 @@ dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block return result; } -//- rjf: win32-level thread injection +//- rjf: remote thread injection internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address) @@ -887,175 +1059,6 @@ dmn_w32_inject_thread(HANDLE process, U64 start_address) return thread_id; } -//- rjf: module image analysis - -internal DMN_W32_ImageInfo -dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) -{ - // rjf: find PE offset - U32 pe_offset = 0; - { - U64 dos_magic_off = base_vaddr; - U16 dos_magic = 0; - dmn_w32_process_read_struct(process, dos_magic_off, &dos_magic); - if(dos_magic == PE_DOS_MAGIC) - { - U64 pe_offset_off = base_vaddr + OffsetOf(PE_DosHeader, coff_file_offset); - dmn_w32_process_read_struct(process, pe_offset_off, &pe_offset); - } - } - - // rjf: get COFF header - B32 got_coff_header = 0; - U64 coff_header_off = 0; - COFF_Header coff_header = {0}; - if(pe_offset > 0) - { - U64 pe_magic_off = base_vaddr + pe_offset; - U32 pe_magic = 0; - dmn_w32_process_read_struct(process, pe_magic_off, &pe_magic); - if(pe_magic == PE_MAGIC) - { - coff_header_off = pe_magic_off + sizeof(pe_magic); - if(dmn_w32_process_read_struct(process, coff_header_off, &coff_header)) - { - got_coff_header = 1; - } - } - } - - // rjf: get arch and size - DMN_W32_ImageInfo result = zero_struct; - if(got_coff_header) - { - U64 optional_size_off = 0; - Architecture arch = Architecture_Null; - switch(coff_header.machine) - { - case COFF_MachineType_X86: - { - arch = Architecture_x86; - optional_size_off = OffsetOf(PE_OptionalHeader32, sizeof_image); - }break; - case COFF_MachineType_X64: - { - arch = Architecture_x64; - optional_size_off = OffsetOf(PE_OptionalHeader32Plus, sizeof_image); - }break; - default: - {}break; - } - if(arch != Architecture_Null) - { - U64 optional_off = coff_header_off + sizeof(coff_header); - U32 size = 0; - if(dmn_w32_process_read_struct(process, optional_off+optional_size_off, &size) >= sizeof(size)) - { - result.arch = arch; - result.size = size; - } - } - } - - return result; -} - -//- rjf: module full path extraction - -internal String8 -dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module) -{ - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: extract path from module - String16 path16 = {0}; - String8 path8 = {0}; - { - // rjf: handle -> full path - if(module->handle != 0) - { - DWORD cap16 = GetFinalPathNameByHandleW(module->handle, 0, 0, VOLUME_NAME_DOS); - U16 *buffer16 = push_array_no_zero(scratch.arena, U16, cap16); - DWORD size16 = GetFinalPathNameByHandleW(module->handle, (WCHAR*)buffer16, cap16, VOLUME_NAME_DOS); - path16 = str16(buffer16, size16); - } - - // rjf: fallback (main module only): process -> full path - if(path16.size == 0 && module->module.is_main) - { - DMN_W32_Entity *process = module->parent; - DWORD size = KB(4); - U16 *buf = push_array_no_zero(scratch.arena, U16, size); - if(QueryFullProcessImageNameW(process->handle, 0, (WCHAR*)buf, &size)) - { - path16 = str16(buf, size); - } - } - - // rjf: fallback (any module - no guarantee): address_of_name -> full path - if(path16.size == 0 && module->module.address_of_name_pointer != 0) - { - DMN_W32_Entity *process = module->parent; - U64 ptr_size = bit_size_from_arch(process->arch)/8; - U64 name_pointer = 0; - if(dmn_w32_process_read(process->handle, r1u64(module->module.address_of_name_pointer, module->module.address_of_name_pointer+ptr_size), &name_pointer)) - { - if(name_pointer != 0) - { - if(module->module.name_is_unicode) - { - path16 = dmn_w32_read_memory_str16(scratch.arena, process->handle, name_pointer); - } - else - { - path8 = dmn_w32_read_memory_str(scratch.arena, process->handle, name_pointer); - } - } - } - } - } - - // rjf: produce finalized result - String8 result = {0}; - { - if(path16.size > 0) - { - // rjf: skip the extended path thing if necessary - if(path16.size >= 4 && - path16.str[0] == L'\\' && - path16.str[1] == L'\\' && - path16.str[2] == L'?' && - path16.str[3] == L'\\') - { - path16.size -= 4; - path16.str += 4; - } - - // rjf: convert to UTF-8 - result = str8_from_16(arena, path16); - } - else - { - // rjf: skip the extended path thing if necessary - if (path8.size >= 4 && - path8.str[0] == L'\\' && - path8.str[1] == L'\\' && - path8.str[2] == L'?' && - path8.str[3] == L'\\') - { - path8.size -= 4; - path8.str += 4; - } - - // rjf: copy to output arena - result = push_str8_copy(arena, path8); - } - } - - scratch_end(scratch); - return result; -} - //////////////////////////////// //~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS) diff --git a/src/demon2/win32/demon2_core_win32.h b/src/demon2/win32/demon2_core_win32.h index 55a7a463..572691c6 100644 --- a/src/demon2/win32/demon2_core_win32.h +++ b/src/demon2/win32/demon2_core_win32.h @@ -229,12 +229,14 @@ global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0; //////////////////////////////// -//~ rjf: Helpers +//~ rjf: Basic Helpers -//- rjf: hashes internal U64 dmn_w32_hash_from_string(String8 string); internal U64 dmn_w32_hash_from_id(U64 id); +//////////////////////////////// +//~ rjf: Entity Helpers + //- rjf: entity <-> handle internal DMN_Handle dmn_w32_handle_from_entity(DMN_W32_Entity *entity); internal DMN_W32_Entity *dmn_w32_entity_from_handle(DMN_Handle handle); @@ -246,27 +248,30 @@ internal void dmn_w32_entity_release(DMN_W32_Entity *entity); //- rjf: kind*id -> entity internal DMN_W32_Entity *dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id); -//- rjf: win32-level process reads/writes +//////////////////////////////// +//~ rjf: Module Info Extraction + +internal String8 dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module); + +//////////////////////////////// +//~ rjf: Win32-Level Process/Thread Reads/Writes + +//- rjf: processes internal U64 dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst); internal B32 dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src); internal String8 dmn_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address); internal String16 dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address); #define dmn_w32_process_read_struct(process, vaddr, ptr) dmn_w32_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) #define dmn_w32_process_write_struct(process, vaddr, ptr) dmn_w32_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) +internal DMN_W32_ImageInfo dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr); -//- rjf: win32-level thread register reads/writes +//- rjf: threads internal U16 dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave); internal U16 dmn_w32_xsave_tag_word_from_real_tag_word(U16 ftw); internal B32 dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block); internal B32 dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block); -//- rjf: win32-level thread injection +//- rjf: remote thread injection internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address); -//- rjf: module image analysis -internal DMN_W32_ImageInfo dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr); - -//- rjf: module full path extraction -internal String8 dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module); - #endif // DEMON2_CORE_WIN32_H diff --git a/src/pe/pe.c b/src/pe/pe.c index 39447b98..f2b243f9 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -1,6 +1,54 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Basic Enum Functions + +internal U32 +pe_slot_count_from_unwind_op_code(PE_UnwindOpCode opcode) +{ + U32 result = 0; + switch(opcode) + { + case PE_UnwindOpCode_PUSH_NONVOL: result = 1; break; + case PE_UnwindOpCode_ALLOC_LARGE: result = 2; break; + case PE_UnwindOpCode_ALLOC_SMALL: result = 1; break; + case PE_UnwindOpCode_SET_FPREG: result = 1; break; + case PE_UnwindOpCode_SAVE_NONVOL: result = 2; break; + case PE_UnwindOpCode_SAVE_NONVOL_FAR: result = 3; break; + case PE_UnwindOpCode_EPILOG: result = 2; break; + case PE_UnwindOpCode_SPARE_CODE: result = 3; break; + case PE_UnwindOpCode_SAVE_XMM128: result = 2; break; + case PE_UnwindOpCode_SAVE_XMM128_FAR: result = 3; break; + case PE_UnwindOpCode_PUSH_MACHFRAME: result = 1; break; + } + return result; +} + +internal String8 +pe_string_from_windows_subsystem(PE_WindowsSubsystem subsystem) +{ + String8 result = {0}; + switch(subsystem) + { + default:{}break; + case PE_WindowsSubsystem_UNKNOWN: result = str8_lit("UNKNOWN"); break; + case PE_WindowsSubsystem_NATIVE: result = str8_lit("NATIVE"); break; + case PE_WindowsSubsystem_WINDOWS_GUI: result = str8_lit("WINDOWS_GUI"); break; + case PE_WindowsSubsystem_WINDOWS_CUI: result = str8_lit("WINDOWS_CUI"); break; + case PE_WindowsSubsystem_OS2_CUI: result = str8_lit("OS2_CUI"); break; + case PE_WindowsSubsystem_POSIX_CUI: result = str8_lit("POSIX_CUI"); break; + case PE_WindowsSubsystem_NATIVE_WINDOWS: result = str8_lit("NATIVE_WINDOWS"); break; + case PE_WindowsSubsystem_WINDOWS_CE_GUI: result = str8_lit("WINDOWS_CE_GUID"); break; + case PE_WindowsSubsystem_EFI_APPLICATION: result = str8_lit("EFI_APPLICATION"); break; + case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER: result = str8_lit("EFI_BOOT_SERVICE_DRIVER"); break; + case PE_WindowsSubsystem_EFI_ROM: result = str8_lit("EFI_ROM"); break; + case PE_WindowsSubsystem_XBOX: result = str8_lit("XBOX"); break; + case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: result = str8_lit("WINDOWS_BOOT_APPLICATION"); break; + } + return result; +} + //////////////////////////////// //~ rjf: Parser Functions @@ -535,7 +583,7 @@ pe_resource_dir_push_dir_node(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID PE_Resource *res = &res_node->data; res->id = id; - res->type = PE_ResData_DIR; + res->kind = PE_ResDataKind_DIR; res->u.dir = sub_dir; return res_node; @@ -558,7 +606,7 @@ pe_resource_dir_push_entry_node(Arena *arena, PE_ResourceDir *dir, COFF_Resource PE_Resource *res = &res_node->data; res->id = id; - res->type = PE_ResData_COFF_RESOURCE; + res->kind = PE_ResDataKind_COFF_RESOURCE; res->u.coff_res.type = type; res->u.coff_res.data_version = data_version; res->u.coff_res.version = version; @@ -716,7 +764,7 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) entry->id.type = COFF_ResourceIDType_STRING; entry->id.u.string = str8_from_16(arena, name16); - entry->type = is_dir ? PE_ResData_DIR : PE_ResData_COFF_LEAF; + entry->kind = is_dir ? PE_ResDataKind_DIR : PE_ResDataKind_COFF_LEAF; if (is_dir) { struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); @@ -745,7 +793,7 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) entry->id.type = COFF_ResourceIDType_NUMBER; entry->id.u.number = coff_entry.name.id; - entry->type = is_dir ? PE_ResData_DIR : PE_ResData_COFF_LEAF; + entry->kind = is_dir ? PE_ResDataKind_DIR : PE_ResDataKind_COFF_LEAF; if (is_dir) { struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); @@ -766,43 +814,3 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) scratch_end(scratch); return bottom_frame->table; } - -//////////////////////////////// - -internal String8 -pe_get_dos_program(void) -{ - // generated from pe/dos_program.asm - static U8 program[] = { - 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, - 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x24, 0x00, 0x00 - }; - return str8(program, sizeof(program)); -} - -//////////////////////////////// - -internal String8 -pe_string_from_subsystem(PE_WindowsSubsystem subsystem) -{ - switch (subsystem) { - case PE_WindowsSubsystem_UNKNOWN: return str8_lit("UNKNOWN"); - case PE_WindowsSubsystem_NATIVE: return str8_lit("NATIVE"); - case PE_WindowsSubsystem_WINDOWS_GUI: return str8_lit("WINDOWS_GUI"); - case PE_WindowsSubsystem_WINDOWS_CUI: return str8_lit("WINDOWS_CUI"); - case PE_WindowsSubsystem_OS2_CUI: return str8_lit("OS2_CUI"); - case PE_WindowsSubsystem_POSIX_CUI: return str8_lit("POSIX_CUI"); - case PE_WindowsSubsystem_NATIVE_WINDOWS: return str8_lit("NATIVE_WINDOWS"); - case PE_WindowsSubsystem_WINDOWS_CE_GUI: return str8_lit("WINDOWS_CE_GUID"); - case PE_WindowsSubsystem_EFI_APPLICATION: return str8_lit("EFI_APPLICATION"); - case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER: return str8_lit("EFI_BOOT_SERVICE_DRIVER"); - case PE_WindowsSubsystem_EFI_ROM: return str8_lit("EFI_ROM"); - case PE_WindowsSubsystem_XBOX: return str8_lit("XBOX"); - case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: return str8_lit("WINDOWS_BOOT_APPLICATION"); - default: break; - } - return str8(0,0); -} - diff --git a/src/pe/pe.h b/src/pe/pe.h index 28635a48..ebb89f4b 100644 --- a/src/pe/pe.h +++ b/src/pe/pe.h @@ -1,13 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -/* date = September 6th 2023 8:54 am */ - #ifndef PE_H #define PE_H //////////////////////////////// -//~ rjf: PE Format Types +//~ rjf: PE Format-Defined Types/Constants #pragma pack(push,1) @@ -287,7 +285,7 @@ enum PE_GlobalFlags_HEAP_ENABLE_TAG_BY_DLL = (1 << 15), PE_GlobalFlags_DISABLE_STACK_EXTENSION = (1 << 16), PE_GlobalFlags_ENABLE_CSRDEBUG = (1 << 17), - PE_GlobalFlags_ENABLE_KDEBUG_SYMBOL_LOAD = (1 << 18), + PE_GlobalFlags_ENABLE_KDEBUG_SYMBOL_LOAD = (1 << 18), PE_GlobalFlags_DISABLE_PAGE_KERNEL_STACKS = (1 << 19), PE_GlobalFlags_ENABLE_SYSTEM_CRIT_BREAKS = (1 << 20), PE_GlobalFlags_HEAP_DISABLE_COALESCING = (1 << 21), @@ -445,11 +443,273 @@ struct PE_TLSHeader64 U32 characteristics; // COFF_SectionFlags but only align flags are used. }; +#define PE_RES_ALIGN 4u + +global read_only U8 PE_RES_MAGIC[] = +{ + 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +typedef U32 PE_ResourceKind; +enum +{ + PE_ResourceKind_CURSOR = 0x1, + PE_ResourceKind_BITMAP = 0x2, + PE_ResourceKind_ICON = 0x3, + PE_ResourceKind_MENU = 0x4, + PE_ResourceKind_DIALOG = 0x5, + PE_ResourceKind_STRING = 0x6, + PE_ResourceKind_FONTDIR = 0x7, + PE_ResourceKind_FONT = 0x8, + PE_ResourceKind_ACCELERATOR = 0x9, + PE_ResourceKind_RCDATA = 0xA, + PE_ResourceKind_MESSAGETABLE = 0xB, + PE_ResourceKind_GROUP_CURSOR = 0xC, + PE_ResourceKind_GROUP_ICON = 0xE, + PE_ResourceKind_VERSION = 0x10, + PE_ResourceKind_DLGINCLUDE = 0x11, + PE_ResourceKind_PLUGPLAY = 0x13, + PE_ResourceKind_VXD = 0x14, + PE_ResourceKind_ANICURSOR = 0x15, + PE_ResourceKind_ANIICON = 0x16, + PE_ResourceKind_HTML = 0x17, + PE_ResourceKind_MANIFEST = 0x18, + PE_ResourceKind_BITMAP_NEW = 0x2002, + PE_ResourceKind_MENU_NEW = 0x2004, + PE_ResourceKind_DIALOG_NEW = 0x2005, +}; + +typedef enum PE_ResDataKind +{ + PE_ResDataKind_NULL, + PE_ResDataKind_DIR, + PE_ResDataKind_COFF_LEAF, + PE_ResDataKind_COFF_RESOURCE, +} +PE_ResDataKind; + +typedef struct PE_ResourceHeader PE_ResourceHeader; +struct PE_ResourceHeader +{ + COFF_ResourceHeaderPrefix prefix; + U16 type; + U16 pad0; + U16 name; + U16 pad1; + U32 data_version; + COFF_ResourceMemoryFlags memory_flags; + U16 language_id; + U32 version; + U32 characteristics; +}; + +typedef U16 PE_BaseRelocKind; +enum +{ + PE_BaseRelocKind_ABSOLUTE = 0, // No reallocation is applied. Can be used as padding. + PE_BaseRelocKind_HIGH = 1, + PE_BaseRelocKind_LOW = 2, + PE_BaseRelocKind_HIGHLOW = 3, + PE_BaseRelocKind_HIGHADJ = 4, + PE_BaseRelocKind_MIPS_JMPADDR = 5, + PE_BaseRelocKind_ARM_MOV32 = 5, + PE_BaseRelocKind_RISCV_HIGH20 = 5, + // 6 is reserved + PE_BaseRelocKind_THUMB_MOV32 = 7, + PE_BaseRelocKind_RISCV_LOW12I = 7, + PE_BaseRelocKind_RISCV_LOW12S = 8, + PE_BaseRelocKind_LOONGARCH32_MARK_LA = 8, + PE_BaseRelocKind_LOONGARCH64_MARK_LA = 8, + PE_BaseRelocKind_MIPS_JMPADDR16 = 9, + PE_BaseRelocKind_DIR64 = 10, +}; +#define PE_BaseRelocOffsetFromEntry(x) ((x) & 0x1fff) +#define PE_BaseRelocKindFromEntry(x) (((x) >> 12) & 0xf) +#define PE_BaseRelocMake(k, off) ((((U16)(k) & 0xf) << 12) | (U16)((off) & 0x1fff)) + +typedef U32 PE_UnwindOpCode; +enum +{ + PE_UnwindOpCode_PUSH_NONVOL = 0, + PE_UnwindOpCode_ALLOC_LARGE = 1, + PE_UnwindOpCode_ALLOC_SMALL = 2, + PE_UnwindOpCode_SET_FPREG = 3, + PE_UnwindOpCode_SAVE_NONVOL = 4, + PE_UnwindOpCode_SAVE_NONVOL_FAR = 5, + PE_UnwindOpCode_EPILOG = 6, + PE_UnwindOpCode_SPARE_CODE = 7, + PE_UnwindOpCode_SAVE_XMM128 = 8, + PE_UnwindOpCode_SAVE_XMM128_FAR = 9, + PE_UnwindOpCode_PUSH_MACHFRAME = 10, +}; + +typedef U8 PE_UnwindGprRegX64; +enum +{ + PE_UnwindGprRegX64_RAX = 0, + PE_UnwindGprRegX64_RCX = 1, + PE_UnwindGprRegX64_RDX = 2, + PE_UnwindGprRegX64_RBX = 3, + PE_UnwindGprRegX64_RSP = 4, + PE_UnwindGprRegX64_RBP = 5, + PE_UnwindGprRegX64_RSI = 6, + PE_UnwindGprRegX64_RDI = 7, + PE_UnwindGprRegX64_R8 = 8, + PE_UnwindGprRegX64_R9 = 9, + PE_UnwindGprRegX64_R10 = 10, + PE_UnwindGprRegX64_R11 = 11, + PE_UnwindGprRegX64_R12 = 12, + PE_UnwindGprRegX64_R13 = 13, + PE_UnwindGprRegX64_R14 = 14, + PE_UnwindGprRegX64_R15 = 15, +}; + +typedef U8 PE_UnwindInfoFlags; +enum +{ + PE_UnwindInfoFlag_EHANDLER = (1<<0), + PE_UnwindInfoFlag_UHANDLER = (1<<1), + PE_UnwindInfoFlag_FHANDLER = 3, + PE_UnwindInfoFlag_CHAINED = (1<<2), +}; + +#define PE_UNWIND_OPCODE_FROM_FLAGS(f) ((f)&0xF) +#define PE_UNWIND_INFO_FROM_FLAGS(f) (((f) >> 4)&0xF) + +typedef union PE_UnwindCode PE_UnwindCode; +union PE_UnwindCode +{ + struct + { + U8 off_in_prolog; + U8 flags; + }; + U16 u16; +}; + +#define PE_UNWIND_INFO_VERSION_FROM_HDR(x) ((x)&0x7) +#define PE_UNWIND_INFO_FLAGS_FROM_HDR(x) (((x) >> 3)&0x1F) +#define PE_UNWIND_INFO_REG_FROM_FRAME(x) ((x)&0xF) +#define PE_UNWIND_INFO_OFF_FROM_FRAME(x) (((x) >> 4)&0xF) + +typedef struct PE_UnwindInfo PE_UnwindInfo; +struct PE_UnwindInfo +{ + U8 header; + U8 prolog_size; + U8 codes_num; + U8 frame; +}; + #pragma pack(pop) +//////////////////////////////// +//~ rjf: DOS Program + +// generated from pe/dos_program.asm +read_only global U8 pe_dos_program_data[] = +{ + 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, + 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x24, 0x00, 0x00 +}; +read_only global String8 pe_dos_program = {pe_dos_program_data, sizeof(pe_dos_program_data)}; + //////////////////////////////// //~ rjf: Parsed Info Types +//- rjf: relocation blocks + +typedef struct PE_BaseRelocBlock PE_BaseRelocBlock; +struct PE_BaseRelocBlock +{ + U64 page_virt_off; + U64 entry_count; + U16 *entries; +}; + +typedef struct PE_BaseRelocBlockNode PE_BaseRelocBlockNode; +struct PE_BaseRelocBlockNode +{ + PE_BaseRelocBlockNode *next; + PE_BaseRelocBlock v; +}; + +typedef struct PE_BaseRelocBlockList PE_BaseRelocBlockList; +struct PE_BaseRelocBlockList +{ + PE_BaseRelocBlockNode *first; + PE_BaseRelocBlockNode *last; + U64 count; +}; + +//- rjf: resources + +typedef struct PE_Resource PE_Resource; +struct PE_Resource +{ + COFF_ResourceID id; + PE_ResDataKind kind; + union + { + COFF_ResourceDataEntry leaf; + struct PE_ResourceDir *dir; + struct + { + COFF_ResourceID type; + U32 data_version; + U32 version; + COFF_ResourceMemoryFlags memory_flags; + String8 data; + } + coff_res; + } + u; +}; + +typedef struct PE_ResourceNode PE_ResourceNode; +struct PE_ResourceNode +{ + PE_ResourceNode *next; + PE_Resource data; +}; + +typedef struct PE_ResourceList PE_ResourceList; +struct PE_ResourceList +{ + PE_ResourceNode *first; + PE_ResourceNode *last; + U64 count; +}; + +typedef struct PE_ResourceArray PE_ResourceArray; +struct PE_ResourceArray +{ + PE_Resource *v; + U64 count; +}; + +typedef struct PE_ResourceDir PE_ResourceDir; +struct PE_ResourceDir +{ + U32 characteristics; + COFF_TimeStamp time_stamp; + U16 major_version; + U16 minor_version; + PE_ResourceList named_list; + PE_ResourceList id_list; +}; + +//- rjf: bundle + typedef struct PE_BinInfo PE_BinInfo; struct PE_BinInfo { @@ -475,161 +735,10 @@ struct PE_BinInfo }; //////////////////////////////// -//~ rjf: Parsed Info Extraction Helper Types +//~ rjf: Basic Enum Functions -typedef U16 PE_BaseRelocKind; -enum -{ - PE_BaseRelocKind_ABSOLUTE = 0, // No reallocation is applied. Can be used as padding. - PE_BaseRelocKind_HIGH = 1, - PE_BaseRelocKind_LOW = 2, - PE_BaseRelocKind_HIGHLOW = 3, - PE_BaseRelocKind_HIGHADJ = 4, - PE_BaseRelocKind_MIPS_JMPADDR = 5, - PE_BaseRelocKind_ARM_MOV32 = 5, - PE_BaseRelocKind_RISCV_HIGH20 = 5, - // 6 is reserved - PE_BaseRelocKind_THUMB_MOV32 = 7, - PE_BaseRelocKind_RISCV_LOW12I = 7, - PE_BaseRelocKind_RISCV_LOW12S = 8, - PE_BaseRelocKind_LOONGARCH32_MARK_LA = 8, - PE_BaseRelocKind_LOONGARCH64_MARK_LA = 8, - PE_BaseRelocKind_MIPS_JMPADDR16 = 9, - PE_BaseRelocKind_DIR64 = 10, -}; -#define PE_BaseRelocOffsetFromEntry(x) ((x) & 0x1fff) -#define PE_BaseRelocKindFromEntry(x) (((x) >> 12) & 0xf) -#define PE_BaseRelocMake(k, off) ((((U16)(k) & 0xf) << 12) | (U16)((off) & 0x1fff)) - -typedef struct PE_BaseRelocBlock PE_BaseRelocBlock; -struct PE_BaseRelocBlock -{ - U64 page_virt_off; - U64 entry_count; - U16 *entries; -}; - -typedef struct PE_BaseRelocBlockNode PE_BaseRelocBlockNode; -struct PE_BaseRelocBlockNode -{ - PE_BaseRelocBlockNode *next; - PE_BaseRelocBlock v; -}; - -typedef struct PE_BaseRelocBlockList PE_BaseRelocBlockList; -struct PE_BaseRelocBlockList -{ - PE_BaseRelocBlockNode *first; - PE_BaseRelocBlockNode *last; - U64 count; -}; - -//////////////////////////////// -//~ Resources - -#define PE_RES_ALIGN 4u - -read_only U8 PE_RES_MAGIC[] = { 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -enum -{ - PE_Resource_CURSOR = 0x1, - PE_Resource_BITMAP = 0x2, - PE_Resource_ICON = 0x3, - PE_Resource_MENU = 0x4, - PE_Resource_DIALOG = 0x5, - PE_Resource_STRING = 0x6, - PE_Resource_FONTDIR = 0x7, - PE_Resource_FONT = 0x8, - PE_Resource_ACCELERATOR = 0x9, - PE_Resource_RCDATA = 0xA, - PE_Resource_MESSAGETABLE = 0xB, - PE_Resource_GROUP_CURSOR = 0xC, - PE_Resource_GROUP_ICON = 0xE, - PE_Resource_VERSION = 0x10, - PE_Resource_DLGINCLUDE = 0x11, - PE_Resource_PLUGPLAY = 0x13, - PE_Resource_VXD = 0x14, - PE_Resource_ANICURSOR = 0x15, - PE_Resource_ANIICON = 0x16, - PE_Resource_HTML = 0x17, - PE_Resource_MANIFEST = 0x18, - PE_Resource_BITMAP_NEW = 0x2002, - PE_Resource_MENU_NEW = 0x2004, - PE_Resource_DIALOG_NEW = 0x2005, -}; -typedef U32 PE_ResourceType; - -#pragma pack(push, 1) -typedef struct PE_ResourceHeader -{ - COFF_ResourceHeaderPrefix prefix; - U16 type; - U16 pad0; - U16 name; - U16 pad1; - U32 data_version; - COFF_ResourceMemoryFlags memory_flags; - U16 language_id; - U32 version; - U32 characteristics; -} PE_ResourceHeader; -#pragma pack(pop) - -typedef enum -{ - PE_ResData_NULL, - PE_ResData_DIR, - PE_ResData_COFF_LEAF, - PE_ResData_COFF_RESOURCE, -} PE_ResDataType; - -typedef struct PE_Resource -{ - COFF_ResourceID id; - PE_ResDataType type; - union { - COFF_ResourceDataEntry leaf; - struct PE_ResourceDir *dir; - struct { - COFF_ResourceID type; - U32 data_version; - U32 version; - COFF_ResourceMemoryFlags memory_flags; - String8 data; - } coff_res; - } u; -} PE_Resource; - -typedef struct PE_ResourceNode -{ - struct PE_ResourceNode *next; - PE_Resource data; -} PE_ResourceNode; - -typedef struct PE_ResourceList -{ - U64 count; - PE_ResourceNode *first; - PE_ResourceNode *last; -} PE_ResourceList; - -typedef struct PE_ResourceArray -{ - U64 count; - PE_Resource *v; -} PE_ResourceArray; - -typedef struct PE_ResourceDir -{ - U32 characteristics; - COFF_TimeStamp time_stamp; - U16 major_version; - U16 minor_version; - PE_ResourceList named_list; - PE_ResourceList id_list; -} PE_ResourceDir; +internal U32 pe_slot_count_from_unwind_op_code(PE_UnwindOpCode opcode); +internal String8 pe_string_from_windows_subsystem(PE_WindowsSubsystem subsystem); //////////////////////////////// //~ rjf: Parser Functions @@ -661,12 +770,4 @@ internal PE_Resource * pe_resource_dir_search(PE_ResourceDir *dir, COFF_Reso internal PE_ResourceArray pe_resource_list_to_array(Arena *arena, PE_ResourceList *list); internal PE_ResourceDir * pe_resource_table_from_directory_data(Arena *arena, String8 data); -//////////////////////////////// - -internal String8 pe_get_dos_program(void); - -//////////////////////////////// - -internal String8 pe_string_from_subsystem(PE_WindowsSubsystem subsystem); - -#endif //PE_H +#endif // PE_H diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 6616ce90..02e32ecf 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -43,10 +43,10 @@ #include "regs/raddbgi/regs_raddbgi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" -#include "demon/demon_inc.h" +#include "demon2/demon2_inc.h" #include "eval/eval_inc.h" #include "unwind/unwind.h" -#include "ctrl/ctrl_inc.h" +#include "ctrl2/ctrl2_inc.h" //- rjf: [c] #include "base/base_inc.c" @@ -71,10 +71,10 @@ #include "regs/raddbgi/regs_raddbgi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" -#include "demon/demon_inc.c" +#include "demon2/demon2_inc.c" #include "eval/eval_inc.c" #include "unwind/unwind.c" -#include "ctrl/ctrl_inc.c" +#include "ctrl2/ctrl2_inc.c" //////////////////////////////// //~ rjf: Entry Point