Daniel Eugen
Daniel Eugen

Reputation: 2780

C++ memcpy returning true with no changes

I am trying to write a simple hook class that installs a hook at the target address and detouring the flow into custom function.

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);
}

The problem now is that when i install the hook and try calling originalFunction() it still goes into original function and no call to fakeFunction() is made... i have double checked the code and everything seems to be fine but there must be a gotcha somewhere.

Upvotes: 0

Views: 233

Answers (2)

Ben Voigt
Ben Voigt

Reputation: 283893

It's important to note that the C and C++ Standards do not associate any meaning to casts between function pointers and object pointers -- if the destination variable is big enough to hold the entire address (not guaranteed, systems do exist that have different sizes for code and data), and you cast back to the original pointer type, you get back the original value. Any other usage is undefined behavior.

Self-mutating code is also undefined behavior.

The only supported mechanism for redirecting function calls at runtime is when the call is made indirectly, using a function pointer, to change the function pointer.

Since the language provides no guarantees, you're delving into details of the actual instructions the compiler generated... which means you had better look at those instructions, see whether the call is to the address you expected (under various conditions &originalFunction might be the address of a trampoline, but the compiler might still emit calls directly to the real function body, or inline the call, etc.)

You might also have to use machine-specific instructions to flush the instruction cache, because changes to data normally are assumed NOT to change code. On Windows, there's a FlushInstructionCache API call which you need to use when patching code. Read this explanation of why it is needed (discusses a non-Windows system but still expresses the concept well)

Upvotes: -1

Andrey Nasonov
Andrey Nasonov

Reputation: 2629

Just look here:

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

The value &originalFunction is the address of the variable originalFunction on the stack. Use (void*)originalFunction instead.

Upvotes: 4

Related Questions