2015-09-27 51 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系统,但仍然表达了概念以及)