2013-08-27 13 views
10

po this instrukcji Udało mi się wyprodukować tylko 528 bajtów o rozmiarze a.out (kiedy gcc main.c dał mi początkowo 8539 bajtów dużego pliku).Wykonaj kod maszyny binarnej z C

main.c było:

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

    return 42; 
} 

ale ja zbudowałem a.out z tego pliku zespołu Zamiast:

main.s:

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

z:

[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 

ponieważ potrzebuję maszyny co de zrobić:

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 

plik znajduje się w małej konwencji 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 

teraz chcę wykonać to tak:

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

jednak otrzymuję winy segmentacji. Moje pytanie brzmi: czy jest to fragment tekstu

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

(ten kod maszynowy) wszystko czego naprawdę potrzebujemy? Co robię źle (endiannes?), Może po prostu muszę to nazwać w inny sposób od SIGSEGV?

+0

nie można traktować tylko kilka losowych bajtów jako funkcja. Musisz przestrzegać konwencji wywoływania kompilatora i dostarczać odpowiednich prologów funkcyjnych i epilogów. –

+0

ofcourse, te kody opcyjne są generowane z tego samego kompilatora, a nie losowe, więc powinno być OK, czy wiesz co dokładnie powinienem zrobić? dlaczego mogę go uruchomić z terminala? – 4pie0

+0

Po pierwsze, upewnij się, że kod znajduje się w pamięci wykonywalnej. Spróbuj dodać coś w rodzaju '__attribute __ ((section," .text ")) lub podobne (patrz instrukcja). Jak już powiedziałem, upewnij się, że implementujesz prawidłowe konwencje wywoływania. –

Odpowiedz

12

Zrobiłem to. Kod musi zostać oznaczony jako kod wykonywalny. Jednym ze sposobów na to jest skopiowanie tego binarnego kodu maszynowego do wykonywanego bufora.

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

wyjściowa:

aby to zrobić. zwracane: 42

RUN skuteczne (całkowity czas: 57ms)

+4

Przyjemnie, ale z wielką wiedzą przychodzi wielka odpowiedzialność, pomyśl o tym zanim zaczniesz nadużywać tego ... –

+0

możesz użyć tego kodu z drobnymi korektami, jako wykonawca kodu powłoki, gdy jest przeciek pamięci, ale jest o wiele trudniej go naprawić. ale myślę, że ty budujesz coś w rodzaju maszyny wirtualnej? –

+0

Nie, chciałem tylko wykonać kod maszynowy C/C++ napisany przeze mnie. – 4pie0