Code:
HRESULT EndsceneHook(IDirect3DDevice9 *pDevice)
{
pDevice->Clear(...);
HRESULT hrRealEndscene = pDevice->Endscene(); //See how you can call the original endscene with no worries?
hooker->GiveHerpes(); //reset the hook on Endscene now, so next time it's called we'll hook it again :)
return hrRealEndscene;
}
or, using my lazyman "SloppySeconds" function:
Code:
/*
FilthyHooker class written by Jason.
Feel free to use this class however you please, I take no responsibility for how you use it, though.
You are welcome to use the class, all I ask is that you leave this message at the top, and give credit
where it's due.
*/
#ifndef FILTHYHOOKER_H
#define FILTHYHOOKER_H
#include <Windows.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#define SZ_HOOK 0x000A //the size of the hook, don't fucking touch this or I will bang your mum.
#define N_HOOKS 0x00FF //maximum number of hooks at any one time, if you're really hooking more than 255 functions at once, you have a sad, sad addiction and should seek help, or just change the definition :3
//normalize the buffer so I don't have to keep creating SZ_HOOK sized BYTE buffers everywhere; it's boring.
typedef struct _hbuff
{
BYTE value[SZ_HOOK];
} HOOK_BUFFER, *PHOOK_BUFFER;
//structure to hold information about a particular hook.
typedef struct _hinfo : HOOK_BUFFER
{
PBYTE function;
PBYTE detour;
} HOOK_INFO, *PHOOK_INFO;
class FilthyHooker
{
private:
//static vars for out-of-class access.
static HOOK_INFO hooks[N_HOOKS];
static DWORD ref;
//couple of members, just the unique stub and the index for this instance.
DWORD index;
HOOK_BUFFER stub;
//repatch the original function back to its former glory, returns the address of the detour corresponding to the function.
static PBYTE Repatch(int id);
//little stubby bastard to allow for function repatching before handing over control to the user's detour.
static void Proxy(int id);
public:
//Construct a new hook, redirecting pFunction to pDetour.
FilthyHooker(PBYTE pFunction, PBYTE pDetour);
//destroy.
~FilthyHooker(void);
//check if the hook is set
BOOL HasAids(void);
//Set the hook.
void GiveHerpes(void);
//Unset the hook.
void SeeDoctor(void);
//purely a lazymans function. Just resets the hook on the function and then returns the param you gave it.
//It's nice when you just want to return the original function's value, then reset the hook, i.e for an Endscene hook (pDevice = IDirect3DDevice9*, pHook = JHook*)
//return pHook->SloppySeconds<HRESULT>(pDevice->Endscene());
//resets the hook and returns the value all at once. Easy as.
template <class T>
T SloppySeconds(T retval)
{
this->GiveHerpes();
return reval;
}
};
#endif
pastie:
Code:
#include "FilthyHooker.h"
//just a couple of simple pointer arithmetic macros.
#define AddPtr(t,p1,p2) (t)((ULONG_PTR)(p1) + (ULONG_PTR)(p2))
#define SubPtr(t,p1,p2) (t)((ULONG_PTR)(p1) - (ULONG_PTR)(p2))
//copy an existing HOOK_BUFFER into another.
#define CopyBuffer(p1, p2) (*(PHOOK_BUFFER)(p1) = *(PHOOK_BUFFER)(p2))
//same as CopyBuffer but with memory protection to allow writing as well.
#define SafeCopyBuffer(p1, p2) DWORD d1, d2; VirtualProtect(p1, SZ_HOOK, PAGE_EXECUTE_READWRITE, &d1); CopyBuffer(p1, p2); VirtualProtect(p1, SZ_HOOK, d1, &d2)
//static initializer list.
DWORD FilthyHooker::ref = 0;
HOOK_INFO FilthyHooker::hooks[N_HOOKS];
FilthyHooker::FilthyHooker(PBYTE pFunction, PBYTE pDetour)
{
this->index = FilthyHooker::ref++;
//check if the max number of hooks has been overrun. Basically this isn't my fault if it does happen
//so fuck you; I'll half ass my error checking. Basically just piss around and do nothing if there's too many hooks.
if (this->index < N_HOOKS)
{
//create the assembler stub for the hook. Cbf using my HOOK_BUFFER struct, too much dereferencing hurts my head.
BYTE bStub[SZ_HOOK] = { 0x68, 0xC3, 0xE1, 0xCC, 0xCC, 0xE9, 0x90, 0x32, 0xFF, 0xE9 };
//start building the hook info struct.
HOOK_INFO *pHook = &FilthyHooker::hooks[this->index];
pHook->detour = pDetour;
pHook->function = pFunction;
//patching
*(DWORD*)(&bStub[1]) = this->index;
*(DWORD*)(&bStub[6]) = SubPtr(DWORD, &Proxy, AddPtr(DWORD, pHook->function, SZ_HOOK));
CopyBuffer(&this->stub, bStub); //create our internal copy of the assembler stub.
CopyBuffer(pHook, pHook->function); //backup the functions prologue code.
//set the hook.
this->GiveHerpes();
}
}
//destructor? pfft, half this class is static anyway. Just unhook and that's about that.
FilthyHooker::~FilthyHooker(void)
{
this->SeeDoctor();
}
inline
BOOL FilthyHooker::HasAids(void)
{
//very straightforward, test to see if the hook is set by comparing bytes.
BOOL same = TRUE;
HOOK_INFO pHook = FilthyHooker::hooks[this->index];
for(DWORD i = 0; i < SZ_HOOK && same; i++)
same = (pHook.function[i] == this->stub.value[i]);
return same;
}
inline
PBYTE FilthyHooker::Repatch(int id)
{
//restore the original function's prologue code so that it works again.
HOOK_INFO *pHook = &FilthyHooker::hooks[id];
SafeCopyBuffer(pHook->function, pHook);
return pHook->detour;
}
__declspec(naked) void FilthyHooker::Proxy(int id)
{
//I'm lazy so I split 'Repatch' and this function into two seperate functions to avoid actually having
//to think about stack offsets in too much detail. Turns out it was rather handy in that I could just
//write the Unhook as a public wrapper for Repatch. Winner?
__asm
{
push [esp]; //push id back onto the stack.
call Repatch; //call the repatch function.
add esp, 8; //clean
jmp eax; //call the user-defined detour.
}
}
void FilthyHooker::GiveHerpes(void)
{
if (this->index < N_HOOKS && !this->HasAids())
{
HOOK_INFO *pHook = &FilthyHooker::hooks[this->index];
SafeCopyBuffer(pHook->function, &this->stub);
}
}
void FilthyHooker::SeeDoctor(void)
{
//As I mentioned before, by splitting Repatch and Proxy into 2 seperate functions I had to do zero work
//with this function. I call awesome.
if (this->index < N_HOOKS && this->HasAids())
FilthyHooker::Repatch(this->index);
}
pastie: