Skip to main content

动态链接库文件

DLL 文件

对于 Windows 操作系统,exeEXEdllDLL 虽然同为 PE 文件,但是这 2 种文件类型依旧有着诸多的不同。DLL 是可执行函数或数据的共享库,可供多个应用程序同时使用。DLL 文件用于导出供进程使用的函数。与 EXE 文件不同,DLL 文件不能独自被用于执行代码 (例如不能双击运行),而是需要由其他程序调用 DLL 中的函数来实现代码执行。如我们之前探讨的 MessageBoxW,MessageBoxW是从 user32.dll 导出的,因此如果程序想要调用该函数,首先需要将 user32.dll 加载到其地址空间中。

默认情况下,一些 DLL 会自动加载到每个进程中,例如 ntdll.dll、dllkernel32.dll kernelbase.dlldll 等,因为这些导出函数对于进程的正常执行非常重要。

下图显示了例如,我们查看 explorer.exe进程当前exe 与 firefox.exe 加载的 DLL,它们都加载了 kernel32.dll,且该 DLL 的基址都是一样的,这也印证了同DLL。 DLL 可供多个应用程序同时使用。

image.png

image.png

总之,DLL 在 Windows 上被广泛使用的原因有代码模块化代码重用内存高效使用等。

 

编写 DLL

让我们使用 C++ 编写一个 DLL 文件以了解 DLL 在代码层面的结构。虽然 C# 也可以用于编写 DLL 文件,但是 C# 编译的 DLL 是托管DLL,而 C++ 编译的 DLL 是非托管 DLL,用途和用法上也有较大的不同,因此我们现在着眼于 C++ 编写的 DLL 文件。

使用 Visual Studio 新建一个 C++ 语言的 Dynamic-Link Library 项目:

image.png

让我们来分析如下代码:

#include "pch.h"
#include "windows.h"
#include "stdlib.h"


extern "C" __declspec(dllexport) void calc()
{
    MessageBoxA(NULL, "Execution happened", "Bypass", MB_OK);
}



BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        system("calc.exe");
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

 

 

 

 

载入 DLL 入口