【问题标题】:x86 assember - illegal opcode 0xff /7 under Windowsx86 汇编 - Windows 下的非法操作码 0xff /7
【发布时间】:2010-10-07 03:45:10
【问题描述】:

我目前正在开发一个 x86 反汇编程序,并开始反汇编一个 win32 PE 文件。大部分反汇编代码看起来不错,但是有一些非法 0xff /7 操作码的出现(/7 表示 reg=111,0xff 是操作码组 inc/dec/call/callf/jmp/jmpf/push/非法 操作数 r/m 16/32)。第一个猜测是,/7 是 pop 指令,但它是用 0x8f /0 编码的。我已经对照官方的英特尔架构软件开发人员手册第 2 卷:指令集参考检查了这一点 - 所以我不只是被误导了。

反汇编示例:(S0000O0040683a 是被另一条指令跳转到的标签)

S0000O0040683a: inc    edi                      ; 0000:0040683a  ff c7
                test   dword ptr [eax+0xff],edi ; 0000:0040683c  85 78 ff
                0xff/7 edi                      ; 0000:0040683f  ff ff

顺便说一句:gdb 对它进行同样的反汇编(除了错误 0xff 在我的反汇编中没有产生 -1):

(gdb) disassemble 0x0040683a 0x00406840
Dump of assembler code from 0x40683a to 0x406840:
0x0040683a:     inc    %edi
0x0040683c:     test   %edi,0xffffffff(%eax)
0x0040683f:     (bad)  
End of assembler dump.

所以问题是:Windows的非法操作码异常处理程序中是否有任何默认处理程序,它实现了这个非法操作码中的任何功能,如果有:那里发生了什么?

问候,博多

【问题讨论】:

  • 如果您使用调试器介入会发生什么?
  • 大量的FF字节比较可疑。
  • >> 你似乎已经提交了两次这个问题。您可能应该删除一个 - Nathan Fellman(10 分钟前)感谢您的提示 -> 完成。首次提交问题时,我收到一条错误消息,但由于消息没有显示,我再次发布(然后没有错误消息)。

标签: windows assembly x86


【解决方案1】:

在让我的反汇编程序以与 gdb 完全相同的语法生成输出之后,我可以区分这两个版本。这在我的反汇编中揭示了一个相当尴尬的错误:我忘记考虑到 0x0f 0x8x 跳转指令有一个两字节操作码(加上 rel16/32 操作数)。因此,每个 0x0f 0x8x 跳转目标都偏离了一个,导致代码在现实中无法访问。修复此错误后,不再反汇编 0xff/7 操作码。

感谢所有回答我的问题(并评论该答案)并因此至少试图帮助我的人。

【讨论】:

    【解决方案2】:

    Visual Studio 将其反汇编为以下内容:

    00417000 FF C7            inc         edi  
    00417002 85 78 FF         test        dword ptr [eax-1],edi 
    00417005 ??               db          ffh  
    00417006 FF 00            inc         dword ptr [eax] 
    

    显然,一般保护错误发生在 00417002,因为 eax 没有指向任何有意义的东西,但即使我将其 nop 出来 (90 90 90),它也会在 00417005 处引发非法操作码异常(它不会被内核处理)。我很确定这是某种数据,而不是可执行代码。

    【讨论】:

    • 所以 Visual Studio 可以方便地回避这个问题。我想知道为什么它没有写“dw ffffh”并决定00是下一条指令的第一个字节(我相信它是某种类型的“add”)
    • @Nathan,如果在一个字节之后,就知道该指令是非法的,为什么要假定它是一个2字节的指令?我会说 Visual Studio 处理得非常理智。
    • 大多数其他反汇编程序的执行方式与 Visual Studio 相同。一方面,在读取第一个字节 0xff 后,尚不清楚它是否是无效的操作码。另一方面:CPU 会引发一个无效的操作码异常,因此假设 1、2 或 20 字节都没有关系......
    • 实际上这将是访问冲突(来自页面错误) - 而不是一般的保护错误。内核正在处理它——它把异常交给你的进程,看看它是否想处理它。您的进程没有围绕代码的 SEH 处理程序,因此程序崩溃。如果内核没有处理它,你的机器会立即重启。
    【解决方案3】:

    为回答您的问题,Windows 将关闭应用程序,异常代码为 0xC000001D STATUS_ILLEGAL_INSTRUCTION。该对话框将匹配用于任何其他应用程序崩溃的对话框,无论它提供调试器还是发送错误报告。

    关于所提供的代码,它看起来要么组装不正确(编码大于 8 位位移),要么实际上是数据(正如其他人已经建议的那样)。

    【讨论】:

      【解决方案4】:

      看起来测试指令插入的是 0xFFFFFFFF 而不是 0xFF,可能有错误?

      85 = test r/m32, 78 是参数 [eax+d​​isp8], edi 的字节,后面跟着的 disp8 应该是 0xFF (-1) 但作为 32 位有符号整数,这是 0xFFFFFFFF .

      所以我假设你有 85 78 FF FF FF FF 应该是 85 B8 FF FF FF FF 用于 32 位位移或 85 78 FF 用于 8 位位移?如果是这种情况,代码中的下一个字节应该是 0xFF...

      当然,正如已经建议的那样,这可能只是数据,不要忘记数据可以存储在 PE 文件中,并且没有任何特定结构的有力保证。如果您正在积极优化以减小 .exe 大小,您实际上可以将代码或用户定义的数据插入到某些 MZ 或 PE 标头字段中。

      编辑:根据下面的 cmets,我还建议使用您已经确切知道预期的反汇编代码应该是什么的可执行文件。

      【讨论】:

      • 我正在编写 dis 汇编程序,而不是汇编程序;) 数据点很可能也不正确,因为可以通过 JMP 访问上述操作码、CALL 和/或来自程序主入口点的 JCC。
      • bothie:这是什么程序?程序是否有可能在到达那里之前修改了有问题的指令字节?这组操作码在 Windows 或任何其他 x86 操作系统上未经修改是不可能运行的。
      • 如果其他反汇编程序因此输入而崩溃,那么我不会太担心。我建议使用一个可执行文件,您已经知道预期的反汇编代码是什么......
      猜你喜欢
      • 1970-01-01
      • 2011-04-29
      • 2022-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多