2026-07-28 14:35:14 +08:00
|
|
|
|
/* pe_loader.c — PE32+/PE32 解析、节区映射、重定位、import 解析。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 加载流程:
|
|
|
|
|
|
* 1. 验证 MZ + PE 签名
|
|
|
|
|
|
* 2. 区分 PE32(OptionalHeader.Magic=0x10b)/ PE32+(0x20b)
|
|
|
|
|
|
* 3. 分配 SizeOfImage 字节 RWX 内存(kmem_alloc_aligned)
|
|
|
|
|
|
* 4. 复制 SizeOfHeaders + 各节区 raw data 到 virtual_address
|
|
|
|
|
|
* 5. 应用基址重定位(.reloc 节区:DIR64 for PE32+,HIGHLOW for PE32)
|
|
|
|
|
|
* 6. 解析 import 表,用 shim 函数指针填充 IAT
|
|
|
|
|
|
* 7. 构建 IAT 条目表(供 32位解释器 CALL 拦截)
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "pe_loader.h"
|
|
|
|
|
|
#include "pe_shim.h"
|
2026-08-09 22:14:01 +08:00
|
|
|
|
#include "pe_dll_manager.h"
|
2026-07-28 14:35:14 +08:00
|
|
|
|
#include "x86emu32.h"
|
|
|
|
|
|
#include "../include/utsm/pe.h"
|
|
|
|
|
|
#include <utsm/arena.h>
|
|
|
|
|
|
#include <utsm/log.h>
|
2026-10-03 00:30:54 +08:00
|
|
|
|
#include <utsm/panic.h>
|
2026-07-28 14:35:14 +08:00
|
|
|
|
#include <utsm/types.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* 合成 shim 地址范围(32位解释器用):0x00010000..0x0001FFFF */
|
|
|
|
|
|
#define PE_SHIM_ADDR_BASE 0x00010000u
|
|
|
|
|
|
#define PE_SHIM_ADDR_END 0x00020000u
|
|
|
|
|
|
#define PE_SHIM_UNIMPL 0x0001FFFFu
|
|
|
|
|
|
|
|
|
|
|
|
/* 全局 IAT 表(pe_loader 填充,x86emu32 读取) */
|
|
|
|
|
|
static pe_iat_entry g_iat_entries[256];
|
|
|
|
|
|
static int g_iat_count;
|
|
|
|
|
|
|
|
|
|
|
|
/* ---- 辅助:RVA → 文件偏移 ---- */
|
|
|
|
|
|
static u32 rva_to_offset(const image_section_header *sections, int nsec,
|
|
|
|
|
|
u32 rva, u32 *out_size) {
|
|
|
|
|
|
for (int i = 0; i < nsec; i++) {
|
|
|
|
|
|
u32 va = sections[i].virtual_address;
|
|
|
|
|
|
u32 vs = sections[i].virtual_size;
|
|
|
|
|
|
if (vs == 0) vs = sections[i].size_of_raw_data;
|
|
|
|
|
|
if (rva >= va && rva < va + vs) {
|
|
|
|
|
|
if (out_size) *out_size = vs;
|
|
|
|
|
|
return sections[i].pointer_to_raw_data + (rva - va);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (out_size) *out_size = 0;
|
|
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---- 解析 NT 头 ---- */
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
|
const image_file_header *file_hdr;
|
|
|
|
|
|
const void *optional_hdr;
|
|
|
|
|
|
int is_pe32_plus;
|
2026-08-04 18:08:08 +08:00
|
|
|
|
u64 image_base; /* 链接时首选基址(PE32+ 为 64 位,如 0x140000000,必须全宽保留) */
|
2026-07-28 14:35:14 +08:00
|
|
|
|
u32 size_of_image;
|
|
|
|
|
|
u32 size_of_headers;
|
|
|
|
|
|
u32 entry_rva;
|
|
|
|
|
|
const image_data_directory *data_dir;
|
|
|
|
|
|
} pe_nt_info;
|
|
|
|
|
|
|
|
|
|
|
|
static int parse_nt_headers(const void *pe_data, u64 size, pe_nt_info *out) {
|
|
|
|
|
|
if (size < sizeof(image_dos_header)) return -1;
|
|
|
|
|
|
const image_dos_header *dos = (const image_dos_header *)pe_data;
|
|
|
|
|
|
if (dos->e_magic != IMAGE_DOS_SIGNATURE) return -2;
|
|
|
|
|
|
if (dos->e_lfanew + 4 + sizeof(image_file_header) > size) return -3;
|
|
|
|
|
|
|
|
|
|
|
|
const u8 *nt_base = (const u8 *)pe_data + dos->e_lfanew;
|
|
|
|
|
|
u32 sig = *(const u32 *)nt_base;
|
|
|
|
|
|
if (sig != IMAGE_NT_SIGNATURE) return -4;
|
|
|
|
|
|
|
|
|
|
|
|
const image_file_header *fh = (const image_file_header *)(nt_base + 4);
|
|
|
|
|
|
out->file_hdr = fh;
|
|
|
|
|
|
|
|
|
|
|
|
const void *opt = (const void *)(nt_base + 4 + sizeof(image_file_header));
|
|
|
|
|
|
out->optional_hdr = opt;
|
|
|
|
|
|
|
|
|
|
|
|
u16 magic = *(const u16 *)opt;
|
|
|
|
|
|
if (magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
|
|
|
|
|
const image_optional_header64 *oh = (const image_optional_header64 *)opt;
|
|
|
|
|
|
out->is_pe32_plus = 1;
|
2026-08-04 18:08:08 +08:00
|
|
|
|
out->image_base = oh->image_base; /* PE32+: u64 全宽,禁止截断(重定位 delta 依赖高位) */
|
2026-07-28 14:35:14 +08:00
|
|
|
|
out->size_of_image = oh->size_of_image;
|
|
|
|
|
|
out->size_of_headers = oh->size_of_headers;
|
|
|
|
|
|
out->entry_rva = oh->address_of_entry_point;
|
|
|
|
|
|
out->data_dir = oh->data_directory;
|
|
|
|
|
|
} else if (magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
|
|
|
|
const image_optional_header32 *oh = (const image_optional_header32 *)opt;
|
|
|
|
|
|
out->is_pe32_plus = 0;
|
|
|
|
|
|
out->image_base = oh->image_base;
|
|
|
|
|
|
out->size_of_image = oh->size_of_image;
|
|
|
|
|
|
out->size_of_headers = oh->size_of_headers;
|
|
|
|
|
|
out->entry_rva = oh->address_of_entry_point;
|
|
|
|
|
|
out->data_dir = oh->data_directory;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return -5;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (out->size_of_image == 0 || out->size_of_image > 64 * 1024 * 1024) return -6;
|
|
|
|
|
|
if (out->entry_rva == 0 || out->entry_rva >= out->size_of_image) return -7;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---- 应用基址重定位 ---- */
|
2026-08-04 18:08:08 +08:00
|
|
|
|
static void apply_relocations(u8 *image, u32 image_size, u64 image_base_actual, u64 image_base_preferred,
|
2026-07-28 14:35:14 +08:00
|
|
|
|
const image_data_directory *reloc_dir,
|
|
|
|
|
|
const image_section_header *sections, int nsec,
|
|
|
|
|
|
const void *pe_data, u64 pe_size, int is_pe32_plus) {
|
|
|
|
|
|
if (reloc_dir->virtual_address == 0 || reloc_dir->size == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
u32 block_rva = reloc_dir->virtual_address;
|
|
|
|
|
|
u32 block_end = block_rva + reloc_dir->size;
|
|
|
|
|
|
i64 delta = (i64)image_base_actual - (i64)image_base_preferred;
|
|
|
|
|
|
if (delta == 0) return; /* 加载到首选基址,无需重定位 */
|
|
|
|
|
|
|
|
|
|
|
|
while (block_rva < block_end) {
|
|
|
|
|
|
u32 dummy_size;
|
|
|
|
|
|
u32 file_off = rva_to_offset(sections, nsec, block_rva, &dummy_size);
|
|
|
|
|
|
if (file_off == 0xFFFFFFFF || file_off + 8 > pe_size) break;
|
|
|
|
|
|
|
|
|
|
|
|
const u8 *block = (const u8 *)pe_data + file_off;
|
|
|
|
|
|
u32 page_rva = *(const u32 *)block;
|
|
|
|
|
|
u32 block_size = *(const u32 *)(block + 4);
|
|
|
|
|
|
if (block_size < 8 || block_rva + block_size > block_end) break;
|
|
|
|
|
|
|
|
|
|
|
|
u32 entry_count = (block_size - 8) / 2;
|
|
|
|
|
|
const u16 *entries = (const u16 *)(block + 8);
|
|
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < entry_count; i++) {
|
|
|
|
|
|
u16 e = entries[i];
|
|
|
|
|
|
u32 type = (e >> 12) & 0xF;
|
|
|
|
|
|
u32 offset = e & 0xFFF;
|
|
|
|
|
|
|
|
|
|
|
|
if (type == IMAGE_REL_BASED_ABSOLUTE) continue;
|
|
|
|
|
|
|
|
|
|
|
|
u32 target_rva = page_rva + offset;
|
|
|
|
|
|
/* image 缓冲区按 RVA 排列(image[0] = RVA 0) */
|
|
|
|
|
|
if (target_rva >= (u32)image_size) continue;
|
|
|
|
|
|
u8 *target = image + target_rva;
|
|
|
|
|
|
if (type == IMAGE_REL_BASED_DIR64) {
|
|
|
|
|
|
u64 val = *(u64 *)target;
|
|
|
|
|
|
val += (u64)delta;
|
|
|
|
|
|
*(u64 *)target = val;
|
|
|
|
|
|
} else if (type == IMAGE_REL_BASED_HIGHLOW) {
|
|
|
|
|
|
u32 val = *(u32 *)target;
|
|
|
|
|
|
val += (u32)delta;
|
|
|
|
|
|
*(u32 *)target = val;
|
|
|
|
|
|
} else {
|
2026-10-03 12:44:57 +08:00
|
|
|
|
/* 严格错误策略插桩:未实现的重定位类型静默跳过 = 重定位
|
|
|
|
|
|
* 不完整照跑,零降级 panic(PE-E03)。 */
|
|
|
|
|
|
log_error("[PE] unsupported reloc type");
|
|
|
|
|
|
panic_full("PE-E03 RELOC TYPE NOT IMPLEMENTED",
|
|
|
|
|
|
"PE base-reloc type outside ABSOLUTE/HIGHLOW/DIR64: not implemented", 0);
|
2026-07-28 14:35:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
block_rva += block_size;
|
|
|
|
|
|
}
|
|
|
|
|
|
(void)is_pe32_plus;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---- 解析 imports,填充 IAT ---- */
|
|
|
|
|
|
static void resolve_imports(u8 *image, u64 image_base_actual,
|
|
|
|
|
|
const image_data_directory *import_dir,
|
|
|
|
|
|
const image_section_header *sections, int nsec,
|
|
|
|
|
|
const void *pe_data, u64 pe_size, int is_pe32_plus) {
|
|
|
|
|
|
(void)image_base_actual; /* PE32 IAT 用合成地址,不依赖 actual_base */
|
|
|
|
|
|
if (import_dir->virtual_address == 0 || import_dir->size == 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
g_iat_count = 0;
|
|
|
|
|
|
u32 dummy;
|
|
|
|
|
|
u32 imp_off = rva_to_offset(sections, nsec, import_dir->virtual_address, &dummy);
|
|
|
|
|
|
if (imp_off == 0xFFFFFFFF) return;
|
|
|
|
|
|
|
|
|
|
|
|
const image_import_descriptor *imp = (const image_import_descriptor *)
|
|
|
|
|
|
((const u8 *)pe_data + imp_off);
|
|
|
|
|
|
|
|
|
|
|
|
for (int dll_idx = 0; ; dll_idx++) {
|
|
|
|
|
|
const image_import_descriptor *desc = &imp[dll_idx];
|
|
|
|
|
|
if (desc->name == 0 && desc->first_thunk == 0) break;
|
|
|
|
|
|
|
|
|
|
|
|
/* DLL 名 */
|
|
|
|
|
|
u32 name_off = rva_to_offset(sections, nsec, desc->name, &dummy);
|
|
|
|
|
|
if (name_off == 0xFFFFFFFF || name_off >= pe_size) continue;
|
|
|
|
|
|
const char *dll_name = (const char *)pe_data + name_off;
|
|
|
|
|
|
|
|
|
|
|
|
/* IAT (first_thunk) 与 INT (original_first_thunk) */
|
|
|
|
|
|
u32 iat_rva = desc->first_thunk;
|
|
|
|
|
|
u32 int_rva = desc->original_first_thunk;
|
|
|
|
|
|
if (int_rva == 0) int_rva = iat_rva; /* 无 INT,直接用 IAT */
|
|
|
|
|
|
|
|
|
|
|
|
u32 iat_off = rva_to_offset(sections, nsec, iat_rva, &dummy);
|
|
|
|
|
|
u32 int_off = rva_to_offset(sections, nsec, int_rva, &dummy);
|
|
|
|
|
|
|
|
|
|
|
|
for (int fn_idx = 0; ; fn_idx++) {
|
|
|
|
|
|
u32 iat_entry_off = iat_off + (u32)fn_idx * (is_pe32_plus ? 8 : 4);
|
|
|
|
|
|
if (iat_entry_off + (is_pe32_plus ? 8 : 4) > pe_size) break;
|
|
|
|
|
|
|
|
|
|
|
|
u32 int_entry_off = int_off + (u32)fn_idx * (is_pe32_plus ? 8 : 4);
|
|
|
|
|
|
if (int_entry_off + (is_pe32_plus ? 8 : 4) > pe_size) break;
|
|
|
|
|
|
|
|
|
|
|
|
/* 读 INT 条目判断函数名/序号 */
|
|
|
|
|
|
u64 thunk = 0;
|
|
|
|
|
|
if (is_pe32_plus) {
|
|
|
|
|
|
thunk = *(const u64 *)((const u8 *)pe_data + int_entry_off);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
thunk = *(const u32 *)((const u8 *)pe_data + int_entry_off);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (thunk == 0) break; /* 结束 */
|
|
|
|
|
|
|
|
|
|
|
|
const char *func_name = 0;
|
|
|
|
|
|
if (thunk & 0x80000000ULL) {
|
2026-10-03 00:30:54 +08:00
|
|
|
|
/* 严格错误策略插桩:序号导入是未实现路径,零降级 panic
|
|
|
|
|
|
* (PE-E02)。shim 表按名称索引,序号导入无法解析语义。 */
|
|
|
|
|
|
log_error("[PE] ordinal import encountered");
|
|
|
|
|
|
panic_full("PE-E02 ORDINAL IMPORT NOT IMPLEMENTED",
|
|
|
|
|
|
"PE import by ordinal: designed, not implemented", 0);
|
2026-07-28 14:35:14 +08:00
|
|
|
|
func_name = "#ordinal";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
/* 名称导入:thunk 是 IMAGE_IMPORT_BY_NAME 的 RVA */
|
|
|
|
|
|
u32 hint_rva = (u32)thunk;
|
|
|
|
|
|
u32 hint_off = rva_to_offset(sections, nsec, hint_rva, &dummy);
|
|
|
|
|
|
if (hint_off != 0xFFFFFFFF && hint_off + 2 < pe_size) {
|
|
|
|
|
|
func_name = (const char *)pe_data + hint_off + 2; /* 跳过 hint(2字节) */
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 查 shim 表 */
|
|
|
|
|
|
int shim_idx = -1;
|
|
|
|
|
|
if (func_name && func_name[0] != '#') {
|
|
|
|
|
|
shim_idx = pe_shim_lookup(dll_name, func_name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-09 22:14:01 +08:00
|
|
|
|
/* 当 shim 未命中且需要尝试真实 DLL 时,先把 dll_name/func_name
|
|
|
|
|
|
* 复制到本地栈缓冲。原因:pe_dll_resolve 可能触发 fat32_read_path,
|
|
|
|
|
|
* 后者返回的 static 缓冲与外层 pe_data 可能指向同一区域,会被覆盖。 */
|
|
|
|
|
|
char dll_buf[256];
|
|
|
|
|
|
char func_buf[256];
|
|
|
|
|
|
int have_local_names = 0;
|
|
|
|
|
|
if (shim_idx < 0 && is_pe32_plus && g_pe_dll_manager_ready &&
|
|
|
|
|
|
func_name && func_name[0] != '#') {
|
|
|
|
|
|
u32 dl = 0;
|
|
|
|
|
|
while (dll_name[dl] && dl + 1 < sizeof(dll_buf)) {
|
|
|
|
|
|
dll_buf[dl] = dll_name[dl];
|
|
|
|
|
|
dl++;
|
|
|
|
|
|
}
|
|
|
|
|
|
dll_buf[dl] = 0;
|
|
|
|
|
|
u32 fl = 0;
|
|
|
|
|
|
while (func_name[fl] && fl + 1 < sizeof(func_buf)) {
|
|
|
|
|
|
func_buf[fl] = func_name[fl];
|
|
|
|
|
|
fl++;
|
|
|
|
|
|
}
|
|
|
|
|
|
func_buf[fl] = 0;
|
|
|
|
|
|
have_local_names = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-28 14:35:14 +08:00
|
|
|
|
/* 填充 IAT(image 缓冲区内) */
|
|
|
|
|
|
u8 *iat_ptr = image + iat_rva + (u32)fn_idx * (is_pe32_plus ? 8 : 4);
|
2026-08-09 22:14:01 +08:00
|
|
|
|
int resolved_by_real_dll = 0;
|
2026-07-28 14:35:14 +08:00
|
|
|
|
if (is_pe32_plus) {
|
|
|
|
|
|
u64 fn_addr;
|
|
|
|
|
|
if (shim_idx >= 0) {
|
|
|
|
|
|
const pe_shim_entry *se = pe_shim_get(shim_idx);
|
|
|
|
|
|
fn_addr = (u64)se->fn64;
|
2026-08-09 22:14:01 +08:00
|
|
|
|
} else if (have_local_names) {
|
|
|
|
|
|
/* PE32+ 尝试真实 DLL */
|
|
|
|
|
|
u64 real = pe_dll_resolve(dll_buf, func_buf);
|
|
|
|
|
|
if (real != 0) {
|
|
|
|
|
|
fn_addr = real;
|
|
|
|
|
|
resolved_by_real_dll = 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
/* DLL 加载过但函数未找到:填 unimpl stub */
|
|
|
|
|
|
fn_addr = pe_shim_unimpl_stub();
|
|
|
|
|
|
}
|
2026-07-28 14:35:14 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
fn_addr = pe_shim_unimpl_stub();
|
|
|
|
|
|
}
|
|
|
|
|
|
*(u64 *)iat_ptr = fn_addr;
|
|
|
|
|
|
} else {
|
2026-08-09 22:14:01 +08:00
|
|
|
|
/* 32位:填合成地址,解释器拦截(不调真实 DLL) */
|
2026-07-28 14:35:14 +08:00
|
|
|
|
u32 synth_addr;
|
|
|
|
|
|
if (shim_idx >= 0) {
|
|
|
|
|
|
synth_addr = PE_SHIM_ADDR_BASE | (u32)(shim_idx & 0xFFFF);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
synth_addr = PE_SHIM_UNIMPL;
|
|
|
|
|
|
}
|
|
|
|
|
|
*(u32 *)iat_ptr = synth_addr;
|
|
|
|
|
|
|
|
|
|
|
|
/* 记录 IAT 条目供解释器查询 */
|
|
|
|
|
|
if (g_iat_count < 255) {
|
|
|
|
|
|
g_iat_entries[g_iat_count].iat_rva = iat_rva + (u32)fn_idx * 4;
|
|
|
|
|
|
g_iat_entries[g_iat_count].shim_index = shim_idx;
|
|
|
|
|
|
g_iat_entries[g_iat_count].target_addr = synth_addr;
|
|
|
|
|
|
g_iat_count++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-09 22:14:01 +08:00
|
|
|
|
/* shim 未命中且真实 DLL 也未解析:记未实现日志;
|
|
|
|
|
|
* 真实 DLL 解析成功则记来源日志(区分 shim/真实 DLL 路径)。
|
|
|
|
|
|
* 用本地副本(pe_data 可能已被 DLL 加载破坏) */
|
|
|
|
|
|
if (shim_idx < 0 && func_name && !resolved_by_real_dll) {
|
2026-07-28 14:35:14 +08:00
|
|
|
|
log_info("[PE] unimplemented import");
|
2026-08-09 22:14:01 +08:00
|
|
|
|
if (have_local_names) {
|
|
|
|
|
|
serial_write(dll_buf);
|
|
|
|
|
|
serial_write("!");
|
|
|
|
|
|
serial_write(func_buf);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
serial_write(dll_name);
|
|
|
|
|
|
serial_write("!");
|
|
|
|
|
|
serial_write(func_name);
|
|
|
|
|
|
}
|
|
|
|
|
|
serial_write("\n");
|
|
|
|
|
|
} else if (resolved_by_real_dll) {
|
|
|
|
|
|
log_info("[PE] import via real DLL");
|
|
|
|
|
|
serial_write(dll_buf);
|
2026-07-28 14:35:14 +08:00
|
|
|
|
serial_write("!");
|
2026-08-09 22:14:01 +08:00
|
|
|
|
serial_write(func_buf);
|
2026-07-28 14:35:14 +08:00
|
|
|
|
serial_write("\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ---- 主加载函数 ---- */
|
|
|
|
|
|
int pe_load_image(const void *pe_data, u64 size, pe_image_info *out) {
|
|
|
|
|
|
if (!pe_data || !out || size < sizeof(image_dos_header)) return -1;
|
|
|
|
|
|
|
|
|
|
|
|
pe_nt_info nt;
|
|
|
|
|
|
int rc = parse_nt_headers(pe_data, size, &nt);
|
|
|
|
|
|
if (rc != 0) {
|
|
|
|
|
|
log_error("[PE] NT header parse failed");
|
|
|
|
|
|
log_hex64("[PE] rc=", (u64)(i64)rc);
|
|
|
|
|
|
return -2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 节区头 */
|
|
|
|
|
|
int nsec = nt.file_hdr->number_of_sections;
|
|
|
|
|
|
if (nsec <= 0 || nsec > 96) return -3;
|
|
|
|
|
|
usize opt_size = nt.file_hdr->size_of_optional_header;
|
|
|
|
|
|
const image_section_header *sections = (const image_section_header *)
|
|
|
|
|
|
((const u8 *)nt.optional_hdr + opt_size);
|
|
|
|
|
|
|
|
|
|
|
|
/* 分配 SizeOfImage RWX 内存 */
|
|
|
|
|
|
u32 img_size = nt.size_of_image;
|
|
|
|
|
|
u8 *image = (u8 *)kmem_alloc_aligned(img_size, 0x1000);
|
|
|
|
|
|
if (!image) {
|
|
|
|
|
|
log_error("[PE] alloc image failed");
|
|
|
|
|
|
return -4;
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 清零 */
|
|
|
|
|
|
for (u32 i = 0; i < img_size; i++) image[i] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/* 复制 headers */
|
|
|
|
|
|
u32 hdr_copy = nt.size_of_headers;
|
|
|
|
|
|
if (hdr_copy > size) hdr_copy = (u32)size;
|
|
|
|
|
|
if (hdr_copy > img_size) hdr_copy = img_size;
|
|
|
|
|
|
for (u32 i = 0; i < hdr_copy; i++) image[i] = ((const u8 *)pe_data)[i];
|
|
|
|
|
|
|
|
|
|
|
|
/* 复制各节区 raw data */
|
|
|
|
|
|
for (int i = 0; i < nsec; i++) {
|
|
|
|
|
|
u32 va = sections[i].virtual_address;
|
|
|
|
|
|
u32 raw_size = sections[i].size_of_raw_data;
|
|
|
|
|
|
u32 raw_off = sections[i].pointer_to_raw_data;
|
|
|
|
|
|
if (va >= img_size) continue;
|
|
|
|
|
|
u32 copy_size = raw_size;
|
|
|
|
|
|
if (va + copy_size > img_size) copy_size = img_size - va;
|
|
|
|
|
|
if (raw_off + copy_size > size) {
|
|
|
|
|
|
copy_size = (u32)(size - raw_off);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (raw_off + copy_size > size) continue;
|
|
|
|
|
|
for (u32 j = 0; j < copy_size; j++) {
|
|
|
|
|
|
image[va + j] = ((const u8 *)pe_data)[raw_off + j];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 基址重定位 */
|
|
|
|
|
|
u64 actual_base = (u64)image;
|
2026-08-04 18:08:08 +08:00
|
|
|
|
u64 preferred_base = nt.image_base;
|
2026-07-28 14:35:14 +08:00
|
|
|
|
/* image 缓冲区按 RVA 排列(image[0]=RVA 0),重定位写入 image 内 */
|
|
|
|
|
|
/* 注意:apply_relocations 直接操作 image 缓冲区,delta = actual_base - preferred_base */
|
|
|
|
|
|
{
|
|
|
|
|
|
const image_data_directory *reloc_dir = &nt.data_dir[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
|
|
|
|
|
/* 重定位 target 是 RVA,写入 image[rva]。
|
|
|
|
|
|
* 但 image 加载在 actual_base,代码中绝对地址 = actual_base + RVA。
|
|
|
|
|
|
* 重定位修正量 = actual_base - preferred_base。
|
|
|
|
|
|
* image[rva] 处的值原为 preferred_base + rva_offset(链接时假设),
|
|
|
|
|
|
* 修正后应为 actual_base + rva_offset,即加 delta。 */
|
|
|
|
|
|
apply_relocations(image, img_size, actual_base, preferred_base, reloc_dir,
|
|
|
|
|
|
sections, nsec, pe_data, size, nt.is_pe32_plus);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 解析 imports */
|
|
|
|
|
|
{
|
|
|
|
|
|
const image_data_directory *import_dir = &nt.data_dir[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
|
|
|
|
resolve_imports(image, actual_base, import_dir, sections, nsec,
|
|
|
|
|
|
pe_data, size, nt.is_pe32_plus);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
out->image_base = actual_base;
|
|
|
|
|
|
out->image_size = img_size;
|
|
|
|
|
|
out->entry_point = actual_base + nt.entry_rva;
|
|
|
|
|
|
out->is_pe32_plus = nt.is_pe32_plus;
|
|
|
|
|
|
out->load_ok = 1;
|
|
|
|
|
|
|
|
|
|
|
|
log_hex64("[PE] loaded base=", actual_base);
|
|
|
|
|
|
log_hex64("[PE] image size=", img_size);
|
|
|
|
|
|
log_hex64("[PE] entry=", out->entry_point);
|
|
|
|
|
|
log_info(nt.is_pe32_plus ? "[PE] PE32+ (64-bit)" : "[PE] PE32 (32-bit)");
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void pe_unload_image(pe_image_info *info) {
|
|
|
|
|
|
if (!info || !info->load_ok) return;
|
|
|
|
|
|
/* kmem_alloc_aligned 无对应 free(arena 分配器),标记为未加载即可 */
|
|
|
|
|
|
info->load_ok = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u64 pe_get_image_base(const pe_image_info *info) {
|
|
|
|
|
|
return info ? info->image_base : 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u64 pe_get_image_size(const pe_image_info *info) {
|
|
|
|
|
|
return info ? info->image_size : 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 供 x86emu32 获取 IAT 表 */
|
|
|
|
|
|
pe_iat_entry *pe_get_iat_entries(int *count) {
|
|
|
|
|
|
if (count) *count = g_iat_count;
|
|
|
|
|
|
return g_iat_entries;
|
|
|
|
|
|
}
|