wow, il s'est avéré être beaucoup plus douloureux que ce que j'attendais. 100% de la douleur était linux protéger le programme de remplacement et/ou de l'exécution des données.
Deux solutions indiquées ci-dessous. Et beaucoup de googler a été impliqué de manière un peu simple de mettre quelques octets d'instruction et de les exécuter était le mien, le mprotect et en l'alignant sur la taille de la page a été élaboré à partir des recherches effectuées sur google, des choses que j'avais à apprendre de cet exemple.
L'auto-modifiant le code est simple, si vous prenez le programme ou au moins tout les deux fonctions simples, de compiler et puis démonter, vous obtiendrez les opérateurs de ces instructions. ou de l'utilisation des msna de compiler des blocs de l'assembleur, etc. À partir de cela j'ai décidé de l'opcode pour charger immédiatement dans eax, puis retourner.
Idéalement, il vous suffit de mettre ces octets de mémoire ram et de l'exécution de cette ram. Pour obtenir linux que vous avez à modifier la protection, ce qui signifie que vous devez envoyer un pointeur qui est aligné sur un mmap page. Afin d'allouer plus que vous avez besoin, trouver l'adresse alignée à l'intérieur de cette allocation qui est sur une frontière de page et mprotect à partir de cette adresse et d'utiliser cette mémoire pour mettre votre opcodes, et puis l'exécuter.
le deuxième exemple, on prend une fonction existante compilé dans le programme, à cause du mécanisme de protection, vous ne pouvez pas simplement viser et modifier des octets, vous devez ôter la protection de l'écrit. Donc, vous devez sauvegarder à l'état de la limite de la page d'appel mprotect avec cette adresse et assez d'octets pour couvrir le code doit être modifié. Ensuite, vous pouvez modifier les octets/opcodes pour cette fonction de la manière que vous voulez (tant que vous n'avez pas déborder sur toute fonction que vous souhaitez continuer à utiliser) et de l'exécuter. Dans ce cas, vous pouvez voir qu' fun()
de travaux, puis-je le changer tout simplement de retourner une valeur, de l'appeler à nouveau, et maintenant qu'il a été modifié.
#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);
}