diff --git a/Extension/CDetour/detourhelpers.h b/Extension/CDetour/detourhelpers.h
new file mode 100644
index 0000000..cff73cc
--- /dev/null
+++ b/Extension/CDetour/detourhelpers.h
@@ -0,0 +1,100 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod
+ * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id: detourhelpers.h 248 2008-08-27 00:56:22Z pred $
+ */
+
+#ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
+#define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
+
+#if defined PLATFORM_POSIX
+#include
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
+#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
+#endif
+
+struct patch_t
+{
+ patch_t()
+ {
+ patch[0] = 0;
+ bytes = 0;
+ }
+ unsigned char patch[20];
+ size_t bytes;
+};
+
+inline void ProtectMemory(void *addr, int length, int prot)
+{
+#if defined PLATFORM_POSIX
+ void *addr2 = (void *)ALIGN(addr);
+ mprotect(addr2, sysconf(_SC_PAGESIZE), prot);
+#elif defined PLATFORM_WINDOWS
+ DWORD old_prot;
+ VirtualProtect(addr, length, prot, &old_prot);
+#endif
+}
+
+inline void SetMemPatchable(void *address, size_t size)
+{
+ ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE);
+}
+
+inline void DoGatePatch(unsigned char *target, void *callback)
+{
+ SetMemPatchable(target, 20);
+
+ target[0] = 0xFF; /* JMP */
+ target[1] = 0x25; /* MEM32 */
+ *(void **)(&target[2]) = callback;
+}
+
+inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore)
+{
+ ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE);
+
+ unsigned char *addr = (unsigned char *)address + offset;
+ if (restore)
+ {
+ for (size_t i=0; ibytes; i++)
+ {
+ restore->patch[i] = addr[i];
+ }
+ restore->bytes = patch->bytes;
+ }
+
+ for (size_t i=0; ibytes; i++)
+ {
+ addr[i] = patch->patch[i];
+ }
+}
+
+#endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_
diff --git a/Extension/CDetour/detours.cpp b/Extension/CDetour/detours.cpp
new file mode 100644
index 0000000..b4f6cc6
--- /dev/null
+++ b/Extension/CDetour/detours.cpp
@@ -0,0 +1,192 @@
+/**
+* vim: set ts=4 :
+* =============================================================================
+* SourceMod
+* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
+* =============================================================================
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License, version 3.0, as published by the
+* Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+* details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program. If not, see .
+*
+* As a special exception, AlliedModders LLC gives you permission to link the
+* code of this program (as well as its derivative works) to "Half-Life 2," the
+* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+* by the Valve Corporation. You must obey the GNU General Public License in
+* all respects for all other code used. Additionally, AlliedModders LLC grants
+* this exception to all derivative works. AlliedModders LLC defines further
+* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+* or .
+*
+* Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $
+*/
+
+#include "detours.h"
+#include
+
+ISourcePawnEngine *CDetourManager::spengine = NULL;
+IGameConfig *CDetourManager::gameconf = NULL;
+
+void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
+{
+ CDetourManager::spengine = spengine;
+ CDetourManager::gameconf = gameconf;
+}
+
+CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
+{
+ CDetour *detour = new CDetour(callbackfunction, trampoline, signame);
+ if (detour)
+ {
+ if (!detour->Init(spengine, gameconf))
+ {
+ delete detour;
+ return NULL;
+ }
+
+ return detour;
+ }
+
+ return NULL;
+}
+
+CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame)
+{
+ enabled = false;
+ detoured = false;
+ detour_address = NULL;
+ detour_trampoline = NULL;
+ this->signame = signame;
+ this->detour_callback = callbackfunction;
+ spengine = NULL;
+ gameconf = NULL;
+ this->trampoline = trampoline;
+}
+
+bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
+{
+ this->spengine = spengine;
+ this->gameconf = gameconf;
+
+ if (!CreateDetour())
+ {
+ enabled = false;
+ return enabled;
+ }
+
+ enabled = true;
+
+ return enabled;
+}
+
+void CDetour::Destroy()
+{
+ DeleteDetour();
+ delete this;
+}
+
+bool CDetour::IsEnabled()
+{
+ return enabled;
+}
+
+bool CDetour::CreateDetour()
+{
+ if (!gameconf->GetMemSig(signame, &detour_address))
+ {
+ g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
+ return false;
+ }
+
+ if (!detour_address)
+ {
+ g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour to prevent crashes", signame);
+ return false;
+ }
+
+ detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1);
+
+ /* First, save restore bits */
+ for (size_t i=0; iAllocatePageMemory(CodeSize);
+ spengine->SetReadWrite(wr.outbase);
+ wr.outptr = wr.outbase;
+ detour_trampoline = wr.outbase;
+ goto jit_rewind;
+ }
+
+ spengine->SetReadExecute(wr.outbase);
+
+ *trampoline = detour_trampoline;
+
+ return true;
+}
+
+void CDetour::DeleteDetour()
+{
+ if (detoured)
+ {
+ DisableDetour();
+ }
+
+ if (detour_trampoline)
+ {
+ /* Free the allocated trampoline memory */
+ spengine->FreePageMemory(detour_trampoline);
+ detour_trampoline = NULL;
+ }
+}
+
+void CDetour::EnableDetour()
+{
+ if (!detoured)
+ {
+ DoGatePatch((unsigned char *)detour_address, &detour_callback);
+ detoured = true;
+ }
+}
+
+void CDetour::DisableDetour()
+{
+ if (detoured)
+ {
+ /* Remove the patch */
+ ApplyPatch(detour_address, 0, &detour_restore, NULL);
+ detoured = false;
+ }
+}
diff --git a/Extension/CDetour/detours.h b/Extension/CDetour/detours.h
new file mode 100644
index 0000000..cc0d8f9
--- /dev/null
+++ b/Extension/CDetour/detours.h
@@ -0,0 +1,241 @@
+/**
+* vim: set ts=4 :
+* =============================================================================
+* SourceMod
+* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
+* =============================================================================
+*
+* This program is free software; you can redistribute it and/or modify it under
+* the terms of the GNU General Public License, version 3.0, as published by the
+* Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+* details.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program. If not, see .
+*
+* As a special exception, AlliedModders LLC gives you permission to link the
+* code of this program (as well as its derivative works) to "Half-Life 2," the
+* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+* by the Valve Corporation. You must obey the GNU General Public License in
+* all respects for all other code used. Additionally, AlliedModders LLC grants
+* this exception to all derivative works. AlliedModders LLC defines further
+* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+* or .
+*
+* Version: $Id: detours.h 257 2008-09-23 03:12:13Z pred $
+*/
+
+#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
+#define _INCLUDE_SOURCEMOD_DETOURS_H_
+
+#include "extension.h"
+#include
+#include
+#include "detourhelpers.h"
+
+/**
+ * CDetours class for SourceMod Extensions by pRED*
+ * detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume).
+ * asm.h/c from devmaster.net (thanks cybermind) edited by pRED* to handle gcc -fPIC thunks correctly
+ * Concept by Nephyrin Zey (http://www.doublezen.net/) and Windows Detour Library (http://research.microsoft.com/sn/detours/)
+ * Member function pointer ideas by Don Clugston (http://www.codeproject.com/cpp/FastDelegate.asp)
+ */
+
+#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
+#define DETOUR_STATIC_CALL(name) (name##_Actual)
+
+#define DETOUR_DECL_STATIC0(name, ret) \
+ret (*name##_Actual)(void) = NULL; \
+ret name(void)
+
+#define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \
+ret (*name##_Actual)(p1type) = NULL; \
+ret name(p1type p1name)
+
+#define DETOUR_DECL_STATIC4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
+ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
+ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
+
+#define DETOUR_DECL_MEMBER0(name, ret) \
+class name##Class \
+{ \
+public: \
+ ret name(); \
+ static ret (name##Class::* name##_Actual)(void); \
+}; \
+ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \
+ret name##Class::name()
+
+#define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \
+class name##Class \
+{ \
+public: \
+ ret name(p1type p1name); \
+ static ret (name##Class::* name##_Actual)(p1type); \
+}; \
+ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \
+ret name##Class::name(p1type p1name)
+
+#define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \
+class name##Class \
+{ \
+public: \
+ ret name(p1type p1name, p2type p2name); \
+ static ret (name##Class::* name##_Actual)(p1type, p2type); \
+}; \
+ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \
+ret name##Class::name(p1type p1name, p2type p2name)
+
+#define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
+class name##Class \
+{ \
+public: \
+ ret name(p1type p1name, p2type p2name, p3type p3name); \
+ static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \
+}; \
+ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \
+ret name##Class::name(p1type p1name, p2type p2name, p3type p3name)
+
+#define DETOUR_DECL_MEMBER4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
+class name##Class \
+{ \
+public: \
+ ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \
+ static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \
+}; \
+ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
+ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
+
+
+#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
+#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
+
+#define GET_STATIC_CALLBACK(name) (void *)&name
+#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
+
+#define DETOUR_CREATE_MEMBER(name, gamedata) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata);
+#define DETOUR_CREATE_STATIC(name, gamedata) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata);
+
+
+class GenericClass {};
+typedef void (GenericClass::*VoidFunc)();
+
+inline void *GetCodeAddr(VoidFunc mfp)
+{
+ return *(void **)&mfp;
+}
+
+/**
+ * Converts a member function pointer to a void pointer.
+ * This relies on the assumption that the code address lies at mfp+0
+ * This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers
+ * Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp
+ */
+#define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast(mfp))
+
+class CDetourManager;
+
+class CDetour
+{
+public:
+
+ bool IsEnabled();
+
+ /**
+ * These would be somewhat self-explanatory I hope
+ */
+ void EnableDetour();
+ void DisableDetour();
+
+ void Destroy();
+
+ friend class CDetourManager;
+
+protected:
+ CDetour(void *callbackfunction, void **trampoline, const char *signame);
+
+ bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
+private:
+
+ /* These create/delete the allocated memory */
+ bool CreateDetour();
+ void DeleteDetour();
+
+ bool enabled;
+ bool detoured;
+
+ patch_t detour_restore;
+ /* Address of the detoured function */
+ void *detour_address;
+ /* Address of the allocated trampoline function */
+ void *detour_trampoline;
+ /* Address of the callback handler */
+ void *detour_callback;
+ /* The function pointer used to call our trampoline */
+ void **trampoline;
+
+ const char *signame;
+ ISourcePawnEngine *spengine;
+ IGameConfig *gameconf;
+};
+
+class CDetourManager
+{
+public:
+
+ static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
+
+ /**
+ * Creates a new detour
+ *
+ * @param callbackfunction Void pointer to your detour callback function.
+ * @param trampoline Address of the trampoline pointer
+ * @param signame Section name containing a signature to fetch from the gamedata file.
+ * @return A new CDetour pointer to control your detour.
+ *
+ * Example:
+ *
+ * CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
+ *
+ * Define a new class with the required function and a member function pointer to the same type:
+ *
+ * class CBaseServerDetour
+ * {
+ * public:
+ * bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
+ * static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
+ * }
+ *
+ * void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient);
+ * void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual);
+ *
+ * Creation:
+ * CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient");
+ *
+ * Usage:
+ *
+ * CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int)
+ * {
+ * //pre hook code
+ * bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params);
+ * //post hook code
+ * return result;
+ * }
+ *
+ * Note we changed the netadr_s reference into a void* to avoid needing to define the type
+ */
+ static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame);
+
+ friend class CBlocker;
+ friend class CDetour;
+
+private:
+ static ISourcePawnEngine *spengine;
+ static IGameConfig *gameconf;
+};
+
+#endif // _INCLUDE_SOURCEMOD_DETOURS_H_
diff --git a/Extension/asm/asm.c b/Extension/asm/asm.c
new file mode 100644
index 0000000..fd7a540
--- /dev/null
+++ b/Extension/asm/asm.c
@@ -0,0 +1,421 @@
+#include "asm.h"
+
+#ifndef WIN32
+#define _GNU_SOURCE
+#include
+#include
+
+#define REG_EAX 0
+#define REG_ECX 1
+#define REG_EDX 2
+#define REG_EBX 3
+
+#define IA32_MOV_REG_IMM 0xB8 // encoding is +r
+#endif
+
+extern void Msg( const char *, ... );
+
+/**
+* Checks if a call to a fpic thunk has just been written into dest.
+* If found replaces it with a direct mov that sets the required register to the value of pc.
+*
+* @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written.
+* @param pc The program counter value that needs to be set (usually the next address from the source).
+* @noreturn
+*/
+void check_thunks(unsigned char *dest, unsigned char *pc)
+{
+#if defined WIN32
+ return;
+#else
+ /* Step write address back 4 to the start of the function address */
+ unsigned char *writeaddr = dest - 4;
+ unsigned char *calloffset = *(unsigned char **)writeaddr;
+ unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
+
+ /* Lookup name of function being called */
+ if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
+ {
+ //a thunk maybe?
+ char movByte = IA32_MOV_REG_IMM;
+
+ /* Calculate the correct mov opcode */
+ switch (*(calladdr+1))
+ {
+ case 0x04:
+ {
+ movByte += REG_EAX;
+ break;
+ }
+ case 0x1C:
+ {
+ movByte += REG_EBX;
+ break;
+ }
+ case 0x0C:
+ {
+ movByte += REG_ECX;
+ break;
+ }
+ case 0x14:
+ {
+ movByte += REG_EDX;
+ break;
+ }
+ default:
+ {
+ Msg("Unknown thunk: %c\n", *(calladdr+1));
+ break;
+ }
+ }
+
+ /* Move our write address back one to where the call opcode was */
+ writeaddr--;
+
+
+ /* Write our mov */
+ *writeaddr = movByte;
+ writeaddr++;
+
+ /* Write the value - The provided program counter value */
+ *(void **)writeaddr = (void *)pc;
+ writeaddr += 4;
+ }
+
+ return;
+#endif
+}
+
+//if dest is NULL, returns minimum number of bytes needed to be copied
+//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
+//http://www.devmaster.net/forums/showthread.php?t=2311
+int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
+ int bytecount = 0;
+
+ while(bytecount < required_len && *func != 0xCC)
+ {
+ // prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
+ int operandSize = 4;
+ int FPU = 0;
+ int twoByte = 0;
+ unsigned char opcode = 0x90;
+ unsigned char modRM = 0xFF;
+ while(*func == 0xF0 ||
+ *func == 0xF2 ||
+ *func == 0xF3 ||
+ (*func & 0xFC) == 0x64 ||
+ (*func & 0xF8) == 0xD8 ||
+ (*func & 0x7E) == 0x62)
+ {
+ if(*func == 0x66)
+ {
+ operandSize = 2;
+ }
+ else if((*func & 0xF8) == 0xD8)
+ {
+ FPU = *func;
+ if (dest)
+ *dest++ = *func++;
+ else
+ func++;
+ bytecount++;
+ break;
+ }
+
+ if (dest)
+ *dest++ = *func++;
+ else
+ func++;
+ bytecount++;
+ }
+
+ // two-byte opcode byte
+ if(*func == 0x0F)
+ {
+ twoByte = 1;
+ if (dest)
+ *dest++ = *func++;
+ else
+ func++;
+ bytecount++;
+ }
+
+ // opcode byte
+ opcode = *func++;
+ if (dest) *dest++ = opcode;
+ bytecount++;
+
+ // mod R/M byte
+ modRM = 0xFF;
+ if(FPU)
+ {
+ if((opcode & 0xC0) != 0xC0)
+ {
+ modRM = opcode;
+ }
+ }
+ else if(!twoByte)
+ {
+ if((opcode & 0xC4) == 0x00 ||
+ ((opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09)) ||
+ (opcode & 0xF0) == 0x80 ||
+ ((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02) ||
+ (opcode & 0xFC) == 0xD0 ||
+ (opcode & 0xF6) == 0xF6)
+ {
+ modRM = *func++;
+ if (dest) *dest++ = modRM;
+ bytecount++;
+ }
+ }
+ else
+ {
+ if(((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) ||
+ (opcode & 0xF0) == 0x30 ||
+ opcode == 0x77 ||
+ (opcode & 0xF0) == 0x80 ||
+ ((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) ||
+ (opcode & 0xF8) == 0xC8)
+ {
+ // No mod R/M byte
+ }
+ else
+ {
+ modRM = *func++;
+ if (dest) *dest++ = modRM;
+ bytecount++;
+ }
+ }
+
+ // SIB
+ if((modRM & 0x07) == 0x04 &&
+ (modRM & 0xC0) != 0xC0)
+ {
+ if (dest)
+ *dest++ = *func++; //SIB
+ else
+ func++;
+ bytecount++;
+ }
+
+ // mod R/M displacement
+
+ // Dword displacement, no base
+ if((modRM & 0xC5) == 0x05) {
+ if (dest) {
+ *(unsigned int*)dest = *(unsigned int*)func;
+ dest += 4;
+ }
+ func += 4;
+ bytecount += 4;
+ }
+
+ // Byte displacement
+ if((modRM & 0xC0) == 0x40) {
+ if (dest)
+ *dest++ = *func++;
+ else
+ func++;
+ bytecount++;
+ }
+
+ // Dword displacement
+ if((modRM & 0xC0) == 0x80) {
+ if (dest) {
+ *(unsigned int*)dest = *(unsigned int*)func;
+ dest += 4;
+ }
+ func += 4;
+ bytecount += 4;
+ }
+
+ // immediate
+ if(FPU)
+ {
+ // Can't have immediate operand
+ }
+ else if(!twoByte)
+ {
+ if((opcode & 0xC7) == 0x04 ||
+ (opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL
+ (opcode & 0xF0) == 0x70 || // Jcc
+ opcode == 0x80 ||
+ opcode == 0x83 ||
+ (opcode & 0xFD) == 0xA0 || // MOV
+ opcode == 0xA8 || // TEST
+ (opcode & 0xF8) == 0xB0 || // MOV
+ (opcode & 0xFE) == 0xC0 || // RCL
+ opcode == 0xC6 || // MOV
+ opcode == 0xCD || // INT
+ (opcode & 0xFE) == 0xD4 || // AAD/AAM
+ (opcode & 0xF8) == 0xE0 || // LOOP/JCXZ
+ opcode == 0xEB ||
+ (opcode == 0xF6 && (modRM & 0x30) == 0x00)) // TEST
+ {
+ if (dest)
+ *dest++ = *func++;
+ else
+ func++;
+ bytecount++;
+ }
+ else if((opcode & 0xF7) == 0xC2) // RET
+ {
+ if (dest) {
+ *(unsigned short*)dest = *(unsigned short*)func;
+ dest += 2;
+ }
+ func += 2;
+ bytecount += 2;
+ }
+ else if((opcode & 0xFC) == 0x80 ||
+ (opcode & 0xC7) == 0x05 ||
+ (opcode & 0xF8) == 0xB8 ||
+ (opcode & 0xFE) == 0xE8 || // CALL/Jcc
+ (opcode & 0xFE) == 0x68 ||
+ (opcode & 0xFC) == 0xA0 ||
+ (opcode & 0xEE) == 0xA8 ||
+ opcode == 0xC7 ||
+ (opcode == 0xF7 && (modRM & 0x30) == 0x00))
+ {
+ if (dest) {
+ //Fix CALL/JMP offset
+ if ((opcode & 0xFE) == 0xE8) {
+ if (operandSize == 4)
+ {
+ *(long*)dest = ((func + *(long*)func) - dest);
+
+ //pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
+ check_thunks(dest+4, func+4);
+ }
+ else
+ *(short*)dest = ((func + *(short*)func) - dest);
+
+ } else {
+ if (operandSize == 4)
+ *(unsigned long*)dest = *(unsigned long*)func;
+ else
+ *(unsigned short*)dest = *(unsigned short*)func;
+ }
+ dest += operandSize;
+ }
+ func += operandSize;
+ bytecount += operandSize;
+
+ }
+ }
+ else
+ {
+ if(opcode == 0xBA || // BT
+ opcode == 0x0F || // 3DNow!
+ (opcode & 0xFC) == 0x70 || // PSLLW
+ (opcode & 0xF7) == 0xA4 || // SHLD
+ opcode == 0xC2 ||
+ opcode == 0xC4 ||
+ opcode == 0xC5 ||
+ opcode == 0xC6)
+ {
+ if (dest)
+ *dest++ = *func++;
+ else
+ func++;
+ }
+ else if((opcode & 0xF0) == 0x80) // Jcc -i
+ {
+ if (dest) {
+ if (operandSize == 4)
+ *(unsigned long*)dest = *(unsigned long*)func;
+ else
+ *(unsigned short*)dest = *(unsigned short*)func;
+
+ dest += operandSize;
+ }
+ func += operandSize;
+ bytecount += operandSize;
+ }
+ }
+ }
+
+ return bytecount;
+}
+
+//insert a specific JMP instruction at the given location
+void inject_jmp(void* src, void* dest) {
+ *(unsigned char*)src = OP_JMP;
+ *(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
+}
+
+//fill a given block with NOPs
+void fill_nop(void* src, unsigned int len) {
+ unsigned char* src2 = (unsigned char*)src;
+ while (len) {
+ *src2++ = OP_NOP;
+ --len;
+ }
+}
+
+void* eval_jump(void* src) {
+ unsigned char* addr = (unsigned char*)src;
+
+ if (!addr) return 0;
+
+ //import table jump
+ if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
+ addr += 2;
+ addr = *(unsigned char**)addr;
+ //TODO: if addr points into the IAT
+ return *(void**)addr;
+ }
+
+ //8bit offset
+ else if (addr[0] == OP_JMP_BYTE) {
+ addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
+ //mangled 32bit jump?
+ if (addr[0] == OP_JMP) {
+ addr = addr + *(int*)&addr[1];
+ }
+ return addr;
+ }
+ /*
+ //32bit offset
+ else if (addr[0] == OP_JMP) {
+ addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
+ }
+ */
+
+ return addr;
+}
+/*
+from ms detours package
+static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
+{
+ MEMORY_BASIC_INFORMATION mbi;
+ VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
+ __try {
+ PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
+ if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
+ return false;
+ }
+
+ PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
+ pDosHeader->e_lfanew);
+ if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
+ return false;
+ }
+
+ if (pbAddress >= ((PBYTE)pDosHeader +
+ pNtHeader->OptionalHeader
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
+ pbAddress < ((PBYTE)pDosHeader +
+ pNtHeader->OptionalHeader
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
+ pNtHeader->OptionalHeader
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
+ return true;
+ }
+ return false;
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER) {
+ return false;
+ }
+}
+*/
diff --git a/Extension/asm/asm.h b/Extension/asm/asm.h
new file mode 100644
index 0000000..838e691
--- /dev/null
+++ b/Extension/asm/asm.h
@@ -0,0 +1,40 @@
+#ifndef __ASM_H__
+#define __ASM_H__
+
+#define OP_JMP 0xE9
+#define OP_JMP_SIZE 5
+
+#define OP_NOP 0x90
+#define OP_NOP_SIZE 1
+
+#define OP_PREFIX 0xFF
+#define OP_JMP_SEG 0x25
+
+#define OP_JMP_BYTE 0xEB
+#define OP_JMP_BYTE_SIZE 2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void check_thunks(unsigned char *dest, unsigned char *pc);
+
+//if dest is NULL, returns minimum number of bytes needed to be copied
+//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
+//http://www.devmaster.net/forums/showthread.php?t=2311
+int copy_bytes(unsigned char *func, unsigned char* dest, int required_len);
+
+//insert a specific JMP instruction at the given location
+void inject_jmp(void* src, void* dest);
+
+//fill a given block with NOPs
+void fill_nop(void* src, unsigned int len);
+
+//evaluate a JMP at the target
+void* eval_jump(void* src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__ASM_H__