copy and call function

♀尐吖头ヾ 提交于 2019-12-23 04:12:12

问题


I'd like to copy and call a function, but the code below segfaults when calling the buffer. What do I have to change? (Linux, x86)

#include <string.h>
#include <malloc.h>
#include <stdio.h>

int foo () { return 12; }
void foo_end () {}

int main () {
  int s = (unsigned long long) foo_end - (unsigned long long) foo;
  int (*f) () = (int (*)()) malloc (s);
  memcpy ((void*) f, (const void*) foo, s);
  printf ("%d %d\n", f (), foo ());
}

EDIT: Working solution:

#include <string.h>
#include <malloc.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>

int foo () { return 12; }
void foo_end () {}

int main () {
  int s = (unsigned long long) foo_end - (unsigned long long) foo;
  int (*f) () = (int (*)()) malloc (s);
  memcpy ((void*) f, (const void*) foo, s);
  long ps = sysconf (_SC_PAGESIZE);
  void *fp = (void*) ((unsigned long long) f & ~((unsigned long long) (ps-1)));
  if (mprotect ((void*) fp, ps, PROT_READ | PROT_WRITE | PROT_EXEC)) return -1;
  printf ("%d %d\n", f (), foo ());
}

回答1:


Potentially you're using an OS which does not grant execute permission to data segments.

Some environments will protect data pages against execution, to avoid various types of security problems (or exploits for them).

Consider calling mprotect() to enable execute for that page and report what happens.




回答2:


Whoa, that code has so many issues.

  1. You can't know that the functions are laid out sequentially in memory, with no padding between them
  2. You can't know that the pointers to two functions are subtractable
  3. You can't know that memory returned by malloc() can be called into

In short, don't do this.

Update:

In Linux, I think you can use mprotect() to set the permissions on a block of memory. I thought this needed root, but apparently not (as long as you're in your own process' memory).




回答3:


This is a common issue among embedded systems folk. This technique is often times used for copying from Read-Only Memory into Random-Access Memory (write and read capable). There is no elegant nor standard solution using standard C or C++.

A simpler solution is to use the Linker to define some new, non-standard, segments. Use non-standard #pragma to instruct the compiler to place the function into a new segment. Use non-standard compiler directive to access the beginning address and ending address of this segment. This will allow you to get the size of the function.

A safer method for the destination is to create another segment with executable and write attributes. Copy the data in the function segment into this executable segment. Set up a function pointer to point to the start of this segment. Execute the function via the pointer.

Another solution is to perform this in assembly language. Often, assemblers give you more freedom (to shoot your foot) to manipulate memory like this in a lower level.

Also, review your operating system loader, memory attributes and protection schemes. Some OSes may restrict this kind of behavior to Kernel privilege or higher.



来源:https://stackoverflow.com/questions/3717499/copy-and-call-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!