【问题标题】:GAS x86: Reading a jump table / interpreting a switch statementGAS x86:读取跳转表/解释 switch 语句
【发布时间】:2017-03-29 20:09:47
【问题描述】:

我正在尝试对一些程序集进行逆向工程,我已经做到了这一点:

40073f: 89 45 fc                mov    %eax,-0x4(%rbp)
  400742:   83 7d fc 05             cmpl   $0x5,-0x4(%rbp)
  400746:   77 37                   ja     40077f <f51+0x85>
  400748:   8b 45 fc                mov    -0x4(%rbp),%eax
  40074b:   48 8b 04 c5 28 09 40    mov    0x400928(,%rax,8),%rax
  400752:   00 
  400753:   ff e0                   jmpq   *%rax
  400755:   b8 11 00 00 00          mov    $0x11,%eax
  40075a:   eb 28                   jmp    400784 <f51+0x8a>
  40075c:   b8 12 00 00 00          mov    $0x12,%eax
  400761:   eb 21                   jmp    400784 <f51+0x8a>
  400763:   b8 13 00 00 00          mov    $0x13,%eax
  400768:   eb 1a                   jmp    400784 <f51+0x8a>
  40076a:   b8 14 00 00 00          mov    $0x14,%eax
  40076f:   eb 13                   jmp    400784 <f51+0x8a>
  400771:   b8 15 00 00 00          mov    $0x15,%eax
  400776:   eb 0c                   jmp    400784 <f51+0x8a>
  400778:   b8 16 00 00 00          mov    $0x16,%eax
  40077d:   eb 05                   jmp    400784 <f51+0x8a>
  40077f:   b8 0a 00 00 00          mov    $0xa,%eax
  400784:   5d                      pop    %rbp
  400785:   c3                      retq 

我可以看到我在这里看到的是一个 switch 语句,其中默认情况是 -0x4(%rbp) > 5,但我对一些指令感到困惑:

40074b 是否只是转到跳转表上的某个位置并将该指令推入 rax,以便我们可以在之后跳转到 switch case 中的正确位置(即第 400753 行)?

在这种情况下,我不知道如何解释我们的不同案例。如果我的理解是正确的,跳转表从地址 400928 开始,我看到:

  400928:   55                      push   %rbp
  400929:   07                      (bad)  
  40092a:   40 00 00                add    %al,(%rax)
  40092d:   00 00                   add    %al,(%rax)
  40092f:   00 5c 07 40             add    %bl,0x40(%rdi,%rax,1)
  400933:   00 00                   add    %al,(%rax)
  400935:   00 00                   add    %al,(%rax)
  400937:   00 63 07                add    %ah,0x7(%rbx)
  40093a:   40 00 00                add    %al,(%rax)
  40093d:   00 00                   add    %al,(%rax)
  40093f:   00 6a 07                add    %ch,0x7(%rdx)
  400942:   40 00 00                add    %al,(%rax)
  400945:   00 00                   add    %al,(%rax)
  400947:   00 71 07                add    %dh,0x7(%rcx)
  40094a:   40 00 00                add    %al,(%rax)
  40094d:   00 00                   add    %al,(%rax)
  40094f:   00 78 07                add    %bh,0x7(%rax)
  400952:   40 00 00                add    %al,(%rax)
  400955:   00 00                   add    %al,(%rax)

在这一点上,我几乎不知道我在看什么。大概使用第 400753 行,我们会跳转到该表中的某个位置,但是然后呢?还是我的理解完全不对?

【问题讨论】:

  • .rodata 中有 0x400928 吗?如果它只是在 .text 部分中,与代码混合,那很奇怪。通常,出于性能原因,您会将数据和代码单独分组,因为 CPU 具有拆分缓存(以及单独的 dTLB / iTLB)。
  • 它在 .rodata 中
  • 好的,所以你必须使用-D 或其他东西来反汇编那个非代码。现在您知道为什么您的工具不想为您拆卸它:P
  • 使用 -D 是我在第二个代码块中找到指令的方式。
  • 就像 Wumpus 的回答所说,它们不是说明。这就是为什么-d 不会分解它们的原因。

标签: assembly x86 switch-statement gnu-assembler jump-table


【解决方案1】:

跳转表是一个指针数组,不是代码。反汇编器不知道这一点,因此它将字节解码为指令。你必须忽略它,只看字节:

400928:   55                      push   %rbp
400929:   07                      (bad)  
40092a:   40 00 00                add    %al,(%rax)
40092d:   00 00                   add    %al,(%rax)
40092f:   00 5c 07 40             add    %bl,0x40(%rdi,%rax,1)

前 8 个字节是 55 07 40 00 00 00 00 00,指向 0x400755 处的指令的指针。这就是你找到case 0的地方。

【讨论】:

  • 我们怎么知道是case 0 而不是其他号码?
  • @nichow:因为它直接使用switch() 操作数作为数组索引,没有添加/子来抵消它或任何东西。除非在您未显示的代码中早先发生这种情况。
猜你喜欢
  • 2014-08-30
  • 2013-06-21
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
相关资源
最近更新 更多