實現DLL記憶體補丁,DLL劫持技術
阿新 • • 發佈:2019-01-10
在windows下當一個可執行檔案執行時,Windows載入器將可執行模組對映到程序的地址空間中,載入器分析可執行模組的輸入表,並設法找出任何需要的DLL,並將它們對映到程序的地址空間中。由於輸入表是根據DLL名來進行查詢,首先是查詢當前目錄下有沒這檔案,沒有話在去查詢系統目錄C:\\Windows\\system32有沒這檔案,所以我們可以完全趁這個機會去劫持DLL,把他劫持下來後就可以在裡面進行我們要做的事情。
為了讓我們自己開發的補丁DLL有匯出函式,我們可以用 #parma comment(..),如:
#pragma comment(linker, "/EXPORT:testadd=_TESTDLLLIB_testadd,@1")
1.補丁前DLL。
//tstDll.dll 補丁前 //By symanli #include "stdafx.h" #include "dll.h" BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } //原始函式 int testadd(int a,int b) { ::MessageBox(NULL,"這是補丁前的DLL","TODO",MB_OK); return a+b; }
2.補丁後DLL
//這是補丁程式碼。by symanli //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 標頭檔案 #include <Windows.h> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 巨集定義 #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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TESTDLLLIB 名稱空間 namespace TESTDLLLIB { HMODULE m_hModule = NULL; // 原始模組控制代碼 DWORD m_dwReturn[1] = {0}; // 原始函式返回地址 // 載入原始模組 inline BOOL WINAPI Load() { TCHAR tzPath[MAX_PATH]; TCHAR tzTemp[MAX_PATH * 2]; //將原始DLL名改成其他的名字,我們用LoadLibrary去載入他。 lstrcpy(tzPath, TEXT("tstDllold.dll")); m_hModule = LoadLibrary(tzPath); if (m_hModule == NULL) { wsprintf(tzTemp, TEXT("無法載入 %s,程式無法正常執行。"), tzPath); MessageBox(NULL, tzTemp, 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) { wsprintf(szProcName, "%d", pszProcName); pszProcName = szProcName; } wsprintf(tzTemp, TEXT("無法找到函式 %hs,程式無法正常執行。"), pszProcName); MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP); ExitProcess(-2); } return fpAddress; } } using namespace TESTDLLLIB; // 入口函式 BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved) { if (dwReason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(hModule); for (INT i = 0; i < sizeof(m_dwReturn) / sizeof(DWORD); i++) { m_dwReturn[i] = TlsAlloc(); } return Load(); } else if (dwReason == DLL_PROCESS_DETACH) { for (INT i = 0; i < sizeof(m_dwReturn) / sizeof(DWORD); i++) { TlsFree(m_dwReturn[i]); } Free(); } return TRUE; } // 匯出函式 ALCDECL TESTDLLLIB_testadd(void) { ::MessageBox(NULL,"這是補丁後的DLL","TODO",MB_OK); // 儲存返回地址到 TLS //__asm PUSH m_dwReturn[0 * TYPE long]; //__asm CALL DWORD PTR [TlsSetValue]; // 呼叫原始函式 GetAddress("testadd"); __asm JMP EAX; // 獲取返回地址並返回 // __asm PUSH EAX; // __asm PUSH m_dwReturn[0 * TYPE long]; // __asm CALL DWORD PTR [TlsGetValue]; // __asm XCHG EAX, [ESP]; // __asm RET; } #pragma comment(linker, "/EXPORT:testadd=_TESTDLLLIB_testadd,@1") ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
exe呼叫
//exe呼叫程式碼
#pragma comment(lib,"tstDll.lib")//匯入先前DLL的lib,就是最原始的LIB
void CTstExeDlg::OnButton1()
{
// TODO: Add your control notification handler code here
int _sum =testadd(10,20);
CString szSum;
szSum.Format("結果是:[%d]",_sum);
AfxMessageBox(szSum);
}