8

我想知道在 C 中如何将函数的内容复制到内存中并执行它?

我正在尝试做这样的事情:

typedef void(*FUN)(int *);
char * myNewFunc;

char *allocExecutablePages (int pages)
{
    template = (char *) valloc (getpagesize () * pages);
    if (mprotect (template, getpagesize (), 
          PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
        perror ("mprotect");
    } 
}

void f1 (int *v) {
    *v = 10;
}

// allocate enough spcae but how much ??
myNewFunc = allocExecutablePages(...)

/* Copy f1 somewere else
 * (how? assume that i know the size of f1 having done a (nm -S foo.o))
 */

((FUN)template)(&val);
printf("%i",val);

感谢您的回答

4

5 回答 5

6

您似乎已经弄清楚了有关保护标志的部分。如果您知道函数的大小,现在您只需执行 memcpy() 并将 f1 的地址作为源地址传递。

一个重要的警告是,在许多平台上,您将无法从您正在复制的那个 (f1) 调用任何其他函数,因为相对地址被硬编码到函数的二进制代码中,并将其移动到不同的定位它的内存可以使那些相对地址变坏。

于 2010-12-28T13:08:51.447 回答
3

这恰好起作用,因为 function1 和 function2 在内存中的大小完全相同。我们的 memcopy 需要 function2 的长度,所以应该做的是: int diff = (&main - &function2);

您会注意到您可以根据自己的喜好编辑功能 2,并且它可以正常工作!

顺便说一句,巧妙的把戏。Unfurtunate g++ 编译器确实吐出了从 void* 到 int 的无效转换......但实际上使用 gcc 它可以完美编译;)

修改来源:

//Hacky solution and simple proof of concept that works for me (and compiles without warning on Mac OS X/GCC 4.2.1):
//fixed the diff address to also work when function2 is variable size    
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <sys/mman.h>

int function1(int x){ 
   return x-5;
}   

int function2(int x){ 
  //printf("hello world");
  int k=32;
  int l=40;
  return x+5+k+l;
}   


int main(){
  int diff = (&main - &function2);
  printf("pagesize: %d, diff: %d\n",getpagesize(),diff);

  int (*fptr)(int);

  void *memfun = malloc(4096);

  if (mprotect(memfun, 4096, PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
      perror ("mprotect");
  }   

  memcpy(memfun, (const void*)&function2, diff);

  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));
  fptr = memfun;
  printf("memory: %d\n",(*fptr)(6) );
  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));

  free(memfun);
  return 0;
}   

输出:

Walter-Schrepperss-MacBook-Pro:cppWork wschrep$ gcc memoryFun.c 
Walter-Schrepperss-MacBook-Pro:cppWork wschrep$ ./a.out 
pagesize: 4096, diff: 35
native: 1
memory: 83
native: 1

另一个需要注意的是调用 printf 将出现段错误,因为 printf 很可能由于相对地址出错而找不到......

于 2012-03-02T18:00:20.410 回答
1

对我有用的 Hacky 解决方案和简单的概念证明(在 Mac OS X/GCC 4.2.1 上编译时不会发出警告):

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include <sys/mman.h>

int function1(int x){
   return x-5;
}

int function2(int x){
  return x+5;
}


int main(){
  int diff = (&function2 - &function1);
  printf("pagesize: %d, diff: %d\n",getpagesize(),diff);

  int (*fptr)(int);

  void *memfun = malloc(4096);

  if (mprotect(memfun, 4096, PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
      perror ("mprotect");
  }

  memcpy(memfun, (const void*)&function2, diff);

  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));
  fptr = memfun;
  printf("memory: %d\n",(*fptr)(6) );
  fptr = &function1;
  printf("native: %d\n",(*fptr)(6));

  free(memfun);
  return 0;
}
于 2012-01-09T20:32:22.283 回答
0

这可能是这里的黑客解决方案。您能否在函数(要复制)之后直接创建一个虚拟变量或函数,获取该虚拟变量/函数的地址,然后使用函数地址进行求和排序,使用地址来获得函数大小?这可能是可能的,因为内存是线性和有序分配的(而不是随机分配的)。这也将使函数复制保持在 ANSI C 可移植性质内,而不是深入研究系统特定的汇编代码。我发现C相当灵活,只需要考虑一下。

于 2011-09-12T16:07:55.650 回答
0

我在 C 中多次尝试过这个问题,得出的结论是,仅使用 C 语言无法完成。我的主要难题是找到要复制的函数的长度。

标准 C 语言不提供任何方法来获取函数的长度。但是,可以使用汇编语言和“节”来查找长度。一旦找到长度,复制和执行就很容易了。

最简单的解决方案是创建或定义包含该函数的链接器段。编写一个汇编语言模块来计算并公开声明这个段的长度。使用此常量来确定函数的大小。

还有其他方法涉及设置链接器,例如预定义区域或固定位置并复制这些位置。

在嵌入式系统领域,大多数将可执行文件复制到 RAM 中的代码都是用汇编编写的。

于 2010-12-28T18:04:18.687 回答