вау, это оказалось намного более болезненным, чем я ожидал. 100% боли было в том, что linux защищал программу от перезаписи и / или выполнения данных.
Два решения показаны ниже. И было много гугла, поэтому несколько простых байт инструкций и их выполнение были моими, mprotect и выравнивание по размеру страницы были выбраны из поисков Google, материал, который мне пришлось изучить для этого примера.
Самомодифицирующийся код прост: если вы возьмете программу или хотя бы просто две простые функции, скомпилируете, а затем разберете, вы получите коды операций для этих инструкций. или используйте nasm для компиляции блоков ассемблера и т. д. Из этого я определил код операции для немедленной загрузки в eax и возврата.
В идеале вы просто помещаете эти байты в какого-нибудь барана и запускаете этого барана. Чтобы заставить Linux сделать это, вы должны изменить защиту, что означает, что вы должны отправить ему указатель, который выровнен на странице mmap. Поэтому выделите больше, чем вам нужно, найдите выровненный адрес в пределах этого выделения, который находится на границе страницы, и защитите его от этого адреса и используйте эту память для помещения ваших кодов операций, а затем выполните.
во втором примере используется существующая функция, скомпилированная в программу, опять же, из-за механизма защиты, который вы не можете просто указать на нее и изменить байты, вы должны снять защиту с записи. Таким образом, вы должны выполнить резервное копирование до вызова границы предыдущей страницы 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);
}