C++ 如何在Linux中反汇编二进制可执行文件以获得汇编代码?

C++ 如何在Linux中反汇编二进制可执行文件以获得汇编代码?,c++,linux,assembly,executable,disassembly,C++,Linux,Assembly,Executable,Disassembly,我被告知要使用拆卸器。gcc有内置的东西吗?做这件事最简单的方法是什么?使用和。我不认为gcc有标志,因为它主要是一个编译器,但另一个GNU开发工具有objdump采用-d/-反汇编标志: $ objdump -d /path/to/binary 分解过程如下所示: 080483b4 <main>: 80483b4: 8d 4c 24 04 lea 0x4(%esp),%ecx 80483b8: 83 e4 f0

我被告知要使用拆卸器。
gcc
有内置的东西吗?做这件事最简单的方法是什么?

使用和。

我不认为gcc有标志,因为它主要是一个编译器,但另一个GNU开发工具有
objdump
采用
-d
/
-反汇编
标志:

$ 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
080483b4:
80483b4:8d 4c 24 04 lea 0x4(%esp),%ecx
80483b8:83 e4 f0和$0xfffffff0,%esp
80483bb:ff 71 fc PUSH-0x4(%ecx)
80483be:55%推力ebp
80483bf:89 e5 mov%esp%ebp
80483c1:51推力%ecx
80483c2:b8 00 mov$0x0,%eax
80483c7:59%流行音乐ecx
80483c8:5d pop%ebp
80483c9:8D61 fc lea-0x4(%ecx),%esp
80483cc:c3 ret
80483cd:90无
80483ce:90无
80483cf:90无

还有NDISAM,它有一些怪癖,但如果您使用nasm,它会更有用。我同意Michael Mrozek的观点,objdump可能是最好的

[稍后]
您可能还想查看Albert van der Horst的ciasdis:。它可能很难理解,但有一些有趣的功能,你可能在其他地方找不到。

你可能会发现ODA很有用。它是一个基于web的反汇编程序,支持多种体系结构


objdump的一个有趣的替代方案是gdb。您不必运行二进制文件或拥有debuginfo

$ 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-q./a.out
正在从./a.out…(未找到调试符号)读取符号…已完成。
(gdb)信息功能
所有定义的功能:
非调试符号:
0x00000000004003a8_init
0x00000000004003e0\uuuu libc\u启动_main@plt
0x00000000004003f0\uuuuu gmon\u start\uuuu@plt
0x00000000004040400\u开始
0x000000000040430取消注册\u tm\u克隆
0x000000000040460寄存器\u tm\u克隆
0x00000000004004a0\uuuuu do\uu全局\uu数据源\uu辅助
0x00000000004004c0帧_虚拟
0x00000000004004f0 fce
0x00000000004004fb主
0x0000000000400510\uuuu libc\u csu\u init
0x0000000000400580\uuu libc\u csu\u fini
0x0000000000400584_fini
(gdb)拆卸主管道
主功能的汇编程序代码转储:
0x00000000004004fb:推送%rbp
0x00000000004004fc:mov%rsp,%rbp
0x00000000004004ff:子$0x10,%rsp
0x0000000000400503:callq 0x4004f0
0x0000000000400508:mov%eax,-0x4(%rbp)
0x000000000040050b:mov-0x4(%rbp),%eax
0x000000000040050e:LEVEQ
0x000000000040050f:retq
汇编程序转储结束。
(gdb)拆卸fce
函数fce的汇编程序代码转储:
0x00000000004004f0:推送%rbp
0x0000000000404F1:mov%rsp,%rbp
0x0000000000404F4:mov$0x2a,%eax
0x00000000004004f9:弹出%rbp
0x00000000004004fa:retq
汇编程序转储结束。
(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)
(gdb)反汇编/m主
主功能的汇编程序代码转储:
9       {
0x00000000004004fb:推送%rbp
0x00000000004004fc:mov%rsp,%rbp
0x00000000004004ff:子$0x10,%rsp
10 int x=fce();
0x0000000000400503:callq 0x4004f0
0x0000000000400508:mov%eax,-0x4(%rbp)
11返回x;
0x000000000040050b:mov-0x4(%rbp),%eax
12      }
0x000000000040050e:LEVEQ
0x000000000040050f:retq
汇编程序转储结束。
(gdb)

objdump有一个类似的选项(-S)

这个答案是针对x86的。可拆卸AArch64、MIPS或任何机器代码的便携式工具包括
objdump
llvm objdump


objconv
,相当不错。它将为反汇编输出添加关于性能问题的注释(例如,16位立即数常量指令中可怕的LCP暂停)

(它不将
-
识别为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 binutils
objdump-Mintel-d
是非常有用的,如果您有一个普通的Linux gcc设置,它将已经被安装。

可以反汇编多种格式的二进制文件。它类似于Hiew,但是是开源的


要进行反汇编,请打开一个二进制文件,然后按F6键,然后选择elf/image。

您可以非常接近(但没有雪茄)生成将重新组装的程序集,如果您打算这样做的话,使用这个相当粗糙且冗长的管道技巧(将/bin/bash替换为要反汇编的文件,将bash.S替换为要将输出发送到的文件):

objdump——不显示原始insn-Ma
  (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 --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
#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+\.'
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