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


HOOK API(三)

—— HOOK 所有程序的 MessageBox

原文出處:http://www.cnblogs.com/fanling999/p/4595035.html

程序源代碼:https://github.com/hfl15/windows_kernel_development/tree/master/demo_source_code/HoolAllMessageBox

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的實現

 

建立一個MFC 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

MFC DLL的InitInstance()函數

 

/*
    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;
}

MFC DLL的ExitInstance()函數

 

int CHookDllApp::ExitInstance(){

    /*
        dll退出時,一定要記得恢復原API的入口!!!
        我們編寫的dll會被注入到所有目標進程中,若dll退出時,沒有恢復原API入口,
        那么被掛鈎的程序再次調用該API時,會發生錯誤。
        因為我們的dll程序已經退出,但原API的入口仍為我們所定義的API的入口,這
        時被掛鈎的程序無法找到我們實現的API,然而原API的地址又沒有被恢復,也就
        調用不到原API,這時程序自然會發生崩潰了。
    */

    HookOff();
    return CWinApp::ExitInstance();
}

HOOK API實現

  1. 注入函數,保存新的,原來的API的入口

該函數的主要功能是保存新的和原來的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地址
/*
    用新API地址替換原API地址
*/
void HookOn(){

    ASSERT(hProcess != NULL);
    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;

    WriteMemory(pfMsgBoxA,newCodeA,CODE_LENGTH);
    WriteMemory(pfMsgBoxW,newCodeW,CODE_LENGTH);
}
恢復原API地址
/*  
    恢復原API地址
*/
void HookOff(){
    ASSERT(hProcess != NULL);
    DWORD dwTemp,dwOldProtect,dwRet,dwWrited;
    WriteMemory(pfMsgBoxA,oldCodeA,CODE_LENGTH);
    WriteMemory(pfMsgBoxW,oldCodeW,CODE_LENGTH);
}
新API定義
/*
    自己用於替換的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 窗體實現

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

 

StopHook
// 終止 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
// MessageBoxA
void CHookWindowDlg::OnBnClickedButtonMsga(){

    // TODO: 在此添加控件通知處理程序代碼
    MessageBoxA(m_hWnd,"這是正常的MessageBoxA...","哈哈",0);
}
MessageBoxW
// MessageBoxW
void CHookWindowDlg::OnBnClickedButtonMsgw(){

    // TODO: 在此添加控件通知處理程序代碼
    MessageBoxW(_T("這是正常的MessageBoxW..."),_T("呵呵"),0);
}

0x03 測試

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

啟動鈎子

 

單擊"MessageBoxA"按鈕,調用MessageBoxA函數

可以看到,先彈出了我們自己的對話框,然后才彈出真正的對話框。

 

單擊"MessageBoxW"按鈕,調用MessageBoxW函數。

可以看到,先彈出我們的對話框,然后才彈出真正的對話框。

 

記事本的對話框也被HOOK了。

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

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

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM