C: Run machine code from memory -
i want execute code memory; longterm goal create self-decrypting app. understand matter started roots. created following code:
#define unencrypted true #define sizeof_function(x) ( (unsigned long) (&(endof_##x)) - (unsigned long) (&x)) #define endof_function(x) void volatile endof_##x() {} #define declare_end_of_function(x) void endof_##x(); #include <unistd.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/mman.h> #include <sys/types.h> unsigned char *bin; #ifdef unencrypted void hexdump(char *description, unsigned char *todump, unsigned long length) { printf("hex-dump of \"%s\":\n", description); (int = 0; < length; i++) { printf("%02x", todump[i]); } printf("\n"); } void hello_world() { printf("hello world!\n"); } endof_function(hello_world); #endif int main (void) { errno = 0; unsigned long hello_worldsize = sizeof_function(hello_world); bin = malloc(hello_worldsize); //compute start of page size_t pagesize = sysconf(_sc_pagesize); uintptr_t start = (uintptr_t) bin; uintptr_t end = start + (hello_worldsize); uintptr_t pagestart = start & -pagesize; bin = (void *)pagestart; //set mprotect bin write-only if(mprotect(bin, end - pagestart, prot_write) == -1) { printf("\"mprotect\" failed; error: %s\n", strerror(errno)); return(1); } //get size , adresses unsigned long hello_worldadress = (uintptr_t)&hello_world; unsigned long binadress = (uintptr_t)bin; printf("address of hello_world %lu\nsize of hello_world %lu\nadress of bin:%lu\n", hello_worldadress, hello_worldsize, binadress); //check if hello_worldadress points hello_world() void (*checkadress)(void) = (void *)hello_worldadress; checkadress(); //print memory contents of hello_world() hexdump("hello_world", (void *)&hello_world, hello_worldsize); //copy hello_world() bin memcpy(bin, (void *)hello_worldadress, hello_worldsize); //set mprotect bin read-execute if(mprotect(bin, end - pagestart, prot_read|prot_exec) == -1) { printf("\"mprotect\" failed; error: %s\n", strerror(errno)); return(1); } //check if contents @ binadress same of hello_world hexdump("bin", (void *)binadress, hello_worldsize); //execute binadress void (*executebin)(void) = (void *)binadress; executebin(); return(0); }
however segfault-error; programs output following:
(on os x; i86-64):
adress of hello_world 4294970639
size of hello_world 17 adress of bin:4296028160 hello world! hex-dump of "hello_world": 554889e5488d3d670200005de95a010000 hex-dump of "bin": 554889e5488d3d670200005de95a010000 program ended exit code: 9
and on raspi (linux 32-bit arm):
adress of hello_world 67688 size of hello_world 36 hello world! hello world! hex-dump of "hello_world": 00482de90db0a0e108d04de20c009fe512ffffeb04008de50bd0a0e10088bde8d20b0100 hex-dump of "bin": 00482de90db0a0e108d04de20c009fe512ffffeb04008de50bd0a0e10088bde8d20b0100 speicherzugriffsfehler //this german memory access error
where mistake?
the problem was, printf-call in hello_world based on relative jump address, of course doesn't work in copied function. testing purposes changed hello_world to:
int hello_world() { //_printf("hello world!\n"); return 14; }
and code under "//execute binadress" to:
int (*executebin)(void) = (void *)binadress; int test = executebin(); printf("value: %i\n", test);
which prints out 14 :d
on arm, have flush instruction cache using function cacheflush
, or code may not run properly. required self-modifying code , jit compilers, not needed x86.
additionally, if move chunk of code 1 location another, have fixup relative jumps. typically, calls library functions implemented jumps relocation section, , relative.
to avoid having fixup jumps, can use linker tricks compile code start @ different offset. then, when decrypting, load decrypted code offset. two-stage compilation process used: compile real code, append resulting machine code decryption stub, , compile whole program.
Comments
Post a Comment