うわー、これは私が予想していたよりもはるかに苦痛であることが判明しました。苦痛の100%は、Linuxがプログラムを上書きしたり、データを実行したりしないように保護することでした。
以下に示す2つのソリューション。そして、多くのグーグルが含まれていたので、いくらか単純ないくつかの命令バイトを入れてそれらを実行するのは私のものでした、mprotectとページサイズの整列はグーグル検索から選別されました、私がこの例のために学ばなければならなかったもの。
自己変更コードは単純明快です。プログラムまたは少なくとも2つの単純な関数を取得し、コンパイルしてから逆アセンブルすると、それらの命令のオペコードが取得されます。または、nasmを使用してアセンブラのブロックなどをコンパイルします。これから、オペコードを決定して、即時にeaxにロードしてから戻ります。
理想的には、それらのバイトをいくつかのRAMに入れて、そのRAMを実行するだけです。Linuxにそれを行わせるには、保護を変更する必要があります。つまり、mmapページに配置されたポインターをLinuxに送信する必要があります。したがって、必要以上に割り当て、ページ境界にあるその割り当て内で整列されたアドレスを見つけ、そのアドレスからmprotectし、そのメモリを使用してオペコードを配置してから実行します。
2番目の例では、プログラムにコンパイルされた既存の関数を使用します。これも、保護メカニズムのため、単純にそれをポイントしてバイトを変更することはできず、書き込みから保護を解除する必要があります。したがって、前のページ境界にバックアップして、そのアドレスと変更するコードをカバーするのに十分なバイト数でmprotectを呼び出す必要があります。次に、その関数のバイト/オペコードを任意の方法で変更して(引き続き使用する関数に波及しない限り)、実行することができます。この場合、それが機能していることがわかりますfun()
。次に、値を返すように変更し、もう一度呼び出して、変更しました。
#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);
}