程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> HOOK API(三)—— HOOK 所有程序的 MessageBox,hookmessagebox

HOOK API(三)—— HOOK 所有程序的 MessageBox,hookmessagebox

編輯:C++入門知識

HOOK API(三)—— HOOK 所有程序的 MessageBox,hookmessagebox


HOOK API(三)

—— HOOK 所有程序的 MessageBox

0x00 前言

本實例要實現HOOK MessageBox,包括MessageBoxA和MessageBoxW,其實現細節與HOOK API(二)中介紹的基本類似,唯一不同的是,本實例要實現對所有程序的HOOK MessageBox,即無論系統中哪一個程序調用MessageBox都會被重定向到我們實現的新的API中。

 

之前說過,在Windows中,每個進程都有自己的地址空間,進程不能調用別的進程中的函數。這裡涉及到一個關鍵,如何讓我們實現的新的API調用地址存在於所有進程的地址空間中呢?如果這無法實現的話,其他進程就無法調用到我們所實現的API。這裡涉及到的關鍵就是,如何將我們的代碼注入到別的進程中。

 

這裡有一個實現手段,就是將我們實現的代碼隨著系統鉤子注入到目標進程中,我們在HOOK API (一)中講過鼠標鉤子,鼠標鉤子一旦啟動,就會存在於每個當前運行的進程中,實現對屏幕坐標的定位。還有一個關鍵就是,這樣的鉤子需要注入到多個目標進程中,那麼這就要在動態鏈接庫(DLL)中實現,然後啟動某一主調進程將這樣一個DLL注入到目標進程中,從而實現HOOK API。

 

本實例介紹如何將實現了HOOK MessageBox的DLL注入到所有進程中的過程。

0x01 HOOK DLL的實現

由於被實例的DLL用於MFC框架,因此創建的是MFC DLL,需要的話,也可以建立其他類型的DLL工程。

我們的DLL要跟隨鼠標鉤子注入到目標進程中,而鼠標鉤子是系統鉤子,我們需要實現其鉤子回調函數。

/*

     鼠標鉤子子過程,目的是加載本dll到使用鼠標的程序中。

     鼠標鉤子的作用:當鼠標在某程序窗口中時,就會加載我們這個dll。

*/

LRESULT CALLBACK MouseProc(

                        int nCode,     // hook code

                        WPARAM wParam,// message identifier

                        LPARAM lParam // mouse coordinates

                        )

{

    return CallNextHookEx(hhk,nCode,wParam,lParam);

}

 

調用SetWindowsHookEx() API可以安裝鼠標鉤子,其中SetWindowsHookEx() 原型如下:

 

HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn, INSTANCE hMod,DWORD dwThreadId )

參數:

idHook表示鉤子類型,它是和鉤子函數類型一一對應的。比如,WH_KEYBOARD表示安裝的是鍵盤鉤子,WH_MOUSE表示是鼠標鉤子等等。

  Lpfn是鉤子函數的地址。

  HMod是鉤子函數所在的實例的句柄。對於線程鉤子,該參數為NULL;對於系統鉤子,該參數為鉤子函數所在的DLL句柄。

dwThreadId 指定鉤子所監視的線程的線程號。對於全局鉤子,該參數為NULL。

返回值:

  SetWindowsHookEx返回所安裝的鉤子句柄。

 

//

// 安裝鉤子

//

BOOL WINAPI StartHook(HWND hWnd)

{

    g_hWnd = hWnd;

    hhk = ::SetWindowsHookEx(WH_MOUSE,MouseProc,g_hInstance,0);

 

    if (hhk == NULL)

    {

        return FALSE;

    }

    else

    {

        

        return TRUE;

    }

}

 

//

// 卸載鉤子

//

BOOL WINAPI StopHook()

{    

    /*

        卸載鉤子時,一定要記得恢復原API入口。

        這裡恢復的只是主程序的原API入口,其它程序的API入口還沒有被恢復。

        因此我們必須處理dll退出過程,即在函數ExitInstance()中,調用恢復

        API入口的函數HookOff(),只有這樣,其它程序再次調用原API時,才不

        會發生錯誤。

        當我們HOOK所有程序的某個系統API時,千萬要注意在ExitInstance()中

        調用HookOff()!!!!!

    */

    HookOff();

    if (hhk!=NULL)

    {

        UnhookWindowsHookEx(hhk);

        FreeLibrary(g_hInstance);

    }

 

    return TRUE;

}

 

.def內容如下:

將StarHook和StopHook函數導出,一遍主程序安裝和卸載HOOK程序。

; HookDll.def : 聲明 DLL 的模塊參數。

 

LIBRARY "HookMessageBox"

 

EXPORTS

; 此處可以是顯式導出

    StartHook

    StopHook

 

/*

    dll程序入口,當程序加載dll時,會執行InitInstance()

*/

BOOL CHookDllApp::InitInstance()

{

    CWinApp::InitInstance();

    g_hInstance = AfxGetInstanceHandle();//    獲取當前DLL實例句柄

    

    AdjustPrivileges();    //    提高權限

    DWORD dwPid = ::GetCurrentProcessId();

    hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

    if (hProcess == NULL)

    {

        CString str;

        str.Format(_T("OpenProcess fail, and error code = %d"),GetLastError());

        AfxMessageBox(str);

        return FALSE;

    }

 

    Inject();    // 開始注入

    

    return TRUE;

}

 

int CHookDllApp::ExitInstance()

{

    /*

        dll退出時,一定要記得恢復原API的入口!!!

        我們編寫的dll會被注入到所有目標進程中,若dll退出時,沒有恢復原API入口,

        那麼被掛鉤的程序再次調用該API時,會發生錯誤。

        因為我們的dll程序已經退出,但原API的入口仍為我們所定義的API的入口,這

        時被掛鉤的程序無法找到我們實現的API,然而原API的地址又沒有被恢復,也就

        調用不到原API,這時程序自然會發生崩潰了。

    */

 

    HookOff();

 

    return CWinApp::ExitInstance();

}

該函數的主要功能是保存新的和原來的API入口,並且在最後啟動HOOK。需要注意的是,這個函數只能被調用一次,即只能進行一次注入操作。

/*

    注入

*/

void Inject()

{

    if ( TRUE == bIsInJected)

    {

        return;

    }

    bIsInJected = TRUE;    // 保證只調用一次

 

 

    //

    // 獲取函數

    //

    HMODULE hmodle = ::LoadLibrary(_T("User32.dll"));

    oldMsgBoxA = (TypeMsgBoxA) ::GetProcAddress(hmodle,"MessageBoxA");

    pfMsgBoxA = (FARPROC)oldMsgBoxA;

 

    oldMsgBoxW = (TypeMsgBoxW) ::GetProcAddress(hmodle,"MessageBoxW");

    pfMsgBoxW = (FARPROC)oldMsgBoxW;

 

    if (pfMsgBoxA == NULL)

    {

        AfxMessageBox(_T("獲取 MessageBoxA 函數失敗"));

        return;

    }

    if ( pfMsgBoxW == NULL)

    {

        AfxMessageBox(_T("獲取 MessageBoxW 函數失敗"));

        return;

    }

 

    //

    // 保存原API地址

    //

    _asm

    {

        lea edi,oldCodeA    // 取數組基地址

        mov esi,pfMsgBoxA    // API地址

        cld                    // 設置方向

        mov ecx,CODE_LENGTH

        rep movsb

    }

 

    _asm

    {

        lea edi,oldCodeW

        mov esi,pfMsgBoxW

        cld

        mov ecx,CODE_LENGTH

        rep movsb

    }

 

    //

    // 將新地址復制到入口

    //

    newCodeA[0] = newCodeW [0] = 0xe9;    // jmp 指定代碼

    _asm

    {

        lea eax,MyMessageBoxA        // 新API地址

        mov ebx,pfMsgBoxA            // 原API地址

        sub eax,ebx                

        sub eax,CODE_LENGTH            // 跳轉地址 = 新API地址 - 原API地址 - 指令長度

        mov dword ptr [newCodeA+1],eax // eax 32bit = 4 BYTE

    }

 

    _asm

    {

        lea eax,MyMessageBoxW

        mov ebx,pfMsgBoxW

        sub eax,ebx

        sub eax,CODE_LENGTH

        mov dword ptr [newCodeW + 1],eax

    }

 

    HookOn();    //    開始HOOK

 

}

 

 

該函數主要完成向進程控制塊寫寫指令的任務。供HookOn()和HookOff()調用,用來將原API入口,或新的API入口寫入到進程的地址空間中。

/*

    將長度為length的pcode寫入到地址lpAddress中。

*/

void WriteMemory(LPVOID lpAddress,BYTE* pcode,int length)

{

    //

    //    保證本進程句柄不為NULL

    //

    ASSERT(hProcess != NULL);

 

    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

 

    //

    // 修改API入口前length個字節為 jmp xxxx

    //

    VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect);

    dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited);

    if ( 0 == dwRet || 0 == dwWrited)

    {

        AfxMessageBox(_T("哭!!寫入失敗"));

    }

    VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwTemp);

}

 

/*

    用新API地址替換原API地址

*/

void HookOn()

{

    ASSERT(hProcess != NULL);

 

    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

    

    WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH);

    WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH);

 

}

 

/*    

    恢復原API地址

*/

void HookOff()

{

    ASSERT(hProcess != NULL);

 

    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

 

    WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);

    WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);

}

 

/*

    自己用於替換的API

*/

int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType)

{

    int nRet = 0;

 

    HookOff();

    nRet = ::MessageBoxA(hWnd,"哈哈 ^_^,MessageBoxA 被 HOOK 咯",lpCation,uType);

    nRet = ::MessageBoxA(hWnd,lpText,lpCation,uType);

    HookOn();

 

    return nRet;

}

 

int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType)

{

    int nRet = 0;

 

    HookOff();

    nRet = ::MessageBoxW(hWnd,_T("O(∩_∩)O哈哈~,MMessageBoxW 被 HOOK 咯"),lpCation,uType);

    nRet = ::MessageBoxW(hWnd,lpText,lpCation,uType);

    HookOn();

 

    return nRet;

}

 

這段代碼並不是必須的,但有些時候會出現程序權限不足以獲取進程句柄的情況,這個時候需要在代碼執行前調用該函數來提高程序的權限。

/*

     提升權限

*/

bool AdjustPrivileges() {

    HANDLE hToken;

    TOKEN_PRIVILEGES tp;

    TOKEN_PRIVILEGES oldtp;

    DWORD dwSize=sizeof(TOKEN_PRIVILEGES);

    LUID luid;

 

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {

        if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return true;

        else return false;

    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {

        CloseHandle(hToken);

        return false;

    }

    ZeroMemory(&tp, sizeof(tp));

    tp.PrivilegeCount=1;

    tp.Privileges[0].Luid=luid;

    tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;

    /* Adjust Token Privileges */

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) {

        CloseHandle(hToken);

        return false;

    }

    // close handles

    CloseHandle(hToken);

    return true;

}

 

0x02 HOOK 窗體實現

HINSTANCE g_hinstDll = NULL;

//

// 開始 HOOK

//

void CHookWindowDlg::OnBnClickedButtonStart()

{

    // TODO: 在此添加控件通知處理程序代碼

 

    g_hinstDll = LoadLibrary(_T("HookDll.dll"));

    if ( NULL == g_hinstDll)

    {

        AfxMessageBox(_T("加載 HookDll.dll 失敗"));

    }

 

    typedef BOOL (CALLBACK *HookStart)(HWND hwnd);

    HookStart hookStart = NULL;

    hookStart = (HookStart)::GetProcAddress(g_hinstDll,"StartHook");

    if ( NULL == hookStart)

    {

        AfxMessageBox(_T("獲取 StartHook 函數失敗"));

        return;

    }

    bool ret = hookStart(m_hWnd);

    if (ret)

    {

        m_list.InsertItem(m_list.GetItemCount(),_T("啟動鉤子成功"));

        m_list.EnsureVisible(m_list.GetItemCount()-1,FALSE);

    }

    else

    {

        m_list.InsertItem(m_list.GetItemCount(),_T("啟動鉤子失敗"));

        m_list.EnsureVisible(m_list.GetItemCount()-1,FALSE);

    }

}

 

//

// 終止 HOOK

//

void CHookWindowDlg::OnBnClickedButtonStop()

{

    // TODO: 在此添加控件通知處理程序代碼

 

    typedef BOOL (CALLBACK* HookStop)();

    HookStop hookStop = NULL;

    if (NULL == g_hinstDll) // 一定要加這個判斷,若不為空的話就不需要在重新加載,否則會是不同的實例

    {

        g_hinstDll = LoadLibrary(_T("HookDll.dll"));

        if (g_hinstDll == NULL)

        {

            AfxMessageBox(_T("加載 HookDll.dll 失敗"));

            return;

        }

 

    }

    

    hookStop = ::GetProcAddress(g_hinstDll,"StopHook");

    if (hookStop == NULL)

    {

        AfxMessageBox(_T("獲取 StopHook 失敗"));

        FreeLibrary(g_hinstDll);

        g_hinstDll=NULL;

        return;

    }

 

    hookStop();

    if (g_hinstDll!= NULL)

    {

        ::FreeLibrary(g_hinstDll);

    }

    m_list.InsertItem(m_list.GetItemCount(),_T("終止HOOK成功"));

 

}

 

// MessageBoxA

void CHookWindowDlg::OnBnClickedButtonMsga()

{

    // TODO: 在此添加控件通知處理程序代碼

    

    MessageBoxA(m_hWnd,"這是正常的MessageBoxA...","哈哈",0);

}

 

// MessageBoxW

void CHookWindowDlg::OnBnClickedButtonMsgw()

{

    // TODO: 在此添加控件通知處理程序代碼

    MessageBoxW(_T("這是正常的MessageBoxW..."),_T("呵呵"),0);

}

 

0x03 測試

本實例在自己實現的API中打印一句自己的話,然後再彈出原本的對話框。測試結果如下:

 

 

 

 

打開技術本,打開查找對話框,然後輸入一個字符串,"查找一下",這個時候同樣先彈出我們的對話框,然後才彈出原來的,找不到對話框。

0x04 附錄——HOOK DLL關鍵源碼

// HookDll.cpp : 定義 DLL 的初始化例程。

//

 

#include "stdafx.h"

#include "HookDll.h"

#include <Windows.h>

 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

/*

     全局共享變量

*/

#pragma data_seg("Share")

HWND g_hWnd = NULL ;            // 主窗口句柄

HINSTANCE g_hInstance = NULL;    // 本dll實例句柄

HHOOK hhk = NULL;                // 鼠標鉤子句柄

#pragma data_seg()

#pragma comment(linker,"/section:Share,rws")

 

HANDLE hProcess = NULL;                //    當前進程

BOOL bIsInJected = FALSE;            //    是否已注入標記

TCHAR* msgToMain = new TCHAR[200];    //    發給主調程序的信息

 

 

/*

    原函數定義

*/

typedef int (WINAPI *TypeMsgBoxA)(HWND hWnd,LPCSTR lpText, LPCSTR lpCaption,UINT uType);

typedef int (WINAPI *TypeMsgBoxW)(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCaption,UINT uType);

 

TypeMsgBoxA oldMsgBoxA = NULL;    // 用於保存原函數地址

TypeMsgBoxW oldMsgBoxW = NULL;    // 用於保存原楷書地址

FARPROC pfMsgBoxA = NULL;        // 指向原函數地址的遠指針

FARPROC pfMsgBoxW = NULL;        // 指向原函數地址的遠指針

 

#define CODE_LENGTH 5

BYTE oldCodeA[CODE_LENGTH];    // 保存原來API入口代碼

BYTE oldCodeW[CODE_LENGTH];    // 保存原來API入口代碼

BYTE newCodeA[CODE_LENGTH];    // 保存新API入口代碼,jmp xxxx

BYTE newCodeW[CODE_LENGTH];    // 保存新API入口代碼,jmp xxxx

 

/*

    自己編寫的API

*/

int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType);

int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType);

 

/*

    其它函數原型聲明

*/

void HookOn();            //    開始HOOK

void HookOff();            //    關閉HOOK

void Inject();            //    注入

BOOL WINAPI StartHook(HWND hWnd);    // 加載鉤子

BOOL WINAPI StopHook();                // 卸載鉤子

bool AdjustPrivileges();            // 提升權限

 

 

 

//

//TODO: 如果此 DLL 相對於 MFC DLL 是動態鏈接的,

//        則從此 DLL 導出的任何調入

//        MFC 的函數必須將 AFX_MANAGE_STATE 宏添加到

//        該函數的最前面。

//

//        例如:

//

//        extern "C" BOOL PASCAL EXPORT ExportedFunction()

//        {

//            AFX_MANAGE_STATE(AfxGetStaticModuleState());

//            // 此處為普通函數體

//        }

//

//        此宏先於任何 MFC 調用

//        出現在每個函數中十分重要。這意味著

//        它必須作為函數中的第一個語句

//        出現,甚至先於所有對象變量聲明,

//        這是因為它們的構造函數可能生成 MFC

//        DLL 調用。

//

//        有關其他詳細信息,

//        請參閱 MFC 技術說明 33 和 58。

//

 

// CHookDllApp

 

BEGIN_MESSAGE_MAP(CHookDllApp, CWinApp)

END_MESSAGE_MAP()

 

 

// CHookDllApp 構造

 

CHookDllApp::CHookDllApp()

{

    // TODO: 在此處添加構造代碼,

    // 將所有重要的初始化放置在 InitInstance 中

}

 

 

// 唯一的一個 CHookDllApp 對象

 

CHookDllApp theApp;

 

 

// CHookDllApp 初始化

/*

    dll程序入口,當程序加載dll時,會執行InitInstance()

*/

BOOL CHookDllApp::InitInstance()

{

    CWinApp::InitInstance();

    g_hInstance = AfxGetInstanceHandle();//    獲取當前DLL實例句柄

    

    AdjustPrivileges();    //    提高權限

    DWORD dwPid = ::GetCurrentProcessId();

    hProcess = ::OpenProcess(PROCESS_ALL_ACCESS,0,dwPid);

 

    if (hProcess == NULL)

    {

        CString str;

        str.Format(_T("OpenProcess fail, and error code = %d"),GetLastError());

        AfxMessageBox(str);

        return FALSE;

    }

 

    Inject();    // 開始注入

    

    return TRUE;

}

int CHookDllApp::ExitInstance()

{

    /*

        dll退出時,一定要記得恢復原API的入口!!!

        我們編寫的dll會被注入到所有目標進程中,若dll退出時,沒有恢復原API入口,

        那麼被掛鉤的程序再次調用該API時,會發生錯誤。

        因為我們的dll程序已經退出,但原API的入口仍為我們所定義的API的入口,這

        時被掛鉤的程序無法找到我們實現的API,然而原API的地址又沒有被恢復,也就

        調用不到原API,這時程序自然會發生崩潰了。

    */

 

    HookOff();

 

    return CWinApp::ExitInstance();

}

 

/*

     提升權限

*/

bool AdjustPrivileges() {

    HANDLE hToken;

    TOKEN_PRIVILEGES tp;

    TOKEN_PRIVILEGES oldtp;

    DWORD dwSize=sizeof(TOKEN_PRIVILEGES);

    LUID luid;

 

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {

        if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) return true;

        else return false;

    }

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {

        CloseHandle(hToken);

        return false;

    }

    ZeroMemory(&tp, sizeof(tp));

    tp.PrivilegeCount=1;

    tp.Privileges[0].Luid=luid;

    tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;

    /* Adjust Token Privileges */

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &oldtp, &dwSize)) {

        CloseHandle(hToken);

        return false;

    }

    // close handles

    CloseHandle(hToken);

    return true;

}

 

 

/*

     鼠標鉤子子過程,目的是加載本dll到使用鼠標的程序中。

     鼠標鉤子的作用:當鼠標在某程序窗口中時,就會加載我們這個dll。

*/

LRESULT CALLBACK MouseProc(

                        int nCode,     // hook code

                        WPARAM wParam,// message identifier

                        LPARAM lParam // mouse coordinates

                        )

{

 

    return CallNextHookEx(hhk,nCode,wParam,lParam);

}

 

/*

    將長度為length的pcode寫入到地址lpAddress中。

*/

void WriteMemory(LPVOID lpAddress,BYTE* pcode,int length)

{

    //

    //    保證本進程句柄不為NULL

    //

    ASSERT(hProcess != NULL);

 

    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

 

    //

    // 修改API入口前length個字節為 jmp xxxx

    //

    VirtualProtectEx(hProcess,lpAddress,length,PAGE_READWRITE,&dwOldProtect);

    dwRet = WriteProcessMemory(hProcess,lpAddress,pcode,length,&dwWrited);

    if ( 0 == dwRet || 0 == dwWrited)

    {

        AfxMessageBox(_T("哭!!寫入失敗"));

    }

    VirtualProtectEx(hProcess,lpAddress,length,dwOldProtect,&dwTemp);

}

 

/*

    用新API地址替換原API地址

*/

void HookOn()

{

    ASSERT(hProcess != NULL);

 

    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

    

    WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH);

    WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH);

 

}

 

/*    

    恢復原API地址

*/

void HookOff()

{

    ASSERT(hProcess != NULL);

 

    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

 

    WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);

    WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);

}

 

/*

    注入

*/

void Inject()

{

    if ( TRUE == bIsInJected)

    {

        return;

    }

    bIsInJected = TRUE;    // 保證只調用一次

 

 

    //

    // 獲取函數

    //

    HMODULE hmodle = ::LoadLibrary(_T("User32.dll"));

    oldMsgBoxA = (TypeMsgBoxA) ::GetProcAddress(hmodle,"MessageBoxA");

    pfMsgBoxA = (FARPROC)oldMsgBoxA;

 

    oldMsgBoxW = (TypeMsgBoxW) ::GetProcAddress(hmodle,"MessageBoxW");

    pfMsgBoxW = (FARPROC)oldMsgBoxW;

 

    if (pfMsgBoxA == NULL)

    {

        AfxMessageBox(_T("獲取 MessageBoxA 函數失敗"));

        return;

    }

    if ( pfMsgBoxW == NULL)

    {

        AfxMessageBox(_T("獲取 MessageBoxW 函數失敗"));

        return;

    }

 

    //

    // 保存原API地址

    //

    _asm

    {

        lea edi,oldCodeA    // 取數組基地址

        mov esi,pfMsgBoxA    // API地址

        cld                    // 設置方向

        mov ecx,CODE_LENGTH

        rep movsb

    }

 

    _asm

    {

        lea edi,oldCodeW

        mov esi,pfMsgBoxW

        cld

        mov ecx,CODE_LENGTH

        rep movsb

    }

 

    //

    // 將新地址復制到入口

    //

    newCodeA[0] = newCodeW [0] = 0xe9;    // jmp 指定代碼

    _asm

    {

        lea eax,MyMessageBoxA        // 新API地址

        mov ebx,pfMsgBoxA            // 原API地址

        sub eax,ebx                

        sub eax,CODE_LENGTH            // 跳轉地址 = 新API地址 - 原API地址 - 指令長度

        mov dword ptr [newCodeA+1],eax // eax 32bit = 4 BYTE

    }

 

    _asm

    {

        lea eax,MyMessageBoxW

        mov ebx,pfMsgBoxW

        sub eax,ebx

        sub eax,CODE_LENGTH

        mov dword ptr [newCodeW + 1],eax

    }

 

    HookOn();    //    開始HOOK

 

}

 

//

// 安裝鉤子

//

BOOL WINAPI StartHook(HWND hWnd)

{

    g_hWnd = hWnd;

    hhk = ::SetWindowsHookEx(WH_MOUSE,MouseProc,g_hInstance,0);

 

    if (hhk == NULL)

    {

        return FALSE;

    }

    else

    {

        

        return TRUE;

    }

}

 

//

// 卸載鉤子

//

BOOL WINAPI StopHook()

{    

    /*

        卸載鉤子時,一定要記得恢復原API入口。

        這裡恢復的只是主程序的原API入口,其它程序的API入口還沒有被恢復。

        因此我們必須處理dll退出過程,即在函數ExitInstance()中,調用恢復

        API入口的函數HookOff(),只有這樣,其它程序再次調用原API時,才不

        會發生錯誤。

        當我們HOOK所有程序的某個系統API時,千萬要注意在ExitInstance()中

        調用HookOff()!!!!!

    */

    HookOff();

    if (hhk!=NULL)

    {

        UnhookWindowsHookEx(hhk);

        FreeLibrary(g_hInstance);

    }

 

    return TRUE;

}

 

 

/*

    自己用於替換的API

*/

int WINAPI MyMessageBoxA(HWND hWnd,LPCSTR lpText,LPCSTR lpCation,UINT uType)

{

    int nRet = 0;

 

    HookOff();

    nRet = ::MessageBoxA(hWnd,"哈哈 ^_^,MessageBoxA 被 HOOK 咯",lpCation,uType);

    nRet = ::MessageBoxA(hWnd,lpText,lpCation,uType);

    HookOn();

 

    return nRet;

}

 

int WINAPI MyMessageBoxW(HWND hWnd,LPCWSTR lpText,LPCWSTR lpCation,UINT uType)

{

    int nRet = 0;

 

    HookOff();

    nRet = ::MessageBoxW(hWnd,_T("O(∩_∩)O哈哈~,MMessageBoxW 被 HOOK 咯"),lpCation,uType);

    nRet = ::MessageBoxW(hWnd,lpText,lpCation,uType);

    HookOn();

 

    return nRet;

}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved