我正在尝试修改.text段中的一个值,使用protect来给我编写访问权限:
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());保护不起作用。它总是返回一个mprotect failed with error:: Invalid argument错误。
foo是一个返回一个int的方法,它在函数之后存储5个字节(这就是foo+5的原因)。
发布于 2013-12-04 18:16:15
我已经在OSX10.9上执行了以下代码,它似乎具有所需的行为。输出是“foo返回23”。
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
extern int foo(void);
int main(void)
{
// New value to write into foo+5.
int NewValue = 23;
// Find page size for this system.
size_t pagesize = sysconf(_SC_PAGESIZE);
// Calculate start and end addresses for the write.
uintptr_t start = (uintptr_t) &foo + 5;
uintptr_t end = start + sizeof NewValue;
// Calculate start of page for mprotect.
uintptr_t pagestart = start & -pagesize;
// Change memory protection.
if (mprotect((void *) pagestart, end - pagestart,
PROT_READ | PROT_WRITE | PROT_EXEC))
{
perror("mprotect");
exit(EXIT_FAILURE);
}
// Write new bytes to desired location.
memcpy((void *) start, &NewValue, sizeof NewValue);
// Some systems could require an invalidate of instruction cache here.
// Try modified function.
printf("foo returns %d.\n", foo());
return 0;
}对于foo,我使用了这个程序集代码。这两个源都是用cc -arch i386构建的。
.globl _foo
_foo:
nop
nop
nop
nop
mov $42, %eax
ret您应该以这种方式修改代码,将其作为学习练习,而不是在任何已部署的应用程序中使用。
发布于 2013-12-04 17:37:07
来自man mprotect
EINVAL addr is not a valid pointer, or not a multiple of PAGESIZE.显然,你没有注意到addr需要成为PAGESIZE的倍数.尽管至少在手册页的一个版本中,这一要求并没有特别明确,但简单地说“指定了包含部分或全部间隔addr,addr+len-1的内存页的所需保护”。
查找包含特定地址的页面的地址并不特别困难,因为您已经完成了pageSize = sysconf(_SC_PAGE_SIZE);位:
static inline void *pageof(const void* p)
{ return (p & ~(pageSize - 1));
}然后修改mprotect调用以表示mprotect(pageof(toModify), pageSize, ...)。不过,有关您指定的权限的警告,请参见@Zack的回答。回去读mprotect()的手册,确保你真的明白你在做什么.
发布于 2013-12-04 17:43:30
mprotect的address参数需要对页对齐,而size参数是一个完整的页面。另外,仅将页面设置为PROT_WRITE就意味着不再允许您读取它--这个特定的页面将位于文本段中,因此它也需要是PROT_EXEC,否则程序从mprotect返回时就会崩溃(因为该页面上的代码不再被认为是可执行的)。
对程序的这种修改可以满足您的需要:
/* file A */
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
extern const int foo;
int
main (int argc, char *argv[])
{
printf("Before modification: foo = %d @ %p\n", foo, (void *)&foo);
size_t pagesize = sysconf(_SC_PAGESIZE);
void *foo_page = (void *) (((uintptr_t)&foo) & ~(pagesize - 1));
if (mprotect(foo_page, pagesize, PROT_READ|PROT_WRITE|PROT_EXEC)) {
perror("mprotect");
return 1;
}
*(int *)&foo = 42; /* this is still undefined behavior! */
printf("After modification: foo = %d @ %p\n", foo, (void *)&foo);
return 0;
}
/* file B */
const int foo = 23;警告:写入const数据会触发未定义的行为,无论您是否使用操作系统原语来禁用对包含该数据的页面的写入保护。当我第一次测试这段代码时,我自己的文件中没有const int foo = 23;,GCC将这两个printf调用重写为printf("...", 23, &foo)。这是一个有效的优化。如果我打开链接时间优化,那么即使常量的定义被移到自己的文件中,也会发生这种情况。此外,GCC还有权用无条件的*(int *)&foo = 42;或陷阱指令取代abort()。
https://stackoverflow.com/questions/20381812
复制相似问题