首页Dll相关学习 › 合并dll到exe中

合并dll到exe中

前言
  你可能不希望在发布程序时附带上一个外部的 DLL,因为可能会有些用户在无意中把 DLL 删除了而造成 EXE 不能正确运行,也有可能该 DLL 会被别人拿去使用,也有可能,此 DLL 会成为破解者破解你的程序的突破口。无论出于何种原因,如果你想把一个 DLL 合并到一个 EXE 中的话,本文向你介绍这种方法。
Win32 程序调用 DLL 的机制

   Win32 EXE 在调用一个外部 DLL 中的函数时,首先要调用 LoadLibary 函数来载入此 DLL 到程序的进程地址空间。如果 LoadLibary 载入此 DLL 成功,将返回一个该 DLL 的句柄。 这个句柄实际上就是该 DLL 在内存中的起始地址。 在载入 DLL 成功后,还必须调用 GetProcAddress 函数来获取要调用的函数的地址。然后再根据该地址来调用这个函数。
根据上述原理,我们可以把一个 DLL 作为资源文件放到 EXE 文件中,在程序运行时,分配一块内存,然后将此资源复制到该分配的内存中,并根据该内存地址计算得到相关的导出函数地址,然后,当我们需要调用某一函数时,可以用该函数在内存中的地址来调用它。
程序实现。
  首先,把要合并的 DLL 作为资源加入到项目的资源文件中,然后在程序运行时,从资源中载入该资源,以得到该 DLL 在内存中的位置:

然后,从资源中载入 DLL 到内存函数 LoadPbDllFromMemory 将载入 DLL 到内存中,该函数有两个参数,第一个参数是指向 DLL 资源在内存中的地址的指针,也就是前面代码中的 LockResource 函数的返回值。第二个参数是一个空的指针,如果函数 LoadPbDllFromMemory 运行成功,该指针将指向重新组合后的内存中的 DLL 的起始地址。该函数还有一个功能就是如果运行成功,它将手动地用 DLL_PROCESS_ATTACH 参数调用 DLL 的入口函数 DllMain 来初始化该 DLL。除此之外,它还会手动地载入合并的 DLL 的入口表中导入的 DLL 并调整它们在内存中的相对地址。以下是该函数代码:

一但 DLL 被正确地载入到内存中,我们就可以通过自定义函数 GetProcAddressDirectly 来获取某函数在内存中的地址,并根据该地址来调用该函数,该函数也有两个参数,第一个参数是指向载入到内存中的 DLL 的起始地址的指针,第二个是要调用的函数的函数名。以下是 GetProcAddressDirectly 函数代码:

在调用完函数后,不要忘记用 UnloadPbDllFromMemory 来从内存中移去 DLL 以释放分配的内存,该函数还会用 DLL_PROCESS_DETACH 参数调用 DLL 的入口函数 DllMain 来从调用进程的地址空间卸载该 DLL。 以下是 UnloadPbDllFromMemory 函数代码:

关于示例代码的说明
  在本文附带的示例代码中,合并了一个名为 hardware.dll 的动态连接库,该动态连接库是一个获取系统硬件信息的库文件,其中包括了以下函数:

在示例代码中,只调用了其中一个函数 getbios 来获取主板 BIOS ID, 这里说明一下,该函数实际上好象只能检测 AWARD 主板的 BIOS, 也就是说它是读取的是系统内存 0x000fex71 处的值。因为其它牌子的主板 BIOS 的位置稍有不同,但在程序中没有进行这方面的处理,所以在读其它牌子的主板 BIOS 时可能会有些问题(读出的内容可能不正确)。关于此 DLL 的内容和实现,也许我会在另一篇文章中论及。

发表评论