學習windows 應用層 inline hook 原理總結


inline hook 實際上就是指 通過改變目標函數頭部的代碼來使改變后的代碼跳轉到我們自己設置的一個函數里,產生hook。

今天就拿MessageBoxA這個api函數來做實驗。功能就是當程序調用MessageBoxA 時,我們打印出MessageBoxA的參數

 

大概代碼結構應該是這樣

typedef int (WINAPI
    *MessageBox_type) (
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType) ;

MessageBox_type RealMessageBox;

//我們自己的MessageBox,每調用MessageBox都要跳到myMessageBox來處理
int WINAPI
    myMessageBox(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType)
{
    //下面打印MessageBox參數
    printf("hwnd:%8X lpText:%s lpCaption:%s,uType:%8X",hWnd,lpText,lpCaption,uType); 
    return RealMessageBox(hWnd,lpText,lpCaption,uType); //現在開始調用真正的MessageBox
}

VOID HookMessageBoxA()
{

}

int _tmain(int argc, _TCHAR* argv[])
{
    HookMessageBoxA();  //hook操作
    ::MessageBoxA(NULL,"hook test","tip",MB_OK); //執行api MessageBox
    return 0;
}

我們先看看匯編是怎樣調用MessageBoxA的

 

MessageBox流程

首先看到,MessageBoxA里面

mov edi,edi
mov ebp
mov ebp,esp
剛好是5個字節,5個字節可以做一個遠jmp

直接匯編改成我們自己的jmp

改后結果如下

image

單步執行發現hook成功。但程序崩潰。原因主要是由於

我們破壞了真正的MessageBox使們想要調用真正的MessageBox時也會調用失敗了,所以我們要調用真正的MessageBox時要加上頭部被我們換掉的部分,我們要內聯匯編,里面不能含有編譯器自動添加的代碼,所以在myMessageBox頭部要加上 _declspec(naked)

vs2010的debug版本每執行一個函數都要 cmp esi,esp 來驗證堆棧的。所以還要加一句push esi 和pop esi

//我們自己的MessageBox,每調用MessageBox都要跳到myMessageBox來處理
_declspec(naked)  void WINAPI
    myMessageBox(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType)
{
        __asm
    {
        PUSH ebp
        mov ebp,esp

        /*
        vs2010 debug 編譯后的代碼由於要cmp esi esp來比較堆棧。
        所以這里在調用非__asm函數前push一下esi
        */
        push esi
    }
    //下面打印MessageBox參數
    printf("hwnd:%8X lpText:%s lpCaption:%s,uType:%8X",hWnd,lpText,lpCaption,uType); 

    __asm
    {
        /*
        vs2010 debug 編譯后的代碼由於要cmp esi esp來比較堆棧。
        所以這里在調用非__asm函數前push一下esi
        */
        pop esi

        mov ebx,RealMessageBox
        add ebx,5
        jmp ebx
    }
}

下面說一下用代碼來寫MessageBoxA着呢5個字節

首先要懂得 JMP指令轉換公式推導  不懂的話 看 http://www.cnblogs.com/zhangdongsheng/archive/2012/12/06/2804234.html

 

先聲明一個JMP結構體。注意前面加 #pragma pack(1)來避免內存對齊的一些規則

#pragma pack(1)
typedef struct _JMPCODE
{
    BYTE jmp;
    DWORD addr;
}JMPCODE,*PJMPCODE;

接下來寫hook函數

VOID HookMessageBoxA()
{
    JMPCODE jcode;
    jcode.jmp = 0xe9;//jmp
    jcode.addr = (DWORD)myMessageBox - (DWORD)RealMessageBox - 5; 

    RealMessageBox = MessageBoxA;
    ::WriteProcessMemory(GetCurrentProcess(),MessageBoxA,&jcode,sizeof(JMPCODE),NULL);
}

現在測試成功。

image

 

完整源代碼如下:

// hook_blog_writer.cpp : 定義控制台應用程序的入口點。
//

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

typedef int (WINAPI
    *MessageBox_type) (
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType) ;

MessageBox_type RealMessageBox = MessageBoxA;

//我們自己的MessageBox,每調用MessageBox都要跳到myMessageBox來處理
_declspec(naked)  void WINAPI
    myMessageBox(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType)
{
        __asm
    {
        PUSH ebp
        mov ebp,esp

        /*
        vs2010 debug 編譯后的代碼由於要cmp esi esp來比較堆棧。
        所以這里在調用非__asm函數前push一下esi
        */
        push esi
    }
    //下面打印MessageBox參數
    printf("hwnd:%8X lpText:%s lpCaption:%s,uType:%8X",hWnd,lpText,lpCaption,uType); 

    __asm
    {
        /*
        vs2010 debug 編譯后的代碼由於要cmp esi esp來比較堆棧。
        所以這里在調用非__asm函數前push一下esi
        */
        pop esi

        mov ebx,RealMessageBox
        add ebx,5
        jmp ebx
    }
}


#pragma pack(1)
typedef struct _JMPCODE
{
    BYTE jmp;
    DWORD addr;
}JMPCODE,*PJMPCODE;

VOID HookMessageBoxA()
{
    JMPCODE jcode;
    jcode.jmp = 0xe9;//jmp
    jcode.addr = (DWORD)myMessageBox - (DWORD)RealMessageBox - 5; 

    RealMessageBox = MessageBoxA;
    ::WriteProcessMemory(GetCurrentProcess(),MessageBoxA,&jcode,sizeof(JMPCODE),NULL);
}

int _tmain(int argc, _TCHAR* argv[])
{
    HookMessageBoxA();  //hook操作
    ::MessageBoxA(NULL,"hook test","tip",MB_OK); //執行api MessageBox
    return 0;
}

 

 


免責聲明!

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



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