从一个exe文件中加载另一个exe文件

3
我正在从一个C++可执行文件中导出一个函数[使用_declspec(dllexport)]。当这个函数被可执行文件本身调用时,它能够正常工作。我正在使用静态链接的方式(即在编译exe2时使用exe1的.lib文件),从另一个可执行文件[测试项目的可执行文件 - 我将其称为exe2]中加载这个可执行文件。就像任何dll一样,exe2在启动时将其加载到内存中。这会导致函数执行失败。
在函数中的switch case语句的反汇编代码中揭示了确切的问题。
当exe1调用该函数时的汇编代码:
   switch (dwType)
0040FF84  mov         eax,dword ptr [dwType] 
0040FF87  mov         dword ptr [ebp-4],eax 
0040FF8A  cmp         dword ptr [ebp-4],0Bh 
0040FF8E  ja          $LN2+7 (40FFD2h) 
0040FF90  mov         ecx,dword ptr [ebp-4] 
0040FF93  jmp         dword ptr  (40FFE0h)[ecx*4] 

考虑最后两条指令。mov指令将传入的参数移动到ecx寄存器中。在40EFF0h处,我们有各种情况语句的指令地址。因此,jmp指令会将我们带到相关的case指令。
当exe2调用该函数时的汇编代码。
   switch (dwType)
0037FF84  mov         eax,dword ptr [dwType] 
0037FF87  mov         dword ptr [ebp-4],eax 
0037FF8A  cmp         dword ptr [ebp-4],0Bh 
0037FF8E  ja          $LN2+7 (37FFD2h) 
0037FF90  mov         ecx,dword ptr [ebp-4] 
0037FF93  jmp         dword ptr [ecx*4+40FFE0h]

发现问题了吗?指令地址。代码现在已经加载到内存的不同位置。当编译exe1时,编译器假定我们将始终启动它,因此它将始终加载到0x0040000 [与所有Windows exe一样]。因此,它在指令中硬编码了一些值,如40FFE0h。只有在第二种情况下,40FFE0才是无用的内存,因为我们要查找的指令地址表不在那里。

如何在不将exe1转换为dll的情况下解决此问题?

2个回答

1

不要这样做。这不值得麻烦。

我以前尝试过你现在正在尝试的事情。你可以通过在属性窗口中更改“链接器->高级->固定基地址”下的选项来解决非可重定位exe问题,但是那时你会遇到其他问题。
最终让我意识到这是浪费时间的事情的是意识到EXE没有DllMain()函数。这意味着CRT库没有被初始化,所有的东西都不能按照你的期望工作。

这是我以前发布的关于此问题的问题


尝试了做同样的事情,得出了相同的结论。 - Chad

1

你考虑过另一种方法吗?比如将第二个 .exe 转换成 .dll,并在需要使用它作为可执行文件时使用 rundll32 调用它?

否则: 生成的程序集很好。问题在于 Win32 可移植可执行文件具有基地址(在本例中为 0x0040000)和一个包含详细地址位置的部分,以便在需要时可以重新定位。

因此,可能发生以下两种情况之一: - 编译器在构建 .exe 时未包括 IMAGE_BASE_RELOCATION 记录。 - 运行时未在动态加载 .exe 时执行基础重定位。 - (可能是两者都有)

如果 .exe 包含重定位记录,则可以读取它们并自行执行基础重定位。您必须跳过一些麻烦,例如确保您对内存具有写访问权限(VirtualAlloc 等),但从概念上讲非常简单。

如果 .exe 不包含重定位记录,则无法解决 - 要么找到编译器选项强制包含它们,要么找到另一种方法来完成您正在进行的操作。

编辑:正如 shoosh 指出的那样,一旦解决了这个问题,您可能会遇到其他问题。


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