DLL劫持技术
1、介绍
DLL劫持技术是一种权限维持的手段, 通过劫持正常程序DLL的执行流让程序执行恶意代码。
流程
- 正常程序 —-调用—-» 正常的DLL —-执行—» 正常功能
DLL劫持就可以通过劫持正常的DLL, 让恶意的DLL被正常的程序调用。
- 正常程序 —-调用—-» 恶意DLL — 执行 —» 恶意代码 —转发—» 正常DLL —执行—» 执行正常功能
2、DLL介绍
DLL中文名动态链接库 你可以把它看作一个自身无法执行的exe程序通过exe对DLL操作调用DLL里的方法实现相对应的功能
学DLL劫持就学两点就行
- DLL生命周期
- DLL导出函数
2.1、 DLL生命周期
DLL生命周期是指DLL从加载到卸载的个个状态,下面看代码DLL默认就是
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
) //DLL的入口函数
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: //DLL被加载时候执行
case DLL_THREAD_ATTACH: //线程被创建的时候执行
case DLL_THREAD_DETACH: //线程结束时执行
case DLL_PROCESS_DETACH: //DLL被卸载时执行
break;
}
return TRUE;
}
这就是DLL的生命周期 执行到对应的生命周期会执行对应的case代码块
2.2、DLL导出函数
DLL导出函数是DLL提供对外部的函数, 外部的程序可以通过加载DLL访问导出函数从而执行导出函数的功能。
这是DLL里的导出函数
//语言类型 调用约定
extern "C" __declspec(dllexport) void aaa()
{
MessageBoxA(NULL,"我是导出函数", "aaaa", MB_OK);
}
完整的DLL代码
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <Windows.h>
#include <iostream>
#include <string>
extern "C" __declspec(dllexport) void aaa()
{
MessageBoxA(NULL,"我是导出函数", "aaaa", MB_OK);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBoxA(NULL, "DLL加载case", "aaa", MB_HELP);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
写一个程序调用DLL文件
#include <iostream>
#include <Windows.h>
typedef void(*Func)(); //DLL中的函数被默认为私有函数,不会被其他程序调用。因此,需要通过定义导出函数以便其他程序能够调用它们。
int main()
{
HINSTANCE hinst = LoadLibraryA("TestDLL.dll"); //执行到这的时候会调用 MessageBoxA(NULL, "DLL加载case", "aaa", MB_HELP);
Func GetDLLFunc = (Func)GetProcAddress(hinst, "aaa");
GetDLLFunc(); //执行到这执行导出函数 MessageBoxA(NULL,"我是导出函数", "aaaa", MB_OK);
return 0;
}
执行第一次弹出弹窗,是DLL被加载的弹窗。 点击确定后,弹出了第二个弹窗,这显示是导出函数被加载执行了。
3、DLL劫持
现在要完成DLL劫持的流程:
正常程序 —-调用—-» 恶意DLL — 执行 —» 恶意代码 —转发—» 正常DLL —执行—» 执行正常功能
正常情况下我们没正常程序的DLL源码
- 通过Process Monitor找到程序调用神那么DLL文件从而修改。
这样就可以看到都加载了什么DLL文件
- 然后使用工具AheaLib.exe 得到转发
// 头文件
#include <Windows.h>
// 导出函数
#pragma comment(linker, "/EXPORT:aaa=TestDLLOrg.aaa,@1")
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH) //当DLL被加载到进程的地址空间时会执行。
{
DisableThreadLibraryCalls(hModule); //DisableThreadLibraryCalls用来决定DLL线程通知开启与关闭 什么是线程通知 DLL_PROCESS_ATTACH 和 DLL_PROCESS_DETACH 这种就是线程通知
}
else if (dwReason == DLL_PROCESS_DETACH) //当DLL被卸载的时候执行
{
MessageBoxW(NULL, L"aaa", L"tttt", 0x2L); //我自己写的充当恶意代码
}
return TRUE;
}
- 把原来的TestDLL改名为TestDLLOrg。
- 编译这个DLL文件替换掉原来的TestDLL文件。
...