C++輔導(dǎo):如何截獲API函數(shù)

字號:

該程序是基于HOOK原理,主要是將自己的函數(shù)放到目標PROCESS的地址空間,這里是使用HOOK實現(xiàn).首先建立一個MOUSE的HOOK程序,然后在全局鼠標HOOK的DLL中做截獲動作,可以在PROCESS_ATTACH時做,也可以在鼠標的HOOK鏈函數(shù)中做.
    建立全局HOOK我就不說了,可以在網(wǎng)上很多地方看到.主要是截獲動作.我是通過PE格式(使用IMAGE)改變API函數(shù)在調(diào)用時的地址.DLL部分參考如下代碼:
    static int WINAPI MyMessageBoxW(HWND hWnd , LPCWSTR lpText, LPCWSTR lpCaption, UINT uType)//自己的MessageBoxW函數(shù)
    {return MessageBox(hWnd, "TNT"/*lpText*/, "TNT"/*lpCaption*/, uType);
    }
    我定義了一個結(jié)構(gòu)
    typedef struct tag_HOOKAPI
    {
    LPCSTR szFunc;//待HOOK的API函數(shù)名
    PROC pNewProc;//新的函數(shù)指針
    PROC pOldProc;//老的函數(shù)指針
    }HOOKAPI, *LPHOOKAPI;
    extern "C" __declspec(dllexport)PIMAGE_IMPORT_DESCRIPTOR GetNamedImportDescriptor(HMODULE hModule, LPCSTR szImportMod)
    {
    //首先是DOS頭
    PIMAGE_DOS_HEADER pDOSHeader = (PIMAGE_DOS_HEADER) hModule;
    if(pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) return NULL;
    PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDOSHeader + (DWORD)(pDOSHeader->e_lfanew));
    if(pNTHeader->Signature != IMAGE_NT_SIGNATURE) return NULL;
    //如果沒有Import部分,返回失敗
    if(pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0)
    return NULL;
    //取Import部分
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)
    ((DWORD)pDOSHeader + (DWORD)(pNTHeader->OptionalHeader.
    DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
    //尋找與szImportMod相配部分
    while (pImportDesc->Name)
    {
    PSTR szCurrMod = (PSTR)((DWORD)pDOSHeader + (DWORD)(pImportDesc->Name));
    if (stricmp(szCurrMod, szImportMod) == 0)
    break; //找到
    pImportDesc++;
    }
    if(pImportDesc->Name == NULL) return NULL;
    return pImportDesc;
    }
    extern "C" __declspec(dllexport) HookAPIByName(HMODULE hModule/*被HOOK的目標進程MODULE*/, LPCSTR szImportMod/*如GDI32.DLL*/,LPHOOKAPI pHookApi/*指定函數(shù)名,如"MessageBoxW"*/)
    {
    PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
    GetNamedImportDescriptor(hModule, szImportMod);
    if (pImportDesc == NULL)
    return FALSE; //需要改換的API不能取到正確描PIMAGE_THUNK_DATA pOrigThunk = (PIMAGE_THUNK_DATA)((DWORD)hModule + (DWORD)(pImportDesc->OriginalFirstThunk));
    PIMAGE_THUNK_DATA pRealThunk =
    (PIMAGE_THUNK_DATA)((DWORD)hModule + (DWORD)(pImportDesc->FirstThunk));
    while(pOrigThunk->u1.Function)
    {
    if((pOrigThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)
    {
    PIMAGE_IMPORT_BY_NAME pByName = (PIMAGE_IMPORT_BY_NAME)((DWORD)hModule + (DWORD)(pOrigThunk->u1.AddressOfData));
    if(pByName->Name[0] == ’\0’)
    return FALSE; //失敗
    if(strcmpi(pHookApi->szFunc, (char*)pByName->Name) == 0)
    {
    //改變thunk保護屬性
    MEMORY_BASIC_INFORMATION mbi_thunk;
    VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
    VirtualProtect(mbi_thunk.BaseAddress,mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);
    //保存原來的API函數(shù)指針
    if(pHookApi->pOldProc == NULL)
    pHookApi->pOldProc = (PROC)pRealThunk->u1.Function;
    //改變API函數(shù)指針
    pRealThunk->u1.Function = (PDWORD)pHookApi->pNewProc;
    //將thunk保護屬性改回來
    DWORD dwOldProtect;
    VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
    mbi_thunk.Protect, &dwOldProtect);
    }
    }
    pOrigThunk++;
    pRealThunk++;
    }
    SetLastError(ERROR_SUCCESS);
    return TRUE;
    }
    EXE部分很簡單,將該DLL載入,開啟鼠標HOOK.