# VMP 离线业务逻辑恢复(v1.1.0) `ig5_ir level=trace` 接收已经采集的 x86-64 指令、寄存器和内存读取记录,在独立 Triton 子进程中建立输入输出表达式。不启动样本、不打开数据库、不启动 JVM。Core8 / Full40 与执行审批门保持不变;先用 `ig5_profile toolset=full` 展开入口。 当前实现处理 SysV 的 `dil/sil`、`di/si`、`edi/esi`、`rdi/rsi`,以及 Win64 的 `cl/dl`、`cx/dx`、`ecx/edx`、`rcx/rdx` 同宽输入;返回值为 `al/ax/eax/rax`。混合寄存器组拒绝。原生采集通过下述既有审批调试入口执行;离线恢复本身不执行目标。OS/import 语义仍无通用模型。依赖为单独固定的 Windows x64 CPython 3.12 Triton 1.0.0rc4 wheel,保留原始布局、RECORD、逐文件 hash 和许可;普通调用不下载依赖、不改全局 Python/PATH。 ```json { "target": "C:/path/sample.vmp.bin", "level": "trace", "traces": [{"path": "C:/path/sample.trace", "sha256": "64位小写SHA256"}], "trace_entry": "0x4011c0", "trace_exit": "0x4011ef", "trace_inputs": ["edi", "esi"], "trace_output": "eax", "initial_flags": "0x202", "max_instructions": 50000 } ``` 省略 `action`、数据库/内核专用参数。entry/exit 指第一条/最后一条记录的地址,必须显式核对是否包括 RET;只声明边界不会证明轨迹涵盖了整个函数。initial_flags 为记录环境的 EFLAGS 假设,未记录的初始寄存器高位和初始内存也属于固定环境。 支持作者发布的三种 ASCII 记录:`r:` 后为 RAX/RBX/RCX/RDX/RDI/RSI/RBP/RSP/R8..R15 的 16 个 64 位十六进制数;`mr:地址:字节数:小端整数值`;`i:地址:字节数:机器码hex`。每条指令必须有前置寄存器快照,输入按原始文件 SHA 绑定;文件最多 4 MiB,最多两份/合计 8 MiB,各最多 50,000 指令,内存记录最多 1 MiB,128 次求解、每次 2 秒/512 MiB、子进程请求硬期限 60 秒。超限/取消/不支持/状态冲突不发布恢复证明。取消只终止所属子进程。 `recoveredExpression` 是结构化位向量表达式,8 位输出按模 256 回绕;不将 EAX 的高位冒认为 char 返回值。候选合成、低位投影都经独立 SMT 反例查询,只有 `unsat` 发布等价。地址选择与原生控制流约束决定路径;两份互补路径经互斥/覆盖查询才能合并 select。除有限 x/y signed/unsigned 比较外,还从记录条件的 AST 提取小型 add/sub/xor/and/or 候选及常量(包括相邻值和二补码),最多 2,048 个遍历节点、3 个种子、4 个常量和 42 个谓词;每个发布条件都须证明等价。达到候选求解预算时保留未知约束,不升级为完整模型。`guard.conditionExpression` / `select.conditionExpression` 为结构化谓词,旧 `condition` 文本仍保留。 未定义标志位、零输入 BSF/BSR 目标和 CPUID/RDTSC 观测保留为独立未知量;仅根据快照求取其记录值,禁止覆盖输入依赖。普通状态冲突、缺失初始内存、syscall/interrupt 或输入相关 CPUID 明确拒绝。返回表达式与未知量无关仍须证明。最大值样本的路径归约依赖记录中的两个 AF=0 环境观察,报告逐项列出。 返回值仍依赖硬件/未定义环境量时,结构化表达式用 `op=environment` 保留变量及是否有明确观察,不伪装为 x/y 参数,也不固定成普通常量。表达式等价证明与输入域恢复分开:这类路径仍为 partial,`recoveredExpression=null`;有快照也不等于跨环境业务恢复。 ELF 轨迹字节绑定按 PT_LOAD,仍核验范围/对齐/重叠/初始化字节,不依赖壳修改后的 section 语义;静态 kernel 原有严格 section 检查保持默认。报告包含每条轨迹的 SHA、指令数、字节匹配统计、环境读取、快照协调、路径条件、证明和独立保存报告 ID/hash/path。产物保存在 `artifactDir/trace-recovery`,不改数据库修订。 `coverage=trace-model-input-domain` 仅表示所供轨迹模型在已声明输入域及记录环境下覆盖;`wholeBinaryVerified=false` 始终保留。指令字节相符也不能证明所有真实运行路径、外部副作用、不同硬件环境或隐藏服务器实现均已恢复。只读静态 SSA、轨迹恢复、原生采集/执行的证据分别报告。 ## 三份实际样本 固定来源为 [作者研究仓库](https://github.com/JonathanSalwan/VMProtect-devirtualization/tree/d2b26d66db59e341f179c7e326246d28c4d25491)。外部样本及轨迹只保存在 artifacts,不分发、不启动;没有运行上游 attack 脚本,也没有向恢复器提供参考业务公式。 | 样本 | 记录指令数 | 恢复返回值 | 独立验证 | | --- | ---: | --- | --- | | sample2.vmp.bin | 12,462 | x XOR y(32 位) | SMT + 边界/固定随机对 | | sample3.vmp.bin | 25,085 | ((x XOR 0x5c) + y) mod 256 | SMT + 原 MBA 的全部 65,536 个输入对 | | sample4.vmp.bin | 17,986 / 18,068 | signed(x)` 继续使用公共审批,新增只读 `selectedThreadDebuggerVisibility`。它通过 Windows `NtQueryInformationThread` 的 ThreadHideFromDebugger 类观察;成功给出 True/False,失败给出 null、NTSTATUS/Windows错误,不能把权限不足当作未隐藏。读取不调用隐藏/恢复线程API,不切换调试器当前线程。`selectedThreadRegisterObservationScope` 明确:稳定调试暂停 epoch 不等于独立证明隐藏线程已暂停或所有寄存器具有一致性。 原生验收入口为 `scripts/test_thread_visibility_runtime.mjs <自产编译证明目录> <全新证据目录>`,仅使用 `scripts/fixtures/debug_hidden_thread.c` 的编译证明。主线程先可见,再自设隐藏;可见辅助线程制造可观测暂停。须验证 False→True、辅助线程 False、当前线程与GPR/暂停序号不变、目标SHA不变。该验收证明诊断能力,不证明隐藏线程可正常单步,也不证明 Enigma 或其他壳的业务逻辑已经恢复。