1. 程式人生 > >實現DLL記憶體補丁,DLL劫持技術

實現DLL記憶體補丁,DLL劫持技術



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