在内存中运行存储的代码

3

问题:

如何将存储在另一个c程序的堆或数据段中的非常规c程序作为汇编指令运行。

我的进展:

运行了一组简单的指令,用于将某些内容打印到stdout。这些指令存储在堆中,并允许执行包含指令的页面,然后调用原始数据,就像它是一个函数一样。这个方法很好地起作用了。

接下来,我想针对任何静态链接的c程序,只需读取其二进制文件并能够从另一个c程序中在内存中运行其主函数。

我认为存在以下问题: * 跳转到主函数代码所在的位置 * 更改链接时创建的二进制文件地址,使其相对于代码现在在内存中的位置

请告诉我我的方法是否正确,或者我是否错过了重要的东西以及最佳的解决方法。

谢谢!


2
问题正是您列举的那些。第一个称为“跳转到入口点”,第二个是“重定位”。您可能需要查阅操作系统的二进制加载器的源代码。 - user529758
如果您已将其他程序静态链接,难道不能直接使用 exec 吗? - Kerrek SB
是的,你错过了一些东西:请考虑在其他编程语言中,您将执行基本相同的步骤,并且对于其他操作系统,这些步骤将发生变化。现在您是否可以看到,这个问题与C几乎没有任何关系,而实际上与您的实现有着密切的关系?顺便说一下,您可能想了解一下“实现”的含义... - autistic
1个回答

2
现代操作系统会尽量避免在数据中执行代码,因为这样做会带来安全威胁。即使你成功绕过了这个限制,也会有很多其他的问题,因为两个程序都认为它们“拥有”堆栈/堆等内存空间。一旦新程序执行,就会覆盖掉旧程序的各种内存区域。(exec 的存在就是为了干净地从一个程序切换到另一个程序。)如果你确实需要加载代码,你应该将第一个程序作为库,然后使用 dlopen 运行它。(你可以使用 objcopy 提取想要的子程序并将其转换为库。)或者,你可以启动程序(在另一个进程中),使用 strace 将一小段代码注入它们的进程以控制它。 (如果你真的想要进入 shell 代码,你应该说出来。那是另一个完全不同的问题。)

1
你在问题中漏掉了“我允许执行包含指令的页面”的部分。 - user529758
哦,你说得对,我漏了那个。你仍然需要手动重新链接。让objcopy和dlopen为您完成这项工作会更容易。 - BraveNewCurrency
要在Linux下测试shellcode,请参考如何使c代码执行十六进制机器码?-z execstack不再适用于.data.rodata,因此您需要将机器码实际上放在堆栈上(本地数组),或使用mprotect或mmap,或Windows VirtualProtect / VirtualAlloc。) - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接