2013-08-27 23 views
10

seguendo le istruzioni this Sono riuscito a produrre solo 528 byte in dimensione a.out (quando gcc main.c mi ha dato inizialmente un grande file 8539 byte).esegui codice macchina binaria da C

main.c era:

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

    return 42; 
} 

ma ho costruito a.out da questo file assembly invece:

main.s:

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

con:

[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 

perché ho bisogno di macchina co de faccio:

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 

file è in poco convenzione endian:

[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 

ora voglio eseguire questo come questo:

#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; 
} 

tuttavia ottengo segmentation fault. La mia domanda è: è questa sezione del testo

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

(questo codice macchina) tutto quello che ho veramente bisogno? Cosa faccio di sbagliato (endiannes ??), forse ho solo bisogno di chiamare questo in modo diverso dal SIGSEGV?

+0

non si può solo trattare un paio di byte casuali come una funzione. Devi rispettare le convenzioni di chiamata del compilatore e fornire prologhi ed epiloghi di funzione adeguati. –

+0

naturalmente, questi codici operativi sono generati con lo stesso compilatore e non casuali, quindi dovrebbe essere OK, sai cosa dovrei fare esattamente? perché posso eseguirlo dal terminale? – 4pie0

+0

Prima di tutto, è necessario assicurarsi che il codice risieda nella memoria eseguibile. Prova ad aggiungere qualcosa come '__attribute __ ((section," .text "))' o simili (vedi il manuale). E come ho detto, assicurati di implementare le convenzioni di chiamata corrette. –

risposta

12

Ho fatto questo. Il codice deve essere contrassegnato come codice eseguibile. Un modo per farlo è copiare questo codice macchina binaria nel buffer eseguibile.

#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; 
} 

uscita:

ottenere questo fatto. tornato: 42

corsa di successo (tempo totale: 57ms)

+4

Bello ma con grande conoscenza è una grande responsabilità pensarci prima di usare questo codice in modo errato ... –

+0

è possibile utilizzare questo codice con alcune modifiche minori come un exececut shellcode quando c'è una perdita di memoria è il software ma è molto più difficile farlo correttamente .. ma ti penso stanno costruendo qualche tipo come macchina virtuale? –

+0

no, volevo solo eseguire dal codice macchina del programma C/C++ scritto da me stesso. – 4pie0