-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use proper length for tostring operator and serialization routines
Fix #237
- Loading branch information
Showing
13 changed files
with
377 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
#pragma once | ||
|
||
#ifdef _M_ARM_ | ||
#error Does't support ARM | ||
#endif | ||
|
||
#define WIN32_LEAN_AND_MEN | ||
#include <Windows.h> | ||
#include <inttypes.h> | ||
#include <intrin.h> | ||
#include <map> | ||
#include <mutex> | ||
|
||
#include "detours.h" | ||
#include "x86Decoder.h" | ||
|
||
namespace easydetour_internals { class __easy_detour_Iternal_class; } | ||
|
||
|
||
namespace EasyDetour | ||
{ | ||
|
||
template<typename T, typename R, typename ... Types> | ||
class EasyDetour | ||
{ | ||
public: | ||
typedef R(*TARGET_FUNCTION)(Types...); | ||
typedef R(T::*DETOUR_CLASS_FUNCTION)(TARGET_FUNCTION, Types ...); | ||
typedef R(*DETOUR_FUNCTION)(T*, TARGET_FUNCTION, Types ...); | ||
|
||
EasyDetour(T* pClassIntance, TARGET_FUNCTION lpTargetFunction) | ||
: pInstance(pClassIntance), lpTargetFunction(lpTargetFunction), bitFlag(0) | ||
{ | ||
this->lpTrampolineFunction = lpTargetFunction; | ||
lpDetourFunction.lpClassFunction = nullptr; | ||
} | ||
~EasyDetour() | ||
{ | ||
if (isFunHooked()) | ||
{ | ||
easydetour_internals::__easy_detour_Iternal_class::_removeDetourInstance(lpTargetFunction); | ||
UnHookFunction(); | ||
} | ||
} | ||
|
||
bool HookFunction(DETOUR_CLASS_FUNCTION lpClassFunction) | ||
{ | ||
if (isFunHooked()) | ||
return false; | ||
if (DetourTransactionBegin() == NO_ERROR) | ||
{ | ||
DetourUpdateThread(GetCurrentThread()); | ||
DetourAttach((LPVOID*)&this->lpTrampolineFunction, (LPVOID)&GenericDetour); | ||
if (DetourTransactionCommit() == NO_ERROR) | ||
{ | ||
lpDetourFunction.lpClassFunction = lpClassFunction; | ||
easydetour_internals::__easy_detour_Iternal_class::_addEasyDetourInstance(this, (LPVOID)this->lpTargetFunction); | ||
isClassFunction(true); | ||
isFunHooked(true); | ||
return true; | ||
} | ||
else | ||
DetourTransactionAbort(); | ||
} | ||
return false; | ||
} | ||
bool HookFunction(DETOUR_FUNCTION lpDetourFunction) | ||
{ | ||
if (isFunHooked()) | ||
return false; | ||
|
||
if (DetourTransactionBegin() == NO_ERROR) | ||
{ | ||
DetourUpdateThread(GetCurrentThread()); | ||
DetourAttach((LPVOID*)&this->lpTrampolineFunction, (LPVOID)&GenericDetour); | ||
if (DetourTransactionCommit() == NO_ERROR) | ||
{ | ||
this->lpDetourFunction.lpDetourFunction = lpDetourFunction; | ||
easydetour_internals::__easy_detour_Iternal_class::_addEasyDetourInstance(this, (LPVOID)this->lpTargetFunction); | ||
isClassFunction(false); | ||
isFunHooked(true); | ||
return true; | ||
} | ||
else | ||
DetourTransactionAbort(); | ||
} | ||
return false; | ||
} | ||
bool UnHookFunction() | ||
{ | ||
if (!isFunHooked()) | ||
return false; | ||
|
||
if (DetourTransactionBegin() == NO_ERROR) | ||
{ | ||
DetourUpdateThread(GetCurrentThread()); | ||
DetourDetach((LPVOID*)&this->lpTrampolineFunction, (PVOID)&GenericDetour); | ||
if (DetourTransactionCommit() == NO_ERROR) | ||
{ | ||
easydetour_internals::__easy_detour_Iternal_class::_removeDetourInstance(lpTargetFunction); | ||
isFunHooked(false); | ||
return true; | ||
} | ||
else | ||
DetourTransactionAbort(); | ||
} | ||
return false; | ||
} | ||
|
||
|
||
private: | ||
T* const pInstance; | ||
uint8_t bitFlag; | ||
const TARGET_FUNCTION lpTargetFunction; | ||
TARGET_FUNCTION lpTrampolineFunction; | ||
|
||
union | ||
{ | ||
DETOUR_CLASS_FUNCTION lpClassFunction; | ||
DETOUR_FUNCTION lpDetourFunction; | ||
}lpDetourFunction; | ||
|
||
constexpr bool isFunHooked() { return (bool)((bitFlag & 0xF0) > 0x7); } | ||
constexpr void isFunHooked(bool value) | ||
{ | ||
if (value) | ||
bitFlag |= 0xF0; | ||
else | ||
bitFlag -= bitFlag & 0xF0; | ||
} | ||
constexpr bool isClassFunction() { return (bool)((bitFlag & 0xF) > 0x3); } | ||
constexpr void isClassFunction(bool value) | ||
{ | ||
if (value) | ||
bitFlag |= 0xF; | ||
else | ||
bitFlag -= bitFlag & 0xF; | ||
} | ||
|
||
static R __cdecl GenericDetour(Types ...args) | ||
{ | ||
const void* stackR = _AddressOfReturnAddress(); | ||
|
||
const uintptr_t retAddrs = *(uintptr_t*)stackR; | ||
|
||
void* lpHookFunction; | ||
EasyDetour<T, R, Types...>* pInstance; | ||
|
||
CallCommand pCallCmd; | ||
if (decodeCall((void*)retAddrs, &pCallCmd)) | ||
{ | ||
if (pCallCmd.type == NEAR_ABSOLUTE_CALL) | ||
{ | ||
/* | ||
============================ ISSUE #1 ============================ | ||
We cant get the function pointer if is store in another register than EBP | ||
because EBP is saved in every function call. | ||
To solve this issue we need to create a custom prolog and epilog of this function | ||
and save the registers in the process. | ||
EBP is the most likely to be the register used because locals use EBP | ||
with some offset to be accessed | ||
================================================================== | ||
*/ | ||
if (pCallCmd.types.callMPTR.reg == REG_EBP) | ||
{ | ||
const void* basePointer = (void*)((char*)stackR - sizeof(void*)); | ||
lpHookFunction = (void*)(*(intptr_t*)(*((intptr_t*)basePointer) + pCallCmd.types.callMPTR.offset)); | ||
} | ||
else | ||
lpHookFunction = nullptr; | ||
} | ||
else | ||
{ | ||
#ifdef _M_AMD64 | ||
const uintptr_t relativePtr = *((uint32_t*)(retAddrs - 0x4)) | 0xffffffff00000000; | ||
#else | ||
//const uintptr_t relativePtr = *((uintptr_t*)(retAddrs - 0x4)); | ||
const uintptr_t relativePtr = *((uint32_t*)(retAddrs - 0x4)); | ||
#endif | ||
lpHookFunction = (void*)(relativePtr + retAddrs); | ||
} | ||
} | ||
else | ||
lpHookFunction = nullptr; | ||
|
||
pInstance = reinterpret_cast<EasyDetour<T, R, Types...>*>(easydetour_internals::__easy_detour_Iternal_class::_getDetourInstance(lpHookFunction)); | ||
|
||
if (!pInstance) | ||
{ | ||
// if We reach here, we got a big problem. But we can't call a null pointer, so is nothing left to do... | ||
return (R)0; | ||
} | ||
if (pInstance->isClassFunction()) | ||
{ | ||
T* const klass = pInstance->pInstance; | ||
return (*klass.*pInstance->lpDetourFunction.lpClassFunction)(pInstance->lpTrampolineFunction, args...); | ||
} | ||
return pInstance->lpDetourFunction.lpDetourFunction(pInstance->pInstance, pInstance->lpTrampolineFunction, args...); | ||
} | ||
}; | ||
|
||
template<typename T, typename R, typename ...Types> | ||
EasyDetour<T, R, Types...> make_detour(T* klass, R(*pTargetFunction)(Types...)) | ||
{ | ||
return EasyDetour<T, R, Types...>(klass, pTargetFunction); | ||
} | ||
|
||
} | ||
|
||
|
||
namespace easydetour_internals { | ||
|
||
class __easy_detour_Iternal_class | ||
{ | ||
public: | ||
template<typename T, typename R, typename ...Types> | ||
friend class EasyDetour; | ||
|
||
static void _addEasyDetourInstance(void* pInstance, void* pDetourTargetFunction); | ||
static void _removeDetourInstance(void* pDetourTargetFunction); | ||
static void* _getDetourInstance(void* pDetourTargetFunction); | ||
|
||
private: | ||
/// <summary> | ||
/// key-> TargetFunction | value -> easyDetour instance | ||
/// </summary> | ||
static std::map<void*, void*> easydetourMap; | ||
static std::mutex mtx; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#pragma once | ||
#include <inttypes.h> | ||
|
||
#define NONE 0xFFFFFFFF | ||
|
||
#define REG_EAX 0 | ||
#define REG_ECX 1 | ||
#define REG_EDX 2 | ||
#define REG_EBX 3 | ||
#define REG_ESP 4 | ||
#define REG_EBP 5 | ||
#define REG_ESI 6 | ||
#define REG_EDI 7 | ||
#define REG_EPI 8 | ||
#ifdef REG_NONE | ||
#undef REG_NONE | ||
#endif | ||
#define REG_NONE NONE | ||
|
||
#define CMD_NOP 1 | ||
#define CMD_PUSH 2 | ||
#define CMD_CALL 3 | ||
#define CMD_XCHG 4 | ||
|
||
#define NEAR_REALTIVE_CALL 0 | ||
#define NEAR_ABSOLUTE_CALL 1 | ||
|
||
#define TYPE_REG8 1 | ||
#define TYPE_REG32 2 | ||
#define TYPE_REG64 3 | ||
#define TYPE_NONE NONE | ||
|
||
#define COMMAND 0 | ||
#define OPCODE 1 | ||
#define OPERAND0_TYPE 2 | ||
#define OPERAND0 3 | ||
#define OPERAND1_TYPE 4 | ||
#define OPERAND1 5 | ||
|
||
// Command opcode type dest type source | ||
static const unsigned int single_opcode_map[][6] = | ||
{ | ||
{NONE, NONE, TYPE_NONE, REG_NONE, TYPE_NONE, REG_NONE}, | ||
|
||
{CMD_NOP, 0x90, TYPE_NONE, REG_NONE, TYPE_NONE, REG_NONE}, | ||
|
||
{CMD_PUSH, 0x50, TYPE_REG32, REG_EAX, TYPE_NONE, REG_NONE}, | ||
{CMD_PUSH, 0x51, TYPE_REG32, REG_ECX, TYPE_NONE, REG_NONE}, | ||
{CMD_PUSH, 0x52, TYPE_REG32, REG_EDX, TYPE_NONE, REG_NONE}, | ||
{CMD_PUSH, 0x53, TYPE_REG32, REG_EBX, TYPE_NONE, REG_NONE}, | ||
{CMD_PUSH, 0x54, TYPE_REG32, REG_ESP, TYPE_NONE, REG_NONE}, | ||
{CMD_PUSH, 0x55, TYPE_REG32, REG_EBP, TYPE_NONE, REG_NONE}, | ||
{CMD_PUSH, 0x56, TYPE_REG32, REG_ESI, TYPE_NONE, REG_NONE}, | ||
{CMD_PUSH, 0x57, TYPE_REG32, REG_EDI, TYPE_NONE, REG_NONE}, | ||
|
||
{CMD_XCHG, 0x91, TYPE_REG32, REG_ECX, TYPE_REG32, REG_EAX}, | ||
{CMD_XCHG, 0x92, TYPE_REG32, REG_EDX, TYPE_REG32, REG_EAX}, | ||
{CMD_XCHG, 0x93, TYPE_REG32, REG_EBX, TYPE_REG32, REG_EAX}, | ||
{CMD_XCHG, 0x94, TYPE_REG32, REG_ESP, TYPE_REG32, REG_EAX}, | ||
{CMD_XCHG, 0x95, TYPE_REG32, REG_EBP, TYPE_REG32, REG_EAX}, | ||
{CMD_XCHG, 0x96, TYPE_REG32, REG_ESI, TYPE_REG32, REG_EAX}, | ||
{CMD_XCHG, 0x97, TYPE_REG32, REG_EDI, TYPE_REG32, REG_EAX} | ||
}; | ||
|
||
typedef const unsigned int* singleOpcodeMap; | ||
|
||
typedef struct sCallCmd | ||
{ | ||
unsigned int type; | ||
union | ||
{ | ||
unsigned int call_r; | ||
struct | ||
{ | ||
unsigned int reg; | ||
signed int offset; | ||
} callMPTR; | ||
} types; | ||
} CallCommand, *PCallCommand; | ||
|
||
/// <summary> | ||
/// WARNING! This is not a complete decoder! It can fail in some cases | ||
/// </summary> | ||
/// <param name="retAddrs">The address of the next instruction relative to call</param> | ||
/// <param name="pCallCmd">A pointer to CallCommand struct</param> | ||
/// <returns>On success, it returns true</returns> | ||
bool decodeCall(const void* const retAddrs, PCallCommand pCallCmd); | ||
const singleOpcodeMap getSingleOpcodeMap(const unsigned char opcode); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.