x86-64指令集是否存在阻碍反向取指与逆向确定指令边界的根本特性
x86-64 反向取指可行性结论
x86-64 指令集本身存在固有编码特性,无法实现通用、100% 可靠的反向取指,哪怕完全排除分支跳转、ROP 非对齐执行等场景,也无法仅通过指令结束边界逆向推导出前一条指令的准确起始位置,核心原因如下:
- 指令前缀无唯一标识
x86-64 的指令前缀(包括 REX、VEX/EVEX、操作数/地址大小覆盖、段超越等前缀)均为单字节可选字段,取值范围和操作码、立即数、位移字段完全重叠。例如0x48既可以是 REX.W 前缀,也可以是DEC EAX指令的单字节操作码,反向扫描时无法判定该字节属于前缀还是其他字段。 - 操作码长度不固定且无边界标记
x86-64 操作码长度从 1 字节到 3 字节不等,扩展操作码也没有专门的标记位区分于其他字段。正向解码时从指令起始位顺序读取可以明确区分前缀与操作码,反向解码时无法确定当前读取的字节是操作码的最后一位,还是前面位移/立即数字段的一部分,根本无法定位操作码的起始位置。 - 立即数、位移字段无边界标记
x86-64 的位移长度支持 0/1/2/4 字节,立即数长度支持 0/1/2/4/8 字节,两类字段的取值范围和操作码、前缀完全重合,没有任何特殊标识说明字段长度。例如一个 4 字节立即数中完全可能包含合法的操作码、ModR/M 序列,反向解码时会误将立即数的一部分识别为指令字段。 - 存在天然歧义的编码实例
以下面的指令编码为例:48 05 c0 01 48 00对应的正向解码结果是add rax, 0x4801c0,最后 4 字节c0 01 48 00是立即数字段。如果从该指令的结束边界反向扫描,很容易将立即数中的0x48判定为 REX 前缀、0x01判定为操作码、0xc0判定为 ModR/M 字节,解码出完全错误的add rax, rax指令,无法找到真实的指令起始边界。
注:如果有符号表、控制流图、已完成的正向解码结果等额外辅助信息,可以在特定场景下实现部分反向推导,但仅依赖 x86-64 本身的编码规则,不存在通用的反向取指方案。
内容的提问来源于stack exchange,提问作者J.Todd
相关产品推荐
相关产品推荐

