FUCK2
This commit is contained in:
@@ -0,0 +1,368 @@
|
||||
/* 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"
|
||||
#include "x86emu32.h"
|
||||
#include "../include/utsm/pe.h"
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/log.h>
|
||||
#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;
|
||||
u32 image_base; /* 32位截断的加载基址(PE32+ 也截断用于 RVA 计算) */
|
||||
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;
|
||||
out->image_base = (u32)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 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;
|
||||
}
|
||||
|
||||
/* ---- 应用基址重定位 ---- */
|
||||
static void apply_relocations(u8 *image, u32 image_size, u64 image_base_actual, u32 image_base_preferred,
|
||||
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 {
|
||||
/* 其他重定位类型暂不支持 */
|
||||
}
|
||||
}
|
||||
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) {
|
||||
/* 序号导入:暂不支持,记为未实现 */
|
||||
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);
|
||||
}
|
||||
|
||||
/* 填充 IAT(image 缓冲区内) */
|
||||
u8 *iat_ptr = image + iat_rva + (u32)fn_idx * (is_pe32_plus ? 8 : 4);
|
||||
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;
|
||||
} else {
|
||||
fn_addr = pe_shim_unimpl_stub();
|
||||
}
|
||||
*(u64 *)iat_ptr = fn_addr;
|
||||
} else {
|
||||
/* 32位:填合成地址,解释器拦截 */
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
if (shim_idx < 0 && func_name) {
|
||||
log_info("[PE] unimplemented import");
|
||||
serial_write(dll_name);
|
||||
serial_write("!");
|
||||
serial_write(func_name);
|
||||
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;
|
||||
u32 preferred_base = nt.image_base;
|
||||
/* 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;
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#ifndef PE_LOADER_H
|
||||
#define PE_LOADER_H
|
||||
|
||||
/* pe_loader.h — PE32+/PE32 解析与加载器内部接口。 */
|
||||
|
||||
#include <utsm/types.h>
|
||||
#include <utsm/pe.h>
|
||||
|
||||
/* ===== PE 常量 ===== */
|
||||
#define IMAGE_DOS_SIGNATURE 0x5A4D /* "MZ" */
|
||||
#define IMAGE_NT_SIGNATURE 0x00004550 /* "PE\0\0" */
|
||||
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
|
||||
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
|
||||
|
||||
/* Section characteristics */
|
||||
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
|
||||
#define IMAGE_SCN_MEM_READ 0x40000000
|
||||
#define IMAGE_SCN_MEM_WRITE 0x80000000
|
||||
|
||||
/* Data directory indices */
|
||||
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
|
||||
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
|
||||
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
|
||||
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
|
||||
#define IMAGE_DIRECTORY_ENTRY_IAT 12
|
||||
|
||||
/* Relocation types */
|
||||
#define IMAGE_REL_BASED_ABSOLUTE 0
|
||||
#define IMAGE_REL_BASED_HIGHLOW 3 /* 32位: base + offset 写 32位 */
|
||||
#define IMAGE_REL_BASED_DIR64 10 /* 64位: base + offset 写 64位 */
|
||||
|
||||
/* ===== PE 结构体定义(packed) ===== */
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u16 e_magic; /* "MZ" */
|
||||
u16 e_cblp;
|
||||
u16 e_cp;
|
||||
u16 e_crlc;
|
||||
u16 e_cparhdr;
|
||||
u16 e_minalloc;
|
||||
u16 e_maxalloc;
|
||||
u16 e_ss;
|
||||
u16 e_sp;
|
||||
u16 e_csum;
|
||||
u16 e_ip;
|
||||
u16 e_cs;
|
||||
u16 e_lfarlc;
|
||||
u16 e_ovno;
|
||||
u16 e_res[4];
|
||||
u16 e_oemid;
|
||||
u16 e_oeminfo;
|
||||
u16 e_res2[10];
|
||||
u32 e_lfanew; /* PE 头偏移 */
|
||||
} image_dos_header;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u16 machine;
|
||||
u16 number_of_sections;
|
||||
u32 time_date_stamp;
|
||||
u32 pointer_to_symbol_table;
|
||||
u32 number_of_symbols;
|
||||
u16 size_of_optional_header;
|
||||
u16 characteristics;
|
||||
} image_file_header;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u32 virtual_address;
|
||||
u32 size;
|
||||
} image_data_directory;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u16 magic;
|
||||
u8 major_linker_version;
|
||||
u8 minor_linker_version;
|
||||
u32 size_of_code;
|
||||
u32 size_of_initialized_data;
|
||||
u32 size_of_uninitialized_data;
|
||||
u32 address_of_entry_point;
|
||||
u32 base_of_code;
|
||||
u32 base_of_data; /* PE32 only */
|
||||
u32 image_base; /* PE32: 32位 */
|
||||
u32 section_alignment;
|
||||
u32 file_alignment;
|
||||
u16 major_os_version;
|
||||
u16 minor_os_version;
|
||||
u16 major_image_version;
|
||||
u16 minor_image_version;
|
||||
u16 major_subsystem_version;
|
||||
u16 minor_subsystem_version;
|
||||
u32 win32_version_value;
|
||||
u32 size_of_image;
|
||||
u32 size_of_headers;
|
||||
u32 check_sum;
|
||||
u16 subsystem;
|
||||
u16 dll_characteristics;
|
||||
u32 size_of_stack_reserve;
|
||||
u32 size_of_stack_commit;
|
||||
u32 size_of_heap_reserve;
|
||||
u32 size_of_heap_commit;
|
||||
u32 loader_flags;
|
||||
u32 number_of_rva_and_sizes;
|
||||
image_data_directory data_directory[16];
|
||||
} image_optional_header32;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u16 magic;
|
||||
u8 major_linker_version;
|
||||
u8 minor_linker_version;
|
||||
u32 size_of_code;
|
||||
u32 size_of_initialized_data;
|
||||
u32 size_of_uninitialized_data;
|
||||
u32 address_of_entry_point;
|
||||
u32 base_of_code;
|
||||
u64 image_base; /* PE32+: 64位 */
|
||||
u32 section_alignment;
|
||||
u32 file_alignment;
|
||||
u16 major_os_version;
|
||||
u16 minor_os_version;
|
||||
u16 major_image_version;
|
||||
u16 minor_image_version;
|
||||
u16 major_subsystem_version;
|
||||
u16 minor_subsystem_version;
|
||||
u32 win32_version_value;
|
||||
u32 size_of_image;
|
||||
u32 size_of_headers;
|
||||
u32 check_sum;
|
||||
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;
|
||||
u32 loader_flags;
|
||||
u32 number_of_rva_and_sizes;
|
||||
image_data_directory data_directory[16];
|
||||
} image_optional_header64;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u8 name[8];
|
||||
u32 virtual_size;
|
||||
u32 virtual_address;
|
||||
u32 size_of_raw_data;
|
||||
u32 pointer_to_raw_data;
|
||||
u32 pointer_to_relocations;
|
||||
u32 pointer_to_linenumbers;
|
||||
u16 number_of_relocations;
|
||||
u16 number_of_linenumbers;
|
||||
u32 characteristics;
|
||||
} image_section_header;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u32 original_first_thunk; /* INT (Import Name Table) RVA */
|
||||
u32 time_date_stamp;
|
||||
u32 forwarder_chain;
|
||||
u32 name; /* DLL 名 RVA */
|
||||
u32 first_thunk; /* IAT RVA */
|
||||
} image_import_descriptor;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
u32 original_first_thunk; /* 指向 IMAGE_IMPORT_BY_NAME */
|
||||
} image_import_by_name_ref;
|
||||
|
||||
/* ===== 加载器 API ===== */
|
||||
|
||||
/* 解析并加载 PE 到内存。
|
||||
* - 分配 SizeOfImage 字节 RWX 内存
|
||||
* - 复制 headers + 各节区
|
||||
* - 应用基址重定位
|
||||
* - 解析 imports(填 IAT 为 shim 函数指针)
|
||||
* 返回 0 成功,info 填充;负数失败。 */
|
||||
int pe_load_image(const void *pe_data, u64 size, pe_image_info *out);
|
||||
|
||||
/* 释放 pe_load_image 分配的内存 */
|
||||
void pe_unload_image(pe_image_info *info);
|
||||
|
||||
/* 获取 PE 内部信息(供 shim/解释器使用) */
|
||||
u64 pe_get_image_base(const pe_image_info *info);
|
||||
u64 pe_get_image_size(const pe_image_info *info);
|
||||
|
||||
/* 获取 IAT 条目表(供 32位解释器 CALL 拦截)。
|
||||
* pe_iat_entry 定义在 x86emu32.h。返回表指针,*count 填充条目数。 */
|
||||
struct pe_iat_entry;
|
||||
struct pe_iat_entry *pe_get_iat_entries(int *count);
|
||||
|
||||
#endif /* PE_LOADER_H */
|
||||
@@ -0,0 +1,290 @@
|
||||
/* pe_service.c — PE 兼容层服务装配。
|
||||
*
|
||||
* 将 pe_loader + pe_shim + x86emu32 整合为统一的 pe_service,
|
||||
* 通过 pe_get_service() 暴露给 DSK/cmd.elf(经 dsk_boot_context.reserved[4])。
|
||||
*
|
||||
* 执行策略:
|
||||
* PE32+ (64位):pe_load_image 加载(actual_base 重定位),
|
||||
* IAT 填 ms_abi shim 函数地址,Ring0 原生执行入口。
|
||||
* ExitProcess 经 __builtin_longjmp 跳回 pe_service_run。
|
||||
* PE32 (32位):直接以 preferred_base 加载到一块含栈/堆的大缓冲区,
|
||||
* 无需重定位。IAT 填合成地址(0x00010000 | shim_idx),
|
||||
* x86emu32 解释执行,CALL 合成地址时拦截分发到 shim32。
|
||||
*/
|
||||
|
||||
#include "pe_loader.h"
|
||||
#include "pe_shim.h"
|
||||
#include "x86emu32.h"
|
||||
#include "../include/utsm/pe.h"
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
|
||||
/* 32位 PE 用的栈与堆 */
|
||||
#define PE32_STACK_SIZE (64 * 1024) /* 64KB 栈 */
|
||||
#define PE32_HEAP_SIZE (256 * 1024) /* 256KB 堆 */
|
||||
#define PE32_MAX_IAT 256
|
||||
|
||||
/* 合成 shim 地址范围(与 pe_loader.c 一致) */
|
||||
#define PE32_SHIM_ADDR_BASE 0x00010000u
|
||||
#define PE32_SHIM_UNIMPL 0x0001FFFFu
|
||||
|
||||
/* 前向声明(服务表引用) */
|
||||
int pe_service_load(const void *pe_data, u64 size, pe_image_info *out);
|
||||
int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit_code);
|
||||
void pe_service_unload(pe_image_info *info);
|
||||
|
||||
/* 全局服务表实例 */
|
||||
static const pe_service g_pe_service = {
|
||||
PE_SERVICE_MAGIC,
|
||||
pe_service_load,
|
||||
pe_service_run,
|
||||
pe_service_unload,
|
||||
};
|
||||
|
||||
const pe_service *pe_get_service(void) {
|
||||
return &g_pe_service;
|
||||
}
|
||||
|
||||
/* ===== 加载(不执行)===== */
|
||||
int pe_service_load(const void *pe_data, u64 size, pe_image_info *out) {
|
||||
if (!pe_data || !out) return -1;
|
||||
return pe_load_image(pe_data, size, out);
|
||||
}
|
||||
|
||||
void pe_service_unload(pe_image_info *info) {
|
||||
pe_unload_image(info);
|
||||
}
|
||||
|
||||
/* ===== PE32 专用加载器(加载到指定缓冲区,base=preferred_base,无重定位)===== */
|
||||
typedef struct {
|
||||
u8 *mem; /* 大缓冲区起始 */
|
||||
u32 mem_size; /* 缓冲区总大小 */
|
||||
u32 image_base; /* = preferred_base */
|
||||
u32 image_size;
|
||||
u32 entry_point; /* 绝对入口 = image_base + entry_rva */
|
||||
pe_iat_entry iat[PE32_MAX_IAT];
|
||||
int iat_count;
|
||||
} pe32_interp_image;
|
||||
|
||||
static int pe32_load_into(const void *pe_data, u64 size, pe32_interp_image *img) {
|
||||
const u8 *base = (const u8 *)pe_data;
|
||||
if (size < sizeof(image_dos_header)) return -1;
|
||||
const image_dos_header *dos = (const image_dos_header *)base;
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE) return -2;
|
||||
if ((u64)dos->e_lfanew + 4 + sizeof(image_file_header) > size) return -3;
|
||||
|
||||
const u8 *nt = base + dos->e_lfanew;
|
||||
if (*(const u32 *)nt != IMAGE_NT_SIGNATURE) return -4;
|
||||
const image_file_header *fh = (const image_file_header *)(nt + 4);
|
||||
const void *opt = (const void *)(nt + 4 + sizeof(image_file_header));
|
||||
u16 magic = *(const u16 *)opt;
|
||||
if (magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return -5; /* 仅 PE32 */
|
||||
|
||||
const image_optional_header32 *oh = (const image_optional_header32 *)opt;
|
||||
u32 preferred_base = oh->image_base;
|
||||
u32 image_size = oh->size_of_image;
|
||||
u32 entry_rva = oh->address_of_entry_point;
|
||||
if (image_size == 0 || image_size > 64 * 1024 * 1024) return -6;
|
||||
if (preferred_base > 0x10000000u) return -7; /* 解释器地址空间限制 */
|
||||
|
||||
int nsec = fh->number_of_sections;
|
||||
if (nsec <= 0 || nsec > 96) return -8;
|
||||
const image_section_header *sections = (const image_section_header *)
|
||||
((const u8 *)opt + fh->size_of_optional_header);
|
||||
|
||||
/* 分配大缓冲区:[0 .. preferred_base + image_size + stack + heap] */
|
||||
u32 total = preferred_base + image_size + PE32_STACK_SIZE + PE32_HEAP_SIZE;
|
||||
u8 *mem = (u8 *)kmem_alloc_aligned((u64)total, 0x1000);
|
||||
if (!mem) return -9;
|
||||
for (u32 i = 0; i < total; i++) mem[i] = 0;
|
||||
|
||||
/* 复制 headers */
|
||||
u32 hdr_copy = oh->size_of_headers;
|
||||
if (hdr_copy > size) hdr_copy = (u32)size;
|
||||
if (hdr_copy > image_size) hdr_copy = image_size;
|
||||
u8 *img_start = mem + preferred_base;
|
||||
for (u32 i = 0; i < hdr_copy; i++) img_start[i] = base[i];
|
||||
|
||||
/* 复制各节区 */
|
||||
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 >= image_size) continue;
|
||||
u32 copy_size = raw_size;
|
||||
if (va + copy_size > image_size) copy_size = image_size - va;
|
||||
if ((u64)raw_off + copy_size > size) copy_size = (u32)(size - raw_off);
|
||||
for (u32 j = 0; j < copy_size; j++) img_start[va + j] = base[raw_off + j];
|
||||
}
|
||||
|
||||
/* 解析 imports,填充 IAT(合成地址) */
|
||||
img->iat_count = 0;
|
||||
const image_data_directory *import_dir = &oh->data_directory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
if (import_dir->virtual_address != 0 && import_dir->size != 0) {
|
||||
/* RVA→offset 辅助 */
|
||||
for (int dll_idx = 0; ; dll_idx++) {
|
||||
u32 imp_rva = import_dir->virtual_address + (u32)dll_idx * sizeof(image_import_descriptor);
|
||||
/* imp_rva 在 image 内 */
|
||||
if (imp_rva + sizeof(image_import_descriptor) > image_size) break;
|
||||
const image_import_descriptor *desc = (const image_import_descriptor *)(img_start + imp_rva);
|
||||
if (desc->name == 0 && desc->first_thunk == 0) break;
|
||||
|
||||
/* DLL 名 */
|
||||
u32 name_rva = desc->name;
|
||||
const char *dll_name = 0;
|
||||
if (name_rva < image_size) dll_name = (const char *)(img_start + name_rva);
|
||||
|
||||
u32 iat_rva = desc->first_thunk;
|
||||
u32 int_rva = desc->original_first_thunk;
|
||||
if (int_rva == 0) int_rva = iat_rva;
|
||||
|
||||
for (int fn_idx = 0; ; fn_idx++) {
|
||||
u32 int_entry_rva = int_rva + (u32)fn_idx * 4;
|
||||
if (int_entry_rva + 4 > image_size) break;
|
||||
u32 thunk = *(const u32 *)(img_start + int_entry_rva);
|
||||
if (thunk == 0) break;
|
||||
|
||||
const char *func_name = 0;
|
||||
if (thunk & 0x80000000u) {
|
||||
func_name = "#ordinal";
|
||||
} else {
|
||||
u32 hint_rva = thunk;
|
||||
if (hint_rva + 2 < image_size) {
|
||||
func_name = (const char *)(img_start + hint_rva + 2);
|
||||
}
|
||||
}
|
||||
|
||||
int shim_idx = -1;
|
||||
if (func_name && func_name[0] != '#') {
|
||||
shim_idx = pe_shim_lookup(dll_name, func_name);
|
||||
}
|
||||
|
||||
u32 synth_addr;
|
||||
if (shim_idx >= 0) {
|
||||
synth_addr = PE32_SHIM_ADDR_BASE | (u32)(shim_idx & 0xFFFF);
|
||||
} else {
|
||||
synth_addr = PE32_SHIM_UNIMPL;
|
||||
}
|
||||
|
||||
u32 iat_entry_rva = iat_rva + (u32)fn_idx * 4;
|
||||
if (iat_entry_rva + 4 <= image_size) {
|
||||
*(u32 *)(img_start + iat_entry_rva) = synth_addr;
|
||||
}
|
||||
|
||||
if (img->iat_count < PE32_MAX_IAT) {
|
||||
img->iat[img->iat_count].iat_rva = iat_entry_rva;
|
||||
img->iat[img->iat_count].shim_index = shim_idx;
|
||||
img->iat[img->iat_count].target_addr = synth_addr;
|
||||
img->iat_count++;
|
||||
}
|
||||
|
||||
if (shim_idx < 0 && func_name) {
|
||||
log_info("[PE32] unimplemented import");
|
||||
if (dll_name) serial_write(dll_name);
|
||||
serial_write("!");
|
||||
serial_write(func_name);
|
||||
serial_write("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
img->mem = mem;
|
||||
img->mem_size = total;
|
||||
img->image_base = preferred_base;
|
||||
img->image_size = image_size;
|
||||
img->entry_point = preferred_base + entry_rva;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ===== 运行 =====
|
||||
* 加载 + 执行 + 卸载。返回 0 成功,*exit_code 为进程退出码。 */
|
||||
int pe_service_run(const void *pe_data, u64 size, const char *cmdline, u64 *exit_code) {
|
||||
if (!pe_data || size == 0) return -1;
|
||||
|
||||
/* 初始化 shim 状态(cmdline for GetCommandLineA) */
|
||||
pe_shim_init(cmdline ? cmdline : "");
|
||||
|
||||
/* 先解析 PE 判断 32/64 位 */
|
||||
if (size < sizeof(image_dos_header)) return -2;
|
||||
const image_dos_header *dos = (const image_dos_header *)pe_data;
|
||||
if (dos->e_magic != IMAGE_DOS_SIGNATURE) return -3;
|
||||
const u8 *nt_base = (const u8 *)pe_data + dos->e_lfanew;
|
||||
if (*(const u32 *)nt_base != IMAGE_NT_SIGNATURE) return -4;
|
||||
const void *opt = (const void *)(nt_base + 4 + sizeof(image_file_header));
|
||||
u16 opt_magic = *(const u16 *)opt;
|
||||
|
||||
if (opt_magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
||||
/* ===== PE32+ : Ring0 原生执行 ===== */
|
||||
pe_image_info info;
|
||||
int rc = pe_load_image(pe_data, size, &info);
|
||||
if (rc != 0) {
|
||||
log_error("[PE] PE32+ load failed");
|
||||
return -5;
|
||||
}
|
||||
log_info("[PE] running PE32+ natively");
|
||||
|
||||
u64 code = 0;
|
||||
int jumped = pe_shim_setup_exit();
|
||||
if (jumped == 0) {
|
||||
typedef void (*pe_entry_fn)(void);
|
||||
pe_entry_fn entry = (pe_entry_fn)info.entry_point;
|
||||
log_hex64("[PE] entry=", (u64)entry);
|
||||
entry();
|
||||
code = 0;
|
||||
} else {
|
||||
code = pe_shim_get_exit_code();
|
||||
log_hex64("[PE] ExitProcess code=", code);
|
||||
}
|
||||
|
||||
pe_unload_image(&info);
|
||||
if (exit_code) *exit_code = code;
|
||||
return 0;
|
||||
|
||||
} else if (opt_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
/* ===== PE32 : x86-32 解释器执行 ===== */
|
||||
pe32_interp_image img;
|
||||
int rc = pe32_load_into(pe_data, size, &img);
|
||||
if (rc != 0) {
|
||||
log_error("[PE] PE32 interp load failed");
|
||||
log_hex64("[PE] rc=", (u64)(i64)rc);
|
||||
return -6;
|
||||
}
|
||||
log_info("[PE] running PE32 via x86emu32");
|
||||
|
||||
u32 stack_top = img.image_base + img.image_size + PE32_STACK_SIZE - 16;
|
||||
|
||||
x86emu_state emu;
|
||||
int irc = x86emu32_init(&emu, img.mem, img.mem_size,
|
||||
img.image_base, img.image_size,
|
||||
img.iat, img.iat_count, stack_top);
|
||||
if (irc != 0) {
|
||||
log_error("[PE32] emu init failed");
|
||||
return -7;
|
||||
}
|
||||
emu.eip = img.entry_point;
|
||||
|
||||
u64 code = 0;
|
||||
int jumped = pe_shim_setup_exit();
|
||||
if (jumped == 0) {
|
||||
int rrc = x86emu32_run(&emu, &code);
|
||||
if (rrc != 0) {
|
||||
log_error("[PE32] emulator error");
|
||||
code = 0xFFFFFFFFULL;
|
||||
}
|
||||
} else {
|
||||
code = pe_shim_get_exit_code();
|
||||
log_hex64("[PE32] ExitProcess code=", code);
|
||||
}
|
||||
|
||||
if (emu.error && !emu.exited) {
|
||||
log_warn("[PE32] emulator stopped with error");
|
||||
}
|
||||
|
||||
if (exit_code) *exit_code = code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -8; /* 未知 PE magic */
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
/* pe_shim.c — Windows API shim 实现。
|
||||
*
|
||||
* 所有 64位 shim 用 __attribute__((ms_abi)) 声明,匹配 PE32+ 调用约定。
|
||||
* 32位 shim 从模拟栈读参数,供 x86emu32 解释器调用。
|
||||
*
|
||||
* 支持 API:kernel32.dll(GetStdHandle/WriteFile/ReadFile/ExitProcess/
|
||||
* HeapAlloc/HeapFree/VirtualAlloc/VirtualFree/GetCommandLineA/...)
|
||||
* msvcrt.dll(printf/puts/putchar/malloc/free/exit/memcpy/memset/
|
||||
* strlen/strcmp/strcpy/_initterm/_initterm_e)
|
||||
*/
|
||||
|
||||
#include "pe_shim.h"
|
||||
#include <utsm/arena.h>
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
|
||||
/* setjmp/longjmp for ExitProcess — 使用 __builtin_setjmp/__builtin_longjmp
|
||||
* (clang/gcc 内置,freestanding 可用,无需 libc)。
|
||||
* __builtin_setjmp 接受 void** 缓冲区,至少需要 8 个指针槽。 */
|
||||
static void *g_exit_jmp[24];
|
||||
static int g_exit_jmp_set;
|
||||
static u64 g_exit_code;
|
||||
static const char *g_cmdline = "";
|
||||
|
||||
void pe_shim_init(const char *cmdline) {
|
||||
g_cmdline = cmdline ? cmdline : "";
|
||||
g_exit_jmp_set = 0;
|
||||
g_exit_code = 0;
|
||||
}
|
||||
|
||||
/* pe_run 调用:保存上下文,返回 0 = 首次(继续执行),1 = ExitProcess 触发 */
|
||||
int pe_shim_setup_exit(void) {
|
||||
g_exit_jmp_set = 1;
|
||||
return __builtin_setjmp(g_exit_jmp);
|
||||
}
|
||||
|
||||
void pe_shim_exit_process(u64 exit_code) {
|
||||
g_exit_code = exit_code;
|
||||
if (g_exit_jmp_set) {
|
||||
__builtin_longjmp(g_exit_jmp, 1);
|
||||
}
|
||||
/* 无 jmpbuf:直接返回 */
|
||||
}
|
||||
|
||||
int pe_shim_is_exit_call(u64 target) {
|
||||
/* 64位 ExitProcess shim 地址 */
|
||||
extern u64 pe_shim_exitprocess64_addr(void);
|
||||
if (target == pe_shim_exitprocess64_addr()) return 1;
|
||||
/* 32位合成地址中 ExitProcess 的标记 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *pe_shim_get_cmdline(void) { return g_cmdline; }
|
||||
|
||||
u64 pe_shim_unimpl_stub(void) {
|
||||
extern u64 pe_shim_unimpl64_addr(void);
|
||||
return pe_shim_unimpl64_addr();
|
||||
}
|
||||
|
||||
/* ===== 串口/帧缓冲输出(shim 内部复用) ===== */
|
||||
static void shim_output(const char *s, u64 len) {
|
||||
for (u64 i = 0; i < len; i++) {
|
||||
serial_putc(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void shim_output_str(const char *s) {
|
||||
serial_write(s);
|
||||
}
|
||||
|
||||
/* ===== kernel32.dll shims (64位, ms_abi) ===== */
|
||||
|
||||
/* 句柄定义 */
|
||||
#define STD_INPUT_HANDLE ((u64)0xFFFFFFF6)
|
||||
#define STD_OUTPUT_HANDLE ((u64)0xFFFFFFF5)
|
||||
#define STD_ERROR_HANDLE ((u64)0xFFFFFFF4)
|
||||
#define SHIM_STDOUT_HANDLE ((u64)0x10000001)
|
||||
#define SHIM_STDERR_HANDLE ((u64)0x10000002)
|
||||
#define SHIM_STDIN_HANDLE ((u64)0x10000003)
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_GetStdHandle(u64 n_std_handle) {
|
||||
if (n_std_handle == STD_OUTPUT_HANDLE) return SHIM_STDOUT_HANDLE;
|
||||
if (n_std_handle == STD_ERROR_HANDLE) return SHIM_STDERR_HANDLE;
|
||||
if (n_std_handle == STD_INPUT_HANDLE) return SHIM_STDIN_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_WriteFile(u64 handle, u64 buffer, u64 length,
|
||||
u64 bytes_written_ptr, u64 overlapped) {
|
||||
(void)overlapped;
|
||||
if (handle == SHIM_STDOUT_HANDLE || handle == SHIM_STDERR_HANDLE) {
|
||||
const char *buf = (const char *)buffer;
|
||||
shim_output(buf, length);
|
||||
if (bytes_written_ptr) *(u64 *)bytes_written_ptr = length;
|
||||
return 1; /* TRUE */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_ReadFile(u64 handle, u64 buffer, u64 max_length,
|
||||
u64 bytes_read_ptr, u64 overlapped) {
|
||||
(void)handle; (void)buffer; (void)max_length; (void)overlapped;
|
||||
/* 暂不支持输入读取 */
|
||||
if (bytes_read_ptr) *(u64 *)bytes_read_ptr = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_ExitProcess(u64 exit_code) {
|
||||
pe_shim_exit_process(exit_code);
|
||||
return 0; /* 不返回 */
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_GetCommandLineA(void) {
|
||||
return (u64)g_cmdline;
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_GetCommandLineW(void) {
|
||||
return (u64)g_cmdline; /* 简化:返回 ASCII */
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_GetLastError(void) { return 0; }
|
||||
static u64 __attribute__((ms_abi)) shim_SetLastError(u64 code) { (void)code; return 0; }
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_HeapCreate(u64 fl, u64 init, u64 max) {
|
||||
(void)fl; (void)init; (void)max;
|
||||
return 0x10000010; /* 假堆句柄 */
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_HeapAlloc(u64 heap, u64 flags, u64 size) {
|
||||
(void)heap; (void)flags;
|
||||
return (u64)kmem_alloc(size);
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_HeapFree(u64 heap, u64 flags, u64 ptr) {
|
||||
(void)heap; (void)flags; (void)ptr;
|
||||
return 1; /* arena 无 free,返回 TRUE */
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_VirtualAlloc(u64 addr, u64 size, u64 alloc_type, u64 protect) {
|
||||
(void)addr; (void)alloc_type; (void)protect;
|
||||
return (u64)kmem_alloc(size);
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_VirtualFree(u64 addr, u64 size, u64 free_type) {
|
||||
(void)addr; (void)size; (void)free_type;
|
||||
return 1;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_GetModuleHandleA(u64 module_name) {
|
||||
(void)module_name;
|
||||
return 0x10000000; /* 假模块基址 */
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_GetModuleHandleW(u64 module_name) {
|
||||
(void)module_name;
|
||||
return 0x10000000;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_GetEnvironmentVariableA(u64 name, u64 buf, u64 size) {
|
||||
(void)name; (void)buf; (void)size;
|
||||
return 0;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_CreateFileA(u64 filename, u64 access, u64 share,
|
||||
u64 sa, u64 disp, u64 flags, u64 template) {
|
||||
(void)filename; (void)access; (void)share; (void)sa; (void)disp; (void)flags; (void)template;
|
||||
return 0; /* 暂不支持文件 */
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_CloseHandle(u64 handle) { (void)handle; return 1; }
|
||||
static u64 __attribute__((ms_abi)) shim_GetFileSize(u64 handle, u64 high) {
|
||||
(void)handle; (void)high; return 0;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_SetFilePointer(u64 handle, i64 dist, u64 high_ptr, u64 method) {
|
||||
(void)handle; (void)dist; (void)high_ptr; (void)method; return 0;
|
||||
}
|
||||
|
||||
/* ===== msvcrt.dll shims (64位, ms_abi) ===== */
|
||||
|
||||
static void shim_msvcrt_output(const char *s) {
|
||||
shim_output_str(s);
|
||||
}
|
||||
|
||||
/* printf — 简化版,只支持 %s %d %c %x %u %% */
|
||||
static u64 __attribute__((ms_abi)) shim_printf(u64 fmt, u64 a1, u64 a2, u64 a3) {
|
||||
/* 可变参数:MS x64 ABI 下 a1-a3 在 RDX/R8/R9,更多参数在栈上。
|
||||
* 简化处理:只处理前 3 个参数。 */
|
||||
const char *f = (const char *)fmt;
|
||||
u64 args[3] = {a1, a2, a3};
|
||||
int argi = 0;
|
||||
char outbuf[512];
|
||||
int oi = 0;
|
||||
for (int i = 0; f[i] && oi < 510; i++) {
|
||||
if (f[i] == '%' && f[i+1]) {
|
||||
i++;
|
||||
switch (f[i]) {
|
||||
case 's': {
|
||||
const char *s = (const char *)(args[argi++ & 3]);
|
||||
if (s) while (*s && oi < 510) outbuf[oi++] = *s++;
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
i64 v = (i64)args[argi++ & 3];
|
||||
if (v < 0) { outbuf[oi++] = '-'; v = -v; }
|
||||
char tmp[24]; int ti = 0;
|
||||
if (v == 0) tmp[ti++] = '0';
|
||||
while (v > 0 && ti < 23) { tmp[ti++] = '0' + (v % 10); v /= 10; }
|
||||
while (ti > 0 && oi < 510) outbuf[oi++] = tmp[--ti];
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
u64 v = args[argi++ & 3];
|
||||
char tmp[24]; int ti = 0;
|
||||
if (v == 0) tmp[ti++] = '0';
|
||||
while (v > 0 && ti < 23) { tmp[ti++] = '0' + (v % 10); v /= 10; }
|
||||
while (ti > 0 && oi < 510) outbuf[oi++] = tmp[--ti];
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
u64 v = args[argi++ & 3];
|
||||
char tmp[24]; int ti = 0;
|
||||
if (v == 0) tmp[ti++] = '0';
|
||||
while (v > 0 && ti < 23) { int d = (int)(v & 0xF); tmp[ti++] = d < 10 ? '0'+d : 'a'+d-10; v >>= 4; }
|
||||
while (ti > 0 && oi < 510) outbuf[oi++] = tmp[--ti];
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
outbuf[oi++] = (char)(args[argi++ & 3] & 0xFF);
|
||||
break;
|
||||
}
|
||||
case '%': outbuf[oi++] = '%'; break;
|
||||
default: outbuf[oi++] = '%'; outbuf[oi++] = f[i]; break;
|
||||
}
|
||||
} else {
|
||||
outbuf[oi++] = f[i];
|
||||
}
|
||||
}
|
||||
outbuf[oi] = 0;
|
||||
shim_msvcrt_output(outbuf);
|
||||
return (u64)oi;
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_puts(u64 str) {
|
||||
const char *s = (const char *)str;
|
||||
shim_msvcrt_output(s);
|
||||
shim_msvcrt_output("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_putchar(u64 ch) {
|
||||
serial_putc((char)(ch & 0xFF));
|
||||
return ch & 0xFF;
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_malloc(u64 size) {
|
||||
return (u64)kmem_alloc(size);
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_calloc(u64 count, u64 size) {
|
||||
u64 total = count * size;
|
||||
u8 *p = kmem_alloc(total);
|
||||
if (p) for (u64 i = 0; i < total; i++) p[i] = 0;
|
||||
return (u64)p;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_free(u64 ptr) { (void)ptr; return 0; }
|
||||
static u64 __attribute__((ms_abi)) shim_realloc(u64 ptr, u64 size) {
|
||||
(void)ptr; return (u64)kmem_alloc(size);
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_exit(u64 code) {
|
||||
pe_shim_exit_process(code);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u64 __attribute__((ms_abi)) shim_memcpy(u64 dst, u64 src, u64 n) {
|
||||
u8 *d = (u8 *)dst; const u8 *s = (const u8 *)src;
|
||||
for (u64 i = 0; i < n; i++) d[i] = s[i];
|
||||
return dst;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_memset(u64 dst, u64 val, u64 n) {
|
||||
u8 *d = (u8 *)dst; u8 v = (u8)(val & 0xFF);
|
||||
for (u64 i = 0; i < n; i++) d[i] = v;
|
||||
return dst;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_memmove(u64 dst, u64 src, u64 n) {
|
||||
u8 *d = (u8 *)dst; const u8 *s = (const u8 *)src;
|
||||
if (d < s) { for (u64 i = 0; i < n; i++) d[i] = s[i]; }
|
||||
else { for (u64 i = n; i > 0; i--) d[i-1] = s[i-1]; }
|
||||
return dst;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_strlen(u64 str) {
|
||||
const char *s = (const char *)str;
|
||||
u64 n = 0; while (s[n]) n++; return n;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_strcmp(u64 a, u64 b) {
|
||||
const char *pa = (const char *)a; const char *pb = (const char *)b;
|
||||
while (*pa && *pa == *pb) { pa++; pb++; }
|
||||
return (u64)(i64)(*pa - *pb);
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_strcpy(u64 dst, u64 src) {
|
||||
char *d = (char *)dst; const char *s = (const char *)src;
|
||||
while (*s) *d++ = *s++;
|
||||
*d = 0;
|
||||
return dst;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_strncmp(u64 a, u64 b, u64 n) {
|
||||
const char *pa = (const char *)a; const char *pb = (const char *)b;
|
||||
for (u64 i = 0; i < n; i++) {
|
||||
if (pa[i] != pb[i]) return (u64)(i64)(pa[i] - pb[i]);
|
||||
if (pa[i] == 0) return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_fwrite(u64 ptr, u64 size, u64 nmemb, u64 stream) {
|
||||
(void)stream;
|
||||
u64 total = size * nmemb;
|
||||
shim_output((const char *)ptr, total);
|
||||
return nmemb;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_fputs(u64 str, u64 stream) {
|
||||
(void)stream;
|
||||
shim_output_str((const char *)str);
|
||||
return 0;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_fputc(u64 ch, u64 stream) {
|
||||
(void)stream;
|
||||
serial_putc((char)(ch & 0xFF));
|
||||
return ch & 0xFF;
|
||||
}
|
||||
/* _initterm / _initterm_e — CRT 初始化,遍历函数指针表调用。
|
||||
* 简化:直接跳过(返回 0)。 */
|
||||
static u64 __attribute__((ms_abi)) shim_initterm(u64 start, u64 end) {
|
||||
(void)start; (void)end;
|
||||
return 0;
|
||||
}
|
||||
static u64 __attribute__((ms_abi)) shim_initterm_e(u64 start, u64 end) {
|
||||
(void)start; (void)end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 未实现 stub(64位)— 日志告警并返回 0 */
|
||||
static u64 __attribute__((ms_abi)) shim_unimpl64(u64 a0, u64 a1, u64 a2, u64 a3) {
|
||||
(void)a0; (void)a1; (void)a2; (void)a3;
|
||||
log_warn("[PE] unimplemented API called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 提供给 pe_shim.h 的地址获取函数 */
|
||||
u64 pe_shim_unimpl64_addr(void) { return (u64)shim_unimpl64; }
|
||||
u64 pe_shim_exitprocess64_addr(void) { return (u64)shim_ExitProcess; }
|
||||
|
||||
/* 获取退出码 */
|
||||
u64 pe_shim_get_exit_code(void) { return g_exit_code; }
|
||||
|
||||
/* ===== shim 表 ===== */
|
||||
static const pe_shim_entry g_shim_table[] = {
|
||||
/* kernel32.dll */
|
||||
{"kernel32.dll", "GetStdHandle", (void*)shim_GetStdHandle, 0},
|
||||
{"kernel32.dll", "WriteFile", (void*)shim_WriteFile, 0},
|
||||
{"kernel32.dll", "ReadFile", (void*)shim_ReadFile, 0},
|
||||
{"kernel32.dll", "ExitProcess", (void*)shim_ExitProcess, 0},
|
||||
{"kernel32.dll", "GetCommandLineA", (void*)shim_GetCommandLineA, 0},
|
||||
{"kernel32.dll", "GetCommandLineW", (void*)shim_GetCommandLineW, 0},
|
||||
{"kernel32.dll", "GetLastError", (void*)shim_GetLastError, 0},
|
||||
{"kernel32.dll", "SetLastError", (void*)shim_SetLastError, 0},
|
||||
{"kernel32.dll", "HeapCreate", (void*)shim_HeapCreate, 0},
|
||||
{"kernel32.dll", "HeapAlloc", (void*)shim_HeapAlloc, 0},
|
||||
{"kernel32.dll", "HeapFree", (void*)shim_HeapFree, 0},
|
||||
{"kernel32.dll", "VirtualAlloc", (void*)shim_VirtualAlloc, 0},
|
||||
{"kernel32.dll", "VirtualFree", (void*)shim_VirtualFree, 0},
|
||||
{"kernel32.dll", "GetModuleHandleA", (void*)shim_GetModuleHandleA, 0},
|
||||
{"kernel32.dll", "GetModuleHandleW", (void*)shim_GetModuleHandleW, 0},
|
||||
{"kernel32.dll", "GetEnvironmentVariableA",(void*)shim_GetEnvironmentVariableA, 0},
|
||||
{"kernel32.dll", "CreateFileA", (void*)shim_CreateFileA, 0},
|
||||
{"kernel32.dll", "CloseHandle", (void*)shim_CloseHandle, 0},
|
||||
{"kernel32.dll", "GetFileSize", (void*)shim_GetFileSize, 0},
|
||||
{"kernel32.dll", "SetFilePointer", (void*)shim_SetFilePointer, 0},
|
||||
/* msvcrt.dll */
|
||||
{"msvcrt.dll", "printf", (void*)shim_printf, 0},
|
||||
{"msvcrt.dll", "puts", (void*)shim_puts, 0},
|
||||
{"msvcrt.dll", "putchar", (void*)shim_putchar, 0},
|
||||
{"msvcrt.dll", "malloc", (void*)shim_malloc, 0},
|
||||
{"msvcrt.dll", "calloc", (void*)shim_calloc, 0},
|
||||
{"msvcrt.dll", "free", (void*)shim_free, 0},
|
||||
{"msvcrt.dll", "realloc", (void*)shim_realloc, 0},
|
||||
{"msvcrt.dll", "exit", (void*)shim_exit, 0},
|
||||
{"msvcrt.dll", "memcpy", (void*)shim_memcpy, 0},
|
||||
{"msvcrt.dll", "memset", (void*)shim_memset, 0},
|
||||
{"msvcrt.dll", "memmove", (void*)shim_memmove, 0},
|
||||
{"msvcrt.dll", "strlen", (void*)shim_strlen, 0},
|
||||
{"msvcrt.dll", "strcmp", (void*)shim_strcmp, 0},
|
||||
{"msvcrt.dll", "strcpy", (void*)shim_strcpy, 0},
|
||||
{"msvcrt.dll", "strncmp", (void*)shim_strncmp, 0},
|
||||
{"msvcrt.dll", "fwrite", (void*)shim_fwrite, 0},
|
||||
{"msvcrt.dll", "fputs", (void*)shim_fputs, 0},
|
||||
{"msvcrt.dll", "fputc", (void*)shim_fputc, 0},
|
||||
{"msvcrt.dll", "_initterm", (void*)shim_initterm, 0},
|
||||
{"msvcrt.dll", "_initterm_e", (void*)shim_initterm_e, 0},
|
||||
};
|
||||
|
||||
int pe_shim_lookup(const char *dll, const char *func) {
|
||||
if (!dll || !func) return -1;
|
||||
for (int i = 0; i < (int)(sizeof(g_shim_table)/sizeof(g_shim_table[0])); i++) {
|
||||
/* 大小写不敏感比较 DLL 名 */
|
||||
const char *a = g_shim_table[i].dll;
|
||||
const char *b = dll;
|
||||
int match = 1;
|
||||
while (*a && *b) {
|
||||
char ca = *a, cb = *b;
|
||||
if (ca >= 'A' && ca <= 'Z') ca += 32;
|
||||
if (cb >= 'A' && cb <= 'Z') cb += 32;
|
||||
if (ca != cb) { match = 0; break; }
|
||||
a++; b++;
|
||||
}
|
||||
if (!match || *a != *b) continue;
|
||||
/* 精确比较函数名 */
|
||||
const char *fa = g_shim_table[i].func;
|
||||
const char *fb = func;
|
||||
while (*fa && *fb) { if (*fa != *fb) break; fa++; fb++; }
|
||||
if (*fa == *fb) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const pe_shim_entry *pe_shim_get(int index) {
|
||||
if (index < 0 || index >= (int)(sizeof(g_shim_table)/sizeof(g_shim_table[0]))) return 0;
|
||||
return &g_shim_table[index];
|
||||
}
|
||||
|
||||
int pe_shim_count(void) {
|
||||
return (int)(sizeof(g_shim_table)/sizeof(g_shim_table[0]));
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef PE_SHIM_H
|
||||
#define PE_SHIM_H
|
||||
|
||||
/* pe_shim.h — Windows API shim 表。
|
||||
*
|
||||
* 将常见 Windows DLL 函数映射到 Deshab 等价实现:
|
||||
* kernel32.dll!WriteFile → 写串口 + 帧缓冲
|
||||
* kernel32.dll!HeapAlloc → kmem_alloc
|
||||
* msvcrt.dll!printf → 串口输出
|
||||
* ...
|
||||
*
|
||||
* 64位 PE:shim 用 __attribute__((ms_abi)) 声明,PE 代码以 MS x64 ABI 调用,
|
||||
* IAT 直接填 shim 函数地址,原生执行。
|
||||
* 32位 PE:解释器在 CALL IAT 时拦截,从模拟栈读参数调用 fn32,结果写 EAX。
|
||||
*/
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
/* 32位 shim:从模拟栈读取参数(cdecl 语义,调用者清栈)。
|
||||
* esp 指向模拟栈(第一个参数在 esp[0])。返回值 = EAX。 */
|
||||
typedef u64 (*pe_shim_fn32)(void *esp);
|
||||
|
||||
/* shim 表条目 */
|
||||
typedef struct pe_shim_entry {
|
||||
const char *dll; /* 小写 DLL 名,如 "kernel32.dll" */
|
||||
const char *func; /* 函数名,如 "WriteFile" */
|
||||
void *fn64; /* 64位 ms_abi 函数地址(可为 NULL) */
|
||||
pe_shim_fn32 fn32; /* 32位实现(可为 NULL) */
|
||||
} pe_shim_entry;
|
||||
|
||||
/* 按 dll+func 名查找 shim。返回表索引,-1 未找到。 */
|
||||
int pe_shim_lookup(const char *dll, const char *func);
|
||||
|
||||
/* 获取 shim 表条目 */
|
||||
const pe_shim_entry *pe_shim_get(int index);
|
||||
|
||||
/* 获取 shim 表大小 */
|
||||
int pe_shim_count(void);
|
||||
|
||||
/* 生成一个唯一的"未实现 stub"地址。
|
||||
* 64位:返回一个固定 stub 函数地址,被调用时日志告警并返回 0。
|
||||
* 32位:返回一个特殊标记值,解释器识别后日志告警。 */
|
||||
u64 pe_shim_unimpl_stub(void);
|
||||
|
||||
/* 初始化 shim 子系统(注册全局状态,如 cmdline) */
|
||||
void pe_shim_init(const char *cmdline);
|
||||
|
||||
/* ExitProcess 实现:通过 __builtin_longjmp 跳回 pe_run。
|
||||
* 64位和32位共用。exit_code = 进程退出码。 */
|
||||
void pe_shim_exit_process(u64 exit_code);
|
||||
|
||||
/* pe_run 调用:保存上下文(__builtin_setjmp)。
|
||||
* 返回 0 = 首次(继续执行 PE),1 = ExitProcess 触发(longjmp 回来)。 */
|
||||
int pe_shim_setup_exit(void);
|
||||
|
||||
/* 获取上次 ExitProcess 的退出码 */
|
||||
u64 pe_shim_get_exit_code(void);
|
||||
|
||||
/* 判断地址是否为 ExitProcess shim(解释器用) */
|
||||
int pe_shim_is_exit_call(u64 target);
|
||||
|
||||
/* 获取 cmdline(shim 内部用) */
|
||||
const char *pe_shim_get_cmdline(void);
|
||||
|
||||
#endif /* PE_SHIM_H */
|
||||
@@ -0,0 +1,975 @@
|
||||
/* x86emu32.c — x86-32 指令解释器(PE32 执行引擎)。
|
||||
*
|
||||
* 寄存器级解释执行 32位 PE 代码。覆盖 mingw-w64 -O0/-O1 控制台程序常用指令:
|
||||
* ALU(ADD/OR/ADC/SBB/AND/SUB/XOR/CMP)、MOV(全形式)、PUSH/POP、
|
||||
* INC/DEC/NEG/NOT、MUL/IMUL/DIV/IDIV、移位/旋转、LEA、XCHG、MOVSX/MOVZX、
|
||||
* JMP/Jcc/CALL/RET/LOOP、字符串指令(+REP)、ENTER/LEAVE、INT(shim 调度)。
|
||||
*
|
||||
* 遇不支持指令时设置 error 并停止。
|
||||
*/
|
||||
|
||||
#include "x86emu32.h"
|
||||
#include "pe_shim.h"
|
||||
#include <utsm/log.h>
|
||||
#include <utsm/types.h>
|
||||
|
||||
/* ===== 内存访问(带边界检查) ===== */
|
||||
u8 x86emu32_read8(x86emu_state *emu, u32 addr) {
|
||||
if (addr >= emu->mem_size) { emu->error = 1; emu->error_msg = "read8 OOB"; return 0; }
|
||||
return emu->mem[addr];
|
||||
}
|
||||
u16 x86emu32_read16(x86emu_state *emu, u32 addr) {
|
||||
if (addr + 1 >= emu->mem_size) { emu->error = 1; emu->error_msg = "read16 OOB"; return 0; }
|
||||
return (u16)emu->mem[addr] | ((u16)emu->mem[addr+1] << 8);
|
||||
}
|
||||
u32 x86emu32_read32(x86emu_state *emu, u32 addr) {
|
||||
if (addr + 3 >= emu->mem_size) { emu->error = 1; emu->error_msg = "read32 OOB"; return 0; }
|
||||
return (u32)emu->mem[addr] | ((u32)emu->mem[addr+1] << 8) |
|
||||
((u32)emu->mem[addr+2] << 16) | ((u32)emu->mem[addr+3] << 24);
|
||||
}
|
||||
void x86emu32_write8(x86emu_state *emu, u32 addr, u8 val) {
|
||||
if (addr >= emu->mem_size) { emu->error = 1; emu->error_msg = "write8 OOB"; return; }
|
||||
emu->mem[addr] = val;
|
||||
}
|
||||
void x86emu32_write16(x86emu_state *emu, u32 addr, u16 val) {
|
||||
if (addr + 1 >= emu->mem_size) { emu->error = 1; emu->error_msg = "write16 OOB"; return; }
|
||||
emu->mem[addr] = (u8)(val & 0xFF);
|
||||
emu->mem[addr+1] = (u8)((val >> 8) & 0xFF);
|
||||
}
|
||||
void x86emu32_write32(x86emu_state *emu, u32 addr, u32 val) {
|
||||
if (addr + 3 >= emu->mem_size) { emu->error = 1; emu->error_msg = "write32 OOB"; return; }
|
||||
emu->mem[addr] = (u8)(val & 0xFF);
|
||||
emu->mem[addr+1] = (u8)((val >> 8) & 0xFF);
|
||||
emu->mem[addr+2] = (u8)((val >> 16) & 0xFF);
|
||||
emu->mem[addr+3] = (u8)((val >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/* ===== 栈操作 ===== */
|
||||
void x86emu32_push32(x86emu_state *emu, u32 val) {
|
||||
emu->regs[X86_ESP] -= 4;
|
||||
x86emu32_write32(emu, emu->regs[X86_ESP], val);
|
||||
}
|
||||
u32 x86emu32_pop32(x86emu_state *emu) {
|
||||
u32 val = x86emu32_read32(emu, emu->regs[X86_ESP]);
|
||||
emu->regs[X86_ESP] += 4;
|
||||
return val;
|
||||
}
|
||||
|
||||
u64 x86emu32_read_arg(x86emu_state *emu, int esp_offset) {
|
||||
return x86emu32_read32(emu, emu->regs[X86_ESP] + (u32)esp_offset * 4);
|
||||
}
|
||||
|
||||
/* ===== 寄存器访问 ===== */
|
||||
/* 32位寄存器名:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI(对应 0-7) */
|
||||
/* 8位寄存器映射:AL,CL,DL,BL,AH,CH,DH,BH(0-3 = 低8位, 4-7 = 高8位) */
|
||||
static u8 get_reg8(x86emu_state *emu, int idx) {
|
||||
if (idx < 4) return (u8)(emu->regs[idx] & 0xFF);
|
||||
return (u8)((emu->regs[idx - 4] >> 8) & 0xFF);
|
||||
}
|
||||
static void set_reg8(x86emu_state *emu, int idx, u8 val) {
|
||||
if (idx < 4) {
|
||||
emu->regs[idx] = (emu->regs[idx] & 0xFFFFFF00) | val;
|
||||
} else {
|
||||
emu->regs[idx - 4] = (emu->regs[idx - 4] & 0xFFFF00FF) | ((u32)val << 8);
|
||||
}
|
||||
}
|
||||
static u16 get_reg16(x86emu_state *emu, int idx) {
|
||||
return (u16)(emu->regs[idx] & 0xFFFF);
|
||||
}
|
||||
static void set_reg16(x86emu_state *emu, int idx, u16 val) {
|
||||
emu->regs[idx] = (emu->regs[idx] & 0xFFFF0000) | val;
|
||||
}
|
||||
static u32 get_reg32(x86emu_state *emu, int idx) { return emu->regs[idx]; }
|
||||
static void set_reg32(x86emu_state *emu, int idx, u32 val) { emu->regs[idx] = val; }
|
||||
|
||||
/* ===== EFLAGS 辅助 ===== */
|
||||
static void set_flag(x86emu_state *emu, u32 mask, int on) {
|
||||
if (on) emu->eflags |= mask; else emu->eflags &= ~mask;
|
||||
}
|
||||
static int get_flag(x86emu_state *emu, u32 mask) { return (emu->eflags & mask) ? 1 : 0; }
|
||||
|
||||
static u8 parity8(u8 v) {
|
||||
v ^= v >> 4; v ^= v >> 2; v ^= v >> 1;
|
||||
return (v & 1) == 0;
|
||||
}
|
||||
|
||||
static void set_zf_sf_pf(x86emu_state *emu, u32 result, int size) {
|
||||
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
|
||||
result &= mask;
|
||||
set_flag(emu, X86_ZF, result == 0);
|
||||
if (size == 1) set_flag(emu, X86_SF, (result & 0x80) != 0);
|
||||
else if (size == 2) set_flag(emu, X86_SF, (result & 0x8000) != 0);
|
||||
else set_flag(emu, X86_SF, (result & 0x80000000) != 0);
|
||||
set_flag(emu, X86_PF, parity8((u8)result));
|
||||
}
|
||||
|
||||
static void set_cf_add(x86emu_state *emu, u32 a, u32 b, int size) {
|
||||
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
|
||||
set_flag(emu, X86_CF, ((u64)(a & mask) + (u64)(b & mask)) > mask);
|
||||
}
|
||||
static void set_cf_sub(x86emu_state *emu, u32 a, u32 b, int size) {
|
||||
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
|
||||
set_flag(emu, X86_CF, (a & mask) < (b & mask));
|
||||
}
|
||||
static void set_of_add(x86emu_state *emu, u32 a, u32 b, u32 r, int size) {
|
||||
u32 sign = (size == 1) ? 0x80 : (size == 2) ? 0x8000 : 0x80000000;
|
||||
set_flag(emu, X86_OF, (~(a ^ b) & (a ^ r) & sign) != 0);
|
||||
}
|
||||
static void set_of_sub(x86emu_state *emu, u32 a, u32 b, u32 r, int size) {
|
||||
u32 sign = (size == 1) ? 0x80 : (size == 2) ? 0x8000 : 0x80000000;
|
||||
set_flag(emu, X86_OF, ((a ^ b) & (a ^ r) & sign) != 0);
|
||||
}
|
||||
|
||||
/* ===== 指令取 ===== */
|
||||
static u8 fetch8(x86emu_state *emu) {
|
||||
u8 v = x86emu32_read8(emu, emu->eip);
|
||||
emu->eip++;
|
||||
return v;
|
||||
}
|
||||
static u16 fetch16(x86emu_state *emu) {
|
||||
u16 v = x86emu32_read16(emu, emu->eip);
|
||||
emu->eip += 2;
|
||||
return v;
|
||||
}
|
||||
static u32 fetch32(x86emu_state *emu) {
|
||||
u32 v = x86emu32_read32(emu, emu->eip);
|
||||
emu->eip += 4;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* ===== ModR/M 解码 ===== */
|
||||
typedef struct {
|
||||
int mod;
|
||||
int reg; /* reg 字段(也可作 opcode 扩展) */
|
||||
int rm; /* rm 字段 */
|
||||
u32 ea; /* 有效地址(若 mod != 3) */
|
||||
int has_ea; /* 是否有内存操作数 */
|
||||
} modrm_dec;
|
||||
|
||||
static modrm_dec decode_modrm(x86emu_state *emu) {
|
||||
modrm_dec m;
|
||||
u8 b = fetch8(emu);
|
||||
m.mod = (b >> 6) & 3;
|
||||
m.reg = (b >> 3) & 7;
|
||||
m.rm = b & 7;
|
||||
m.has_ea = 0;
|
||||
m.ea = 0;
|
||||
|
||||
if (m.mod == 3) return m; /* 寄存器直接寻址 */
|
||||
|
||||
m.has_ea = 1;
|
||||
u32 base = 0;
|
||||
int has_sib = (m.rm == 4);
|
||||
|
||||
if (has_sib) {
|
||||
u8 sib = fetch8(emu);
|
||||
int scale = 1 << ((sib >> 6) & 3);
|
||||
int index = (sib >> 3) & 7;
|
||||
int base_reg = sib & 7;
|
||||
base = emu->regs[base_reg];
|
||||
if (index != 4) { /* ESP 不作 index */
|
||||
base += emu->regs[index] * (u32)scale;
|
||||
}
|
||||
} else {
|
||||
base = emu->regs[m.rm];
|
||||
}
|
||||
|
||||
/* disp */
|
||||
if (m.mod == 0) {
|
||||
if (!has_sib && m.rm == 5) {
|
||||
/* disp32 直接地址 */
|
||||
base = fetch32(emu);
|
||||
}
|
||||
} else if (m.mod == 1) {
|
||||
base += (u32)(i32)(i8)fetch8(emu); /* disp8 符号扩展 */
|
||||
} else { /* mod == 2 */
|
||||
base += fetch32(emu);
|
||||
}
|
||||
|
||||
m.ea = base;
|
||||
return m;
|
||||
}
|
||||
|
||||
/* 读/写 modr/m 操作数 */
|
||||
static u32 read_rm32(x86emu_state *emu, const modrm_dec *m) {
|
||||
if (m->mod == 3) return get_reg32(emu, m->rm);
|
||||
return x86emu32_read32(emu, m->ea);
|
||||
}
|
||||
static void write_rm32(x86emu_state *emu, const modrm_dec *m, u32 val) {
|
||||
if (m->mod == 3) set_reg32(emu, m->rm, val);
|
||||
else x86emu32_write32(emu, m->ea, val);
|
||||
}
|
||||
static u8 read_rm8(x86emu_state *emu, const modrm_dec *m) {
|
||||
if (m->mod == 3) return get_reg8(emu, m->rm);
|
||||
return x86emu32_read8(emu, m->ea);
|
||||
}
|
||||
static void write_rm8(x86emu_state *emu, const modrm_dec *m, u8 val) {
|
||||
if (m->mod == 3) set_reg8(emu, m->rm, val);
|
||||
else x86emu32_write8(emu, m->ea, val);
|
||||
}
|
||||
static u16 read_rm16(x86emu_state *emu, const modrm_dec *m) {
|
||||
if (m->mod == 3) return get_reg16(emu, m->rm);
|
||||
return x86emu32_read16(emu, m->ea);
|
||||
}
|
||||
static void write_rm16(x86emu_state *emu, const modrm_dec *m, u16 val) {
|
||||
if (m->mod == 3) set_reg16(emu, m->rm, val);
|
||||
else x86emu32_write16(emu, m->ea, val);
|
||||
}
|
||||
|
||||
/* ===== ALU 操作(按 op 索引:0=ADD 1=OR 2=ADC 3=SBB 4=AND 5=SUB 6=XOR 7=CMP) ===== */
|
||||
static u32 alu_op(x86emu_state *emu, int op, u32 a, u32 b, int size) {
|
||||
u32 r = 0;
|
||||
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
|
||||
a &= mask; b &= mask;
|
||||
switch (op) {
|
||||
case 0: r = a + b; set_cf_add(emu, a, b, size); set_of_add(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break;
|
||||
case 1: r = a | b; set_flag(emu, X86_CF, 0); set_flag(emu, X86_OF, 0); set_zf_sf_pf(emu, r, size); break;
|
||||
case 2: { int cf = get_flag(emu, X86_CF); r = a + b + cf; set_cf_add(emu, a + cf, b, size); set_of_add(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break; }
|
||||
case 3: { int cf = get_flag(emu, X86_CF); r = a - b - cf; set_cf_sub(emu, a - cf, b, size); set_of_sub(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break; }
|
||||
case 4: r = a & b; set_flag(emu, X86_CF, 0); set_flag(emu, X86_OF, 0); set_zf_sf_pf(emu, r, size); break;
|
||||
case 5: r = a - b; set_cf_sub(emu, a, b, size); set_of_sub(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break;
|
||||
case 6: r = a ^ b; set_flag(emu, X86_CF, 0); set_flag(emu, X86_OF, 0); set_zf_sf_pf(emu, r, size); break;
|
||||
case 7: r = a - b; set_cf_sub(emu, a, b, size); set_of_sub(emu, a, b, r, size); set_zf_sf_pf(emu, r, size); break; /* CMP 不写回 */
|
||||
}
|
||||
return r & mask;
|
||||
}
|
||||
|
||||
/* ===== 移位操作(按 op:ROL/ROR/RCL/RCR/SHL/SHR/SAR/SAL) ===== */
|
||||
static u32 shift_op(x86emu_state *emu, int op, u32 val, u8 count, int size) {
|
||||
u32 mask = (size == 1) ? 0xFF : (size == 2) ? 0xFFFF : 0xFFFFFFFF;
|
||||
val &= mask;
|
||||
count &= 0x1F;
|
||||
if (count == 0) return val;
|
||||
u32 r = val;
|
||||
switch (op) {
|
||||
case 4: case 6: /* SHL / SAL */
|
||||
r = val << count;
|
||||
set_flag(emu, X86_CF, (val >> (32 - count)) & 1);
|
||||
break;
|
||||
case 5: /* SHR */
|
||||
r = val >> count;
|
||||
set_flag(emu, X86_CF, (val >> (count - 1)) & 1);
|
||||
break;
|
||||
case 7: /* SAR */
|
||||
r = (u32)((i32)val >> count);
|
||||
set_flag(emu, X86_CF, (val >> (count - 1)) & 1);
|
||||
break;
|
||||
case 0: /* ROL */
|
||||
r = ((val << count) | (val >> (size * 8 - count))) & mask;
|
||||
set_flag(emu, X86_CF, r & 1);
|
||||
break;
|
||||
case 1: /* ROR */
|
||||
r = ((val >> count) | (val << (size * 8 - count))) & mask;
|
||||
set_flag(emu, X86_CF, (r >> (size * 8 - 1)) & 1);
|
||||
break;
|
||||
default: break; /* RCL/RCR 暂简化 */
|
||||
}
|
||||
if (op >= 4) set_zf_sf_pf(emu, r, size); /* SHL/SHR/SAR 影响 ZF/SF/PF */
|
||||
return r & mask;
|
||||
}
|
||||
|
||||
/* ===== IAT CALL 拦截 ===== */
|
||||
/* stdcall 参数个数表(kernel32.dll 函数:callee 清栈)。
|
||||
* msvcrt.dll 函数为 cdecl(caller 清栈),不在此表。
|
||||
* key = shim 函数名首字符 + 长度组合的简单 hash,避免 strcmp。
|
||||
* 简化:直接用函数指针地址查表。 */
|
||||
static int try_iat_call(x86emu_state *emu, u32 target) {
|
||||
/* 检查是否为合成 shim 地址 */
|
||||
if (target >= 0x00010000 && target < 0x00020000) {
|
||||
int shim_idx = target & 0xFFFF;
|
||||
if (shim_idx == 0xFFFF) {
|
||||
/* 未实现 stub */
|
||||
log_warn("[PE32] call unimplemented API");
|
||||
emu->regs[X86_EAX] = 0;
|
||||
return 1;
|
||||
}
|
||||
const pe_shim_entry *se = pe_shim_get(shim_idx);
|
||||
if (!se) {
|
||||
log_warn("[PE32] shim index out of range");
|
||||
emu->regs[X86_EAX] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 从模拟栈读参数。CALL 被拦截前未 push 返回地址,
|
||||
* 所以 ESP 指向第一个参数。 */
|
||||
u32 esp_val = emu->regs[X86_ESP];
|
||||
if (esp_val + 32 > emu->mem_size) {
|
||||
emu->error = 1;
|
||||
emu->error_msg = "shim esp OOB";
|
||||
return 1;
|
||||
}
|
||||
u64 a0 = x86emu32_read32(emu, esp_val);
|
||||
u64 a1 = x86emu32_read32(emu, esp_val + 4);
|
||||
u64 a2 = x86emu32_read32(emu, esp_val + 8);
|
||||
u64 a3 = x86emu32_read32(emu, esp_val + 12);
|
||||
|
||||
u64 ret;
|
||||
if (se->fn32) {
|
||||
/* 有专用 32位实现 */
|
||||
void *esp_ptr = &emu->mem[esp_val];
|
||||
ret = se->fn32(esp_ptr);
|
||||
} else if (se->fn64) {
|
||||
/* 回退:调用 64位 shim(最多 4 个参数)。
|
||||
* MS x64 ABI 由 C 编译器处理寄存器分配。 */
|
||||
typedef u64 (*fn4_t)(u64, u64, u64, u64);
|
||||
fn4_t f = (fn4_t)se->fn64;
|
||||
ret = f(a0, a1, a2, a3);
|
||||
|
||||
/* stdcall 清栈:kernel32.dll 函数 callee 清栈。
|
||||
* 简化:按已知参数个数调整 ESP。
|
||||
* msvcrt.dll (cdecl) 不清栈。 */
|
||||
if (se->dll[0] == 'k') { /* kernel32.dll */
|
||||
int nargs = 4; /* 默认假设 4 参数 */
|
||||
/* 按函数名精化参数个数 */
|
||||
const char *fn = se->func;
|
||||
if (fn[0]=='G' && fn[1]=='e' && fn[2]=='t' && fn[3]=='S') nargs = 1;
|
||||
else if (fn[0]=='W' && fn[1]=='r' && fn[2]=='i') nargs = 5;
|
||||
else if (fn[0]=='R' && fn[1]=='e' && fn[2]=='a' && fn[3]=='d') nargs = 5;
|
||||
else if (fn[0]=='E' && fn[1]=='x' && fn[2]=='i' && fn[3]=='t') nargs = 1;
|
||||
else if (fn[0]=='G' && fn[1]=='e' && fn[2]=='t' && fn[3]=='C') nargs = 0;
|
||||
else if (fn[0]=='G' && fn[1]=='e' && fn[2]=='t' && fn[3]=='L') nargs = 0;
|
||||
else if (fn[0]=='S' && fn[1]=='e' && fn[2]=='t' && fn[3]=='L') nargs = 1;
|
||||
else if (fn[0]=='H' && fn[1]=='e' && fn[2]=='a' && fn[3]=='p') nargs = 3;
|
||||
else if (fn[0]=='V' && fn[1]=='i' && fn[2]=='r') nargs = 4;
|
||||
else if (fn[0]=='G' && fn[1]=='e' && fn[2]=='t' && fn[3]=='M') nargs = 1;
|
||||
else if (fn[0]=='C' && fn[1]=='l' && fn[2]=='o') nargs = 1;
|
||||
else if (fn[0]=='C' && fn[1]=='r' && fn[2]=='e') nargs = 7;
|
||||
emu->regs[X86_ESP] += (u32)(nargs * 4);
|
||||
}
|
||||
} else {
|
||||
log_warn("[PE32] no shim impl");
|
||||
ret = 0;
|
||||
}
|
||||
emu->regs[X86_EAX] = (u32)ret;
|
||||
return 1;
|
||||
}
|
||||
/* 检查是否为 ExitProcess 特殊地址(64位 ExitProcess shim) */
|
||||
if (pe_shim_is_exit_call((u64)target)) {
|
||||
pe_shim_exit_process(emu->regs[X86_EAX] ? emu->regs[X86_EAX] : 0);
|
||||
emu->exited = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0; /* 不是 IAT/shim 调用 */
|
||||
}
|
||||
|
||||
/* ===== 条件跳转判断 ===== */
|
||||
static int check_jcc(x86emu_state *emu, int cond) {
|
||||
int zf = get_flag(emu, X86_ZF);
|
||||
int sf = get_flag(emu, X86_SF);
|
||||
int of = get_flag(emu, X86_OF);
|
||||
int cf = get_flag(emu, X86_CF);
|
||||
int pf = get_flag(emu, X86_PF);
|
||||
switch (cond & 0xF) {
|
||||
case 0x0: return of;
|
||||
case 0x1: return !of;
|
||||
case 0x2: return cf;
|
||||
case 0x3: return !cf;
|
||||
case 0x4: return zf;
|
||||
case 0x5: return !zf;
|
||||
case 0x6: return cf || zf;
|
||||
case 0x7: return !cf && !zf;
|
||||
case 0x8: return sf;
|
||||
case 0x9: return !sf;
|
||||
case 0xA: return pf;
|
||||
case 0xB: return !pf;
|
||||
case 0xC: return sf != of;
|
||||
case 0xD: return sf == of;
|
||||
case 0xE: return zf || (sf != of);
|
||||
case 0xF: return !zf && (sf == of);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ===== 主执行循环 ===== */
|
||||
int x86emu32_run(x86emu_state *emu, u64 *exit_code) {
|
||||
emu->insn_limit = 500000000ULL; /* 5亿指令上限防死循环 */
|
||||
|
||||
while (!emu->exited && !emu->error && emu->insn_count < emu->insn_limit) {
|
||||
emu->insn_count++;
|
||||
|
||||
/* 前缀处理 */
|
||||
int operand_size = 4; /* 默认 32位 */
|
||||
int rep_prefix = 0; /* 0=无, 1=REP/REPE, 2=REPNE(记录但暂未用于字符串指令) */
|
||||
u8 op;
|
||||
int prefix_done = 0;
|
||||
while (!prefix_done) {
|
||||
op = fetch8(emu);
|
||||
switch (op) {
|
||||
case 0x66: operand_size = 2; break;
|
||||
case 0x67: break; /* 地址大小前缀(忽略,32位寻址) */
|
||||
case 0xF0: break; /* LOCK */
|
||||
case 0xF2: rep_prefix = 2; break; /* REPNE */
|
||||
case 0xF3: rep_prefix = 1; break; /* REP/REPE */
|
||||
case 0x26: case 0x2E: case 0x36: case 0x3E: case 0x64: case 0x65: break; /* 段前缀忽略 */
|
||||
default: prefix_done = 1; break;
|
||||
}
|
||||
}
|
||||
(void)rep_prefix; /* 记录前缀,字符串指令暂未使用 */
|
||||
|
||||
/* 操作数大小:对 0x66 前缀,32位操作变 16位 */
|
||||
int osz = operand_size; /* 4 或 2 */
|
||||
|
||||
switch (op) {
|
||||
/* ---- ALU modr/m(0x00-0x3F)---- */
|
||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
||||
case 0x08: case 0x09: case 0x0A: case 0x0B:
|
||||
case 0x10: case 0x11: case 0x12: case 0x13:
|
||||
case 0x18: case 0x19: case 0x1A: case 0x1B:
|
||||
case 0x20: case 0x21: case 0x22: case 0x23:
|
||||
case 0x28: case 0x29: case 0x2A: case 0x2B:
|
||||
case 0x30: case 0x31: case 0x32: case 0x33:
|
||||
case 0x38: case 0x39: case 0x3A: case 0x3B: {
|
||||
int alu = (op >> 3) & 7;
|
||||
int dir = op & 1; /* 0: r/m8←r8, 1: r/m32←r32 (或反向) */
|
||||
int is8 = !(op & 4); /* 0x00-0x03=8位, 0x04+ =32位 */
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (is8) {
|
||||
u8 a, b; int cmp_only = (alu == 7);
|
||||
if (dir == 0) { a = read_rm8(emu, &m); b = get_reg8(emu, m.reg); }
|
||||
else { a = get_reg8(emu, m.reg); b = read_rm8(emu, &m); }
|
||||
u8 r = (u8)alu_op(emu, alu, a, b, 1);
|
||||
if (alu != 7) { if (dir == 0) write_rm8(emu, &m, r); else set_reg8(emu, m.reg, r); }
|
||||
(void)cmp_only;
|
||||
} else {
|
||||
u32 a, b;
|
||||
if (dir == 0) { a = read_rm32(emu, &m); b = get_reg32(emu, m.reg); }
|
||||
else { a = get_reg32(emu, m.reg); b = read_rm32(emu, &m); }
|
||||
u32 r = alu_op(emu, alu, a, b, osz);
|
||||
if (alu != 7) { if (dir == 0) write_rm32(emu, &m, r); else set_reg32(emu, m.reg, r); }
|
||||
if (osz == 2) { if (alu != 7) { if (dir == 0) write_rm16(emu, &m, (u16)r); else set_reg16(emu, m.reg, (u16)r); } }
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* ---- ALU AL/EAX, imm ---- */
|
||||
case 0x04: case 0x0C: case 0x14: case 0x1C:
|
||||
case 0x24: case 0x2C: case 0x34: case 0x3C: {
|
||||
int alu = (op >> 3) & 7;
|
||||
u8 imm = fetch8(emu);
|
||||
u8 r = (u8)alu_op(emu, alu, get_reg8(emu, 0), imm, 1);
|
||||
if (alu != 7) set_reg8(emu, 0, r);
|
||||
break;
|
||||
}
|
||||
case 0x05: case 0x0D: case 0x15: case 0x1D:
|
||||
case 0x25: case 0x2D: case 0x35: case 0x3D: {
|
||||
int alu = (op >> 3) & 7;
|
||||
if (osz == 2) {
|
||||
u16 imm = fetch16(emu);
|
||||
u16 r = (u16)alu_op(emu, alu, get_reg16(emu, 0), imm, 2);
|
||||
if (alu != 7) set_reg16(emu, 0, r);
|
||||
} else {
|
||||
u32 imm = fetch32(emu);
|
||||
u32 r = alu_op(emu, alu, get_reg32(emu, 0), imm, 4);
|
||||
if (alu != 7) set_reg32(emu, 0, r);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* ---- INC/DEC reg(0x40-0x4F)---- */
|
||||
case 0x40: case 0x41: case 0x42: case 0x43:
|
||||
case 0x44: case 0x45: case 0x46: case 0x47: {
|
||||
int r = op - 0x40;
|
||||
int cf = get_flag(emu, X86_CF);
|
||||
if (osz == 2) { u16 v = get_reg16(emu, r); u16 res = (u16)alu_op(emu, 0, v, 1, 2); set_reg16(emu, r, res); }
|
||||
else { u32 v = get_reg32(emu, r); u32 res = alu_op(emu, 0, v, 1, 4); set_reg32(emu, r, res); }
|
||||
set_flag(emu, X86_CF, cf); /* INC 不影响 CF */
|
||||
break;
|
||||
}
|
||||
case 0x48: case 0x49: case 0x4A: case 0x4B:
|
||||
case 0x4C: case 0x4D: case 0x4E: case 0x4F: {
|
||||
int r = op - 0x48;
|
||||
int cf = get_flag(emu, X86_CF);
|
||||
if (osz == 2) { u16 v = get_reg16(emu, r); u16 res = (u16)alu_op(emu, 5, v, 1, 2); set_reg16(emu, r, res); }
|
||||
else { u32 v = get_reg32(emu, r); u32 res = alu_op(emu, 5, v, 1, 4); set_reg32(emu, r, res); }
|
||||
set_flag(emu, X86_CF, cf);
|
||||
break;
|
||||
}
|
||||
/* ---- PUSH/POP reg ---- */
|
||||
case 0x50: case 0x51: case 0x52: case 0x53:
|
||||
case 0x54: case 0x55: case 0x56: case 0x57:
|
||||
x86emu32_push32(emu, get_reg32(emu, op - 0x50));
|
||||
break;
|
||||
case 0x58: case 0x59: case 0x5A: case 0x5B:
|
||||
case 0x5C: case 0x5D: case 0x5E: case 0x5F:
|
||||
set_reg32(emu, op - 0x58, x86emu32_pop32(emu));
|
||||
break;
|
||||
/* ---- PUSHA/POPA ---- */
|
||||
case 0x60: {
|
||||
u32 sp = emu->regs[X86_ESP];
|
||||
x86emu32_push32(emu, emu->regs[X86_EAX]);
|
||||
x86emu32_push32(emu, emu->regs[X86_ECX]);
|
||||
x86emu32_push32(emu, emu->regs[X86_EDX]);
|
||||
x86emu32_push32(emu, emu->regs[X86_EBX]);
|
||||
x86emu32_push32(emu, sp);
|
||||
x86emu32_push32(emu, emu->regs[X86_EBP]);
|
||||
x86emu32_push32(emu, emu->regs[X86_ESI]);
|
||||
x86emu32_push32(emu, emu->regs[X86_EDI]);
|
||||
break;
|
||||
}
|
||||
case 0x61: {
|
||||
emu->regs[X86_EDI] = x86emu32_pop32(emu);
|
||||
emu->regs[X86_ESI] = x86emu32_pop32(emu);
|
||||
emu->regs[X86_EBP] = x86emu32_pop32(emu);
|
||||
x86emu32_pop32(emu); /* 忽略原始 ESP */
|
||||
emu->regs[X86_EBX] = x86emu32_pop32(emu);
|
||||
emu->regs[X86_EDX] = x86emu32_pop32(emu);
|
||||
emu->regs[X86_ECX] = x86emu32_pop32(emu);
|
||||
emu->regs[X86_EAX] = x86emu32_pop32(emu);
|
||||
break;
|
||||
}
|
||||
/* ---- PUSH imm ---- */
|
||||
case 0x68: x86emu32_push32(emu, fetch32(emu)); break;
|
||||
case 0x6A: x86emu32_push32(emu, (u32)(i32)(i8)fetch8(emu)); break;
|
||||
/* ---- IMUL r, r/m, imm ---- */
|
||||
case 0x69: case 0x6B: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
u32 src = read_rm32(emu, &m);
|
||||
u32 imm = (op == 0x69) ? fetch32(emu) : (u32)(i32)(i8)fetch8(emu);
|
||||
i64 result = (i64)(i32)src * (i64)(i32)imm;
|
||||
set_reg32(emu, m.reg, (u32)result);
|
||||
set_flag(emu, X86_OF, result > 0x7FFFFFFFLL || result < -0x80000000LL);
|
||||
set_flag(emu, X86_CF, get_flag(emu, X86_OF));
|
||||
break;
|
||||
}
|
||||
/* ---- Jcc rel8 ---- */
|
||||
case 0x70: case 0x71: case 0x72: case 0x73:
|
||||
case 0x74: case 0x75: case 0x76: case 0x77:
|
||||
case 0x78: case 0x79: case 0x7A: case 0x7B:
|
||||
case 0x7C: case 0x7D: case 0x7E: case 0x7F: {
|
||||
i8 rel = (i8)fetch8(emu);
|
||||
if (check_jcc(emu, op & 0xF)) emu->eip += (u32)(i32)rel;
|
||||
break;
|
||||
}
|
||||
/* ---- ALU r/m, imm8 (0x80/0x82) / r/m, imm32 (0x81) ---- */
|
||||
case 0x80: case 0x82: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
u8 imm = fetch8(emu);
|
||||
u8 a = read_rm8(emu, &m);
|
||||
u8 r = (u8)alu_op(emu, m.reg, a, imm, 1);
|
||||
if (m.reg != 7) write_rm8(emu, &m, r);
|
||||
break;
|
||||
}
|
||||
case 0x81: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (osz == 2) {
|
||||
u16 imm = fetch16(emu);
|
||||
u16 a = read_rm16(emu, &m);
|
||||
u16 r = (u16)alu_op(emu, m.reg, a, imm, 2);
|
||||
if (m.reg != 7) write_rm16(emu, &m, r);
|
||||
} else {
|
||||
u32 imm = fetch32(emu);
|
||||
u32 a = read_rm32(emu, &m);
|
||||
u32 r = alu_op(emu, m.reg, a, imm, 4);
|
||||
if (m.reg != 7) write_rm32(emu, &m, r);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x83: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
u32 imm = (u32)(i32)(i8)fetch8(emu);
|
||||
if (osz == 2) {
|
||||
u16 a = read_rm16(emu, &m);
|
||||
u16 r = (u16)alu_op(emu, m.reg, a, imm & 0xFFFF, 2);
|
||||
if (m.reg != 7) write_rm16(emu, &m, r);
|
||||
} else {
|
||||
u32 a = read_rm32(emu, &m);
|
||||
u32 r = alu_op(emu, m.reg, a, imm, 4);
|
||||
if (m.reg != 7) write_rm32(emu, &m, r);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* ---- TEST ---- */
|
||||
case 0x84: case 0x85: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (op == 0x84) {
|
||||
u8 a = read_rm8(emu, &m); u8 b = get_reg8(emu, m.reg);
|
||||
alu_op(emu, 4, a, b, 1); /* AND 不写回 */
|
||||
} else if (osz == 2) {
|
||||
u16 a = read_rm16(emu, &m); u16 b = get_reg16(emu, m.reg);
|
||||
alu_op(emu, 4, a, b, 2);
|
||||
} else {
|
||||
u32 a = read_rm32(emu, &m); u32 b = get_reg32(emu, m.reg);
|
||||
alu_op(emu, 4, a, b, 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* ---- XCHG ---- */
|
||||
case 0x86: case 0x87: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (op == 0x86) {
|
||||
u8 a = read_rm8(emu, &m); u8 b = get_reg8(emu, m.reg);
|
||||
write_rm8(emu, &m, b); set_reg8(emu, m.reg, a);
|
||||
} else if (osz == 2) {
|
||||
u16 a = read_rm16(emu, &m); u16 b = get_reg16(emu, m.reg);
|
||||
write_rm16(emu, &m, b); set_reg16(emu, m.reg, a);
|
||||
} else {
|
||||
u32 a = read_rm32(emu, &m); u32 b = get_reg32(emu, m.reg);
|
||||
write_rm32(emu, &m, b); set_reg32(emu, m.reg, a);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* ---- MOV ---- */
|
||||
case 0x88: { modrm_dec m = decode_modrm(emu); write_rm8(emu, &m, get_reg8(emu, m.reg)); break; }
|
||||
case 0x89: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (osz == 2) write_rm16(emu, &m, get_reg16(emu, m.reg));
|
||||
else write_rm32(emu, &m, get_reg32(emu, m.reg));
|
||||
break;
|
||||
}
|
||||
case 0x8A: { modrm_dec m = decode_modrm(emu); set_reg8(emu, m.reg, read_rm8(emu, &m)); break; }
|
||||
case 0x8B: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (osz == 2) set_reg16(emu, m.reg, read_rm16(emu, &m));
|
||||
else set_reg32(emu, m.reg, read_rm32(emu, &m));
|
||||
break;
|
||||
}
|
||||
/* ---- LEA ---- */
|
||||
case 0x8D: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (osz == 2) set_reg16(emu, m.reg, (u16)m.ea);
|
||||
else set_reg32(emu, m.reg, m.ea);
|
||||
break;
|
||||
}
|
||||
/* ---- NOP / XCHG EAX,reg ---- */
|
||||
case 0x90: break; /* NOP */
|
||||
case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: {
|
||||
int r = op - 0x90;
|
||||
u32 tmp = emu->regs[0]; emu->regs[0] = emu->regs[r]; emu->regs[r] = tmp;
|
||||
break;
|
||||
}
|
||||
/* ---- CWDE/CDQ ---- */
|
||||
case 0x98: /* CWDE (32位) / CBW (16位) */
|
||||
if (osz == 2) set_reg16(emu, 0, (u16)(i16)(i8)get_reg8(emu, 0));
|
||||
else emu->regs[0] = (u32)(i32)(i16)get_reg16(emu, 0);
|
||||
break;
|
||||
case 0x99: /* CDQ (32位) / CWD (16位) */
|
||||
if (osz == 2) set_reg16(emu, 2, (get_reg16(emu, 0) & 0x8000) ? 0xFFFF : 0);
|
||||
else emu->regs[2] = (emu->regs[0] & 0x80000000) ? 0xFFFFFFFF : 0;
|
||||
break;
|
||||
/* ---- MOV moffs ---- */
|
||||
case 0xA0: { u32 addr = fetch32(emu); set_reg8(emu, 0, x86emu32_read8(emu, addr)); break; }
|
||||
case 0xA1: { u32 addr = fetch32(emu); if (osz==2) set_reg16(emu,0,x86emu32_read16(emu,addr)); else set_reg32(emu,0,x86emu32_read32(emu,addr)); break; }
|
||||
case 0xA2: { u32 addr = fetch32(emu); x86emu32_write8(emu, addr, get_reg8(emu, 0)); break; }
|
||||
case 0xA3: { u32 addr = fetch32(emu); if (osz==2) x86emu32_write16(emu,addr,get_reg16(emu,0)); else x86emu32_write32(emu,addr,get_reg32(emu,0)); break; }
|
||||
/* ---- 字符串指令(简化:无 REP 单步)---- */
|
||||
case 0xA4: { /* MOVSB */
|
||||
u32 si = emu->regs[X86_ESI], di = emu->regs[X86_EDI];
|
||||
u8 v = x86emu32_read8(emu, si);
|
||||
x86emu32_write8(emu, di, v);
|
||||
int df = get_flag(emu, X86_DF);
|
||||
si += df ? -1 : 1; di += df ? -1 : 1;
|
||||
emu->regs[X86_ESI] = si; emu->regs[X86_EDI] = di;
|
||||
break;
|
||||
}
|
||||
case 0xA5: { /* MOVSD/W */
|
||||
u32 si = emu->regs[X86_ESI], di = emu->regs[X86_EDI];
|
||||
int df = get_flag(emu, X86_DF); int step = (osz==2)?2:4;
|
||||
if (osz==2) { u16 v=x86emu32_read16(emu,si); x86emu32_write16(emu,di,v); }
|
||||
else { u32 v=x86emu32_read32(emu,si); x86emu32_write32(emu,di,v); }
|
||||
si += df ? -step : step; di += df ? -step : step;
|
||||
emu->regs[X86_ESI]=si; emu->regs[X86_EDI]=di;
|
||||
break;
|
||||
}
|
||||
case 0xAA: { /* STOSB */
|
||||
u32 di = emu->regs[X86_EDI];
|
||||
x86emu32_write8(emu, di, get_reg8(emu, 0));
|
||||
int df = get_flag(emu, X86_DF);
|
||||
di += df ? -1 : 1; emu->regs[X86_EDI] = di;
|
||||
break;
|
||||
}
|
||||
case 0xAB: { /* STOSD/W */
|
||||
u32 di = emu->regs[X86_EDI]; int df = get_flag(emu, X86_DF); int step=(osz==2)?2:4;
|
||||
if (osz==2) x86emu32_write16(emu,di,get_reg16(emu,0));
|
||||
else x86emu32_write32(emu,di,emu->regs[0]);
|
||||
di += df?-step:step; emu->regs[X86_EDI]=di;
|
||||
break;
|
||||
}
|
||||
case 0xAC: { /* LODSB */
|
||||
u32 si = emu->regs[X86_ESI];
|
||||
set_reg8(emu, 0, x86emu32_read8(emu, si));
|
||||
int df = get_flag(emu, X86_DF);
|
||||
si += df ? -1 : 1; emu->regs[X86_ESI] = si;
|
||||
break;
|
||||
}
|
||||
case 0xAD: { /* LODSD/W */
|
||||
u32 si = emu->regs[X86_ESI]; int df=get_flag(emu,X86_DF); int step=(osz==2)?2:4;
|
||||
if (osz==2) set_reg16(emu,0,x86emu32_read16(emu,si)); else set_reg32(emu,0,x86emu32_read32(emu,si));
|
||||
si += df?-step:step; emu->regs[X86_ESI]=si;
|
||||
break;
|
||||
}
|
||||
/* ---- TEST AL/EAX, imm ---- */
|
||||
case 0xA8: { u8 imm = fetch8(emu); alu_op(emu, 4, get_reg8(emu,0), imm, 1); break; }
|
||||
case 0xA9: {
|
||||
if (osz==2) { u16 imm=fetch16(emu); alu_op(emu,4,get_reg16(emu,0),imm,2); }
|
||||
else { u32 imm=fetch32(emu); alu_op(emu,4,emu->regs[0],imm,4); }
|
||||
break;
|
||||
}
|
||||
/* ---- MOV reg, imm ---- */
|
||||
case 0xB0: case 0xB1: case 0xB2: case 0xB3:
|
||||
case 0xB4: case 0xB5: case 0xB6: case 0xB7:
|
||||
set_reg8(emu, op - 0xB0, fetch8(emu));
|
||||
break;
|
||||
case 0xB8: case 0xB9: case 0xBA: case 0xBB:
|
||||
case 0xBC: case 0xBD: case 0xBE: case 0xBF:
|
||||
if (osz==2) set_reg16(emu, op-0xB8, fetch16(emu));
|
||||
else set_reg32(emu, op-0xB8, fetch32(emu));
|
||||
break;
|
||||
/* ---- shift r/m, imm8 ---- */
|
||||
case 0xC0: case 0xC1: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
u8 count = fetch8(emu);
|
||||
if (op == 0xC0) { u8 v = read_rm8(emu,&m); write_rm8(emu,&m,(u8)shift_op(emu,m.reg,v,count,1)); }
|
||||
else if (osz==2) { u16 v=read_rm16(emu,&m); write_rm16(emu,&m,(u16)shift_op(emu,m.reg,v,count,2)); }
|
||||
else { u32 v=read_rm32(emu,&m); write_rm32(emu,&m,shift_op(emu,m.reg,v,count,4)); }
|
||||
break;
|
||||
}
|
||||
/* ---- RET ---- */
|
||||
case 0xC2: { u16 imm = fetch16(emu); emu->eip = x86emu32_pop32(emu); emu->regs[X86_ESP] += imm; break; }
|
||||
case 0xC3: { emu->eip = x86emu32_pop32(emu); break; }
|
||||
/* ---- MOV r/m, imm ---- */
|
||||
case 0xC6: { modrm_dec m = decode_modrm(emu); u8 imm = fetch8(emu); write_rm8(emu,&m,imm); break; }
|
||||
case 0xC7: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (osz==2) { u16 imm=fetch16(emu); write_rm16(emu,&m,imm); }
|
||||
else { u32 imm=fetch32(emu); write_rm32(emu,&m,imm); }
|
||||
break;
|
||||
}
|
||||
/* ---- LEAVE ---- */
|
||||
case 0xC9:
|
||||
emu->regs[X86_ESP] = emu->regs[X86_EBP];
|
||||
emu->regs[X86_EBP] = x86emu32_pop32(emu);
|
||||
break;
|
||||
/* ---- INT3 / INT ---- */
|
||||
case 0xCC: /* INT3 */
|
||||
emu->error = 1; emu->error_msg = "INT3 breakpoint";
|
||||
break;
|
||||
case 0xCD: { /* INT imm8 */
|
||||
u8 v = fetch8(emu); (void)v;
|
||||
/* 简化:忽略软件中断 */
|
||||
break;
|
||||
}
|
||||
/* ---- shift r/m, 1 / CL ---- */
|
||||
case 0xD0: case 0xD1: case 0xD2: case 0xD3: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
u8 count = (op & 2) ? (get_reg8(emu, 1) & 0x1F) : 1;
|
||||
int is8 = !(op & 1);
|
||||
if (is8) { u8 v=read_rm8(emu,&m); write_rm8(emu,&m,(u8)shift_op(emu,m.reg,v,count,1)); }
|
||||
else if (osz==2) { u16 v=read_rm16(emu,&m); write_rm16(emu,&m,(u16)shift_op(emu,m.reg,v,count,2)); }
|
||||
else { u32 v=read_rm32(emu,&m); write_rm32(emu,&m,shift_op(emu,m.reg,v,count,4)); }
|
||||
break;
|
||||
}
|
||||
/* ---- CALL rel32 ---- */
|
||||
case 0xE8: {
|
||||
i32 rel = (i32)fetch32(emu);
|
||||
x86emu32_push32(emu, emu->eip); /* return address */
|
||||
emu->eip += (u32)rel;
|
||||
break;
|
||||
}
|
||||
/* ---- JMP rel32 ---- */
|
||||
case 0xE9: { i32 rel = (i32)fetch32(emu); emu->eip += (u32)rel; break; }
|
||||
/* ---- JMP rel8 ---- */
|
||||
case 0xEB: { i8 rel = (i8)fetch8(emu); emu->eip += (u32)(i32)rel; break; }
|
||||
/* ---- LOOP ---- */
|
||||
case 0xE0: case 0xE1: case 0xE2: {
|
||||
i8 rel = (i8)fetch8(emu);
|
||||
u32 cx = emu->regs[X86_ECX] - 1;
|
||||
emu->regs[X86_ECX] = cx;
|
||||
int do_jump = (cx != 0);
|
||||
if (op == 0xE0 && get_flag(emu, X86_ZF)) do_jump = 0; /* LOOPNE */
|
||||
if (op == 0xE1 && !get_flag(emu, X86_ZF)) do_jump = 0; /* LOOPE */
|
||||
if (do_jump) emu->eip += (u32)(i32)rel;
|
||||
break;
|
||||
}
|
||||
case 0xE3: { /* JECXZ */
|
||||
i8 rel = (i8)fetch8(emu);
|
||||
if (emu->regs[X86_ECX] == 0) emu->eip += (u32)(i32)rel;
|
||||
break;
|
||||
}
|
||||
/* ---- CALL/JMP r/m ---- */
|
||||
case 0xFF: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
switch (m.reg) {
|
||||
case 0: { /* INC r/m */
|
||||
int cf=get_flag(emu,X86_CF);
|
||||
if (osz==2) { u16 v=read_rm16(emu,&m); write_rm16(emu,&m,(u16)alu_op(emu,0,v,1,2)); }
|
||||
else { u32 v=read_rm32(emu,&m); write_rm32(emu,&m,alu_op(emu,0,v,1,4)); }
|
||||
set_flag(emu,X86_CF,cf);
|
||||
break;
|
||||
}
|
||||
case 1: { /* DEC r/m */
|
||||
int cf=get_flag(emu,X86_CF);
|
||||
if (osz==2) { u16 v=read_rm16(emu,&m); write_rm16(emu,&m,(u16)alu_op(emu,5,v,1,2)); }
|
||||
else { u32 v=read_rm32(emu,&m); write_rm32(emu,&m,alu_op(emu,5,v,1,4)); }
|
||||
set_flag(emu,X86_CF,cf);
|
||||
break;
|
||||
}
|
||||
case 2: { /* CALL r/m32 */
|
||||
u32 target = read_rm32(emu, &m);
|
||||
if (try_iat_call(emu, target)) break;
|
||||
x86emu32_push32(emu, emu->eip);
|
||||
emu->eip = target;
|
||||
break;
|
||||
}
|
||||
case 4: { /* JMP r/m32 */
|
||||
u32 target = read_rm32(emu, &m);
|
||||
if (try_iat_call(emu, target)) { emu->exited = 1; break; }
|
||||
emu->eip = target;
|
||||
break;
|
||||
}
|
||||
case 6: { /* PUSH r/m32 */
|
||||
x86emu32_push32(emu, read_rm32(emu, &m));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
emu->error = 1; emu->error_msg = "FF /reg unsupported";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* ---- F6/F7 组 ---- */
|
||||
case 0xF6: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (m.reg == 0 || m.reg == 1) { /* TEST r/m8, imm8 */
|
||||
u8 imm = fetch8(emu);
|
||||
alu_op(emu, 4, read_rm8(emu,&m), imm, 1);
|
||||
} else if (m.reg == 2) { /* NOT r/m8 */
|
||||
write_rm8(emu, &m, ~read_rm8(emu, &m));
|
||||
} else if (m.reg == 3) { /* NEG r/m8 */
|
||||
u8 v = read_rm8(emu, &m);
|
||||
u8 r = (u8)(-(i8)v);
|
||||
set_flag(emu, X86_CF, v != 0);
|
||||
set_zf_sf_pf(emu, r, 1);
|
||||
write_rm8(emu, &m, r);
|
||||
} else if (m.reg == 4) { /* MUL r/m8 */
|
||||
u16 result = (u16)get_reg8(emu, 0) * (u16)read_rm8(emu, &m);
|
||||
set_reg8(emu, 0, (u8)result);
|
||||
set_reg8(emu, 4, (u8)(result >> 8));
|
||||
set_flag(emu, X86_CF, result >> 8 != 0);
|
||||
set_flag(emu, X86_OF, get_flag(emu, X86_CF));
|
||||
} else {
|
||||
emu->error = 1; emu->error_msg = "F6 /reg unsupported";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0xF7: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (m.reg == 0 || m.reg == 1) { /* TEST r/m32, imm32 */
|
||||
if (osz==2) { u16 imm=fetch16(emu); alu_op(emu,4,read_rm16(emu,&m),imm,2); }
|
||||
else { u32 imm=fetch32(emu); alu_op(emu,4,read_rm32(emu,&m),imm,4); }
|
||||
} else if (m.reg == 2) { /* NOT */
|
||||
if (osz==2) write_rm16(emu,&m,~read_rm16(emu,&m));
|
||||
else write_rm32(emu,&m,~read_rm32(emu,&m));
|
||||
} else if (m.reg == 3) { /* NEG */
|
||||
if (osz==2) { u16 v=read_rm16(emu,&m); u16 r=(u16)(-(i16)v); set_flag(emu,X86_CF,v!=0); set_zf_sf_pf(emu,r,2); write_rm16(emu,&m,r); }
|
||||
else { u32 v=read_rm32(emu,&m); u32 r=(u32)(-(i32)v); set_flag(emu,X86_CF,v!=0); set_zf_sf_pf(emu,r,4); write_rm32(emu,&m,r); }
|
||||
} else if (m.reg == 4) { /* MUL */
|
||||
if (osz==2) { u32 result=(u32)get_reg16(emu,0)*(u32)read_rm16(emu,&m); set_reg16(emu,0,(u16)result); set_reg16(emu,2,(u16)(result>>16)); set_flag(emu,X86_CF,result>>16!=0); set_flag(emu,X86_OF,get_flag(emu,X86_CF)); }
|
||||
else { u64 result=(u64)emu->regs[0]*(u64)read_rm32(emu,&m); emu->regs[0]=(u32)result; emu->regs[2]=(u32)(result>>32); set_flag(emu,X86_CF,result>>32!=0); set_flag(emu,X86_OF,get_flag(emu,X86_CF)); }
|
||||
} else if (m.reg == 5) { /* IMUL */
|
||||
if (osz==2) { i32 result=(i32)(i16)get_reg16(emu,0)*(i32)(i16)read_rm16(emu,&m); set_reg16(emu,0,(u16)result); set_reg16(emu,2,(u16)(result>>16)); set_flag(emu,X86_OF,result>32767||result<-32768); set_flag(emu,X86_CF,get_flag(emu,X86_OF)); }
|
||||
else { i64 result=(i64)(i32)emu->regs[0]*(i64)(i32)read_rm32(emu,&m); emu->regs[0]=(u32)result; emu->regs[2]=(u32)(result>>32); set_flag(emu,X86_OF,result>0x7FFFFFFFLL||result<-0x80000000LL); set_flag(emu,X86_CF,get_flag(emu,X86_OF)); }
|
||||
} else if (m.reg == 6) { /* DIV */
|
||||
if (osz==2) { u32 dividend=((u32)get_reg16(emu,2)<<16)|get_reg16(emu,0); u16 divisor=read_rm16(emu,&m); if(divisor){set_reg16(emu,0,(u16)(dividend/divisor));set_reg16(emu,2,(u16)(dividend%divisor));} }
|
||||
else { u64 dividend=((u64)emu->regs[2]<<32)|emu->regs[0]; u32 divisor=read_rm32(emu,&m); if(divisor){emu->regs[0]=(u32)(dividend/divisor);emu->regs[2]=(u32)(dividend%divisor);} }
|
||||
} else if (m.reg == 7) { /* IDIV */
|
||||
if (osz==2) { i32 dividend=((i32)(i16)get_reg16(emu,2)<<16)|(i16)get_reg16(emu,0); i16 divisor=(i16)read_rm16(emu,&m); if(divisor){set_reg16(emu,0,(u16)(dividend/divisor));set_reg16(emu,2,(u16)(dividend%divisor));} }
|
||||
else { i64 dividend=((i64)(i32)emu->regs[2]<<32)|(i32)emu->regs[0]; i32 divisor=(i32)read_rm32(emu,&m); if(divisor){emu->regs[0]=(u32)(dividend/divisor);emu->regs[2]=(u32)(dividend%divisor);} }
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* ---- CLC/STC/CLI/STI/CLD/STD ---- */
|
||||
case 0xF8: set_flag(emu, X86_CF, 0); break;
|
||||
case 0xF9: set_flag(emu, X86_CF, 1); break;
|
||||
case 0xFA: break; /* CLI(忽略) */
|
||||
case 0xFB: break; /* STI(忽略) */
|
||||
case 0xFC: set_flag(emu, X86_DF, 0); break;
|
||||
case 0xFD: set_flag(emu, X86_DF, 1); break;
|
||||
/* ---- INC/DEC r/m8 ---- */
|
||||
case 0xFE: {
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
int cf = get_flag(emu, X86_CF);
|
||||
u8 v = read_rm8(emu, &m);
|
||||
if (m.reg == 0) write_rm8(emu, &m, (u8)alu_op(emu, 0, v, 1, 1));
|
||||
else if (m.reg == 1) write_rm8(emu, &m, (u8)alu_op(emu, 5, v, 1, 1));
|
||||
set_flag(emu, X86_CF, cf);
|
||||
break;
|
||||
}
|
||||
/* ---- MOVSX/MOVZX 在 0x0F 两字节 opcode 中处理 ---- */
|
||||
case 0x0F: { /* 两字节 opcode */
|
||||
u8 op2 = fetch8(emu);
|
||||
if (op2 >= 0x80 && op2 <= 0x8F) { /* Jcc rel32 */
|
||||
i32 rel = (i32)fetch32(emu);
|
||||
if (check_jcc(emu, op2 & 0xF)) emu->eip += (u32)rel;
|
||||
} else if (op2 == 0xAF) { /* IMUL r32, r/m32 */
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
i64 result = (i64)(i32)get_reg32(emu, m.reg) * (i64)(i32)read_rm32(emu, &m);
|
||||
set_reg32(emu, m.reg, (u32)result);
|
||||
set_flag(emu, X86_OF, result > 0x7FFFFFFFLL || result < -0x80000000LL);
|
||||
set_flag(emu, X86_CF, get_flag(emu, X86_OF));
|
||||
} else if (op2 == 0xB6 || op2 == 0xB7) { /* MOVZX r32, r/m8/16 */
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (op2 == 0xB6) { set_reg32(emu, m.reg, (u32)read_rm8(emu, &m)); }
|
||||
else { set_reg32(emu, m.reg, (u32)read_rm16(emu, &m)); }
|
||||
} else if (op2 == 0xBE || op2 == 0xBF) { /* MOVSX r32, r/m8/16 */
|
||||
modrm_dec m = decode_modrm(emu);
|
||||
if (op2 == 0xBE) { set_reg32(emu, m.reg, (u32)(i32)(i8)read_rm8(emu, &m)); }
|
||||
else { set_reg32(emu, m.reg, (u32)(i32)(i16)read_rm16(emu, &m)); }
|
||||
} else if (op2 == 0x1F) { /* NOP r/m(多字节 NOP) */
|
||||
decode_modrm(emu);
|
||||
} else if (op2 == 0x05) { /* SYSCALL(不应出现在32位PE) */
|
||||
emu->error = 1; emu->error_msg = "SYSCALL in 32-bit PE";
|
||||
} else {
|
||||
emu->error = 1; emu->error_msg = "0F opcode unsupported";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
emu->error = 1; emu->error_msg = "unsupported opcode";
|
||||
break;
|
||||
} /* end switch(op) */
|
||||
|
||||
if (emu->error) {
|
||||
log_hex64("[PE32] error at EIP=", emu->eip);
|
||||
log_hex64("[PE32] opcode=", op);
|
||||
log_info("[PE32] ");
|
||||
log_info(emu->error_msg ? emu->error_msg : "(null)");
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
if (emu->insn_count >= emu->insn_limit) {
|
||||
log_error("[PE32] instruction limit reached");
|
||||
emu->error = 1;
|
||||
}
|
||||
|
||||
if (exit_code) *exit_code = emu->exit_code;
|
||||
return emu->error ? -1 : 0;
|
||||
}
|
||||
|
||||
int x86emu32_init(x86emu_state *emu, u8 *mem, u64 mem_size,
|
||||
u32 image_base, u32 image_size,
|
||||
pe_iat_entry *iat_entries, int iat_count,
|
||||
u32 stack_top) {
|
||||
for (int i = 0; i < 8; i++) emu->regs[i] = 0;
|
||||
emu->eip = 0;
|
||||
emu->eflags = 0x2; /* 保留位 = 1 */
|
||||
emu->mem = mem;
|
||||
emu->mem_size = mem_size;
|
||||
emu->image_base = image_base;
|
||||
emu->image_size = image_size;
|
||||
emu->iat_entries = iat_entries;
|
||||
emu->iat_count = iat_count;
|
||||
emu->stack_base = stack_top;
|
||||
emu->stack_size = 0x10000; /* 64KB 栈 */
|
||||
emu->heap_base = image_base + image_size;
|
||||
emu->heap_size = 0x100000; /* 1MB heap */
|
||||
emu->heap_next = emu->heap_base;
|
||||
emu->exited = 0;
|
||||
emu->exit_code = 0;
|
||||
emu->error = 0;
|
||||
emu->error_msg = 0;
|
||||
emu->insn_count = 0;
|
||||
|
||||
/* 设置 ESP 到栈顶,对齐 16 */
|
||||
emu->regs[X86_ESP] = stack_top & ~0xFu;
|
||||
emu->regs[X86_EBP] = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#ifndef X86EMU32_H
|
||||
#define X86EMU32_H
|
||||
|
||||
/* x86emu32.h — x86-32 指令解释器(PE32 执行引擎)。
|
||||
*
|
||||
* 寄存器级解释执行 32位 PE 代码。覆盖 mingw-w64 控制台程序常用指令集。
|
||||
* 遇不支持的指令时日志告警并返回错误。
|
||||
*/
|
||||
|
||||
#include <utsm/types.h>
|
||||
|
||||
/* x86 通用寄存器索引 */
|
||||
enum {
|
||||
X86_EAX = 0, X86_ECX, X86_EDX, X86_EBX,
|
||||
X86_ESP, X86_EBP, X86_ESI, X86_EDI
|
||||
};
|
||||
|
||||
/* EFLAGS 位 */
|
||||
#define X86_CF (1u << 0)
|
||||
#define X86_PF (1u << 2)
|
||||
#define X86_AF (1u << 4)
|
||||
#define X86_ZF (1u << 6)
|
||||
#define X86_SF (1u << 7)
|
||||
#define X86_OF (1u << 11)
|
||||
#define X86_DF (1u << 10)
|
||||
|
||||
/* IAT 条目信息(解释器用于 CALL 拦截) */
|
||||
typedef struct pe_iat_entry {
|
||||
u32 iat_rva; /* IAT 中该条目的 RVA */
|
||||
int shim_index; /* 对应 shim 表索引,-1 = 未实现 stub */
|
||||
u32 target_addr; /* 模拟地址(iat_rva + image_base) */
|
||||
} pe_iat_entry;
|
||||
|
||||
typedef struct x86emu_state {
|
||||
u32 regs[8]; /* EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI */
|
||||
u32 eip; /* 指令指针(相对 mem 基址的偏移) */
|
||||
u32 eflags;
|
||||
|
||||
u8 *mem; /* guest 内存基址(= PE image_base) */
|
||||
u64 mem_size; /* guest 内存大小 */
|
||||
|
||||
u32 image_base; /* PE 加载基址(= mem,32位截断) */
|
||||
u32 image_size;
|
||||
|
||||
/* IAT 表(用于 CALL 拦截) */
|
||||
pe_iat_entry *iat_entries;
|
||||
int iat_count;
|
||||
|
||||
/* 栈区 */
|
||||
u32 stack_base; /* 栈底(高地址) */
|
||||
u32 stack_size;
|
||||
|
||||
/* heap 区 */
|
||||
u32 heap_base;
|
||||
u32 heap_size;
|
||||
u32 heap_next; /* 下次分配偏移 */
|
||||
|
||||
/* 退出状态 */
|
||||
int exited; /* ExitProcess 被调用 */
|
||||
u64 exit_code;
|
||||
int error; /* 解释错误 */
|
||||
const char *error_msg;
|
||||
|
||||
/* 指令计数限制(防死循环) */
|
||||
u64 insn_count;
|
||||
u64 insn_limit;
|
||||
} x86emu_state;
|
||||
|
||||
/* 初始化解释器状态。
|
||||
* mem = PE image 加载基址(已映射节区+重定位+IAT 填充)。
|
||||
* iat_entries / iat_count = pe_loader 解析的 IAT 表。
|
||||
* stack_top = 栈顶 ESP 初始值(相对 mem 的偏移)。
|
||||
* 返回 0 成功。 */
|
||||
int x86emu32_init(x86emu_state *emu, u8 *mem, u64 mem_size,
|
||||
u32 image_base, u32 image_size,
|
||||
pe_iat_entry *iat_entries, int iat_count,
|
||||
u32 stack_top);
|
||||
|
||||
/* 执行直到 ExitProcess 或错误。
|
||||
* 返回 0 正常退出(exit_code 有效),负数错误。 */
|
||||
int x86emu32_run(x86emu_state *emu, u64 *exit_code);
|
||||
|
||||
/* 从模拟栈读取 N 个参数(cdecl/stdcall)。
|
||||
* esp_offset = 参数相对 ESP 的偏移(0=第一个参数)。
|
||||
* 返回参数值。 */
|
||||
u64 x86emu32_read_arg(x86emu_state *emu, int esp_offset);
|
||||
|
||||
/* 模拟栈 push/pop(供 shim32 回调使用) */
|
||||
void x86emu32_push32(x86emu_state *emu, u32 val);
|
||||
u32 x86emu32_pop32(x86emu_state *emu);
|
||||
|
||||
/* 读写模拟内存 */
|
||||
u8 x86emu32_read8(x86emu_state *emu, u32 addr);
|
||||
u16 x86emu32_read16(x86emu_state *emu, u32 addr);
|
||||
u32 x86emu32_read32(x86emu_state *emu, u32 addr);
|
||||
void x86emu32_write8(x86emu_state *emu, u32 addr, u8 val);
|
||||
void x86emu32_write16(x86emu_state *emu, u32 addr, u16 val);
|
||||
void x86emu32_write32(x86emu_state *emu, u32 addr, u32 val);
|
||||
|
||||
#endif /* X86EMU32_H */
|
||||
Reference in New Issue
Block a user