2013-08-27 2 views
10

следующие this инструкции Мне удалось создать только 528 байт размером a.out (когда gcc main.c дал мне 8539 байт большого файла изначально).выполнить двоичный код машины от C

main.c был:

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

    return 42; 
} 

, но я построил a.out из этого сборочного файла вместо:

main.s:

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

с:

[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 

потому что мне нужна машина co де я:

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 

файл находится в небольшой 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 

теперь я хочу, чтобы выполнить это так:

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

однако я получаю ошибку сегментации. Мой вопрос: этот раздел текста

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

(это машинный код) все, что мне действительно нужно? Что я делаю неправильно (endiannes ??), может быть, мне просто нужно назвать это по-другому с SIGSEGV?

+0

Вы не можете рассматривать несколько случайных байт в качестве функции. Вы должны уважать соглашения о вызовах компилятора и предоставлять подходящие прологи и эпилоги. –

+0

, конечно, эти коды кода генерируются с помощью одного и того же компилятора, а не случайные, так что должно быть хорошо, знаете ли вы, что именно я должен делать? почему я могу запустить его с терминала? – 4pie0

+0

Прежде всего, вам нужно убедиться, что код находится в исполняемой памяти. Попробуйте добавить что-то вроде '__attribute __ ((раздел," .text "))' или аналогичный (см. Руководство). И, как я сказал, обязательно выполните правильные соглашения о вызовах. –

ответ

12

Я получил это. Код должен быть помечен как исполняемый код. Один из способов сделать это - скопировать этот двоичный машинный код в исполняемый буфер.

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

выход:

получить это сделать. вернулся: 42

RUN УСПЕШНОГО (общее время: 57ms)

+4

Приятно, но с большими знаниями приходит большая ответственность подумать об этом, прежде чем вы собираетесь злоупотреблять этим .... –

+0

вы можете использовать этот код с некоторыми незначительными корректировками в качестве исполнятеля shellcode, когда есть утечка памяти - это программное обеспечение, но его гораздо труднее понять. но я думаю, что вы что-то вроде виртуальной машины? –

+0

нет, я просто хотел выполнить из машинного кода программы C/C++, написанного мной. – 4pie0