assembly 有没有一种方法可以让GDB反汇编特定范围内的所有内存,而不考虑指令边界?

ig9co6j1  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(108)

x/16i 0xdeadbeef产生:

0x80481be <_init+22>:    shlb   $0x3a,-0x18(%ebp,%eax,1)
   0x80481c3 <_init+27>:    jle    0x80481c0 <_init+24>
   0x80481c5 <_init+29>:    .byte 0xf7
   0x80481c6 <_init+30>:    add    $0x8,%esp
   0x80481c9 <_init+33>:    pop    %ebx
   0x80481ca <_init+34>:    ret

字符串
init+22-27“里面”有一些多汁的指令,如果我能看到它们是什么就好了。
x/16s 0xdeadbeef得到:

0x80481be <_init+22>:   "\300t\005\350:~\373\367\203\304\b"


这一点也不有趣。
我正在写一个ROP链生成器,所以我需要找到可以通过跳转到其他指令的“中间”来执行的指令。(非常)慢的方法是简单地运行x/i 0xdeadbeef; x/i 0xdeadbef0, ...。有没有更快的方法?
我试过x/i+<offset> 0xdeadbeef:* 第一个 * 产生的指令在x/i 0xdeadbeef的中间,但是后续的指令并不是“索引到”的中间,这使得这种方式与慢速方式相同。

cu6pst1q

cu6pst1q1#

GDB是为调试CPU将要执行的代码的正常用例而设计的,因此下一条指令的反汇编从上一条指令的末尾开始。如果您主要是手动查看,您可以定义一个GDB函数来反汇编从范围内的每个字节偏移量开始的短序列。您可以直接输入此函数(一次一行)在GDB的交互式命令行上,或者我认为把它放在你的.gdbinit或你的源文件中。
这定义了一个接受2个参数的函数:起始地址和从每个起始字节开始的反汇编字节长度。

define ROPsearch
  set $i = 0
  while ($i < 32)
     disas /r $arg0+$i, $arg0+$i + $arg1
     set $i=$i+1
  end
end

字符串
您也可以将长度(32字节)参数化为$arg2进行搜索。请参阅GDB手册(https://sourceware.org/gdb/current/onlinedocs/gdb.html/Define.html),其中有示例。
在交互式使用中,这看起来像:

$ gdb /lib/libc.so.6
... (yes, allow it to download debug symbols and source, although I really just want symbol names; Arch Linux separates debug symbols out of binary packages now.)
(gdb) define ROPsearch
Redefine command "ROPsearch"? (y or n) y
Type commands for definition of "ROPsearch".
End with a line saying just "end".
>set $i = 0
>while ($i < 32)
 >disas /r $arg0+$i, $arg0+$i + $arg1
 >set $i=$i+1
 >end
>end

(gdb) ROPsearch abort+4  16
Dump of assembler code from 0x55555557a3e5 to 0x55555557a3f5:
   0x000055555557a3e5 <__GI_abort+4>:   55                      push   rbp
   0x000055555557a3e6 <__GI_abort+5>:   53                      push   rbx
   0x000055555557a3e7 <__GI_abort+6>:   48 8d 1d 62 37 1b 00    lea    rbx,[rip+0x1b3762]        # 0x55555572db50 <lock>
   0x000055555557a3ee <__GI_abort+13>:  48 81 ec a8 00 00 00    sub    rsp,0xa8
End of assembler dump.
Dump of assembler code from 0x55555557a3e6 to 0x55555557a3f6:
   0x000055555557a3e6 <__GI_abort+5>:   53                      push   rbx
   0x000055555557a3e7 <__GI_abort+6>:   48 8d 1d 62 37 1b 00    lea    rbx,[rip+0x1b3762]        # 0x55555572db50 <lock>
   0x000055555557a3ee <__GI_abort+13>:  48 81 ec a8 00 00 00    sub    rsp,0xa8
   0x000055555557a3f5 <__GI_abort+20>:  64 48 8b 04 25 28 00 00 00      mov    rax,QWORD PTR fs:0x28
End of assembler dump.
Dump of assembler code from 0x55555557a3e7 to 0x55555557a3f7:
   0x000055555557a3e7 <__GI_abort+6>:   48 8d 1d 62 37 1b 00    lea    rbx,[rip+0x1b3762]        # 0x55555572db50 <lock>
   0x000055555557a3ee <__GI_abort+13>:  48 81 ec a8 00 00 00    sub    rsp,0xa8
   0x000055555557a3f5 <__GI_abort+20>:  64 48 8b 04 25 28 00 00 00      mov    rax,QWORD PTR fs:0x28
End of assembler dump.
Dump of assembler code from 0x55555557a3e8 to 0x55555557a3f8:
   0x000055555557a3e8 <__GI_abort+7>:   8d 1d 62 37 1b 00       lea    ebx,[rip+0x1b3762]        # 0x55555572db50 <lock>
   0x000055555557a3ee <__GI_abort+13>:  48 81 ec a8 00 00 00    sub    rsp,0xa8
   0x000055555557a3f5 <__GI_abort+20>:  64 48 8b 04 25 28 00 00 00      mov    rax,QWORD PTR fs:0x28
End of assembler dump.
...

Dump of assembler code from 0x55555557a3fc to 0x55555557a40c:
   0x000055555557a3fc <__GI_abort+27>:  00 00                   add    BYTE PTR [rax],al
   0x000055555557a3fe <__GI_abort+29>:  48 89 84 24 98 00 00 00 mov    QWORD PTR [rsp+0x98],rax
   0x000055555557a406 <__GI_abort+37>:  31 c0                   xor    eax,eax
   0x000055555557a408 <__GI_abort+39>:  64 48 8b 2c 25 10 00 00 00      mov    rbp,QWORD PTR fs:0x10
End of assembler dump.
Dump of assembler code from 0x55555557a3fd to 0x55555557a40d:
   0x000055555557a3fd <__GI_abort+28>:  00 48 89                add    BYTE PTR [rax-0x77],cl
   0x000055555557a400 <__GI_abort+31>:  84 24 98                test   BYTE PTR [rax+rbx*4],ah
   0x000055555557a403 <__GI_abort+34>:  00 00                   add    BYTE PTR [rax],al
   0x000055555557a405 <__GI_abort+36>:  00 31                   add    BYTE PTR [rcx],dh
   0x000055555557a407 <__GI_abort+38>:  c0 64 48 8b 2c          shl    BYTE PTR [rax+rcx*2-0x75],0x2c
   0x000055555557a40c <__GI_abort+43>:  25 10 00 00 00          and    eax,0x10
...


abort只是在objdump -drwC -Mintel /lib/libc.so.6 | less中早期出现的符号名称。我的.gdbinit使用set disassembly-flavor intel
所以它是嘈杂的,2行开始/结束“的汇编转储”周围的每个块,但这不是那么糟糕时,看块的多个指令。(GDB将反汇编到一个指令的末尾是disas范围包括第一个字节。)
重要的是CPU将从任何给定的起始点执行的指令序列,所以我使用了16字节的范围,而不仅仅是1来查看您在给定起始点获得的指令。
当然,这并不是对以retpop reg/jmp reg结尾的序列进行过滤,也许可以使用GDB命令来实现这一点。或者,如果你想编写一个完整的程序来分析你粘贴的一段机器代码,或者甚至在可执行文件和库中搜索字节,或者在运行的进程中搜索字节,那么可以使用像capstone和XED这样的反汇编器库。
x86机器码是一个字节流,它不是自同步的,但是从给定的起始点唯一解码。对于典型的用例,如果跳转目标地址错误,查看它将如何解码是没有用的。GDB没有这样做的选项。
尽管不是真正的自我同步(你不能只看一个字节就知道它是不是一条指令的开始或结束),相当多的字节是单字节指令的前缀或操作码,所以re-sync通常发生在2到10个字节内。IDK如果你想过滤掉或不。可能不会,只是看看所有不同的选项,导致一个ret

相关问题