うわー、これは予想以上に痛いものでした痛みの100%は、プログラムが上書きされたりデータが実行されないようにするためのLinuxでした。
下記の2つのソリューション。そしてたくさんのグーグルが関わっていたので、いくらか単純な命令バイトを入れて実行すると、mprotectとページサイズの調整がgoogle検索で行われました。
自己修正コードは簡単です。プログラムを実行するか、少なくとも2つの単純な関数をコンパイルして逆アセンブルすると、それらの命令のオペコードが得られます。またはアセンブラのブロックをコンパイルするためにnasmを使用してください。これから、即座にeaxにロードして戻すオペコードを決定しました。
理想的には、これらのバイトをいくつかのラムに置き、そのラムを実行します。 linuxにこれをさせるためには、保護を変更する必要があります。つまり、mmapページにポインタを合わせて送る必要があります。そのため、必要以上に割り当てる必要があります。ページ境界にあるその割り当て内のアライメントされたアドレスを見つけて、そのアドレスから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);
}
http://linux.die.net/man/2/mprotectは、mprotectの引数が何であるかを説明する必要があります。呼び出す関数IDはEAXで渡され、次の引数はEBX ECXとEDXで渡されます。 – KitsuneYMG