我想知道在运行时是否可以修改一个C程序(或其他二进制文件)?
我写了这个小C程序:
#include <stdio.h>
#include <stdint.h>
static uint32_t gcui32_val_A = 0xAABBCCDD;
int main(int argc, char *argv[]) {
uint32_t ui32_val_B = 0;
uint32_t ui32_cpt = 0;
printf("\n\n Program SHOW\n\n");
while(1) {
if(gcui32_val_A != ui32_val_B) {
printf("Value[%d] of A : %x\n",ui32_cpt,gcui32_val_A);
ui32_val_B = gcui32_val_A;
ui32_cpt++;
}
}
return 0;
}
使用十六进制编辑器,我能够找到&#34; 0xAABBCCDD&#34;并在程序停止时修改它。当我重新编写程序时,修改工作。很酷!
我想在程序运行时这样做吗?
这是一个简单的例子,可以理解这些现象并与之发挥作用,但我真正的项目更大。
我想在游戏运行时动态执行此操作。有可能吗?
PS:我在Debian 64bit下工作
问候
答案 0 :(得分:2)
我想知道在它运行时是否可以修改一个C程序(或其他二进制文件)?
不在标准(和便携式)C11中。阅读n1570规范进行检查。请注意,大部分时间在实践中,不是正在运行的C source程序(由多个translation units组成),而是某些executable&amp; compiler的结果; linker
但是,在Linux上(例如Debian / Sid / x86-64),您可以使用以下一些技巧(通常使用函数指针):
使用plugins,因此请设计您的程序以接受它们并定义有关插件的约定。插件是包含ELF的共享对象position-independent code文件(某些*.so
)(因此应使用特定选项进行编译)。您将使用dlopen(3)&amp; dlsym(3)要执行插件的dynamic loading。
使用一些JIT-compiling库,例如GCCJIT或LLVM或libjit或asmjit。
使用virtual address space和mprotect(2)手动更改mmap(2)(不推荐);然后你可以覆盖code segment中的某些东西(你真的不应该这样做)。这可能很棘手(例如因为ASLR)而且很脆弱。
我建议稍微使用/proc/
(请参阅proc(5)),并尝试至少在某些终端中运行以下命令
cat /proc/self/maps
cat /proc/$$/maps
ls /proc/$$/fd/
(并阅读足够的内容以了解他们的输出)以了解process“是什么”。
所以覆盖你的text segment(如果你真的需要这样做)是可能的,但也许比你相信的更棘手!
(你介意工作几周或几个月只是为了改善一些旧的游戏体验吗?)
另请阅读homoiconic编程语言(使用SBCL尝试使用Common Lisp),约dynamic software updating,约persistence,约application checkpointing和约{{ 3}}(我建议:operating systems&amp; Operating Systems: Three Easy Pieces wiki)
我在Debian 64bit下工作
我认为你有编程技巧并且知道C.然后你应该阅读OsDev或一些较新的Linux编程书(当然还要查看ALP&amp; intro(2)&amp; { {3}}和其他手册等...)
BTW,在您的特定情况下,也许“OS”是DOSBOX(充当某些虚拟机)。您可以在DOSBOX(或其他命令或进程)上使用syscalls(2),或研究其源代码。你在提问时提到游戏。如果您想对某些代码进行编码,请考虑intro(3),strace(1),SDL,SFML,......等库。
答案 1 :(得分:1)
是的,您可以在C中运行时修改一段代码。您必须有指向程序存储区的指针,以及要更改的已编译代码段。当然,这被认为是一种危险的做法,有很多限制,并且有很多错误的可能性。然而,这是在古老时代的记忆是珍贵的。