是否有修改功能的code在运行Linux的C程序的方法吗? [英] Is there a way to modify the code of a function in a Linux C program at runtime?

查看:157
本文介绍了是否有修改功能的code在运行Linux的C程序的方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要简单,我们有两个相似的功能:

To be simple, we have two similar functions:

void f1()
{
    printf("%d", 123);
}
void f2()
{
    printf("%d", 124);
}

现在我们所说的F1在主,它打印123当它被编译, F1的拆卸可能是这样的:

Now we call f1 in main and it prints 123. When it is compiled, the disassembly of f1 may be like:

08048424 <f1>:
 8048424:       55                      push   %ebp
 8048425:       89 e5                   mov    %esp,%ebp
 8048427:       83 ec 18                sub    $0x18,%esp
 804842a:       b8 40 86 04 08          mov    $0x8048640,%eax
 804842f:       c7 44 24 04 7b 00 00    movl   $0x7b,0x4(%esp)
 8048436:       00
 8048437:       89 04 24                mov    %eax,(%esp)
 804843a:       e8 05 ff ff ff          call   8048344 <printf@plt>
 804843f:       c9                      leave
 8048440:       c3                      ret

F2的机器code是类似F1的。

The machine code of f2 is similar to the f1's.

现在我要替换F2在运行时机器code中的F1。我用的memcpy(F1,F2,SIZE_OF_F2_MACHINE_ code)。
当然谈到这个问题 - 段故障

Now I want to replace the f1 with the machine code of f2 at the runtime. I use memcpy(f1, f2, SIZE_OF_F2_MACHINE_CODE). Sure it comes the problem — a segment fault.

现在我想知道是否存在一个解决方案来解决这个问题。这是一个常见的​​C程序。
据我所知,我们可以使用下面这种code设置页写在Linux内核:

Now I want to know if there exists a solution to solve this problem. This is a common C program. As I know, we can use such code below to set page writable in Linux kernel:

int set_page_rw(long unsigned int addr)
{
    unsigned int level;
    pte_t *pte = lookup_address(addr, &level);

    if(pte->pte & ~_PAGE_RW)
        pte->pte |= _PAGE_RW
}

但它不会在普通的Linux C程序的工作。那么是什么在起作用?

but it does not work at normal Linux C programs. Then what works?

推荐答案

你问这个干什么?如果你的愿望就是最终能够调用的code是由相同的过程中产生的一些功能,你可以进行不同的:

Why do you ask? If your wish is just to eventually be able to call some functions whose code was generated by the same process, you can proceed differently:


  1. 始终使用函数指针调用这种动态生成的功能;我的建议是,为便于阅读的原因,的typedef 声明指针之前,他们的签名,看的这个答案

  2. 生成功能,并获得一个指向它。

  1. Always use function pointers to call such dynamically generated functions; my suggestion is, for readability reasons, to typedef their signature before declaring the pointer, see this answer.
  2. Generate the function and get a pointer to it.


  • 例如,你可以生成一个C源文件 generated.c ,创建一个进程,或许与系统(GCC -fPIC -O -​​shared generated.c -o generated.so); 编译它,那么的dlopen(./ generated.so,RTLD_GLOBAL)并获得生成的函数与则dlsym 。请参见的dlopen(3)手册页了解详情。仅供参考,请 MELT 是这样做的。

  • You could for example generate a C source file generated.c, fork a process, perhaps with system("gcc -fPIC -O -shared generated.c -o generated.so"); to compile it, then dlopen("./generated.so", RTLD_GLOBAL) and get the pointer of the generated function with dlsym. See dlopen(3) man page for details. FYI, MELT is doing that.

您也可以在内存中生成(功能与可能的的mmap(2)使用 PROT_EXEC 标志)。目前有几种JIT(刚刚好时间平移)库可用: GNU闪电(快速生成慢速跑步机code), myjit ,的 libjit LLVM (慢一代的优化机code), LuaJIT ...

You could also generate the machine code of the function in memory (probably obtained with mmap(2) using PROT_EXECflag). Several JIT (just-in-time translation) libraries are available: GNU lightning (quick generation of slow running machine code), myjit, libjit, LLVM (slow generation of optimized machine code), LuaJIT...

如果你真的要覆盖现有的一些功能code,你可以做到这一点,但它需要一个大的很多关心的,是痛苦的(例如,因为新的功能code需要比旧更多空间,还因为搬迁问题)。使用的mmap(2)及 /或则mprotect(2)系统调用得到允许这样的把戏。但要ppared用于调试的噩梦$ P $。您可能希望你的剧本 GDB 调试器的你的Python脚本的。

If you really wish to overwrite some existing function code, you might do that, but it requires a big lot of care and is painful (e.g. because the new function code needs more space than the old one, and also because of relocation issues). Use the mmap(2) and/or mprotect(2) syscalls to get permission for such tricks. But be prepared for debugging nightmares. You may want to script your gdb debugger with your python scripts.

有关内核模块的故事是不同的。我听说一些网络相关的内核code(的iptables 也许?)可以使用JIT技术来生成机器code和运行它。

For kernel modules the story is different. I heard that some network related kernel code (iptables perhaps?) may use JIT techniques to generate machine code and run it.

这篇关于是否有修改功能的code在运行Linux的C程序的方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆