WINDOWS下HOOK函數的方法


 

前兩天和dvff談論的一些技術總結。

程序代碼:
//////////////////////////////////////////////////////////////////////////////////// /
//                     HOOKAPI DEMO PROGRAM
// 文件名:HOOKTEST.C
//
// 描述: 演示WINNT下HOOK系統API過程及方法
//       (擴充為HOOK任意函數的方法)
//
// 作者:東海一魚
//
// 時間: 2010.7.22       
//
// 使用編譯器: VC2003
//
// 使用第三方庫: NULL
//
//
// Bug、修復紀錄:
//           1、2010.8.4 增加HOOK私有函數代碼(被hook函數名TestFn,hook函數名MyHookFn2)
//
//             2、2010.8.6 增加HOOK類虛擬函數代碼(被hook函數名TestVirtualFn,
//                hook函數名TestVirtualFn2)
//
//                HOOK類成員函數,主要難度在於成員函數地址的獲得。
//              普通成員函數指針在VC6下無法進行強制類型轉換,
//              解決手段見GetClassFnAddress輔助函數。
//              類虛擬成員函數HOOK需要獲得類實例對象虛表中的虛擬函數指針。                   
////////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include  <stdio.h>
#include  <windows.h>

// #pragma pointers_to_members(best_case)

#ifdef _X86_

#define FLATJMPCODE_LENGTH 5             // x86 平坦內存模式下,絕對跳轉指令長度
#define FLATJMPCMD_LENGTH  1             // 機械碼0xe9長度
#define FLATJMPCMD         0xe9

#else

#error WINVER ERRORSLECT  ONLY USES ON X86!!!

#endif

///////////////////////////////////////////////////////////////////////////
// 測試類函數HOOK
class TestHookFnClass
{
public:
     virtual  void TestVirtualFn( char* szPlay);
     virtual  void TestVirtualFn2( char* szPlay);
     void TestHookFn( char* szPlay);
     void TestHookFn2( char* szPlay);   
};

void TestHookFnClass::TestHookFn( char* szPlay)
{
    printf( " %s\n ",szPlay);
}

void TestHookFnClass::TestHookFn2( char* szPlay)
{
    printf( " %s - %s\n  ",szPlay, " 類函數已被HOOK! ");
}

void TestHookFnClass::TestVirtualFn( char* szPlay)
{
    printf( " %s\n ",szPlay);
}

void TestHookFnClass::TestVirtualFn2( char* szPlay)
{
    printf( " %s - %s\n ",szPlay, " Virtual2 HOOKS ");
}

//////////////////////////////////////////////////////////////////////// /
#ifdef _X86_
// 利用C變參特性,進行類成員函數指針類型轉換
LPVOID GetClassFnAddress(...)                     // Add  2010.8.6
{
    LPVOID FnAddress;
   
     __asm
    {
        lea eax,FnAddress
        mov edx,[ebp+ 8]
        mov [eax],edx
    }
     return FnAddress;
}
#endif

// 獲得類虛擬成員函數指針
LPVOID GetClassVirtualFnAddress(LPVOID pthis, int Index)  // Add 2010.8.6
{
    LPVOID FnAddress;
   
    *( int*)&FnAddress = *( int*)pthis;                        // lpvtable
    *( int*)&FnAddress = *( int*)(( int*)FnAddress + Index);
     return FnAddress;
}
//////////////////////////////////////////////////////////////////////// /
// 我的新API函數
int  __stdcall MyHookFn(HWND hwnd, char* sztext, char* szTitle, int stly)
{          
   
     return printf( " %s - %s\n ",sztext, " 原API函數已被HOOK! ");    //
}

// 我的新私有樁函數
void MyHookFn2( char* szTxt)
{
     char* pBuf = ( char*)malloc(strlen(szTxt) +  sizeof( char*) *  32);
   
    __try
    {
        sprintf(pBuf, " %s - %s ",szTxt, "  原函數已被HOOK! ");
        printf( " %s\n ",pBuf);
    }
    __finally
    {
        free(pBuf);
    }
}

// 私有測試函數
void TestFn( char* szTitle)
{
    printf( " %s ",szTitle);
}

///////////////////////////////////////////////////////////////////// /
// HOOK函數
BOOL HookApi(LPVOID ApiFun,LPVOID HookFun)
{
    BOOL    IsSuccess = FALSE;
    DWORD   TempProtectVar;               // 臨時保護屬性變量
    MEMORY_BASIC_INFORMATION MemInfo;     // 內存分頁屬性信息
   
    VirtualQuery(ApiFun,&MemInfo, sizeof(MEMORY_BASIC_INFORMATION)); 
   
     if(VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize,
        PAGE_READWRITE,&MemInfo.Protect))                             // 修改頁面為可寫
    {
        *(BYTE*)ApiFun = FLATJMPCMD;                                     
        *(DWORD*)((BYTE*)ApiFun + FLATJMPCMD_LENGTH) = (DWORD)HookFun -
            (DWORD)ApiFun - FLATJMPCODE_LENGTH;
       
        VirtualProtect(MemInfo.BaseAddress,MemInfo.RegionSize,
            MemInfo.Protect,&TempProtectVar);                                // 改回原屬性
       
        IsSuccess = TRUE;
    }
   
     return IsSuccess;
}

int main( int argc, char** argv)
{
    HMODULE hDll;
    LPVOID  OldFun;    

    TestHookFnClass* TestClass =  new TestHookFnClass();

    __try
    {
        hDll = GetModuleHandle( " User32.dll ");
        OldFun = GetProcAddress(hDll, " MessageBoxA ");   // 要HOOK的API函數
   
         if(OldFun)
        {
             if(HookApi(OldFun,MyHookFn))   // 如果HOOK成功
                MessageBoxA( 0, " call Api MessageBox ", " Is Hookd? ",MB_OK);  // 調用原API,測試HOOK

             if(HookApi(TestFn,MyHookFn2))
                TestFn( " Private Function Hook Test ");   // 調用私有函數,測試HOOK   
           
             if(HookApi(GetClassFnAddress(TestHookFnClass::TestHookFn),
                GetClassFnAddress(TestHookFnClass::TestHookFn2)))
                TestClass->TestHookFn( " Hook Class Member Function Test! "); // 調用類成員函數,測試HOOK

             if(HookApi(GetClassVirtualFnAddress(TestClass, 0),
                GetClassFnAddress(TestHookFnClass::TestHookFn2)))
                TestClass->TestVirtualFn( " Call Class Virtual Function Test! "); // 調用類虛擬函數,測試HOOK
           
             if(HookApi(GetClassVirtualFnAddress(TestClass, 0),
                GetClassVirtualFnAddress(TestClass, 1)))                    
                TestClass->TestVirtualFn( " Call Class Virtual Function Test2! "); // 同上,樁函數為另一虛函數
        }
    }
    __finally
    {
         if(hDll)
            FreeLibrary(hDll);
         if(TestClass)
             delete(TestClass);
    }
   
     return  0;
}


免責聲明!

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



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