哇,结果比我想象的要痛苦得多。100% 的痛苦是 linux 保护程序不被覆盖和/或执行数据。
如下所示的两种解决方案。并且涉及到大量的谷歌搜索,所以有些简单的放置一些指令字节并执行它们是我的,页面大小的 mprotect 和对齐是从谷歌搜索中挑选出来的,这是我必须为这个例子学习的东西。
自修改代码是直截了当的,如果您使用程序或至少只是两个简单的函数,编译然后反汇编您将获得这些指令的操作码。或使用 nasm 编译汇编程序块等。据此,我确定操作码将立即数加载到 eax 中,然后返回。
理想情况下,您只需将这些字节放入某个 ram 中并执行该 ram。要让 linux 做到这一点,您必须更改保护,这意味着您必须向它发送一个在 mmap 页面上对齐的指针。因此,分配比您需要的更多的内存,在页面边界上的该分配中找到对齐的地址,并从该地址 mprotect 并使用该内存来放置您的操作码,然后执行。
第二个示例将现有函数编译到程序中,同样由于保护机制,您不能简单地指向它并更改字节,您必须取消保护它免受写入。因此,您必须使用该地址和足够的字节备份到先前的页面边界调用 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);
}