2009-08-06 14 views
50

Ich versuche ein Programm zu zerlegen, um eine syscall Assembly-Anweisung (die INT-Anweisung, glaube ich) und den Handler mit GDB zu sehen und habe ein kleines Programm geschrieben (siehe unten), das eine Datei öffnet und schließt. Ich konnte dem Aufruf folgen, mit GDB zu fopen, bis es einen Anruf ausführte. Als ich versuchte, GDB "disassemble 0x ...." (Adresse des Anrufs) zu sagen, antwortete es mit "Keine Funktion enthält angegebene Adresse." Ist es möglich, GDB zu zwingen, diese Speicheradresse zu zerlegen (oder so gut wie möglich in Assembler anzuzeigen)? Wenn das so ist, wie?Wie kann ich GDB zum Zerlegen zwingen?

#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    FILE* f; 
    f = fopen("main.c", "r"); 
    if (!f) { 
     perror("open"); 
     return -1; 
    } 
fclose(f); 
return 0; 
} 
+2

fopen() ist kein Systemaufruf, es ist ein Aufruf an die C-Standardbibliothek. Und warum sollte ein Systemaufruf über eine INT-Anweisung erfolgen? –

+0

Ich könnte falsch liegen, aber uns wurde beigebracht, dass fopen Aufrufe letztlich zu einem Systemaufruf an den Kernel führen, um die Datei zu öffnen und einen Dateideskriptor zurückzugeben? – Patrick

+1

Patrick: Ja, aber muss das nicht direkt tun. Normalerweise ruft es die libc-Funktion auf, die dann in den Kernel eintritt. Aber Kernel aufrufen kann nicht nur mit int (das ist langsam), sondern mit syscall/sysenter je nach Prozessorarchitektur ... – k3a

Antwort

40

Möchten Sie nur Ihre tatsächliche Haupt zerlegen? Wenn dies der Fall versuchen Sie dies:

(gdb) info line main 
(gdb) disas STARTADDRESS ENDADDRESS 

Wie so:

[email protected] /cygdrive/c/prog/dsa 
$ gcc-3.exe -g main.c 

[email protected] /cygdrive/c/prog/dsa 
$ gdb a.exe 
GNU gdb 6.8.0.20080328-cvs (cygwin-special) 
... 
(gdb) info line main 
Line 3 of "main.c" starts at address 0x401050 <main> and ends at 0x401075 <main+ 
(gdb) disas 0x401050 0x401075 
Dump of assembler code from 0x401050 to 0x401075: 
0x00401050 <main+0>: push %ebp 
0x00401051 <main+1>: mov %esp,%ebp 
0x00401053 <main+3>: sub $0x18,%esp 
0x00401056 <main+6>: and $0xfffffff0,%esp 
0x00401059 <main+9>: mov $0x0,%eax 
0x0040105e <main+14>: add $0xf,%eax 
0x00401061 <main+17>: add $0xf,%eax 
0x00401064 <main+20>: shr $0x4,%eax 
0x00401067 <main+23>: shl $0x4,%eax 
0x0040106a <main+26>: mov %eax,-0xc(%ebp) 
0x0040106d <main+29>: mov -0xc(%ebp),%eax 
0x00401070 <main+32>: call 0x4010c4 <_alloca> 
End of assembler dump. 

ich nicht Ihr System Interruptaufrufen sehen jedoch. (Es ist schon eine Weile her, seit ich das letzte Mal versucht habe, einen Systemaufruf in Assembly zu machen. INT 21h, zuletzt erinnere ich mich

+0

ok, dann werde ich versuchen, in Zukunft INT 21h zu suchen. Danke für diesen Hinweis. Aber was ich versuchen wollte ist, folgen Sie der Anruffolge in fopen() (sehe es nicht in Ihrem Code ...) 'unten', bis ich den INT-Befehl sehen kann. – Patrick

+1

Verwaltet es - Der Weg zu gehen ist, Ihre Antwort und Falaina zu verwenden. Ich musste es statisch mit gcc --static main.c kompilieren und dann mit gdb/objdump tief in die C - Bibliothek gehen. Ultimativ führte dies zu einem Aufruf von __open_nocancel, der ein * INT 0x80 * tat. Vielen Dank an euch beide – Patrick

+4

Hinweis: die 'disas 0x401050 0x401075' Syntax zumindest in der Version gdb 7.7 wird nicht funktionieren. Sie haben es eher wie 'disas 0x401050,0x401075' geschrieben. Vielleicht möchten Sie auch das Präfix «/ m» hinzufügen, um einen Quellcode anzuzeigen: 'disas \ m 0x401050,0x401075' –

28

Dies ist nicht die direkte Antwort auf Ihre Frage, aber da Sie scheinen, nur die Binärdatei zu zerlegen vielleicht könnten Sie einfach objdump verwenden:

objdump -d program 

Dies sollte Ihnen seine Zerlegen Sie können -S hinzufügen, wenn Sie es quell kommentierten wollen

+0

⁺¹ für '-S', ich wusste nicht, dass es den Quellcode enthalten könnte. –

6

Sie gcc zur Ausgabe von direkt an Assembler-Code zwingen kann, hinzufügen.. der -S Schalter

gcc -S hello.c 
83

Ja, zerlegen ist nicht der beste Befehl hier zu verwenden. Der Befehl Sie wollen, ist „x/i“ (wie Anweisungen untersuchen):

(gdb) x/i 0xdeadbeef 
+3

DANKE! Hinzufügen dieses Texts, um anderen zu helfen, diesen Hinweis zu finden: Dies ist die Anweisung, die verwendet wird, um binäre Blobs zu zerlegen, ROM zu disassemblieren, Anweisungen in einer binären Bilddatei zu untersuchen usw. Schreiben Sie ein kleines C-Programm, um den binären Blob in einen Puffer zu bringen. Dann mache 'x/i' auf dem Puffer. – user188012

+0

@ user188012 Wenn Sie einen binären Blob disassemblieren möchten, ist es einfacher, einen eigenständigen Disassembler wie ndisasm o.ä. zu verwenden. –

+0

Sie können verwenden: x/i $ pc, um die Anweisung für den pc, der die Adresse der aktuellen Anweisung ist – k3a

3

Wenn alles, was Sie wollen, ist die Demontage mit dem INTC Anruf, um zu sehen, verwenden Sie objdump -d als jemand erwähnt, aber die Verwendung - statische Option beim Kompilieren. Andernfalls wird die fopen-Funktion nicht in die Elfe kompiliert und zur Laufzeit verknüpft.

7

fopen() ist eine C-Bibliotheksfunktion und Sie werden keine syscall-Anweisungen in Ihrem Code sehen, nur einen normalen Funktionsaufruf. Irgendwann heißt es offen (2), aber das über ein Trampolin. Es gibt einfach einen Sprung zur VDSO-Seite, die der Kernel jedem Prozess zur Verfügung stellt. Das VDSO stellt dann Code bereit, um den Systemaufruf zu tätigen. Bei modernen Prozessoren werden die Anweisungen SYSCALL oder SYSENTER verwendet, Sie können aber auch INT 80h auf x86-Prozessoren verwenden.

1

Sie müssen nicht gdb verwenden. GCC wird es tun.

gcc -S foo.c 

Dies wird foo.s erstellen, die die Baugruppe ist.

gcc -m32 -c -g -Wa,-a,-ad foo.c > foo.lst 

Die obige Version erstellt eine Listendatei, die sowohl das C als auch die von ihm generierte Assembly enthält. GCC FAQ

1

gdb zerlegen hat eine/m, um Quellcode neben den Anweisungen aufzunehmen. Dies ist äquivalent zu objdump -S, mit dem zusätzlichen Vorteil der Beschränkung auf nur eine interessierende Funktion (oder Adressbereich).