Powiedziano mi, żebym użył dezasemblera. Czy gcc
coś jest wbudowane? Jaki jest najłatwiejszy sposób na zrobienie tego?
c++
linux
assembly
executable
disassembly
Błąd składni
źródło
źródło
Odpowiedzi:
Myślę, że nie
gcc
ma na to flagi, ponieważ jest to przede wszystkim kompilator, ale inne narzędzie programistyczne GNU ma.objdump
przyjmuje flagę-d
/--disassemble
:Demontaż wygląda następująco:
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
źródło
objdump -Mintel -d
. Lub deasembler objconv firmy Agner Fog jest najładniejszym, jakiego do tej pory próbowałem (zobacz moją odpowiedź). Dodawanie numerowanych etykiet do celów gałęzi jest naprawdę fajne.objdump -drwC -Mintel
.-r
pokazuje przemieszczenia z tabeli symboli.-C
demantuje nazwy C ++.-W
unika zawijania wierszy w przypadku długich instrukcji. Jeśli używamy go często, to jest poręczny:alias disas='objdump -drwC -Mintel'
.-S
aby wyświetlić kod źródłowy zmieszany z deasemblacją. (Jak wskazano w innej odpowiedzi .)Ciekawą alternatywą dla objdump jest gdb. Nie musisz uruchamiać pliku binarnego ani mieć informacji o debugowaniu.
$ 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)
Z pełnymi informacjami o debugowaniu jest jeszcze lepiej.
(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 ma podobną opcję (-S)
źródło
Ta odpowiedź jest specyficzna dla x86. Przenośne narzędzia, które mogą rozmontować AArch64, MIPS lub dowolny kod maszynowy, w tym
objdump
illvm-objdump
.Dezasembler Agner Fog jest ,
objconv
jest bardzo miłe. Doda komentarze do danych wyjściowych demontażu dla problemów z wydajnością (na przykład przerażające przeciągnięcie LCP z instrukcji z 16-bitowymi stałymi natychmiastowymi).objconv -fyasm a.out /dev/stdout | less
(Nie rozpoznaje go
-
jako skrótu dla standardowego wyjścia i domyślnie wyprowadza do pliku o podobnej nazwie do pliku wejściowego, z.asm
dołączonym.)Dodaje również cele gałęzi do kodu. Inne deasemblery zazwyczaj demontują instrukcje skoku z tylko numerycznym miejscem docelowym i nie umieszczają żadnego znacznika w celu rozgałęzienia, aby pomóc ci znaleźć szczyt pętli i tak dalej.
Wskazuje również NOP wyraźniej niż inne deasemblery (wyjaśniając, kiedy jest wypełnienie, zamiast rozmontowywać go jako kolejną instrukcję).
Jest open source i łatwy do skompilowania dla systemu Linux. Można go rozłożyć na składnię NASM, YASM, MASM lub GNU (AT&T).
Przykładowe dane wyjściowe:
; 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 ...
Zauważ, że to wyjście jest gotowe do złożenia z powrotem do pliku obiektowego, więc możesz modyfikować kod na poziomie źródła asm, zamiast za pomocą edytora szesnastkowego w kodzie maszynowym. (Więc nie musisz ograniczać się do utrzymywania tego samego rozmiaru). Bez żadnych zmian wynik powinien być prawie identyczny. Może jednak nie być, ponieważ demontaż takich rzeczy
(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
nie ma niczego w źródle, aby upewnić się, że składa się z dłuższego kodowania, co pozostawia miejsce na relokacje, aby przepisać go z 32-bitowym przesunięciem.
Jeśli nie chcesz go instalować objconv, GNU binutils
objdump -Mintel -d
jest bardzo użyteczny i będzie już zainstalowany, jeśli masz normalną konfigurację gcc dla Linuksa.źródło
jest też ndisasm, który ma pewne dziwactwa, ale może być bardziej przydatny, jeśli używasz nasm. Zgadzam się z Michałem Mrozkiem, że chyba najlepiej jest objdump.
[później] możesz również sprawdzić ciasdis Alberta van der Horsta: http://home.hccnet.nl/awmvan.der.horst/forthassembler.html . może być trudny do zrozumienia, ale ma kilka interesujących funkcji, których prawdopodobnie nie znajdziesz nigdzie indziej.
źródło
Użyj IDA Pro i Decompiler .
źródło
Może się przydać ODA. Jest to dezasembler internetowy, który obsługuje mnóstwo architektur.
http://onlinedisassembler.com/
źródło
Możesz podejść cholernie blisko (ale nie cygara) do wygenerowania zestawu, który zostanie ponownie złożony, jeśli to jest to, co zamierzasz zrobić, używając tej dość prymitywnej i żmudnej sztuczki z rurociągiem (zastąp / bin / bash plikiem, który zamierzasz zdemontować i bash.S z tym, do czego zamierzasz wysłać dane wyjściowe):
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
Zwróć jednak uwagę, jak długo to trwa. Naprawdę chciałbym, żeby był lepszy sposób (lub, jeśli o to chodzi, deasembler zdolny do generowania kodu, który rozpozna asembler), ale niestety nie ma.
źródło
redaktor ht może deasemblować pliki binarne w wielu formatach. Jest podobny do Hiew, ale open source.
Aby zdemontować, otwórz plik binarny, a następnie naciśnij klawisz F6, a następnie wybierz elf / obraz.
źródło
Powiedzmy, że masz:
#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); }
Aby uzyskać kod asemblera za pomocą gcc, możesz zrobić:
g++ prog.cpp -c -S -o - -masm=intel | c++filt | grep -vE '\s+\.'
c++filt
demantuje symbolegrep -vE '\s+\.'
usuwa niepotrzebne informacjeTeraz, jeśli chcesz zwizualizować oznaczoną część, po prostu użyj:
g++ prog.cpp -c -S -o - -masm=intel | c++filt | grep -vE '\s+\.' | grep "MyTag BEGIN" -A 20
Z moim komputerem otrzymuję:
# 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
Bardziej przyjaznym podejściem jest użycie: Compiler Explorer
źródło
-O0
asm.