mprotect始终返回无效参数

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的原因)

twa*_*erg 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()确保你真正理解你在做什么......


Eri*_*hil 5

我已在 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}\n
Run Code Online (Sandbox Code Playgroud)\n\n

对于foo,我使用了这个汇编代码。两个源都是用cc -arch i386.

\n\n
    .globl  _foo\n_foo:\n    nop\n    nop\n    nop\n    nop\n    mov $42, %eax\n    ret\n
Run Code Online (Sandbox Code Playgroud)\n\n

您应该仅将这种方式修改代码作为学习练习,而不应在任何已部署的应用程序中使用它。

\n