2015-09-27 52 views
0

我試圖寫一個簡單的掛鉤類,在目標地址安裝一個鉤子返回true和迂迴流入自定義函數。C++ memcpy的,沒有變化

Main.cpp的

#include "SingleHook.h" 
#include <iostream> 

using namespace std; 

void originalFunction() 
{ 
    cout << "originalFunction()" << endl; 
} 

void fakeFunction() 
{ 
    cout << "fakeFunction()" << endl; 
} 

void main() 
{ 
    SingleHook sHook((DWORD)originalFunction, (DWORD)fakeFunction); 

    originalFunction(); //Should call the original function 
    sHook.InstallHook(); 

    originalFunction(); //Should call the fake function 

    sHook.UninstallHook(); 
    originalFunction(); //Should again call the original function 

    cin.get(); 
} 

SingleHook.h

#pragma once 
#define HLength 6 
#include <windows.h> 

class SingleHook { 
private: 
    void* hookTarget; 
    byte originalBytes[HLength]; 
    byte hookBytes[HLength]; 

public: 
    SingleHook(DWORD originalFunction, DWORD targetFunction) 
    { 
     //backing up original bytes 
     ::memcpy(originalBytes, &originalFunction, HLength); 

     //generating hook bytes 
     hookBytes[0] = 0x68; //push 
     hookBytes[1] = ((byte*)targetFunction)[0]; 
     hookBytes[2] = ((byte*)targetFunction)[1]; 
     hookBytes[3] = ((byte*)targetFunction)[2]; 
     hookBytes[4] = ((byte*)targetFunction)[3]; 
     hookBytes[5] = 0xC3; //retn 

     //setting up hook target 
     hookTarget = &originalFunction; 
    } 

    void* InvokeOriginalFunction(...); 
    void InstallHook(); 
    void UninstallHook(); 
}; 

SingleHook.cpp

#include "SingleHook.h" 

void* SingleHook::InvokeOriginalFunction(...) 
{ 
    UninstallHook(); 
    //TODO INVOKE ORIGINAL SOMEHOW 
    InstallHook(); 

    return nullptr; 
} 

void SingleHook::InstallHook() 
{ 
    DWORD oldProt; 
    ::VirtualProtect(hookTarget, HLength, PAGE_EXECUTE_READWRITE, &oldProt); 
    ::memcpy(hookTarget, hookBytes, HLength); 
    ::VirtualProtect(hookTarget, HLength, oldProt, nullptr); 
} 

void SingleHook::UninstallHook() 
{ 
    DWORD oldProt; 
    ::VirtualProtect(hookTarget, HLength, PAGE_EXECUTE_READWRITE, &oldProt); 
    ::memcpy(hookTarget, originalBytes, HLength); 
    ::VirtualProtect(hookTarget, HLength, oldProt, nullptr); 
} 

現在的問題是叔當我安裝鉤子,並嘗試呼叫originalFunction()它仍然進入原來的功能,並沒有打電話給fakeFunction() ...我仔細檢查了代碼,一切似乎都很好,但必須有一個陷阱。

+0

你的標題是沒有意義的。 'memcpy()'不返回一個布爾值,並且在這段代碼中沒有任何地方可以檢查它返回的結果。 – EJP

回答

4

只要看看這裏:

SingleHook(DWORD originalFunction, DWORD targetFunction) 
{ 
    //backing up original bytes 
    ::memcpy(originalBytes, &originalFunction, HLength); 

&originalFunction是在棧上的變量originalFunction的地址。改爲使用(void*)originalFunction

+0

我已經用相同的結果測試過,我在做另一件事情是錯的嗎? –

+1

從'originalFunction'複製'HLength'字節是不好的,因爲'DWORD'只有4個字節而'HLength'是6,所以它會讀取垃圾。 – MikeCAT

+0

@MikeCAT仔細觀察我們不復制DWORD,我們正在複製一個長度爲6的字節數組到目標函數(基本上用push fakeFunction()retn替代函數序言) –

-1

需要注意的是,C和C++標準沒有將任何含義與函數指針和對象指針之間的轉換相關聯 - 如果目標變量足夠大以保存整個地址(不保證,系統確實存在代碼和數據的大小不同),並且您轉回到原始指針類型,您將返回原始值。任何其他用法都是未定義的行爲。

自變異代碼也是未定義的行爲。

重定向功能僅支持機制調用在運行時是當呼叫被間接作出,使用函數指針,以改變函數指針。

由於語言不提供擔保,你鑽研的實際指令編譯器生成......這意味着你必須在這些指令更好看詳細信息,請參閱該呼叫是否是您預期的地址(下各種條件&originalFunction可能是蹦牀的地址,但編譯器可能仍然直接向真實函數體發出調用,或者內聯調用等)。

您可能還必須使用機器特定的指令來刷新指令緩存,因爲通常情況下對數據的更改不會改變代碼。在Windows上,有一個FlushInstructionCache API調用,您在修補代碼時需要使用它。閱讀本explanation of why it is needed(討論了非Windows系統,但仍然表達了概念以及)