进程里直接跑机器码:轻量 x86-64 仿真库 Cpueaxh 的 Guest/Host 双模式拆解

进程里直接跑机器码:轻量 x86-64 仿真库 Cpueaxh 的 Guest/Host 双模式拆解

进程里直接跑机器码:轻量 x86-64 仿真库 Cpueaxh 的 Guest/Host 双模式拆解

进程内仿真 Cpueaxh 封面

说明:微信源页触发「环境异常 / 验证码」,无法直读原文。本文按题意(开源 x86-64 CPU 仿真库 Cpueaxh),并基于官方仓库 saileaxh/cpueaxh 的中英文 README、公开 API 头文件与示例说明做工程向改写;版本口径以撰写时 README 为准。本篇只讨论合法研究/插桩场景下的仿真执行与宿主对接,不涉及对抗检测、绕过安全产品或恶意利用。

做二进制分析、沙箱原型或主机侧插桩时,很多人第一反应是上 Unicorn:自己 mem_map 一块客户机地址空间,再 emu_start。这很稳,但有一类需求它不够顺手——你已经在本进程里,目标函数就躺在真实虚拟地址上,只想「用模拟 CPU 跑一段,而不是再拷一份镜像」。

saileaxh/cpueaxh(MIT)把这件事做成了产品点:轻量、无第三方依赖的 x86-64 仿真库,API 尽量贴近 Unicorn,同时提供:

  • Guest 模式:自管理内存,用法接近传统模拟器;
  • Host 模式:直接对着当前进程真实地址空间模拟执行,并支持内存补丁叠层(模拟 CPU 看到的字节可以和底层真实内存不一致)。

同一套核心还能经薄平台层编进用户态静态库或内核驱动侧(kcpueaxh + KMDF 示例)。项目仍在积极开发,不是完整 Unicorn 替代品,也不是系统级虚拟化;但已经覆盖常用整数/控制流/字符串指令,以及 SSE/SSE2/AVX/部分 AVX2,并带状态化异常、Hook 与指令 Escape。


一、它解决什么问题:Guest 够用,Host 才是差异化

Mermaid Diagram

维度 Guest 模式 Host 模式
内存来源 用户显式映射 当前进程真实地址空间
典型用途 隔离执行、自建沙箱页 主机侧跟踪、在线函数分析、插桩实验
补丁 正常写映射页 mem_patch_* 叠层:模拟视图 ≠ 真实内存
API 气质 刻意接近 Unicorn 额外暴露完整 cpueaxh_x86_context、Escape/Host Call

README 的定位很清楚:研究向 / 实验向 x86-64 模拟器、Windows 主机分析与插桩核心、轻量执行引擎。若你要跨架构(ARM + Dalvik)或完整系统仿真,应继续看 Unicorn / QEMU / Unidbg 一类方案——本篇同日另有 Unidbg+MCP 文,产品与问题域不同,勿混为一谈。

Cpueaxh Guest 与 Host 双模式示意


二、工程画像:C ABI、静态库、用户态与内核共用核心

公开接口在 cpueaxh/cpueaxh.hpp,导出符号统一 cpueaxh_*,C/C++ 均可调用。核心以静态库形式集成(VS2022 / MSVC v143 / x64);内核示例 kexample 链接 kcpueaxh,演示 KMDF 非 PnP 驱动里跑 Host 模式。

设计取舍(对实践有感的几条):

1. 执行不依赖异常处理机制:异常状态写在 CPU 上下文里,用 cpueaxh_code_exception() / cpueaxh_error_code_exception() 查询,而不是靠宿主 SEH/VEH「撞出来」。

2. 已建模的 CPU 异常:#DE #GP #SS #NP #UD #PF #AC。

3. 页属性不止 R/W/X:cpueaxh_mem_set_cpu_attrs() + CPUEAXH_MEM_ATTR_USER,CPL 与页属性不匹配时可走正确的页错误语义。

4. Guest 内存语义类 Unicorn:4KB 对齐、unmap/protect 可按区间拆分、区分 UNMAPPED / PROT 的读/写/取指结果。

仓库骨架可记成:

cpueaxh/          # 用户态核心静态库
cpu/ # 上下文、执行器、访存
memory/ # 虚拟内存管理
instructions/ # 指令族实现
example/ # 用户态示例(含 Hook / Escape / Host MessageBox 等)
kcpueaxh/ # 内核态静态库变体
kexample/ # KMDF Host 示例

构建环境目前以 Windows + Visual Studio 2022 + WDK/KMDF(可选) 为主;示例除 MSVC/MASM 外无额外第三方库依赖。


三、最小可用路径:打开引擎 → 映射 → 跑起来

下面片段直接来自官方 README 的「快速示例」口径,适合作为集成冒烟测试。

1. 创建引擎

cpueaxh_engine* engine = NULL;
cpueaxh_err err = cpueaxh_open(CPUEAXH_ARCH_X86, CPUEAXH_MODE_64, &engine);
if (err != CPUEAXH_ERR_OK) {
/* 处理打开失败 */
}

2. Guest:映射代码页并写入机器码

cpueaxh_set_memory_mode(engine, CPUEAXH_MEMORY_MODE_GUEST);
cpueaxh_mem_map(engine, 0x1000, 0x1000,
CPUEAXH_PROT_READ | CPUEAXH_PROT_WRITE | CPUEAXH_PROT_EXEC);
cpueaxh_mem_write(engine, 0x1000, code, code_size);

3. 设置 RIP 并启动

uint64_t rip = 0x1000;
cpueaxh_reg_write(engine, CPUEAXH_X86_REG_RIP, &rip);
cpueaxh_emu_start(engine, 0x1000, 0, 0, 0);

4. 枚举映射区

cpueaxh_mem_region* regions = NULL;
uint32_t count = 0;
if (cpueaxh_mem_regions(engine, &regions, &count) == CPUEAXH_ERR_OK) {
/* 使用 regions[0..count) */
cpueaxh_free(regions);
}

生命周期上记得配对 cpueaxh_close()。寄存器用 cpueaxh_reg_read / cpueaxh_reg_write;执行还有 cpueaxh_emu_start_function() 与 cpueaxh_emu_stop()。

边界:指令覆盖仍在扩展中;遇到未实现操作码会走 #UD 等异常路径。上线前用目标工作负载做覆盖率抽检,不要假设「能跑完任意商业 PE」。


四、Hook 与 Escape:观察流、补洞、把特权指令交回宿主

Cpueaxh 的可观测性分三层,和 Unicorn 用户的心智模型基本对齐,但 Escape + cpueaxh_host_call() 是 Host 场景的关键拼图。

Hook Escape 与 Host Call 协作

1. 代码与内存 Hook

  • cpueaxh_hook_add() / cpueaxh_hook_del()
  • cpueaxh_hook_add_address():精确地址
  • 代码:CPUEAXH_HOOK_CODE_PRE / POST
  • 成功访存:MEM_READ / WRITE / FETCH(回调拿地址、大小、值)
  • 非法访存:*_UNMAPPED / *_PROT;回调可修复映射/权限后返回非 0 让引擎重试,返回 0 则维持失败路径

示例工程里演示了:pre-hook 打印后续 16 字节、post-hook 打 RIP、精确地址 hook、访存观察、以及 READ_UNMAPPED / WRITE_PROT 自愈。

2. Escape:把「不该在纯软模拟里硬扛」的指令交出去

按指令类别注册(当前每类一个 Escape),可限制地址范围。已支持类别包括:

syscall / sysenter、int / int3 / hlt、cpuid / xgetbv / rdtsc / rdtscp / rdrand、rdsspd / rdsspq、端口 in / out。

回调拿到已解码指令字节 + 可修改的 cpueaxh_x86_context,两条路:

1. 纯 C/C++ 软模拟(示例里 rdtsc / rdtscp / rdrand 等);

2. cpueaxh_host_call() 原生桥:把模拟上下文的寄存器/标志/SIMD 灌进真实 CPU 上下文 → 跳进用户桥接例程 → 再把结果写回模拟上下文。桥接前 guest 栈顶会预置恢复地址,例程结束可通过 [rsp] 跳回模拟流。示例对 syscall / cpuid / xgetbv 用了 MASM 原生桥。

公开的 cpueaxh_x86_context 含 GPR、RIP、RFLAGS、XMM/高位 YMM、MMX、MXCSR、段寄存器、GDTR/LDTR、CPL、当前异常状态——Host 模式、Escape、调试同步都靠它。

3. Host 模式补丁

cpueaxh_mem_patch_add() / cpueaxh_mem_patch_del():让模拟 CPU 看见与真实内存不同的字节,适合「只改模拟视图、不动宿主映像」的实验。示例含 Host 下跑 MessageBoxA 与补丁演示——请在自有样本与授权环境中复现,勿对未授权第三方进程做注入式实验。


五、和 Unicorn / Unidbg 怎么选(防预期错位)

需求 更合适的选择 原因
多架构、生态成熟、跨平台脚本 Unicorn 覆盖广、绑定多、社区大
Android/iOS Native + JNI/ART Unidbg Dalvik/JNI 补环境是强项
Windows 进程内就地跑 x64、要补丁叠层 / Escape 回宿主 Cpueaxh Host 模式 + 用户态/内核同核
完整 OS / 设备模型 QEMU 等 Cpueaxh 明确不做系统虚拟化

诚实边界(来自 README 定位):

  • 积极开发中,目标含完整 x86-64 与 Heaven's Gate,但现状是「常用指令 + 部分 SIMD」;
  • 非完整 Unicorn 替代;
  • 构建与示例偏 Windows/MSVC;跨平台移植要自己评估平台抽象层成本;
  • Escape 每指令类仅一个注册槽——复杂多插件场景要自己做分发层。

六、排坑清单(集成前先过一遍)

1. 页对齐:Guest 映射按 4KB;随意地址会在 map/protect 阶段失败。

2. 模式切错:Host 下再按 Guest 习惯 mem_map 一块「假进程」会浪费时间;先 cpueaxh_set_memory_mode。

3. 未实现指令:用 #UD / Escape 兜底策略提前设计,避免长跑到一半静默偏航。

4. 非法访存回调语义:返回值决定「重试还是失败」;忘记修复映射会陷入反复失败。

进程里直接跑机器码:轻量 x86-64 仿真库 Cpueaxh 的 Guest/Host 双模式拆解

5. 内核示例:需要 WDK/KMDF;先在用户态 example 验证逻辑再上驱动。

6. 合规:Host 模式能力强,只用于授权分析、自有软件测试与研究原型。

配套目录 practice/ 可放你本地精简的 Guest 冒烟工程(机器码片段 + 寄存器断言)。本环境为 Linux 沙箱,未强行交叉编译 Windows/MSVC 工程;以官方 example/main.cpp 为准做复现。


七、小结

Cpueaxh(saileaxh/cpueaxh)把「类 Unicorn 的 Guest 沙箱」和「对着真实进程 VA 的 Host 模拟」放进同一份无依赖 x86-64 核心,再用 Hook、状态化异常、Escape/host_call 和内存补丁叠层补齐主机侧分析闭环。适合做 Windows 向研究引擎与插桩原型;若要多架构生态或移动 Native 全家桶,请继续 Unicorn / Unidbg。先跑通 Guest 冒烟,再按需切 Host——比一上来对复杂二进制「全量仿真」更不容易踩坑。

仓库:https://github.com/saileaxh/cpueaxh
协议:MIT
交流:README 公布的 QQ 群 / Discord(以仓库为准)

💻 配套实训环境与动手练习

本文涉及的相关技术指令、开发环境与工具链已内置在边学边练在线实验室中,无需繁琐安装配置,随时在浏览器中实践体验:

文章版权声明:除非注明,否则均为边学边练网络文章,版权归原作者所有

最新文章

热门文章

本栏目文章