exécuter le code machine binary à partir de C

En suivant ces instructions, j’ai réussi à ne produire que 528 octets de taille a.out (lorsque gcc main.c m’a initialement fourni un fichier de 8539 octets).

main.c était:

int main(int argc, char** argv) { return 42; } 

mais j’ai construit a.out à partir de ce fichier d’assemblage à la place:

main.s:

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

avec:

 me@comp# nasm -f elf64 tiny.s me@comp# gcc -Wall -s -nostartfiles -nostdlib tiny.o me@comp# ./a.out ; echo $? 42 me@comp# wc -c a.out 528 a.out 

parce que j’ai besoin de code machine, je fais:

 objdump -d a.out a.out: file format elf64-x86-64 Disassembly of section .text: 00000000004000e0 : 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 

le fichier est en convention little endian:

 me@comp# 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 ssortingng table index: 3 

maintenant je veux exécuter ceci comme ceci:

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

Cependant, je reçois une erreur de segmentation Ma question est la suivante: cette section de texte est-elle

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

(ce code machine) tout ce dont j’ai vraiment besoin? Qu’est-ce que je fais mal (endiannes ??), peut-être je dois juste appeler cela de manière différente depuis SIGSEGV?

J’ai fait ça. Le code doit être marqué en tant que code exécutable. Une façon de le faire est de copier ce code machine binary dans un tampon exécutable.

 #include  #include  #include  char code[] = {0x55,0x48,0x89,0xe5,0x89,0x7d,0xfc,0x48, 0x89,0x75,0xf0,0xb8,0x2a,0x00,0x00,0x00,0xc9,0xc3,0x00}; /* * 00000000004004b4 
55 push %rbp 00000000004004b5 48 89 e5 mov %rsp,%rbp 00000000004004b8 89 7d fc mov %edi,-0x4(%rbp) 00000000004004bb 48 89 75 f0 mov %rsi,-0x10(%rbp) /NetBeansProjects/examples/tiny_c/tiny.c:15 return 42; 00000000004004bf b8 2a 00 00 00 mov $0x2a,%eax /NetBeansProjects/examples/tiny_c/tiny.c:16 } 00000000004004c4 c9 leaveq 00000000004004c5 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; }

sortie:

faites-le. retourné: 42

RUN SUCCESSFUL (durée totale: 57ms)