复制和调用功能

发布于 2024-09-19 08:47:34 字数 1056 浏览 11 评论 0原文

我想复制并调用一个函数,但是下面的代码在调用缓冲区时出现段错误。我必须改变什么? (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 ());
}

编辑:工作解决方案:

#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 ());
}

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 ());
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

倥絔 2024-09-26 08:47:34

哇,这段代码有很多问题。

  1. 你无法知道函数在内存中是按顺序排列的,没有填充
    它们之间
  2. 你无法知道指向两个函数的指针是可以相减的
  3. 你无法知道malloc()返回的内存可以被调用

总之,不要这样做。

更新:

在Linux中,我认为你可以使用 mprotect() 设置内存块的权限。我认为这需要根,但显然不需要(只要你在你自己的进程的内存中)。

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).

溺ぐ爱和你が 2024-09-26 08:47:34

您可能使用的操作系统不授予数据段执行权限。

某些环境将保护数据页不被执行,以避免各种类型的安全问题(或针对这些问题的利用)。

考虑调用 mprotect() 来启用该页面的执行并报告发生的情况。

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.

烦人精 2024-09-26 08:47:34

这是嵌入式系统人员中的一个常见问题。该技术通常用于从只读存储器复制到随机存取存储器(能够写入和读取)。没有使用标准 C 或 C++ 的优雅或标准的解决方案。

一个更简单的解决方案是使用链接器定义一些新的非标准段。使用非标准#pragma 指示编译器将函数放入新段中。使用非标准编译指令访问该段的起始地址和结束地址。这将允许您获得函数的大小。

对于目标来说,更安全的方法是创建另一个具有可执行和写入属性的段。将函数段中的数据复制到该可执行段中。设置一个函数指针指向该段的开头。通过指针执行函数。

另一种解决方案是用汇编语言执行此操作。通常,汇编器会给你更多的自由(发射你的脚)来在较低的级别上像这样操纵内存。

另外,检查您的操作系统加载程序、内存属性和保护方案。某些操作系统可能会将这种行为限制为内核权限或更高权限。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文