begin process of moving pe unwinding info into pe layer; more demon2 work checkpoint

This commit is contained in:
Ryan Fleury
2024-03-05 16:54:57 -08:00
parent e25364a835
commit 0d0c599e00
6 changed files with 518 additions and 410 deletions
-9
View File
@@ -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
+178 -175
View File
@@ -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)
+16 -11
View File
@@ -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
+52 -44
View File
@@ -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);
}
+268 -167
View File
@@ -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
+4 -4
View File
@@ -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