什么是DLL?

dll (Dynamic Link Library) 动态链接库,对于Windows,操作系统的很多功能都由 DLL 提供。 此外,当您在这些操作DLL为 Windows提供了许多的操作系统的特性。另外, DLL可以为你的 Windows应用程序添加许多的特性。比如,一个特定的程式可以包括很多不同的组件,而程式的各个组件都被包括在 DLL中,然后被分配。DLL可以帮助模块化代码,重用代码,有效地利用内存,并且降低硬盘的占用。这样,操作系统和程式就可以更快速地装入,更快速地工作,而且使用的硬盘也更小。

微软

DLL 结构

DLL 入口点

BOOL APIENTRY DllMain(
HANDLE hModule,// Handle to DLL module
DWORD ul_reason_for_call,// Reason for calling function
LPVOID lpReserved ) // Reserved
{
    switch ( ul_reason_for_call )
    {
        case DLL_PROCESS_ATTACHED: // A process is loading the DLL.
        break;
        case DLL_THREAD_ATTACHED: // A process is creating a new thread.
        break;
        case DLL_THREAD_DETACH: // A thread exits normally.
        break;
        case DLL_PROCESS_DETACH: // A process unloads the DLL.
        break;
    }
    return TRUE;
}

当入口点函数返回 FALSE 值时,如果使用加载时动态链接,应用程序将不会启动。 如果使用运行时动态链接,将不会加载单个 DLL。

导出 DLL 函数

通过 __declspec(dllexport) 来声明

DLL 劫持的原理

首先我们需要了解dll的加载方式,我们基本上都通过系统APILoadLibrary来加载dll文件,而其参数又有相对路径和绝对路径,在使用相对路径调用LoadLibrary系统会依次从以下6个位置去查找所需要的DLL文件:

Windows XP SP2之前

进程对应的应用程序所在目录;
当前目录(Current Directory);
系统目录(通过 GetSystemDirectory 获取);
16位系统目录;
Windows目录(通过 GetWindowsDirectory 获取);
PATH环境变量中的各个目录;

Windows xp sp2之后

进程对应的应用程序所在目录;
系统目录(即%windir%system32);
16位系统目录(即%windir%system);
Windows目录(即%windir%);
当前目录(运行的某个文件所在目录);
PATH环境变量中的各个目录;

Windows7以上

系统使用了 KnownDLLs 在注册表中的

计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
「渗透分析」有关DLL劫持原理的解析插图

凡是此项里的DLL文件就会被系统禁止从可执行文件自身所在的目录下调用,而且只能从系统目录调用,这样就可以减少劫持的发生,但仍有可能被劫持

劫持如何发生的呢?

当我们将一个程序假的和本应该在系统目录调用的dll同名的dll放在exe文件的根目录时,就会发生下面的情况:

原本

stateDiagram direction LR EXE–> B.dll:调用LoadLibrary(“B.dll”) state B.dll { direction LR 系统目录下的 }

劫持

stateDiagram direction LR EXE–> B.dll*:调用LoadLibrary(“B.dll”) B.dll*–>B.dll:调用 state B.dll* { direction LR EXE文件根目录下的 } state B.dll { direction LR 系统目录下的 }

就可以在 B.dll* 中添加自己的代码,来实现自己的功能,下面我举一个例子

「渗透分析」有关DLL劫持原理的解析插图1

他在自己的根目录检索了很多dll程序,其中排除上面注册表中的我们选择 dxgi.dll 作为我们的劫持目标

「渗透分析」有关DLL劫持原理的解析插图2

将我们自己的dxgi.dll放入和exe文件同级目录,运行exe文件,我们可以看见

我写的一个注入窗口直接弹出来了,劫持成功~ 我们已经进入了软件的内部,下面就交给你们了

如何编写这个假的DLL呢?

首先我们先获取到原始的dll文件

「渗透分析」有关DLL劫持原理的解析插图4
火绒剑

将该dll导出到一个文件夹中,使用一个开源项目

通过他,我们可以很方便的生成相关的fake dll文件

python .\DLL_Hijacker.py .\dxgi.dll

修改其中的 DLLMain 函数

// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		DisableThreadLibraryCalls(hModule);
		DWORD dwThreadID;
		AllocConsole(); // 打开命令窗口
		freopen("CONOUT$", "w+t", stdout);
		freopen("CONIN$", "r+t", stdin);
		SetConsoleTitle("Enjoy https://mcenjoy.cn");
		CreateThread(0, 0, ThreadProc, NULL, 0, &dwThreadID); // 启动自己的进程 这个我就不给了
		printf("注入成功\n");
		return Load();
	}
	else if (dwReason == DLL_PROCESS_DETACH)
	{
		Free();
	}

	return TRUE;
}

到这里我基本上就介绍完成了,上面的软件大部分都可以查到,我就不贴了

如何防止这种劫持呢?

我认为程序在导入时尽量使用绝对路径,或者对dll文件进行数字签名的校验,这都可以避免劫持的发生