2013-08-27 4 views
10

folgenden Anweisungen Ich habe es geschafft, nur 528 Bytes in der Größe a.out zu produzieren (wenn gcc main.c gab mir 8539 Bytes große Datei zunächst).binären Maschinencode aus C

main.c war:

int main(int argc, char** argv) { 

    return 42; 
} 

aber ich habe a.out aus dieser Assembly-Datei stattdessen gebaut:

main.s:

; tiny.asm 
    BITS 64 
    GLOBAL _start 
    SECTION .text 
    _start: 
       mov  eax, 1 
       mov  ebx, 42 
       int  0x80 

mit:

[email protected]# nasm -f elf64 tiny.s 
[email protected]# gcc -Wall -s -nostartfiles -nostdlib tiny.o 
[email protected]# ./a.out ; echo $? 
42 
[email protected]# wc -c a.out 
528 a.out 

weil ich Maschine co. Brauche de ich tun:

objdump -d a.out 

a.out:  file format elf64-x86-64 


Disassembly of section .text: 

00000000004000e0 <.text>: 
    4000e0: b8 01 00 00 00   mov $0x1,%eax 
    4000e5: bb 2a 00 00 00   mov $0x2a,%ebx 
    4000ea: cd 80     int $0x80 

># objdump -hrt a.out 

a.out:  file format elf64-x86-64 

Sections: 
Idx Name   Size  VMA    LMA    File off Algn 
0 .note.gnu.build-id 00000024 00000000004000b0 00000000004000b0 000000b0 2**2 
        CONTENTS, ALLOC, LOAD, READONLY, DATA 
1 .text   0000000c 00000000004000e0 00000000004000e0 000000e0 2**4 
        CONTENTS, ALLOC, LOAD, READONLY, CODE 
SYMBOL TABLE: 
no symbols 

Datei ist in Little-Endian-Konvention:

[email protected]# readelf -a a.out 
ELF Header: 
    Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
    Class:        ELF64 
    Data:        2's complement, little endian 
    Version:       1 (current) 
    OS/ABI:       UNIX - System V 
    ABI Version:      0 
    Type:        EXEC (Executable file) 
    Machine:       Advanced Micro Devices X86-64 
    Version:       0x1 
    Entry point address:    0x4000e0 
    Start of program headers:   64 (bytes into file) 
    Start of section headers:   272 (bytes into file) 
    Flags:        0x0 
    Size of this header:    64 (bytes) 
    Size of program headers:   56 (bytes) 
    Number of program headers:   2 
    Size of section headers:   64 (bytes) 
    Number of section headers:   4 
    Section header string table index: 3 

jetzt ich dies wie folgt ausgeführt werden soll:

#include <unistd.h> 
// which version is (more) correct? 
// this might be related to endiannes (???) 
char code[] = "\x01\xb8\x00\x00\xbb\x00\x00\x2a\x00\x00\x80\xcd\x00"; 
char code_v1[] = "\xb8\x01\x00\x00\x00\xbb\x2a\x00\x00\x00\xcd\x80\x00"; 

int main(int argc, char **argv) 
{ 
/*creating a function pointer*/ 
int (*func)(); 
func = (int (*)()) code; 
(int)(*func)(); 

return 0; 
} 

aber ich Segmentierungsfehler bekommen. Meine Frage ist: ist dieser Abschnitt des Textes

4000e0: b8 01 00 00 00   mov $0x1,%eax 
    4000e5: bb 2a 00 00 00   mov $0x2a,%ebx 
    4000ea: cd 80     int $0x80 

(dieser Maschinencode) all wirklich benötige ich? Was mache ich falsch (endiannes ??), muss ich das vielleicht seit SIGSEGV anders nennen?

+0

Sie können ein paar zufälliges Bytes als Funktion nicht nur behandeln. Sie müssen die Aufrufkonventionen des Compilers beachten und geeignete Funktionsprologe und Epiloge bereitstellen. –

+0

natürlich, diese Opcodes sind mit dem gleichen Compiler generiert, und nicht zufällig, so sollte in Ordnung sein, wissen Sie, was genau soll ich tun? Warum kann ich es vom Terminal aus starten? – 4pie0

+0

Zunächst müssen Sie sicherstellen, dass der Code im ausführbaren Speicher liegt. Versuchen Sie etwas wie "__attribute __ ((section," .text "))' oder ähnliches hinzuzufügen (siehe Handbuch). Und wie gesagt, stellen Sie sicher, dass Sie die korrekten Aufrufkonventionen implementieren. –

Antwort

12

Ich habe das getan. Der Code muss als ausführbarer Code markiert sein. Eine Möglichkeit besteht darin, diesen binären Maschinencode in einen ausführbaren Puffer zu kopieren.

#include <unistd.h> 
#include <sys/mman.h> 
#include <string.h> 

char code[] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x48, 
    0x89,0x75,0xf0,0xb8,0x2a,0x00,0x00,0x00,0xc9,0xc3,0x00}; 
/* 
* 00000000004004b4 <main> 55      push %rbp 
00000000004004b5 <main+0x1> 48 89 e5    mov %rsp,%rbp 
00000000004004b8 <main+0x4> 89 7d fc    mov %edi,-0x4(%rbp) 
00000000004004bb <main+0x7> 48 89 75 f0    mov %rsi,-0x10(%rbp) 
/NetBeansProjects/examples/tiny_c/tiny.c:15 
    return 42; 
00000000004004bf <main+0xb> b8 2a 00 00 00   mov $0x2a,%eax 
/NetBeansProjects/examples/tiny_c/tiny.c:16 
} 
00000000004004c4 <main+0x10> c9      leaveq 
00000000004004c5 <main+0x11> c3      retq 
*/ 
int main(int argc, char **argv) 
{ 
    void *buf; 

    /* copy code to executable buffer */  
    buf = mmap (0,sizeof(code),PROT_READ|PROT_WRITE|PROT_EXEC, 
       MAP_PRIVATE|MAP_ANON,-1,0); 
    memcpy (buf, code, sizeof(code)); 

    /* run code */ 
    int i = ((int (*) (void))buf)(); 
    printf("get this done. returned: %d", i); 
return 0; 
} 

Ausgabe:

dies getan. zurückgegeben: 42

erfolgreiche Lauf (Gesamtzeit: 57ms)

+4

Nett aber mit großem Wissen kommt große Verantwortung Denken Sie daran, bevor Sie dies missbrauchen .... –

+0

Sie können diesen Code mit einigen kleineren Anpassungen als Shellcode Executer verwenden, wenn es ein Speicherleck gibt, ist die Software aber es ist viel schwieriger, es richtig zu machen .. aber ich denke dir bauen eine Art als virtuelle Maschine? –

+0

Nein, ich wollte nur aus dem von mir geschriebenen C/C++ - Programmmaschinencode ausführen. – 4pie0