From 6ebf0c48e3c47fcf8863373e567728ed31626ff8 Mon Sep 17 00:00:00 2001 From: zzy <2450266535@qq.com> Date: Sun, 15 Mar 2026 11:53:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(pe):=20=E6=B7=BB=E5=8A=A0PE=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E6=9E=84=E5=BB=BA=E5=99=A8=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增PE库的基础设施包括: - 创建README.md文档,说明代码参考rust cargo的object库实现 - 配置cbuild.toml包依赖,添加scc_utils依赖项 - 定义scc_pe_builder.h头文件,包含PE构建器的数据结构和API函数 - 实现PE文件的段管理、头信息处理和文件写入功能 --- libs/target/pe/README.md | 4 + libs/target/pe/cbuild.toml | 9 + libs/target/pe/include/scc_pe_builder.h | 80 +++ libs/target/pe/include/scc_pe_def.h | 848 ++++++++++++++++++++++++ libs/target/pe/include/scc_pe_idata.h | 77 +++ libs/target/pe/src/main.c | 102 +++ libs/target/pe/src/scc_pe_builder.c | 369 +++++++++++ libs/target/pe/src/scc_pe_idata.c | 171 +++++ libs/target/pe/tests/test_winpe_unit.c | 10 + runtime/scc_core/include/scc_core_vec.h | 2 + 10 files changed, 1672 insertions(+) create mode 100644 libs/target/pe/README.md create mode 100644 libs/target/pe/cbuild.toml create mode 100644 libs/target/pe/include/scc_pe_builder.h create mode 100644 libs/target/pe/include/scc_pe_def.h create mode 100644 libs/target/pe/include/scc_pe_idata.h create mode 100644 libs/target/pe/src/main.c create mode 100644 libs/target/pe/src/scc_pe_builder.c create mode 100644 libs/target/pe/src/scc_pe_idata.c create mode 100644 libs/target/pe/tests/test_winpe_unit.c diff --git a/libs/target/pe/README.md b/libs/target/pe/README.md new file mode 100644 index 0000000..7c17e95 --- /dev/null +++ b/libs/target/pe/README.md @@ -0,0 +1,4 @@ + +代码参考了 rust cargo 里面的 object = { version = "0.38.0", features = ["all"] } 库的实现 + +并且从 winnt.h (10.0.17763.0) 里面获取头文件结构但是修改了部分原始结构以适配当前环境 diff --git a/libs/target/pe/cbuild.toml b/libs/target/pe/cbuild.toml new file mode 100644 index 0000000..4a2cc74 --- /dev/null +++ b/libs/target/pe/cbuild.toml @@ -0,0 +1,9 @@ +[package] +name = "scc_pe" +version = "0.1.0" +authors = [] +description = "" + +dependencies = [{ name = "scc_utils", path = "../../../runtime/scc_utils" }] +# features = {} +# default_features = [] diff --git a/libs/target/pe/include/scc_pe_builder.h b/libs/target/pe/include/scc_pe_builder.h new file mode 100644 index 0000000..a5445a3 --- /dev/null +++ b/libs/target/pe/include/scc_pe_builder.h @@ -0,0 +1,80 @@ +#ifndef __SCC_WINPE_H__ +#define __SCC_WINPE_H__ + +#include "scc_pe_def.h" + +typedef SCC_VEC(IMAGE_DATA_DIRECTORY) scc_winpe_image_data_directory_vec_t; +typedef SCC_VEC(IMAGE_SECTION_HEADER) scc_winpe_image_section_header_vec_t; + +/** + * @brief + * + */ +typedef struct { + scc_pe_buffer_t buffer; ///< 镜像文件(File Data)数据 + + u32 section_alignment; ///< 文件镜像(Virtual Address)各个段的对齐方式 + u32 file_alignment; ///< PE文件内(File Adderss)各个段对齐方式 + + u32 baseof_code; ///< 代码段基地址(Virtual Address) + u32 sizeof_code; ///< 代码段大小 + u32 baseof_data; ///< 数据段基地址(Virtual Address) + u32 sizeof_init_data; ///< 初始化数据段大小 + u32 sizeof_uninit_data; ///< 未初始化数据段大小 + + u32 file_offset; ///< 内部使用变量,用于追踪文件内偏移地址 + u32 virtual_offset; ///< 内部使用变量,用于追踪镜像内偏移地址 + u32 nt_headers_offset; ///< 内部使用变量,用于追踪NT头偏移地址 + u32 sizeof_headers; ///< 内部使用变量,用于追踪完整镜像头大小 + + scc_winpe_image_data_directory_vec_t image_data_directory_vec; + scc_winpe_image_section_header_vec_t image_section_header_vec; + u16 section_header_num; + + u32 symbol_offset; + u32 symbol_num; + + cbool is_64; +} scc_pe_builder_t; + +typedef struct { + u16 machine; + u32 time_date_stamp; + u16 characteristics; + u8 major_linker_version; + u8 minor_linker_version; + u32 address_of_entry_point; + u64 image_base; + u16 major_operating_system_version; + u16 minor_operating_system_version; + u16 major_image_version; + u16 minor_image_version; + u16 major_subsystem_version; + u16 minor_subsystem_version; + u16 subsystem; + u16 dll_characteristics; + u64 size_of_stack_reserve; + u64 size_of_stack_commit; + u64 size_of_heap_reserve; + u64 size_of_heap_commit; +} scc_pe_config_t; + +void scc_pe_builder_init(scc_pe_builder_t *builder, bool is_64, + u32 section_alignment, u32 file_alignment); + +void scc_pe_reserve_header(scc_pe_builder_t *builder, u32 num_of_section); +scc_pe_section_range scc_pe_reserve_section_header(scc_pe_builder_t *builder, + BYTE name[8], + u32 characteristics, + u32 virtual_size, + u32 data_size); + +void scc_pe_write_header(scc_pe_builder_t *builder, scc_pe_config_t *config); + +void scc_pe_write_section(scc_pe_builder_t *builder, + scc_pe_section_range *range, u8 *data, + usize data_size); + +void scc_pe_dump_to_file(scc_pe_builder_t *builder, const char *file_path); + +#endif /* __SCC_WINPE_H__ */ diff --git a/libs/target/pe/include/scc_pe_def.h b/libs/target/pe/include/scc_pe_def.h new file mode 100644 index 0000000..6d7fb65 --- /dev/null +++ b/libs/target/pe/include/scc_pe_def.h @@ -0,0 +1,848 @@ +/** + * @brief pe.h - PE/COFF 结构定义头文件 + * 基于 winnt.h (10.0.17763.0) 和 object-0.38.0/src/pe.rs + */ +#ifndef __SCC_PE_DEF_H__ +#define __SCC_PE_DEF_H__ + +// #include +#include + +// FIXME +/** + * @brief DUMMYUNIONNAME会在被支持空联合体名称的编译器中定义为空, + * 从而导致bug,所以自行定义 + * + * @bug 可以有更好的方式解决这个问题 + */ +#define DUMMYUNIONNAME DUMMYUNIONNAME + +// 基本类型定义 +typedef u8 BYTE; +typedef u16 WORD; +typedef u32 DWORD; +typedef u64 QWORD; +typedef i8 CHAR; +typedef i16 SHORT; +typedef i32 LONG; +typedef i64 LONGLONG; +typedef DWORD PBYTE; // TODO ? + +#ifndef UNALIGNED +#define UNALIGNED +#endif + +// 常量定义 +#define IMAGE_DOS_SIGNATURE 0x5A4D // "MZ" +#define IMAGE_OS2_SIGNATURE 0x454E // "NE" +#define IMAGE_OS2_SIGNATURE_LE 0x454C // "LE" +#define IMAGE_VXD_SIGNATURE 0x454C // "LE" +#define IMAGE_NT_SIGNATURE 0x00004550 // "PE\0\0" + +// DOS 头部结构 +typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header + WORD e_magic; // Magic number + WORD e_cblp; // Bytes on last page of file + WORD e_cp; // Pages in file + WORD e_crlc; // Relocations + WORD e_cparhdr; // Size of header in paragraphs + WORD e_minalloc; // Minimum extra paragraphs needed + WORD e_maxalloc; // Maximum extra paragraphs needed + WORD e_ss; // Initial (relative) SS value + WORD e_sp; // Initial SP value + WORD e_csum; // Checksum + WORD e_ip; // Initial IP value + WORD e_cs; // Initial (relative) CS value + WORD e_lfarlc; // File address of relocation table + WORD e_ovno; // Overlay number + WORD e_res[4]; // Reserved words + WORD e_oemid; // OEM identifier (for e_oeminfo) + WORD e_oeminfo; // OEM information; e_oemid specific + WORD e_res2[10]; // Reserved words + DWORD e_lfanew; // File address of new exe header +} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; + +// NT 头部标志 +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. +#define IMAGE_FILE_EXECUTABLE_IMAGE \ + 0x0002 // File is executable (i.e. no unresolved external references). +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line numbers stripped from file. +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED \ + 0x0008 // Local symbols stripped from file. +#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses +#define IMAGE_FILE_BYTES_REVERSED_LO \ + 0x0080 // Bytes of machine word are reversed. +#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. +#define IMAGE_FILE_DEBUG_STRIPPED \ + 0x0200 // Debugging info stripped from file in .DBG file +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP \ + 0x0400 // If Image is on removable media, copy and run from the swap file. +#define IMAGE_FILE_NET_RUN_FROM_SWAP \ + 0x0800 // If Image is on Net, copy and run from the swap file. +#define IMAGE_FILE_SYSTEM 0x1000 // System File. +#define IMAGE_FILE_DLL 0x2000 // File is a DLL. +#define IMAGE_FILE_UP_SYSTEM_ONLY \ + 0x4000 // File should only be run on a UP machine +#define IMAGE_FILE_BYTES_REVERSED_HI \ + 0x8000 // Bytes of machine word are reversed. + +// 机器类型定义 +#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 // Unknown +#define IMAGE_FILE_MACHINE_TARGET_HOST \ + 0x0001 // Useful for indicating we want to interact with the host and not a + // WoW guest. +#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386. +#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian +#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian +#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian +#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2 +#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP +#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian +#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 // SH3 DSP +#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian +#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian +#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5 +#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian +#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian +#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian +#define IMAGE_FILE_MACHINE_AM33 0x01d3 // Matsushita AM33 +#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian +#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 // IBM PowerPC FP +#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64 +#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS +#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64 +#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS +#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS +#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 +#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon +#define IMAGE_FILE_MACHINE_CEF 0x0CEF // EFI Byte Code +#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code +#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8) +#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian +#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian +#define IMAGE_FILE_MACHINE_CEE 0xC0EE + +// 文件头结构 +#define IMAGE_SIZEOF_FILE_HEADER 20 + +typedef struct _IMAGE_FILE_HEADER { + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; +} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; + +// 数据目录结构 +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct _IMAGE_DATA_DIRECTORY { + DWORD VirtualAddress; + DWORD Size; +} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; + +// 可选头部魔数 +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +// 可选头部结构 (32位) +typedef struct _IMAGE_OPTIONAL_HEADER32 { + // + // 标准域 + // + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + DWORD BaseOfData; + + // + // NT 附加域 + // + DWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + // IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +// 可选头部结构 (64位) +typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + QWORD ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + QWORD SizeOfStackReserve; + QWORD SizeOfStackCommit; + QWORD SizeOfHeapReserve; + QWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + // IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + +// NT 头部结构 (32位) +typedef struct _IMAGE_NT_HEADERS32 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +// NT 头部结构 (64位) +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; + +#ifdef _WIN64 +typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; +#else +typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +#endif + +// 子系统类型 +#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem. +#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_GUI \ + 2 // Image runs in the Windows GUI subsystem. +#define IMAGE_SUBSYSTEM_WINDOWS_CUI \ + 3 // Image runs in the Windows character subsystem. +#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem. +#define IMAGE_SUBSYSTEM_POSIX_CUI \ + 7 // image runs in the Posix character subsystem. +#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // image is a native Win9x driver. +#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI \ + 9 // Image runs in the Windows CE subsystem. +#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 // Image runs as an EFI application. +#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER \ + 11 // Image runs as an EFI boot service driver. +#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER \ + 12 // Image runs as an EFI runtime driver. +#define IMAGE_SUBSYSTEM_EFI_ROM 13 // Image is an EFI ROM image. +#define IMAGE_SUBSYSTEM_XBOX 14 // Image runs in an Xbox environment. +#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 // Boot application. + +// DLL 特性 +#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA \ + 0x0020 // Image can handle a high entropy 64-bit virtual address space. +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 // DLL can move. +#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 // Code Integrity Image +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 // Image is NX compatible +#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION \ + 0x0200 // Image understands isolation and doesn't want it +#define IMAGE_DLLCHARACTERISTICS_NO_SEH \ + 0x0400 // Image does not use SEH. No SE handler may reside in this image +#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 // Do not bind this image. +#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER \ + 0x1000 // Image should execute in an AppContainer +#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 // Driver uses WDM model +#define IMAGE_DLLCHARACTERISTICS_GUARD_CF \ + 0x4000 // Image supports Control Flow Guard. +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +// 数据目录索引 +#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory +#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory +#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory +#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory +#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory +#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table +#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory +#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data +#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP +#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory +#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory +#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT \ + 11 // Bound Import Directory in headers +#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table +#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors +#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor + +// 节头大小 +#define IMAGE_SIZEOF_SHORT_NAME 8 +#define IMAGE_SIZEOF_SECTION_HEADER 40 + +// 节头部结构 +typedef struct _IMAGE_SECTION_HEADER { + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; + union { + DWORD PhysicalAddress; + DWORD VirtualSize; + } Misc; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; +} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; + +// 节特性标志 +#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved. +#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code. +#define IMAGE_SCN_CNT_INITIALIZED_DATA \ + 0x00000040 // Section contains initialized data. +#define IMAGE_SCN_CNT_UNINITIALIZED_DATA \ + 0x00000080 // Section contains uninitialized data. + +#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved. +#define IMAGE_SCN_LNK_INFO \ + 0x00000200 // Section contains comments or some other type of information. +#define IMAGE_SCN_LNK_REMOVE \ + 0x00000800 // Section contents will not become part of image. +#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat. +#define IMAGE_SCN_NO_DEFER_SPEC_EXC \ + 0x00004000 // Reset speculative exceptions handling bits in the TLB entries + // for this section. +#define IMAGE_SCN_GPREL \ + 0x00008000 // Section content can be accessed relative to GP +#define IMAGE_SCN_MEM_FARDATA 0x00008000 +#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 + +#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 // +#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 // +#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 // +#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 // +#define IMAGE_SCN_ALIGN_16BYTES \ + 0x00500000 // Default alignment if no others are specified. +#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 // +#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 // +#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 // +#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 // +#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 // +#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 // +#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 // +#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 // +#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 // +#define IMAGE_SCN_ALIGN_MASK 0x00F00000 + +#define IMAGE_SCN_LNK_NRELOC_OVFL \ + 0x01000000 // Section contains extended relocations. +#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. +#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cacheable. +#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable. +#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. +#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. +#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable. + +// 导入表相关 +typedef struct _IMAGE_IMPORT_DESCRIPTOR { + union { + DWORD Characteristics; // 0 for terminating null import descriptor + DWORD OriginalFirstThunk; // RVA to original unbound IAT + // (PIMAGE_THUNK_DATA) + } DUMMYUNIONNAME; + DWORD TimeDateStamp; // 0 if not bound, + // -1 if bound, and real date\time stamp + // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) + // O.W. date/time stamp of DLL bound to (Old BIND) + + DWORD ForwarderChain; // -1 if no forwarders + DWORD Name; + DWORD FirstThunk; // RVA to IAT (if bound this IAT has actual addresses) +} IMAGE_IMPORT_DESCRIPTOR; +typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR; + +// Thunk 数据结构 +typedef struct _IMAGE_THUNK_DATA32 { + union { + DWORD ForwarderString; // PBYTE + DWORD Function; // PDWORD + DWORD Ordinal; + DWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME + } u1; +} IMAGE_THUNK_DATA32; +typedef IMAGE_THUNK_DATA32 *PIMAGE_THUNK_DATA32; + +typedef struct _IMAGE_THUNK_DATA64 { + union { + QWORD ForwarderString; // PBYTE + QWORD Function; // PDWORD + QWORD Ordinal; + QWORD AddressOfData; // PIMAGE_IMPORT_BY_NAME + } u1; +} IMAGE_THUNK_DATA64; +typedef IMAGE_THUNK_DATA64 *PIMAGE_THUNK_DATA64; + +// 导入名称结构 +typedef struct _IMAGE_IMPORT_BY_NAME { + WORD Hint; + BYTE Name[1]; +} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; + +// 导出表结构 +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; // RVA from base of image + DWORD AddressOfNames; // RVA from base of image + DWORD AddressOfNameOrdinals; // RVA from base of image +} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; + +// 基址重定位结构 +#define IMAGE_SIZEOF_BASE_RELOCATION 8 + +typedef struct _IMAGE_BASE_RELOCATION { + DWORD VirtualAddress; + DWORD SizeOfBlock; + // WORD TypeOffset[1]; +} IMAGE_BASE_RELOCATION; +typedef IMAGE_BASE_RELOCATION UNALIGNED *PIMAGE_BASE_RELOCATION; + +// 基址重定位类型 +#define IMAGE_REL_BASED_ABSOLUTE 0 +#define IMAGE_REL_BASED_HIGH 1 +#define IMAGE_REL_BASED_LOW 2 +#define IMAGE_REL_BASED_HIGHLOW 3 +#define IMAGE_REL_BASED_HIGHADJ 4 +#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5 5 +#define IMAGE_REL_BASED_RESERVED 6 +#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7 7 +#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8 8 +#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9 9 +#define IMAGE_REL_BASED_DIR64 10 + +// 调试目录结构 +typedef struct _IMAGE_DEBUG_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Type; + DWORD SizeOfData; + DWORD AddressOfRawData; + DWORD 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_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 + +// TLS 目录结构 +typedef struct _IMAGE_TLS_DIRECTORY32 { + DWORD StartAddressOfRawData; + DWORD EndAddressOfRawData; + DWORD AddressOfIndex; // PDWORD + DWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * + DWORD SizeOfZeroFill; + DWORD Characteristics; +} IMAGE_TLS_DIRECTORY32, *PIMAGE_TLS_DIRECTORY32; + +typedef struct _IMAGE_TLS_DIRECTORY64 { + QWORD StartAddressOfRawData; + QWORD EndAddressOfRawData; + QWORD AddressOfIndex; // PDWORD + QWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * + DWORD SizeOfZeroFill; + DWORD Characteristics; +} IMAGE_TLS_DIRECTORY64, *PIMAGE_TLS_DIRECTORY64; + +#ifdef _WIN64 +typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY; +typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY; +#else +typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY; +typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY; +#endif + +// 资源目录结构 +typedef struct _IMAGE_RESOURCE_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + WORD NumberOfNamedEntries; + WORD NumberOfIdEntries; + // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; +} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; + +#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 +#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + +typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { + union { + struct { + DWORD NameOffset : 31; + DWORD NameIsString : 1; + }; + DWORD Name; + WORD Id; + }; + union { + DWORD OffsetToData; + struct { + DWORD OffsetToDirectory : 31; + DWORD DataIsDirectory : 1; + }; + }; +} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY; + +typedef struct _IMAGE_RESOURCE_DATA_ENTRY { + DWORD OffsetToData; + DWORD Size; + DWORD CodePage; + DWORD Reserved; +} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY; + +// 资源类型 +#define RT_CURSOR 1 +#define RT_BITMAP 2 +#define RT_ICON 3 +#define RT_MENU 4 +#define RT_DIALOG 5 +#define RT_STRING 6 +#define RT_FONTDIR 7 +#define RT_FONT 8 +#define RT_ACCELERATOR 9 +#define RT_RCDATA 10 +#define RT_MESSAGETABLE 11 +#define RT_GROUP_CURSOR 12 +#define RT_GROUP_ICON 14 +#define RT_VERSION 16 +#define RT_DLGINCLUDE 17 +#define RT_PLUGPLAY 19 +#define RT_VXD 20 +#define RT_ANICURSOR 21 +#define RT_ANIICON 22 +#define RT_HTML 23 +#define RT_MANIFEST 24 + +// 加载配置目录结构 +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY32 { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + DWORD DeCommitFreeBlockThreshold; + DWORD DeCommitTotalFreeThreshold; + DWORD LockPrefixTable; // VA + DWORD MaximumAllocationSize; + DWORD VirtualMemoryThreshold; + DWORD ProcessAffinityMask; + DWORD ProcessHeapFlags; + WORD CsdVersion; + WORD DependentLoadFlags; + DWORD EditList; // VA + DWORD SecurityCookie; // VA + DWORD SEHandlerTable; // VA + DWORD SEHandlerCount; + DWORD GuardCFCheckFunctionPointer; // VA + DWORD GuardCFDispatchFunctionPointer; // VA + DWORD GuardCFFunctionTable; // VA + DWORD GuardCFFunctionCount; + DWORD GuardFlags; +} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32; + +typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 { + DWORD Size; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD GlobalFlagsClear; + DWORD GlobalFlagsSet; + DWORD CriticalSectionDefaultTimeout; + QWORD DeCommitFreeBlockThreshold; + QWORD DeCommitTotalFreeThreshold; + QWORD LockPrefixTable; // VA + QWORD MaximumAllocationSize; + QWORD VirtualMemoryThreshold; + QWORD ProcessAffinityMask; + DWORD ProcessHeapFlags; + WORD CsdVersion; + WORD DependentLoadFlags; + QWORD EditList; // VA + QWORD SecurityCookie; // VA + QWORD SEHandlerTable; // VA + QWORD SEHandlerCount; + QWORD GuardCFCheckFunctionPointer; // VA + QWORD GuardCFDispatchFunctionPointer; // VA + QWORD GuardCFFunctionTable; // VA + QWORD GuardCFFunctionCount; + DWORD GuardFlags; +} IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64; + +#ifdef _WIN64 +typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY; +typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY; +#else +typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY; +typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY; +#endif + +// GUID 定义 +typedef struct _GUID { + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[8]; +} GUID, *PGUID; + +// 符号相关定义 +#define IMAGE_SIZEOF_SYMBOL 18 + +typedef struct _IMAGE_SYMBOL { + union { + BYTE ShortName[8]; + struct { + DWORD Short; // if 0, use LongName + DWORD Long; // offset into string table + } Name; + PBYTE LongName[2]; + } N; + DWORD Value; + SHORT SectionNumber; + WORD Type; + BYTE StorageClass; + BYTE NumberOfAuxSymbols; +} IMAGE_SYMBOL; +typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL; + +// 符号存储类 +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE) - 1 +#define IMAGE_SYM_CLASS_NULL 0x0000 +#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 +#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 +#define IMAGE_SYM_CLASS_STATIC 0x0003 +#define IMAGE_SYM_CLASS_REGISTER 0x0004 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 +#define IMAGE_SYM_CLASS_LABEL 0x0006 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 +#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 +#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B +#define IMAGE_SYM_CLASS_UNION_TAG 0x000C +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E +#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 +#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 + +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 +#define IMAGE_SYM_CLASS_BLOCK 0x0064 +#define IMAGE_SYM_CLASS_FUNCTION 0x0065 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 +#define IMAGE_SYM_CLASS_FILE 0x0067 +#define IMAGE_SYM_CLASS_SECTION 0x0068 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 +#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B + +// 档案格式 +#define IMAGE_ARCHIVE_START_SIZE 8 +#define IMAGE_ARCHIVE_START "!\n" +#define IMAGE_ARCHIVE_END "`\n" +#define IMAGE_ARCHIVE_PAD "\n" +#define IMAGE_ARCHIVE_LINKER_MEMBER "/ " +#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// " + +typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER { + BYTE Name[16]; // File member name - `/' terminated. + BYTE Date[12]; // File member date - decimal. + BYTE UserID[6]; // File member user id - decimal. + BYTE GroupID[6]; // File member group id - decimal. + BYTE Mode[8]; // File member mode - octal. + BYTE Size[10]; // File member size - decimal. + BYTE EndHeader[2]; // String to end header. +} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER; + +#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60 + +// 重新定位类型 +#define IMAGE_REL_I386_ABSOLUTE \ + 0x0000 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_I386_DIR16 \ + 0x0001 // Direct 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_REL16 \ + 0x0002 // PC-relative 16-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32 \ + 0x0006 // Direct 32-bit reference to the symbols virtual address +#define IMAGE_REL_I386_DIR32NB \ + 0x0007 // Direct 32-bit reference to the symbols virtual address, base not + // included +#define IMAGE_REL_I386_SEG12 \ + 0x0009 // Direct 16-bit reference to the segment-selector bits of a 32-bit + // virtual address +#define IMAGE_REL_I386_SECTION 0x000A // Section table index +#define IMAGE_REL_I386_SECREL 0x000B // Offset within section +#define IMAGE_REL_I386_TOKEN 0x000C // clr token +#define IMAGE_REL_I386_SECREL7 \ + 0x000D // 7 bit offset from base of section containing target +#define IMAGE_REL_I386_REL32 \ + 0x0014 // PC-relative 32-bit reference to the symbols virtual address + +// ARM 重新定位类型 +#define IMAGE_REL_ARM_ABSOLUTE 0x0000 // No relocation required +#define IMAGE_REL_ARM_ADDR32 0x0001 // 32 bit address +#define IMAGE_REL_ARM_ADDR32NB 0x0002 // 32 bit address w/o image base +#define IMAGE_REL_ARM_BRANCH24 0x0003 // 24 bit offset << 2 & sign ext. +#define IMAGE_REL_ARM_BRANCH11 0x0004 // Thumb: 2 11 bit offsets +#define IMAGE_REL_ARM_TOKEN 0x0005 // clr token +#define IMAGE_REL_ARM_GPREL12 0x0006 // GP-relative addressing (ARM) +#define IMAGE_REL_ARM_GPREL7 0x0007 // GP-relative addressing (Thumb) +#define IMAGE_REL_ARM_BLX24 0x0008 +#define IMAGE_REL_ARM_BLX11 0x0009 +#define IMAGE_REL_ARM_SECTION 0x000E // Section table index +#define IMAGE_REL_ARM_SECREL 0x000F // Offset within section +#define IMAGE_REL_ARM_MOV32A 0x0010 // ARM: MOVW/MOVT +#define IMAGE_REL_ARM_MOV32T 0x0011 // Thumb: MOVW/MOVT +#define IMAGE_REL_ARM_BRANCH20T 0x0012 // Thumb: 32-bit conditional B +#define IMAGE_REL_ARM_BRANCH24T 0x0014 // Thumb: 32-bit B or BL +#define IMAGE_REL_ARM_BLX23T 0x0015 // Thumb: BLX immediate + +// ARM64 重新定位类型 +#define IMAGE_REL_ARM64_ABSOLUTE 0x0000 // No relocation required +#define IMAGE_REL_ARM64_ADDR32 0x0001 // 32 bit address (do not use this type) +#define IMAGE_REL_ARM64_ADDR32NB 0x0002 // 32 bit address w/o image base +#define IMAGE_REL_ARM64_BRANCH26 \ + 0x0003 // 26 bit offset << 2 & sign ext. for B & BL +#define IMAGE_REL_ARM64_PAGEBASE_REL21 0x0004 // ADRP +#define IMAGE_REL_ARM64_REL21 0x0005 // ADR +#define IMAGE_REL_ARM64_PAGEOFFSET_12A \ + 0x0006 // ADD/ADDS (immediate) with zero shift +#define IMAGE_REL_ARM64_PAGEOFFSET_12L \ + 0x0007 // LDR (indexed, unsigned immediate) +#define IMAGE_REL_ARM64_SECREL \ + 0x0008 // Offset within section -- legal only since 8.1 +#define IMAGE_REL_ARM64_SECREL_LOW12A \ + 0x0009 // ADD/ADDS (immediate) with zero shift, for bit 0:11 of section + // offset +#define IMAGE_REL_ARM64_SECREL_HIGH12A \ + 0x000A // ADD/ADDS (immediate) with zero shift, for bit 12:23 of section + // offset +#define IMAGE_REL_ARM64_SECREL_LOW12L \ + 0x000B // LDR (indexed, unsigned immediate), for bit 0:11 of section offset +#define IMAGE_REL_ARM64_TOKEN 0x000C // clr token +#define IMAGE_REL_ARM64_SECTION 0x000D // Section table index +#define IMAGE_REL_ARM64_ADDR64 0x000E // 64 bit address +#define IMAGE_REL_ARM64_BRANCH19 \ + 0x000F // 19 bit offset << 2 & sign ext. for conditional B +#define IMAGE_REL_ARM64_BRANCH14 \ + 0x0010 // 14 bit offset << 2 & sign ext. for TBZ/TBNZ + +// x64 重新定位类型 +#define IMAGE_REL_AMD64_ABSOLUTE \ + 0x0000 // Reference is absolute, no relocation is necessary +#define IMAGE_REL_AMD64_ADDR64 0x0001 // 64-bit address (VA). +#define IMAGE_REL_AMD64_ADDR32 0x0002 // 32-bit address (VA). +#define IMAGE_REL_AMD64_ADDR32NB 0x0003 // 32-bit address w/o image base (RVA). +#define IMAGE_REL_AMD64_REL32 \ + 0x0004 // 32-bit relative address from byte following reloc +#define IMAGE_REL_AMD64_REL32_1 \ + 0x0005 // 32-bit relative address from byte distance 1 from reloc +#define IMAGE_REL_AMD64_REL32_2 \ + 0x0006 // 32-bit relative address from byte distance 2 from reloc +#define IMAGE_REL_AMD64_REL32_3 \ + 0x0007 // 32-bit relative address from byte distance 3 from reloc +#define IMAGE_REL_AMD64_REL32_4 \ + 0x0008 // 32-bit relative address from byte distance 4 from reloc +#define IMAGE_REL_AMD64_REL32_5 \ + 0x0009 // 32-bit relative address from byte distance 5 from reloc +#define IMAGE_REL_AMD64_SECTION 0x000A // Section index +#define IMAGE_REL_AMD64_SECREL \ + 0x000B // 32 bit offset from base of section containing target +#define IMAGE_REL_AMD64_SECREL7 \ + 0x000C // 7 bit unsigned offset from base of section containing target +#define IMAGE_REL_AMD64_TOKEN 0x000D // 32 bit metadata token +#define IMAGE_REL_AMD64_SREL32 \ + 0x000E // 32 bit signed span-dependent value emitted into object +#define IMAGE_REL_AMD64_PAIR \ + 0x000F // 32 bit signed span-dependent value applied at link time +#define IMAGE_REL_AMD64_SSPAN32 \ + 0x0010 // 32 bit signed span-dependent value applied at link time + +///< +#include +#include +typedef SCC_VEC(u8) scc_pe_buffer_t; + +typedef struct { + u32 virual_address; + u32 virual_size; + u32 file_offset; + u32 file_size; +} scc_pe_section_range; + +// FIXME 小端序? 当前简化为直接返回 +#define SCC_LE16(x) (x) +#define SCC_LE32(x) (x) +#define SCC_LE64(x) (x) + +#endif /* __SCC_PE_DEF_H__ */ diff --git a/libs/target/pe/include/scc_pe_idata.h b/libs/target/pe/include/scc_pe_idata.h new file mode 100644 index 0000000..41500bc --- /dev/null +++ b/libs/target/pe/include/scc_pe_idata.h @@ -0,0 +1,77 @@ +#ifndef __SCC_PE_IDATA_H__ +#define __SCC_PE_IDATA_H__ + +#include "scc_pe_def.h" + +typedef SCC_VEC(IMAGE_THUNK_DATA64) scc_winpe_lookup_table_vec_t; + +/// @brief Hint Name Table Builder +typedef struct { + scc_pe_buffer_t data; ///< 具体数据 + scc_hashtable_t str_map; ///< 符号名称映射到data的idx + u32 section_offset; ///< 在idata中的偏移 +} scc_winpe_hnt_builder_t; + +typedef struct { + u32 offset; ///< 相对代码段的偏移地址 + i32 addend; ///< 可选的偏移量的附加值 可选默认为0 + u8 size; ///< 引用的地址的大小 + const char *library_name; ///< 库名称 eg. "Kernel32.dll" + const char *symbol_name; ///< 导入dll的符号名称 eg. "CreateFileW" + u16 ordinal; ///< 符号的序号 eg. 可选 +} scc_winpe_extern_t; +typedef SCC_VEC(scc_winpe_extern_t) scc_winpe_extern_vec_t; + +typedef SCC_VEC(const char *) scc_winpe_name_vec_t; +typedef struct { + const char *name; + scc_winpe_name_vec_t symbol_names; +} scc_winpe_idata_lib_t; +typedef SCC_VEC(scc_winpe_idata_lib_t) scc_winpe_idata_lib_vec_t; +typedef struct { + scc_pe_buffer_t buffer; ///< 导入表数据 + scc_winpe_extern_vec_t externs; + scc_hashtable_t externs_set; + + scc_winpe_hnt_builder_t hnt_builder; + scc_hashtable_t iat_map; ///< 符号名称映射到idata的虚拟镜像地址 + scc_winpe_idata_lib_vec_t idata_libs; +} scc_winpe_idata_builder_t; + +/** + * @brief PE格式导入表构建器初始化 + * @warning 需要提前构造导入表所需的信息,不会检查导入表信息正确性 + * + * @param builder + * @param idata_libs + */ +void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder, + scc_winpe_idata_lib_vec_t *idata_libs); + +/** + * @brief 获取导入表占据的大小 + * @warning 必须初始化导入表构建器 + * + * @param builder + * @return u32 + */ +u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder); + +/** + * @brief 构造导入表 + * @warning 必须初始化导入表构建器 + * + * @param builder + * @param idata_range + */ +scc_pe_buffer_t scc_pe_construct_idata(scc_winpe_idata_builder_t *builder, + scc_pe_section_range *idata_range); + +// RVA Relative Virtual Address +static inline u64 +scc_pe_idata_get_symbol_rva(scc_winpe_idata_builder_t *builder, + const char *symbol_name) { + return (u64)scc_hashtable_get(&builder->iat_map, symbol_name); +} + +#endif diff --git a/libs/target/pe/src/main.c b/libs/target/pe/src/main.c new file mode 100644 index 0000000..b11bf4a --- /dev/null +++ b/libs/target/pe/src/main.c @@ -0,0 +1,102 @@ +#include +#include +#include + +int main() { + const char data[] = "Hello, World from SCC PE Builder!\n\0"; + + /* clang-format off */ + const char code[] = { + // sub rsp, 0x28 ; 为函数调用分配栈空间 + 0x48, 0x83, 0xEC, 0x28, + // lea rcx, [rip + data_offset] ; 将字符串地址加载到RCX(第一个参数) + 0x48, 0x8D, 0x0D, 0x00, 0x00, 0x00, 0x00, + // call qword ptr [rip + puts_iat] ; 通过IAT调用puts + 0xFF, 0x15, 0x00, 0x00, 0x00, 0x00, + // add rsp, 0x28 ; 恢复栈空间 + 0x48, 0x83, 0xC4, 0x28, + // xor eax, eax ; 设置返回值为0 + 0x33, 0xC0, + // ret ; 返回 + 0xC3, + }; + /* clang-format on */ + scc_pe_builder_t builder = {0}; + scc_pe_builder_init(&builder, true, 4096, 512); + scc_pe_reserve_header(&builder, 3); + scc_pe_section_range code_range = scc_pe_reserve_section_header( + &builder, (BYTE *)".text\0\0", + IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE, + sizeof(code), sizeof(code)); + + scc_pe_section_range data_range = scc_pe_reserve_section_header( + &builder, (BYTE *)".data\0\0", + IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | + IMAGE_SCN_MEM_WRITE, + sizeof(data), sizeof(data)); + + scc_winpe_idata_builder_t idata_builder; + scc_winpe_idata_lib_vec_t idata_libs; + scc_vec_init(idata_libs); + scc_winpe_idata_lib_t ucrtbase; + ucrtbase.name = "ucrtbase.dll"; + scc_vec_init(ucrtbase.symbol_names); + scc_vec_push(ucrtbase.symbol_names, "puts"); + scc_vec_push(idata_libs, ucrtbase); + scc_pe_idata_builder_init(&idata_builder, &idata_libs); + u32 idata_size = scc_pe_reserve_idata(&idata_builder); + scc_pe_section_range idata_range = scc_pe_reserve_section_header( + &builder, (BYTE *)".idata\0", + IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | + IMAGE_SCN_MEM_WRITE, + idata_size, idata_size); + scc_vec_at(builder.image_data_directory_vec, IMAGE_DIRECTORY_ENTRY_IMPORT) = + (IMAGE_DATA_DIRECTORY){.VirtualAddress = idata_range.virual_address, + .Size = idata_range.virual_size}; + scc_pe_buffer_t idata_buffer = + scc_pe_construct_idata(&idata_builder, &idata_range); + + u32 entry_point_offset = 0; + u64 base_address = 0x140000000; + u32 entry_point = code_range.virual_address + entry_point_offset; + scc_pe_config_t config = (scc_pe_config_t){ + .machine = IMAGE_FILE_MACHINE_AMD64, + .time_date_stamp = 0, + .characteristics = + IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LARGE_ADDRESS_AWARE, + .major_linker_version = 14, + .minor_linker_version = 0, + .address_of_entry_point = entry_point, + .image_base = base_address, + .major_operating_system_version = 6, + .minor_operating_system_version = 0, + .major_image_version = 0, + .minor_image_version = 0, + .major_subsystem_version = 6, + .minor_subsystem_version = 0, + .subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI, + .dll_characteristics = IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | + IMAGE_DLLCHARACTERISTICS_NX_COMPAT, + .size_of_stack_reserve = 0x100000, + .size_of_stack_commit = 0x1000, + .size_of_heap_reserve = 0x100000, + .size_of_heap_commit = 0x1000, + }; + + // FIXME 需要确保宿主机为小端 + *(u32 *)((u8 *)code + 7) = + (data_range.virual_address + 0) - (code_range.virual_address + 7 + 4); + *(u32 *)((u8 *)code + 13) = + (u64)scc_pe_idata_get_symbol_rva(&idata_builder, "puts") - + (code_range.virual_address + 13 + 4); + + scc_pe_write_header(&builder, &config); + scc_pe_write_section(&builder, &code_range, (u8 *)code, sizeof(code)); + scc_pe_write_section(&builder, &data_range, (u8 *)data, sizeof(data)); + scc_pe_write_section(&builder, &idata_range, + scc_vec_unsafe_get_data(idata_buffer), + scc_vec_size(idata_buffer)); + + scc_pe_dump_to_file(&builder, "hello_world.exe"); +} diff --git a/libs/target/pe/src/scc_pe_builder.c b/libs/target/pe/src/scc_pe_builder.c new file mode 100644 index 0000000..d243954 --- /dev/null +++ b/libs/target/pe/src/scc_pe_builder.c @@ -0,0 +1,369 @@ +#include + +#define reserve_align(offset, size) ((offset) + ((size) - 1)) & ~((size) - 1) + +void scc_pe_builder_init(scc_pe_builder_t *builder, bool is_64, + u32 section_alignment, u32 file_alignment) { + scc_memset(builder, 0, sizeof(scc_pe_builder_t)); + builder->is_64 = is_64; + builder->section_alignment = section_alignment; + builder->file_alignment = file_alignment; + builder->file_offset = 0; +} + +static u32 reserve_file(scc_pe_builder_t *builder, u32 len, u32 align) { + if (len == 0) { + return len; + } + + builder->file_offset = reserve_align(builder->file_offset, align); + u32 offset = builder->file_offset; + builder->file_offset += len; + LOG_INFO("reserve_file %u bytes at %u [%u]", len, offset, + builder->file_offset); + return offset; +} + +static u32 reserve_virtual(scc_pe_builder_t *builder, u32 len, u32 align) { + if (len == 0) { + return len; + } + + u32 offset = builder->virtual_offset; + builder->virtual_offset += len; + builder->virtual_offset = reserve_align(builder->virtual_offset, align); + LOG_INFO("reserve_virtual %u bytes at %u [%u]", len, offset, + builder->virtual_offset); + return offset; +} + +static void padding_util(scc_pe_builder_t *builder, u32 len) { + if (builder->buffer.size > len) { + LOG_FATAL("padding_util less than buffer size [%u]:[%u]", + builder->buffer.size, len); + return; + } + + for (usize i = builder->buffer.size; i < len; i++) { + scc_vec_push(builder->buffer, 0); + } + + Assert(builder->buffer.size == len); +} + +void scc_pe_reserve_dos_header_and_stub(scc_pe_builder_t *builder) { + Assert(builder->file_offset == 0); + reserve_file(builder, sizeof(IMAGE_DOS_HEADER), 1); + reserve_file(builder, 64, 1); +} + +void scc_pe_reserve_nt_header(scc_pe_builder_t *builder, + usize data_directory_num) { + builder->nt_headers_offset = + reserve_file(builder, + builder->is_64 ? sizeof(IMAGE_NT_HEADERS64) + : sizeof(IMAGE_NT_HEADERS32), + 8); + + LOG_INFO("scc_pe_reserve_nt_header %u", builder->nt_headers_offset); + scc_vec_init(builder->image_data_directory_vec); + for (usize i = 0; i < data_directory_num; i += 1) { + scc_vec_push(builder->image_data_directory_vec, + (IMAGE_DATA_DIRECTORY){0}); + } + reserve_file(builder, sizeof(IMAGE_DATA_DIRECTORY) * data_directory_num, 1); +} + +void scc_pe_reserve_section_headers(scc_pe_builder_t *builder, + u32 num_of_section) { + builder->section_header_num = num_of_section; + reserve_file(builder, sizeof(IMAGE_SECTION_HEADER) * num_of_section, 1); + builder->file_offset = + reserve_align(builder->file_offset, builder->file_alignment); + builder->sizeof_headers = builder->file_offset; + reserve_virtual(builder, builder->file_offset, builder->section_alignment); +} + +void scc_pe_reserve_header(scc_pe_builder_t *builder, u32 num_of_section) { + scc_pe_reserve_dos_header_and_stub(builder); + scc_pe_reserve_nt_header(builder, IMAGE_NUMBEROF_DIRECTORY_ENTRIES); + scc_pe_reserve_section_headers(builder, num_of_section); +} + +void scc_pe_write_dos_header_and_stub(scc_pe_builder_t *builder) { + IMAGE_DOS_HEADER dos_header; + dos_header.e_magic = IMAGE_DOS_SIGNATURE; + dos_header.e_cblp = 0x90; + dos_header.e_cp = 3; + dos_header.e_crlc = 0; + dos_header.e_cparhdr = 4; + dos_header.e_minalloc = 0; + dos_header.e_maxalloc = 0xFFFF; + dos_header.e_ss = 0x00; + dos_header.e_sp = 0xB8; + dos_header.e_csum = 0; + dos_header.e_ip = 0x00; + dos_header.e_cs = 0x00; + dos_header.e_lfarlc = 0x40; + dos_header.e_ovno = 0x00; + for (int i = 0; i < 4; i++) { + dos_header.e_res[i] = 0x00; + } + dos_header.e_oemid = 0x00; + dos_header.e_oeminfo = 0x00; + for (int i = 0; i < 10; i++) { + dos_header.e_res2[i] = 0x00; + } + dos_header.e_lfanew = builder->nt_headers_offset; + + for (usize i = 0; i < sizeof(dos_header); ++i) { + scc_vec_push(builder->buffer, ((u8 *)(&dos_header))[i]); + } + static const u8 dos_header_bytes[] = { + 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, 0x0d, 0x0d, + 0x0a, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }; + for (usize i = 0; i < sizeof(dos_header_bytes); i++) { + scc_vec_push(builder->buffer, ((u8 *)(&dos_header_bytes))[i]); + } +} + +void scc_pe_write_nt_header_with_config(scc_pe_builder_t *builder, + const scc_pe_config_t *config) { + IMAGE_NT_HEADERS32 nt_headers32 = {0}; + IMAGE_NT_HEADERS64 nt_headers64 = {0}; + + // 写入PE签名 + DWORD *signature = + builder->is_64 ? &nt_headers64.Signature : &nt_headers32.Signature; + *signature = SCC_LE32(IMAGE_NT_SIGNATURE); + + // 构建文件头 + IMAGE_FILE_HEADER *file_header = + builder->is_64 ? &nt_headers64.FileHeader : &nt_headers32.FileHeader; + file_header->Machine = SCC_LE16(config->machine); + file_header->NumberOfSections = SCC_LE16(builder->section_header_num); + file_header->TimeDateStamp = SCC_LE32(config->time_date_stamp); + file_header->PointerToSymbolTable = SCC_LE32(builder->symbol_offset); + file_header->NumberOfSymbols = SCC_LE32(builder->symbol_num); + // 设置可选头大小 + if (builder->is_64) { + file_header->SizeOfOptionalHeader = + SCC_LE16(sizeof(IMAGE_OPTIONAL_HEADER64) + + scc_vec_size(builder->image_data_directory_vec) * + sizeof(IMAGE_DATA_DIRECTORY)); + } else { + file_header->SizeOfOptionalHeader = + SCC_LE16(sizeof(IMAGE_OPTIONAL_HEADER32) + + scc_vec_size(builder->image_data_directory_vec) * + sizeof(IMAGE_DATA_DIRECTORY)); + } + file_header->Characteristics = SCC_LE16(config->characteristics); + + // 根据是否为64位写入不同的可选头 + if (builder->is_64) { + IMAGE_OPTIONAL_HEADER64 *optional = &nt_headers64.OptionalHeader; + optional->Magic = SCC_LE16(IMAGE_NT_OPTIONAL_HDR64_MAGIC); + optional->MajorLinkerVersion = config->major_linker_version; + optional->MinorLinkerVersion = config->minor_linker_version; + optional->SizeOfCode = SCC_LE32(builder->sizeof_code); + optional->SizeOfInitializedData = SCC_LE32(builder->sizeof_init_data); + optional->SizeOfUninitializedData = + SCC_LE32(builder->sizeof_uninit_data); + optional->AddressOfEntryPoint = + SCC_LE32(config->address_of_entry_point); + optional->BaseOfCode = SCC_LE32(builder->baseof_code); + optional->ImageBase = SCC_LE64(config->image_base); + optional->SectionAlignment = SCC_LE32(builder->section_alignment); + optional->FileAlignment = SCC_LE32(builder->file_alignment); + optional->MajorOperatingSystemVersion = + SCC_LE16(config->major_operating_system_version); + optional->MinorOperatingSystemVersion = + SCC_LE16(config->minor_operating_system_version); + optional->MajorImageVersion = SCC_LE16(config->major_image_version); + optional->MinorImageVersion = SCC_LE16(config->minor_image_version); + optional->MajorSubsystemVersion = + SCC_LE16(config->major_subsystem_version); + optional->MinorSubsystemVersion = + SCC_LE16(config->minor_subsystem_version); + optional->Win32VersionValue = SCC_LE32(0); + optional->SizeOfImage = SCC_LE32(builder->virtual_offset); + optional->SizeOfHeaders = SCC_LE32(builder->sizeof_headers); + optional->CheckSum = SCC_LE32(0); + optional->Subsystem = SCC_LE16(config->subsystem); + optional->DllCharacteristics = SCC_LE16(config->dll_characteristics); + optional->SizeOfStackReserve = SCC_LE64(config->size_of_stack_reserve); + optional->SizeOfStackCommit = SCC_LE64(config->size_of_stack_commit); + optional->SizeOfHeapReserve = SCC_LE64(config->size_of_heap_reserve); + optional->SizeOfHeapCommit = SCC_LE64(config->size_of_heap_commit); + optional->LoaderFlags = SCC_LE32(0); + optional->NumberOfRvaAndSizes = + SCC_LE32(scc_vec_size(builder->image_data_directory_vec)); + } else { + IMAGE_OPTIONAL_HEADER32 *optional = &nt_headers32.OptionalHeader; + optional->Magic = SCC_LE16(IMAGE_NT_OPTIONAL_HDR32_MAGIC); + optional->MajorLinkerVersion = config->major_linker_version; + optional->MinorLinkerVersion = config->minor_linker_version; + optional->SizeOfCode = SCC_LE32(builder->sizeof_code); + optional->SizeOfInitializedData = SCC_LE32(builder->sizeof_init_data); + optional->SizeOfUninitializedData = + SCC_LE32(builder->sizeof_uninit_data); + optional->AddressOfEntryPoint = + SCC_LE32(config->address_of_entry_point); + optional->BaseOfCode = SCC_LE32(builder->baseof_code); + optional->BaseOfData = SCC_LE32(builder->baseof_data); // 32位特有的字段 + optional->ImageBase = + SCC_LE32((uint32_t)(config->image_base & 0xFFFFFFFF)); + optional->SectionAlignment = SCC_LE32(builder->section_alignment); + optional->FileAlignment = SCC_LE32(builder->file_alignment); + optional->MajorOperatingSystemVersion = + SCC_LE16(config->major_operating_system_version); + optional->MinorOperatingSystemVersion = + SCC_LE16(config->minor_operating_system_version); + optional->MajorImageVersion = SCC_LE16(config->major_image_version); + optional->MinorImageVersion = SCC_LE16(config->minor_image_version); + optional->MajorSubsystemVersion = + SCC_LE16(config->major_subsystem_version); + optional->MinorSubsystemVersion = + SCC_LE16(config->minor_subsystem_version); + optional->Win32VersionValue = SCC_LE32(0); + optional->SizeOfImage = SCC_LE32(builder->virtual_offset); + optional->SizeOfHeaders = SCC_LE32(builder->sizeof_headers); + optional->CheckSum = SCC_LE32(0); + optional->Subsystem = SCC_LE16(config->subsystem); + optional->DllCharacteristics = SCC_LE16(config->dll_characteristics); + optional->SizeOfStackReserve = + SCC_LE32((uint32_t)(config->size_of_stack_reserve & 0xFFFFFFFF)); + optional->SizeOfStackCommit = + SCC_LE32((uint32_t)(config->size_of_stack_commit & 0xFFFFFFFF)); + optional->SizeOfHeapReserve = + SCC_LE32((uint32_t)(config->size_of_heap_reserve & 0xFFFFFFFF)); + optional->SizeOfHeapCommit = + SCC_LE32((uint32_t)(config->size_of_heap_commit & 0xFFFFFFFF)); + optional->LoaderFlags = SCC_LE32(0); + optional->NumberOfRvaAndSizes = + SCC_LE32(scc_vec_size(builder->image_data_directory_vec)); + } + + if (builder->is_64) { + for (usize i = 0; i < sizeof(nt_headers64); i++) { + scc_vec_push(builder->buffer, ((u8 *)(&nt_headers64))[i]); + } + } else { + for (usize i = 0; i < sizeof(nt_headers32); i++) { + scc_vec_push(builder->buffer, ((u8 *)(&nt_headers32))[i]); + } + } + + scc_vec_foreach(builder->image_data_directory_vec, i) { + IMAGE_DATA_DIRECTORY *data = + &scc_vec_at(builder->image_data_directory_vec, i); + for (usize i = 0; i < sizeof(IMAGE_DATA_DIRECTORY); i++) { + scc_vec_push(builder->buffer, ((u8 *)(data))[i]); + } + } +} + +void scc_pe_write_section_headers(scc_pe_builder_t *builder) { + Assert(builder->section_header_num == + builder->image_section_header_vec.size); + scc_vec_foreach(builder->image_section_header_vec, i) { + IMAGE_SECTION_HEADER *section_header = + &scc_vec_at(builder->image_section_header_vec, i); + for (usize j = 0; j < sizeof(IMAGE_SECTION_HEADER); j += 1) { + scc_vec_push(builder->buffer, ((u8 *)section_header)[j]); + } + } +} + +void scc_pe_write_header(scc_pe_builder_t *builder, scc_pe_config_t *config) { + scc_vec_init(builder->buffer); + scc_pe_write_dos_header_and_stub(builder); + padding_util(builder, builder->nt_headers_offset); + scc_pe_write_nt_header_with_config(builder, config); + scc_pe_write_section_headers(builder); +} + +scc_pe_section_range scc_pe_reserve_section_header(scc_pe_builder_t *builder, + BYTE name[8], + u32 characteristics, + u32 virtual_size, + u32 data_size) { + scc_pe_section_range range = {0}; + range.virual_address = + reserve_virtual(builder, virtual_size, builder->section_alignment); + range.virual_size = virtual_size; + + range.file_size = reserve_align(data_size, builder->file_alignment); + range.file_offset = + range.file_size != 0 + ? reserve_file(builder, range.file_size, builder->file_alignment) + : 0; + + u32 aligned_virtual_size = + reserve_align(virtual_size, builder->file_alignment); + + if (characteristics & IMAGE_SCN_CNT_CODE) { + if (!builder->baseof_code) { + builder->baseof_code = range.virual_address; + } + builder->sizeof_code += aligned_virtual_size; + } else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) { + if (!builder->baseof_data) { + builder->baseof_data = range.virual_address; + } + builder->sizeof_init_data += aligned_virtual_size; + } else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) { + if (!builder->baseof_data) { + builder->baseof_data = range.virual_address; + } + builder->sizeof_uninit_data += aligned_virtual_size; + } + + IMAGE_SECTION_HEADER section_header = (IMAGE_SECTION_HEADER){ + .Name[0] = name[0], + .Name[1] = name[1], + .Name[2] = name[2], + .Name[3] = name[3], + .Name[4] = name[4], + .Name[5] = name[5], + .Name[6] = name[6], + .Name[7] = name[7], + .Misc.VirtualSize = SCC_LE32(range.virual_size), + .VirtualAddress = SCC_LE32(range.virual_address), + .SizeOfRawData = SCC_LE32(range.file_size), + .PointerToRawData = SCC_LE32(range.file_offset), + .PointerToRelocations = SCC_LE32(0), + .PointerToLinenumbers = SCC_LE32(0), + .NumberOfRelocations = SCC_LE16(0), + .NumberOfLinenumbers = SCC_LE16(0), + .Characteristics = SCC_LE32(characteristics), + }; + scc_vec_push(builder->image_section_header_vec, section_header); + return range; +} + +void scc_pe_write_section(scc_pe_builder_t *builder, + scc_pe_section_range *range, u8 *data, + usize data_size) { + if (range == null || data == null || data_size == 0) { + return; + } + padding_util(builder, range->file_offset); + for (usize i = 0; i < data_size; i += 1) { + scc_vec_push(builder->buffer, data[i]); + } + usize size = scc_vec_size(builder->buffer); + size = reserve_align(size, builder->file_alignment); + padding_util(builder, size); +} + +void scc_pe_dump_to_file(scc_pe_builder_t *builder, const char *file_path) { + scc_file_t fp = scc_fopen(file_path, SCC_FILE_WRITE); + scc_fwrite(fp, builder->buffer.data, builder->buffer.size); + scc_fclose(fp); +} diff --git a/libs/target/pe/src/scc_pe_idata.c b/libs/target/pe/src/scc_pe_idata.c new file mode 100644 index 0000000..7927213 --- /dev/null +++ b/libs/target/pe/src/scc_pe_idata.c @@ -0,0 +1,171 @@ +#include + +// RVA Relative Virtual Address +static inline IMAGE_IMPORT_DESCRIPTOR +image_import_descriptor_init(u32 import_lookup_table_rva, u32 name_rva, + u32 import_address_table_rva) { + IMAGE_IMPORT_DESCRIPTOR iid = {0}; + iid.DUMMYUNIONNAME.OriginalFirstThunk = SCC_LE32(import_lookup_table_rva); + iid.TimeDateStamp = SCC_LE32(0); + iid.ForwarderChain = SCC_LE32(0); + iid.Name = SCC_LE32(name_rva); + iid.FirstThunk = SCC_LE32(import_address_table_rva); + return iid; +}; + +static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder, + const char *name, u16 hint); +static void scc_winpe_hnt_builder_init(scc_winpe_hnt_builder_t *builder) { + scc_vec_init(builder->data); + builder->section_offset = 0; + scc_hashtable_init(&builder->str_map, + (scc_hashtable_hash_func_t)scc_strhash32, + (scc_hashtable_equal_func_t)scc_strcmp); +} + +static void scc_winpe_hnt_builder_push(scc_winpe_hnt_builder_t *builder, + const char *name, u16 hint) { + ///< 可选哈希表去重 + if (scc_hashtable_get(&builder->str_map, name)) { + return; + } + scc_hashtable_set(&builder->str_map, name, (void *)(u64)builder->data.size); + + /// FIXME WARNING需要转换为little endian + scc_vec_push(builder->data, hint >> 8); + scc_vec_push(builder->data, hint & 0xff); + + while (*name) { + scc_vec_push(builder->data, *name); + name++; + } + scc_vec_push(builder->data, 0); + + if (scc_vec_size(builder->data) % 2 != 0) { + scc_vec_push(builder->data, 0); + } + + // return scc_vec_size(builder->data); + Assert(scc_vec_size(builder->data) % 2 == 0); +} + +static u64 scc_winpe_hnt_get_offset(scc_winpe_hnt_builder_t *builder, + const char *name) { + return (u64)scc_hashtable_get(&builder->str_map, name); +} + +void scc_pe_idata_builder_init(scc_winpe_idata_builder_t *builder, + scc_winpe_idata_lib_vec_t *idata_libs) { + scc_vec_init(builder->buffer); + builder->idata_libs = *idata_libs; + + scc_winpe_hnt_builder_init(&builder->hnt_builder); + + scc_hashtable_init(&builder->iat_map, + (scc_hashtable_hash_func_t)scc_strhash32, + (scc_hashtable_equal_func_t)scc_strcmp); +} + +u32 scc_pe_reserve_idata(scc_winpe_idata_builder_t *builder) { + u32 idata_size = (scc_vec_size(builder->idata_libs) + 1) * + sizeof(IMAGE_IMPORT_DESCRIPTOR); + + scc_vec_foreach(builder->idata_libs, i) { + scc_winpe_idata_lib_t *lib = &scc_vec_at(builder->idata_libs, i); + idata_size += (scc_vec_size(lib->symbol_names) + 1) * 2 * + sizeof(IMAGE_THUNK_DATA64); + scc_winpe_hnt_builder_push(&builder->hnt_builder, lib->name, 0); + + scc_vec_foreach(lib->symbol_names, j) { + scc_winpe_hnt_builder_push(&builder->hnt_builder, + scc_vec_at(lib->symbol_names, j), 0); + } + } + builder->hnt_builder.section_offset = idata_size; + idata_size += scc_vec_size(builder->hnt_builder.data); + + scc_vec_realloc(builder->buffer, idata_size); + scc_vec_size(builder->buffer) = idata_size; + return idata_size; +} + +scc_pe_buffer_t scc_pe_construct_idata(scc_winpe_idata_builder_t *builder, + scc_pe_section_range *idata_range) { + u32 idata_rva = idata_range->virual_address; + u32 hnt_offset = builder->hnt_builder.section_offset; + + usize import_file_count = scc_vec_size(builder->idata_libs); + usize current_offset = + (import_file_count + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR); + scc_vec_foreach(builder->idata_libs, i) { + scc_winpe_idata_lib_t *lib = &scc_vec_at(builder->idata_libs, i); + scc_winpe_lookup_table_vec_t lookup_table; + scc_vec_init(lookup_table); + + scc_vec_foreach(lib->symbol_names, j) { + u64 name_offset = scc_winpe_hnt_get_offset( + &builder->hnt_builder, scc_vec_at(lib->symbol_names, j)); + u64 name_rva = idata_rva + hnt_offset + name_offset; + + IMAGE_THUNK_DATA64 lookup_table_entry = {.u1.AddressOfData = + name_rva}; + scc_vec_push(lookup_table, lookup_table_entry); + } + scc_vec_push(lookup_table, (IMAGE_THUNK_DATA64){0}); + usize table_size = + scc_vec_size(lookup_table) * sizeof(IMAGE_THUNK_DATA64); + + usize ilt_offset = current_offset; + usize iat_offset = ilt_offset + table_size; + current_offset += table_size * 2; + + scc_vec_foreach(lib->symbol_names, j) { + // 构造IAT链接 + scc_hashtable_set( + &builder->iat_map, scc_vec_at(lib->symbol_names, j), + (void *)(usize)(idata_rva + j * sizeof(IMAGE_THUNK_DATA64)) + + iat_offset); + } + + usize name_rva = idata_rva + hnt_offset + + scc_winpe_hnt_get_offset(&builder->hnt_builder, + lib->name); ///< hashtable get + + // 构造并写入导入目录项 + // The address of an ASCII string that contains the name of the DLL. + // This address is relative to the image base. + // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#import-directory-table + // so add 2 to skip the two bytes of the Hint + IMAGE_IMPORT_DESCRIPTOR dir_entry = image_import_descriptor_init( + ilt_offset + idata_rva, name_rva + 2, iat_offset + idata_rva); + scc_memcpy( + &scc_vec_at(builder->buffer, i * sizeof(IMAGE_IMPORT_DESCRIPTOR)), + &dir_entry, + sizeof(IMAGE_IMPORT_DESCRIPTOR)); // FIXME 大小端 + + Assert(table_size == + scc_vec_size(lookup_table) * sizeof(IMAGE_THUNK_DATA64)); + + // 转换为字节序列并写入 + // FIXME 大小端 + // 写入ILT表 + scc_memcpy(&scc_vec_at(builder->buffer, ilt_offset), + &scc_vec_at(lookup_table, 0), table_size); + // 写入IAT表 + scc_memcpy(&scc_vec_at(builder->buffer, iat_offset), + &scc_vec_at(lookup_table, 0), table_size); + } + + // 添加NULL终止的目录项 + IMAGE_IMPORT_DESCRIPTOR null_entry = image_import_descriptor_init(0, 0, 0); + scc_memcpy(&scc_vec_at(builder->buffer, + import_file_count * sizeof(IMAGE_IMPORT_DESCRIPTOR)), + &null_entry, sizeof(IMAGE_IMPORT_DESCRIPTOR)); + + // 填充Hint/Name表 + scc_memcpy(&scc_vec_at(builder->buffer, hnt_offset), + &scc_vec_at(builder->hnt_builder.data, 0), + scc_vec_size(builder->hnt_builder.data)); + + return builder->buffer; +} diff --git a/libs/target/pe/tests/test_winpe_unit.c b/libs/target/pe/tests/test_winpe_unit.c new file mode 100644 index 0000000..1616237 --- /dev/null +++ b/libs/target/pe/tests/test_winpe_unit.c @@ -0,0 +1,10 @@ +#include + +void test_example() { + printf("Test passed!\n"); +} + +int main() { + test_example(); + return 0; +} diff --git a/runtime/scc_core/include/scc_core_vec.h b/runtime/scc_core/include/scc_core_vec.h index a50ba89..13c628e 100644 --- a/runtime/scc_core/include/scc_core_vec.h +++ b/runtime/scc_core/include/scc_core_vec.h @@ -150,6 +150,8 @@ typedef size_t usize; (vec).size = (vec).cap = 0; \ } while (0) +#define scc_vec_unsafe_get_data(vec) (vec).data + #define scc_vec_unsafe_from_array(vec, array) \ do { \ (vec).size = sizeof(array) / sizeof((array)[0]); \