Wow, that turned out to be a lot more painful than I expected. 100% of the pain was linux, protecting the program from overwriting and / or executing data.
The two solutions shown below. And a lot of googling was involved, so a few simple ones put a few bytes of commands and executed them, my mprotect and page alignment were rejected from Google search queries, which I had to study for this example.
Self-modifying code is straightforward, if you take a program or at least only two simple functions, compile and then parse it, you will get operation codes for these instructions. or use nasm to compile assembler blocks, etc. From this, I defined the opcode to load eax right away, then return.
Ideally, you just put these bytes in some ram and execute that ram. To force Linux to do this, you need to change the protection, which means that you need to send a pointer that is aligned on the mmap page. Therefore, select more than you need, find the aligned address within this selection, located on the page border, and mprotect from this address and use this memory to place your operation codes and then execute.
the second example takes an existing function compiled into a program, again, due to the protection mechanism, you cannot just point to it and change the bytes, you must protect it from writing. Thus, you need to back up to the previous call to the mprotect page with this address and enough bytes to cover the code that needs to be changed. Then you can change the bytes / operation codes for this function in any way (until you switch to any function that you want to continue to use) and execute it. In this case, you can see that fun() works, then I change it to just return the value, call it again and now it has been changed.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> unsigned char *testfun; unsigned int fun ( unsigned int a ) { return(a+13); } unsigned int fun2 ( void ) { return(13); } int main ( void ) { unsigned int ra; unsigned int pagesize; unsigned char *ptr; unsigned int offset; pagesize=getpagesize(); testfun=malloc(1023+pagesize+1); if(testfun==NULL) return(1); //need to align the address on a page boundary printf("%p\n",testfun); testfun = (unsigned char *)(((long)testfun + pagesize-1) & ~(pagesize-1)); printf("%p\n",testfun); if(mprotect(testfun, 1024, PROT_READ|PROT_EXEC|PROT_WRITE)) { printf("mprotect failed\n"); return(1); } //400687: b8 0d 00 00 00 mov $0xd,%eax //40068d: c3 retq testfun[ 0]=0xb8; testfun[ 1]=0x0d; testfun[ 2]=0x00; testfun[ 3]=0x00; testfun[ 4]=0x00; testfun[ 5]=0xc3; ra=((unsigned int (*)())testfun)(); printf("0x%02X\n",ra); testfun[ 0]=0xb8; testfun[ 1]=0x20; testfun[ 2]=0x00; testfun[ 3]=0x00; testfun[ 4]=0x00; testfun[ 5]=0xc3; ra=((unsigned int (*)())testfun)(); printf("0x%02X\n",ra); printf("%p\n",fun); offset=(unsigned int)(((long)fun)&(pagesize-1)); ptr=(unsigned char *)((long)fun&(~(pagesize-1))); printf("%p 0x%X\n",ptr,offset); if(mprotect(ptr, pagesize, PROT_READ|PROT_EXEC|PROT_WRITE)) { printf("mprotect failed\n"); return(1); } //for(ra=0;ra<20;ra++) printf("0x%02X,",ptr[offset+ra]); printf("\n"); ra=4; ra=fun(ra); printf("0x%02X\n",ra); ptr[offset+0]=0xb8; ptr[offset+1]=0x22; ptr[offset+2]=0x00; ptr[offset+3]=0x00; ptr[offset+4]=0x00; ptr[offset+5]=0xc3; ra=4; ra=fun(ra); printf("0x%02X\n",ra); return(0); }