如何在 Linux 中反汇编二进制可执行文件以获取汇编代码?
- 2024-10-14 08:40:00
- admin 原创
- 134
问题描述:
我被告知要使用反汇编程序。gcc
它有内置功能吗?最简单的方法是什么?
解决方案 1:
我认为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
解决方案 2:
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)
解决方案 3:
此答案特定于 x86。可拆卸工具可以反汇编 AArch64、MIPS 或任何包含objdump
和的机器代码llvm-objdump
。
Agner Fog 的反汇编程序,objconv
,相当不错。它会在反汇编输出中添加注释,以解决性能问题(例如,16 位立即数指令导致的可怕的 LCP 停顿)。
objconv -fyasm a.out /dev/stdout | less
(它不识别-
为 stdout 的简写,并且默认输出到与输入文件名称相似的文件,并附.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
...
请注意,此输出已准备好重新组装成目标文件,因此您可以在 asm 源代码级别调整代码,而不是使用十六进制编辑器对机器代码进行调整。(因此您不必局限于保持相同的大小。)如果没有变化,结果应该几乎相同。但可能并非如此,因为像
(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
源中没有任何内容来确保它组装成更长的编码,从而为重定位留出空间以使用 32 位偏移量重写它。
如果您不想安装 objconv,GNU binutilsobjdump -drwC -Mintel
也非常实用,如果您有正常的 Linux gcc 设置,它已经安装好了。我alias disas='objdump -drwC -Mintel'
在我的系统上使用。(-w
没有换行,-C
是 demangle,-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 也是一个有用的资源;有关更多信息以及编写编译为有趣的 asm 的小函数,请参阅如何从 GCC/clang 汇编输出中删除“噪音”?)
解决方案 4:
还有 ndisasm,它有一些怪癖,但如果你使用 nasm 它会更有用。我同意 Michael Mrozek 的观点,objdump 可能是最好的。
[稍后] 您可能还想看看 Albert van der Horst 的 ciasdis:http://home.hccnet.nl/awmvan.der.horst/forthassembler.html。它可能很难理解,但有一些有趣的功能您可能在其他地方找不到。
解决方案 5:
使用IDA Pro和反编译器。
解决方案 6:
您可能会发现 ODA 很有用。它是一款基于 Web 的反汇编程序,支持大量架构。
http://onlinedisassembler.com/
解决方案 7:
如果您打算这样做,那么使用这个相当粗糙和冗长的管道技巧(将 /bin/bash 替换为您打算反汇编的文件,将 bash.S 替换为您打算将输出发送到的目标文件),您可以非常接近(但不行)生成可以重新组装的程序集:
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
但请注意这有多长。我真的希望有更好的方法(或者,一个能够输出汇编程序可以识别的代码的反汇编程序),但不幸的是没有。
解决方案 8:
ht 编辑器可以反汇编多种格式的二进制文件。它与 Hiew 类似,但是是开源的。
要反汇编,请打开二进制文件,然后按 F6 并选择 elf/image。
解决方案 9:
假设您有:
#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);
}
要使用 gcc 获取汇编代码,您可以执行以下操作:
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
更友好的方法是使用:Compiler Explorer
解决方案 10:
使用:gcc -S ProgramName.c
例子:
#include <stdio.h>
int myFunc(int x, int y) {
char e = 'A';
printf("%c, %d, %d
", e, x, y);
return 1;
}
int main() {
int z = myFunc(5, 7);
return 0;
}
品牌:
.file "temp.c"
.text
.section .rodata
.LC0:
.string "%c, %d, %d
"
.text
.globl myFunc
.type myFunc, @function
myFunc:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movl %esi, -24(%rbp)
movb $65, -1(%rbp)
movsbl -1(%rbp), %eax
movl -24(%rbp), %ecx
movl -20(%rbp), %edx
movl %eax, %esi
leaq .LC0(%rip), %rax
movq %rax, %rdi
movl $0, %eax
call printf@PLT
movl $1, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size myFunc, .-myFunc
.globl main
.type main, @function
main:
.LFB1:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $7, %esi
movl $5, %edi
call myFunc
movl %eax, -4(%rbp)
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE1:
.size main, .-main
.ident "GCC: (Ubuntu 12.3.0-1ubuntu1~23.04) 12.3.0"
.section .note.GNU-stack,"",@progbits
.section .note.gnu.property,"a"
.align 8
.long 1f - 0f
.long 4f - 1f
.long 5
0:
.string "GNU"
1:
.align 8
.long 0xc0000002
.long 3f - 2f
2:
.long 0x3
3:
.align 8
4:
解决方案 11:
使用 ghidra:https://ghidra-sre.org/。它已安装在 Kali Linux 上。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件