arn*_*app 0 c unix linux memory mprotect
我正在尝试使用protect修改.text段中的值以给我写入权限:
int pageSize = sysconf(_SC_PAGE_SIZE);
int *toModify = (int *)(foo+5);
if (mprotect(toModify, pageSize, PROT_WRITE) < 0 ) {
perror("mprotect failed with error:");
return -1;
}
*toModify = 5;
printf("Modify :%i",foo());
Run Code Online (Sandbox Code Playgroud)
mprotect永远不会工作.它总是返回一个mprotect failed with error:: Invalid argument错误.
foo是一个返回函数后存储5个字节的int的方法(这就是foo + 5的原因)
来自man mprotect:
EINVAL addr is not a valid pointer, or not a multiple of PAGESIZE.
Run Code Online (Sandbox Code Playgroud)
您并没有注意到addr需要成为其倍数的部分PAGESIZE,显然......虽然在该手册页的至少一个版本中,该要求并未特别明确,但只是说"为内存页面指定了所需的保护" (s)包含部分或全部间隔[addr,addr + len-1]".
查找包含特定地址的页面地址并不是特别难,因为您已经完成了这pageSize = sysconf(_SC_PAGE_SIZE);一点:
static inline void *pageof(const void* p)
{ return (p & ~(pageSize - 1));
}
Run Code Online (Sandbox Code Playgroud)
然后修改你的mprotect电话说mprotect(pageof(toModify), pageSize, ...).虽然,请参阅@Zack的答案,获取有关您指定的权限的警告.然后回去阅读手册页,mprotect()确保你真正理解你在做什么......
我已在 OS X 10.9 上执行了以下代码,它似乎具有所需的行为。输出为 \xe2\x80\x9cfoo 返回 23。\xe2\x80\x9d
\n\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <unistd.h>\n#include <sys/mman.h>\n\n\nextern int foo(void);\n\n\nint main(void)\n{\n // New value to write into foo+5.\n int NewValue = 23;\n\n // Find page size for this system.\n size_t pagesize = sysconf(_SC_PAGESIZE);\n\n // Calculate start and end addresses for the write.\n uintptr_t start = (uintptr_t) &foo + 5;\n uintptr_t end = start + sizeof NewValue;\n\n // Calculate start of page for mprotect.\n uintptr_t pagestart = start & -pagesize;\n\n // Change memory protection.\n if (mprotect((void *) pagestart, end - pagestart,\n PROT_READ | PROT_WRITE | PROT_EXEC))\n {\n perror("mprotect");\n exit(EXIT_FAILURE);\n }\n\n // Write new bytes to desired location.\n memcpy((void *) start, &NewValue, sizeof NewValue);\n\n // Some systems could require an invalidate of instruction cache here.\n\n // Try modified function.\n printf("foo returns %d.\\n", foo());\n\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n对于foo,我使用了这个汇编代码。两个源都是用cc -arch i386.
.globl _foo\n_foo:\n nop\n nop\n nop\n nop\n mov $42, %eax\n ret\nRun Code Online (Sandbox Code Playgroud)\n\n您应该仅将这种方式修改代码作为学习练习,而不应在任何已部署的应用程序中使用它。
\n