什么是DLL?
dll (Dynamic Link Library) 动态链接库,对于Windows,操作系统的很多功能都由 DLL 提供。 此外,当您在这些操作系统中的一个Windows程序时,该程序的很多功能可能由 DLL 提供。 例如,某些程序可能包含许多不同的模块,并且程序的每个模块包含在 DLL 中并分发。使用 DLL 有助于促进代码的模块化、代码重用、高效的内存使用并减少磁盘空间。 因此,操作系统和程序加载速度更快,运行速度更快,并且占用了更少的磁盘空间。
https://docs.microsoft.com/zh-CN/troubleshoot/windows-client/deployment/dynamic-link-library
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放在exe文件的根目录时,就会发生下面的情况:
原本
劫持后
就可以在 B.dll* 中添加自己的代码,来实现自己的功能,下面我举一个例子
他在自己的根目录检索了很多dll程序,其中排除上面注册表中的我们选择 dxgi.dll 作为我们的劫持目标
将我们自己的dxgi.dll放入和exe文件同级目录,运行exe文件,我们可以看见
我写的一个注入窗口直接弹出来了,劫持成功~ 我们已经进入了软件的内部,下面就交给你们了
如何编写这个假的DLL呢?
首先我们先获取到原始的dll文件
将该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文件进行数字签名的校验,这都可以避免劫持的发生