有人告诉我要使用反汇编器。 gcc
有内置的工具吗?最简单的方法是什么?
gcc
内置了相关工具?如何实现最简单的方法?有人告诉我要使用反汇编器。 gcc
有内置的工具吗?最简单的方法是什么?
gcc
内置了相关工具?如何实现最简单的方法?我认为gcc
没有这个标志,因为它主要是一个编译器,但GNU开发工具中的另一个工具有。 objdump
使用-d
/--disassemble
标志:
$ objdump -d /path/to/binary
反汇编看起来像这样:
080483b4 <main>:
80483b4: 8d 4c 24 04 lea 0x4(%esp),%ecx
80483b8: 83 e4 f0 and $0xfffffff0,%esp
80483bb: ff 71 fc pushl -0x4(%ecx)
80483be: 55 push %ebp
80483bf: 89 e5 mov %esp,%ebp
80483c1: 51 push %ecx
80483c2: b8 00 00 00 00 mov $0x0,%eax
80483c7: 59 pop %ecx
80483c8: 5d pop %ebp
80483c9: 8d 61 fc lea -0x4(%ecx),%esp
80483cc: c3 ret
80483cd: 90 nop
80483ce: 90 nop
80483cf: 90 nop
objdump -Mintel -d
。Agner Fog的 objconv 反汇编器是我试过的最好用的一个(请参见我的回答)。在分支目标上添加编号标签真的非常好。 - Peter Cordesobjdump -drwC -Mintel
。-r
显示符号表中的重定位信息。-C
解码 C++ 函数名。-W
避免长指令换行显示。如果你经常使用它,可以设置别名 alias disas='objdump -drwC -Mintel'
方便使用。 - Peter Cordes一种有趣的 objdump 替代品是 gdb。您不需要运行二进制文件或拥有调试信息。
$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) info functions
All defined functions:
Non-debugging symbols:
0x00000000004003a8 _init
0x00000000004003e0 __libc_start_main@plt
0x00000000004003f0 __gmon_start__@plt
0x0000000000400400 _start
0x0000000000400430 deregister_tm_clones
0x0000000000400460 register_tm_clones
0x00000000004004a0 __do_global_dtors_aux
0x00000000004004c0 frame_dummy
0x00000000004004f0 fce
0x00000000004004fb main
0x0000000000400510 __libc_csu_init
0x0000000000400580 __libc_csu_fini
0x0000000000400584 _fini
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000004004fb <+0>: push %rbp
0x00000000004004fc <+1>: mov %rsp,%rbp
0x00000000004004ff <+4>: sub $0x10,%rsp
0x0000000000400503 <+8>: callq 0x4004f0 <fce>
0x0000000000400508 <+13>: mov %eax,-0x4(%rbp)
0x000000000040050b <+16>: mov -0x4(%rbp),%eax
0x000000000040050e <+19>: leaveq
0x000000000040050f <+20>: retq
End of assembler dump.
(gdb) disassemble fce
Dump of assembler code for function fce:
0x00000000004004f0 <+0>: push %rbp
0x00000000004004f1 <+1>: mov %rsp,%rbp
0x00000000004004f4 <+4>: mov $0x2a,%eax
0x00000000004004f9 <+9>: pop %rbp
0x00000000004004fa <+10>: retq
End of assembler dump.
(gdb)
有完整的调试信息会更好。
(gdb) disassemble /m main
Dump of assembler code for function main:
9 {
0x00000000004004fb <+0>: push %rbp
0x00000000004004fc <+1>: mov %rsp,%rbp
0x00000000004004ff <+4>: sub $0x10,%rsp
10 int x = fce ();
0x0000000000400503 <+8>: callq 0x4004f0 <fce>
0x0000000000400508 <+13>: mov %eax,-0x4(%rbp)
11 return x;
0x000000000040050b <+16>: mov -0x4(%rbp),%eax
12 }
0x000000000040050e <+19>: leaveq
0x000000000040050f <+20>: retq
End of assembler dump.
(gdb)
objdump有一个类似的选项 (-S)
objdump
和llvm-objdump
。
Agner Fog的反汇编器,objconv
,非常好用。它会为性能问题(例如使用16位立即常数导致的可怕LCP停顿)的反汇编输出添加注释。
objconv -fyasm a.out /dev/stdout | less
(它不将-
识别为标准输出的简写,而是默认将输出到与输入文件类似名称的文件中,并在其后面加上.asm
。)
它还会给代码添加分支目标。其他反汇编器通常只对跳转指令进行反汇编,只有一个数字目标,并且不会在分支目标处放置任何标记,以帮助您找到循环顶部等。
它还比其他反汇编器更清楚地指示NOP指令(明确指示填充时,而不是将其作为另一条指令进行反汇编)。
它是开源的,容易在Linux上编译。它可以反汇编为NASM、YASM、MASM或GNU(AT&T)语法。
示例输出:
; Filling space: 0FH
; Filler type: Multi-byte NOP
; db 0FH, 1FH, 44H, 00H, 00H, 66H, 2EH, 0FH
; db 1FH, 84H, 00H, 00H, 00H, 00H, 00H
ALIGN 16
foo: ; Function begin
cmp rdi, 1 ; 00400620 _ 48: 83. FF, 01
jbe ?_026 ; 00400624 _ 0F 86, 00000084
mov r11d, 1 ; 0040062A _ 41: BB, 00000001
?_020: mov r8, r11 ; 00400630 _ 4D: 89. D8
imul r8, r11 ; 00400633 _ 4D: 0F AF. C3
add r8, rdi ; 00400637 _ 49: 01. F8
cmp r8, 3 ; 0040063A _ 49: 83. F8, 03
jbe ?_029 ; 0040063E _ 0F 86, 00000097
mov esi, 1 ; 00400644 _ BE, 00000001
; Filling space: 7H
; Filler type: Multi-byte NOP
; db 0FH, 1FH, 80H, 00H, 00H, 00H, 00H
ALIGN 8
?_021: add rsi, rsi ; 00400650 _ 48: 01. F6
mov rax, rsi ; 00400653 _ 48: 89. F0
imul rax, rsi ; 00400656 _ 48: 0F AF. C6
shl rax, 2 ; 0040065A _ 48: C1. E0, 02
cmp r8, rax ; 0040065E _ 49: 39. C0
jnc ?_021 ; 00400661 _ 73, ED
lea rcx, [rsi+rsi] ; 00400663 _ 48: 8D. 0C 36
...
(from /lib/x86_64-linux-gnu/libc.so.6)
SECTION .plt align=16 execute ; section number 11, code
?_00001:; Local function
push qword [rel ?_37996] ; 0001F420 _ FF. 35, 003A4BE2(rel)
jmp near [rel ?_37997] ; 0001F426 _ FF. 25, 003A4BE4(rel)
...
ALIGN 8
?_00002:jmp near [rel ?_37998] ; 0001F430 _ FF. 25, 003A4BE2(rel)
; Note: Immediate operand could be made smaller by sign extension
push 11 ; 0001F436 _ 68, 0000000B
; Note: Immediate operand could be made smaller by sign extension
jmp ?_00001 ; 0001F43B _ E9, FFFFFFE0
objdump -drwC -Mintel
非常实用,并且如果您有一个正常的Linux gcc设置,它已经安装好了。我在我的系统上使用alias disas='objdump -drwC -Mintel'
。(-w
是无换行,-C
是解码,-r
打印目标文件中的重定位信息。)
llvm-objdump -d
也可以工作,并且可以从单个二进制文件中反汇编多种架构的代码。(与GNU objdump
不同,你需要为每个架构单独安装,例如aarch64-linux-gnu-objdump -d
。)同样地,clang -O3 -target mips -c
或者clang -O3 -target riscv32 -c
等命令非常有用,可以为你感兴趣的架构进行编译,而无需费心安装交叉编译器。(https://godbolt.org/ Compiler Explorer也是一个很有用的资源;请参阅如何从GCC/clang汇编输出中去除“噪音”?了解更多信息以及编写能够生成有趣汇编代码的小函数。)
此外还有ndisasm,它有一些怪癖,但如果你使用nasm可能会更有用。我同意Michael Mrozek的观点,objdump可能是最好的选择。
[稍后] 您可能还想查看Albert van der Horst的ciasdis:http://home.hccnet.nl/a.w.m.van.der.horst/forthassembler.html。它可能很难理解,但具有一些您不太可能在其他地方找到的有趣功能。
objdump --no-show-raw-insn -Matt,att-mnemonic -Dz /bin/bash | grep -v "file format" | grep -v "(bad)" | sed '1,4d' | cut -d' ' -f2- | cut -d '<' -f2 | tr -d '>' | cut -f2- | sed -e "s/of\ section/#Disassembly\ of\ section/" | grep -v "\.\.\." > bash.S
ht editor 可以反汇编多种格式的二进制文件。它类似于 Hiew,但是开源的。
要进行反汇编,请打开一个二进制文件,然后按 F6 键,选择 elf/image 格式。
#include <iostream>
double foo(double x)
{
asm("# MyTag BEGIN"); // <- asm comment,
// used later to locate piece of code
double y = 2 * x + 1;
asm("# MyTag END");
return y;
}
int main()
{
std::cout << foo(2);
}
g++ prog.cpp -c -S -o - -masm=intel | c++filt | grep -vE '\s+\.'
c++filt
解析符号
grep -vE '\s+\.'
移除一些无用信息
现在,如果你想可视化标记部分,只需使用:
g++ prog.cpp -c -S -o - -masm=intel | c++filt | grep -vE '\s+\.' | grep "MyTag BEGIN" -A 20
# MyTag BEGIN
# 0 "" 2
#NO_APP
movsd xmm0, QWORD PTR -24[rbp]
movapd xmm1, xmm0
addsd xmm1, xmm0
addsd xmm0, xmm1
movsd QWORD PTR -8[rbp], xmm0
#APP
# 9 "poub.cpp" 1
# MyTag END
# 0 "" 2
#NO_APP
movsd xmm0, QWORD PTR -8[rbp]
pop rbp
ret
.LFE1814:
main:
.LFB1815:
push rbp
mov rbp, rsp
一种更友好的方法是使用:编译器浏览器