2016-07-29 31 views
2

Ich lerne Assembly, also arbeite ich an Shellcode. Ich habe ein einfaches "Hallo Welt" -Programm in Nasm geschrieben, aber es stürzt ab, wenn es ausgeführt wird.Basic Nasm Shellcode stürzt ab

; write.asm 
[SECTION .text] 

global _start 

_start: 
    jmp short message; 

write:   ; takes two arguments pushed onto stack -> text, textlen 
    pop edx  ; pop length into edx 
    pop ecx  ; pop ptr to text into ecx 
    pushad 
    mov al, 4 
    mov bl, 1 
    int 80h ; syscall 
    popad 
    ret 

exit:   ; push exit_code onto stack 
    mov al, 1 
    pop ebx  ; pop exit_code into ebx 
    int 80h 

main: 
    pop eax  ; pop ptr to message into eax 
    push 7  ; length of string 
    push eax ; push ptr to message 
    call write 
    xor ebx, ebx; zero out ebx 
    push ebx 
    call exit 
message: 
    call main 
    db 'Hello!', 10 

ich kompilieren mit:

nasm -f elf write.asm 
ld -m elf_i386 -o write write.o 

und diese:

Segmentation fault (core dumped) 

Ich versuchte es mit gdb debuggen, aber es half nicht.

+0

ist nicht die Zeichenfolge Hallo! sollte mit 0 enden? da es eine Schnur ist? – rcd

+1

@rcd Da dies ein Aufruf zum Schreiben ist und ich die Länge der Zeichenfolge angeben muss, nein, muss es nicht nullterminiert sein. – Fluffy

+1

Was zeigt das Ausführen in einem Debugger? Wo denkst du, dass die 'ret'-Anweisung zurückkommen wird, seit du sie am Anfang von' write' vom Stapel genommen hast? Vielleicht hast du vergessen, dass mit einem 'call' die Rücksendeadresse auf den Stack geschoben wird? Ich vermute, dass, seit Sie die Rücksprungadresse plus das erste Argument, dass Ihr Code versucht, zu Speicheradresse 7, die an der Spitze des Stapels gewesen wäre, wenn Ihr Aufruf zum 'write' zurückgegeben wird zurückgegeben. –

Antwort

3

Ich möchte Ihnen zeigen, wie Sie Ihr Problem durch die Verwendung GDB finden konnte:

  1. starten gdb und laden Sie Ihr Programm: >> gdb write Breakpoint
  2. Set direkt am Start: (gdb) b _start konnte .Sie einfach Lassen Sie das Programm bis segfault laufen, aber wenn der Stack durcheinander ist, sind die Chancen hoch, dass Sie nichts sehen werden.
  3. die Anzeige einrichten 5 Top-Werte auf dem Stack nach jedem Schritt automatisch zu zeigen: (gdb) display/x {unsigned int[5]}$sp
  4. Um die nächste ausgeführten Zeile zu sehen: (gdb) display/i $pc
  5. Jetzt laufen: (gdb) run

Debugger trifft den Haltepunkt und sehen Sie den Stapel aufgebaut durch das System:

1: /x {unsigned int[5]}$sp = {0x1, 0xffffd284, 0x0, 0xffffd29d, 0xffffd2b2} 

Alles Ok, so weit, wurde das Programm mit einem Argument gestartet (012.auf der Oberseite) - der Pfad zum Programm (Sie können es durch (gdb) print (char[10])*(0xffffd284) sehen).

  1. machen Sie einen Schritt (gdb) si, jetzt sprangen wir auf das message Symbol.

Mit (gdb) disas kann man mehr von dem Code sehen:

(gdb) disas 
Dump of assembler code for function message: 
=> 0x08048083 <+0>: call 0x8048072 <main> 
    0x08048088 <+5>: dec %eax 
    0x08048089 <+6>: gs 
    0x0804808a <+7>: insb (%dx),%es:(%edi) 
    0x0804808b <+8>: insb (%dx),%es:(%edi) 
    0x0804808c <+9>: outsl %ds:(%esi),(%dx) 
    0x0804808d <+10>: and %ecx,(%edx) 
End of assembler dump. 

Wie Sie sehen können, Ihre "Hallo" -string als Operationen interpretiert wird, beginnend bei 0x08048088

  1. machen Sie einen weiteren Schritt: (gdb) si, gehen in die Funktion main.

nun einen Blick auf den Stapel nehmen:

1: /x {unsigned int[5]}$sp = {0x8048088, 0x1, 0xffffd283, 0x0, 0xffffd29c} 

Die call -Befehl schob die Rücksprungadresse auf dem Stack - 0x08048088 - die Adresse Ihrer Zeichenfolge. Nizza Trick, hoffen wir, dass main wird nie wieder zurückkehren ...

  1. Lassen Sie uns schnell nach vorn auf den Aufruf von write: (gdb) si 3 und gehen innerhalb (gdb) si.

die auf dem Stapel Werfen wir einen Blick, wie erwartet, hinzugefügt call die Rücksprungadresse auf den Stack:

1: /x {unsigned int[5]}$sp = {0x804807b, 0x8048088, 0x7, 0x1, 0xffffd283} 
  1. Ihr Programm erwartet, dass der Zeiger auf den String und die Länge oben zu sein, aber das ist nicht der Fall.
  2. Ermöglicht schnellen Vorlauf zur Rückkehr der Funktion write: (gdb) si 7.

Werfen Sie einen Blick auf den Stapel:

1: /x {unsigned int[5]}$sp = {0x7, 0x1, 0xffffd283, 0x0, 0xffffd29c} 

die nächste Operation - ret0x7 vom Stapel pop und versuchen, die Ausführung an der Adresse 0x7, die in einem segfault führt zu übernehmen (wie rcd Verdacht).

Ihr Problem ist also, dass Ihre Funktionen den Stapel beschädigen. Normalerweise ist die Funktion, die den Stapel für einen Anruf aufbaut, auch dafür verantwortlich, ihn danach zu bereinigen.

+0

Danke. Jedoch kompiliert es in eine Binärdatei und läuft nicht ab, nachdem einige der von den Kommentatoren des Hauptposts präsentierten Sachen repariert wurden. Es funktioniert nicht als Shell-Code, aber ich denke, das könnte ein Problem mit der Art sein, wie ich es als Shell-Code ausführe. – Fluffy

+0

@Fluffy es ist schwer zu sagen, was Ihr Problem sein könnte - aber ich hoffe, Sie können den Debugger verwenden, um das Problem zu finden. Es würde länger dauern, als jemanden zu fragen - aber auf lange Sicht wird es sich auszahlen. – ead