diff --git a/DynamicHooks/convention.h b/DynamicHooks/convention.h index 16adcc7..94c9b63 100644 --- a/DynamicHooks/convention.h +++ b/DynamicHooks/convention.h @@ -67,9 +67,11 @@ typedef struct DataTypeSized_s { { type = DATA_TYPE_POINTER; size = 0; + custom_register = None; } DataType_t type; size_t size; + Register_t custom_register; } DataTypeSized_t; @@ -184,6 +186,11 @@ public: virtual int GetArgStackSize() = 0; virtual void** GetStackArgumentPtr(CRegisters* pRegisters) = 0; + /* + Returns the number of bytes that the buffer to store all the arguments in that are passed in a register. + */ + virtual int GetArgRegisterSize() = 0; + /* Returns a pointer to the argument at the given index. diff --git a/DynamicHooks/conventions/x86MsCdecl.cpp b/DynamicHooks/conventions/x86MsCdecl.cpp index 637f8bf..bf8c834 100644 --- a/DynamicHooks/conventions/x86MsCdecl.cpp +++ b/DynamicHooks/conventions/x86MsCdecl.cpp @@ -78,6 +78,16 @@ ke::Vector x86MsCdecl::GetRegisters() } } + // Save all the custom calling convention registers as well. + for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) + { + if (m_vecArgTypes[i].custom_register == None) + continue; + + // TODO: Make sure the list is unique? Set? + registers.append(m_vecArgTypes[i].custom_register); + } + return registers; } @@ -92,7 +102,8 @@ int x86MsCdecl::GetArgStackSize() for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) { - iArgStackSize += m_vecArgTypes[i].size; + if (m_vecArgTypes[i].custom_register == None) + iArgStackSize += m_vecArgTypes[i].size; } return iArgStackSize; @@ -103,12 +114,36 @@ void** x86MsCdecl::GetStackArgumentPtr(CRegisters* pRegisters) return (void **)(pRegisters->m_esp->GetValue() + 4); } +int x86MsCdecl::GetArgRegisterSize() +{ + int iArgRegisterSize = 0; + + for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) + { + if (m_vecArgTypes[i].custom_register != None) + iArgRegisterSize += m_vecArgTypes[i].size; + } + + return iArgRegisterSize; +} + void* x86MsCdecl::GetArgumentPtr(int iIndex, CRegisters* pRegisters) { + // Check if this argument was passed in a register. + if (m_vecArgTypes[iIndex].custom_register != None) + { + CRegister *pRegister = pRegisters->GetRegister(m_vecArgTypes[iIndex].custom_register); + if (!pRegister) + return NULL; + + return pRegister->m_pAddress; + } + int iOffset = 4; for(int i=0; i < iIndex; i++) { - iOffset += m_vecArgTypes[i].size; + if (m_vecArgTypes[i].custom_register == None) + iOffset += m_vecArgTypes[i].size; } return (void *) (pRegisters->m_esp->GetValue() + iOffset); diff --git a/DynamicHooks/conventions/x86MsCdecl.h b/DynamicHooks/conventions/x86MsCdecl.h index e965468..d07404a 100644 --- a/DynamicHooks/conventions/x86MsCdecl.h +++ b/DynamicHooks/conventions/x86MsCdecl.h @@ -70,6 +70,7 @@ public: virtual int GetPopSize(); virtual int GetArgStackSize(); virtual void** GetStackArgumentPtr(CRegisters* pRegisters); + virtual int GetArgRegisterSize(); virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); diff --git a/DynamicHooks/conventions/x86MsStdcall.cpp b/DynamicHooks/conventions/x86MsStdcall.cpp index c2e284a..d0d9777 100644 --- a/DynamicHooks/conventions/x86MsStdcall.cpp +++ b/DynamicHooks/conventions/x86MsStdcall.cpp @@ -78,6 +78,16 @@ ke::Vector x86MsStdcall::GetRegisters() } } + // Save all the custom calling convention registers as well. + for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) + { + if (m_vecArgTypes[i].custom_register == None) + continue; + + // TODO: Make sure the list is unique? Set? + registers.append(m_vecArgTypes[i].custom_register); + } + return registers; } @@ -87,7 +97,8 @@ int x86MsStdcall::GetPopSize() for(unsigned int i=0; i < m_vecArgTypes.length(); i++) { - iPopSize += m_vecArgTypes[i].size; + if (m_vecArgTypes[i].custom_register == None) + iPopSize += m_vecArgTypes[i].size; } return iPopSize; @@ -99,7 +110,8 @@ int x86MsStdcall::GetArgStackSize() for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) { - iArgStackSize += m_vecArgTypes[i].size; + if (m_vecArgTypes[i].custom_register == None) + iArgStackSize += m_vecArgTypes[i].size; } return iArgStackSize; @@ -110,15 +122,39 @@ void** x86MsStdcall::GetStackArgumentPtr(CRegisters* pRegisters) return (void **)(pRegisters->m_esp->GetValue() + 4); } -void* x86MsStdcall::GetArgumentPtr(int iIndex, CRegisters* pRegisters) +int x86MsStdcall::GetArgRegisterSize() { - int iOffset = 4; - for(int i=0; i < iIndex; i++) + int iArgRegisterSize = 0; + + for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) { - iOffset += m_vecArgTypes[i].size; + if (m_vecArgTypes[i].custom_register != None) + iArgRegisterSize += m_vecArgTypes[i].size; } - return (void *) (pRegisters->m_esp->GetValue() + iOffset); + return iArgRegisterSize; +} + +void* x86MsStdcall::GetArgumentPtr(int iIndex, CRegisters* pRegisters) +{ + // Check if this argument was passed in a register. + if (m_vecArgTypes[iIndex].custom_register != None) + { + CRegister *pRegister = pRegisters->GetRegister(m_vecArgTypes[iIndex].custom_register); + if (!pRegister) + return NULL; + + return pRegister->m_pAddress; + } + + int iOffset = 4; + for (int i = 0; i < iIndex; i++) + { + if (m_vecArgTypes[i].custom_register == None) + iOffset += m_vecArgTypes[i].size; + } + + return (void *)(pRegisters->m_esp->GetValue() + iOffset); } void x86MsStdcall::ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr) diff --git a/DynamicHooks/conventions/x86MsStdcall.h b/DynamicHooks/conventions/x86MsStdcall.h index a1c5ad0..ab21735 100644 --- a/DynamicHooks/conventions/x86MsStdcall.h +++ b/DynamicHooks/conventions/x86MsStdcall.h @@ -70,6 +70,7 @@ public: virtual int GetPopSize(); virtual int GetArgStackSize(); virtual void** GetStackArgumentPtr(CRegisters* pRegisters); + virtual int GetArgRegisterSize(); virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); diff --git a/DynamicHooks/conventions/x86MsThiscall.cpp b/DynamicHooks/conventions/x86MsThiscall.cpp index 56aced7..275715a 100644 --- a/DynamicHooks/conventions/x86MsThiscall.cpp +++ b/DynamicHooks/conventions/x86MsThiscall.cpp @@ -66,6 +66,7 @@ ke::Vector x86MsThiscall::GetRegisters() ke::Vector registers; registers.append(ESP); + // TODO: Allow custom this register. registers.append(ECX); if (m_returnType.type == DATA_TYPE_FLOAT || m_returnType.type == DATA_TYPE_DOUBLE) @@ -81,6 +82,16 @@ ke::Vector x86MsThiscall::GetRegisters() } } + // Save all the custom calling convention registers as well. + for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) + { + if (m_vecArgTypes[i].custom_register == None) + continue; + + // TODO: Make sure the list is unique? Set? + registers.append(m_vecArgTypes[i].custom_register); + } + return registers; } @@ -93,7 +104,9 @@ int x86MsThiscall::GetPopSize() for(unsigned int i=0; i < m_vecArgTypes.length(); i++) { - iPopSize += m_vecArgTypes[i].size; + // Only pop arguments that are actually on the stack. + if (m_vecArgTypes[i].custom_register == None) + iPopSize += m_vecArgTypes[i].size; } return iPopSize; @@ -105,7 +118,8 @@ int x86MsThiscall::GetArgStackSize() for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) { - iArgStackSize += m_vecArgTypes[i].size; + if (m_vecArgTypes[i].custom_register == None) + iArgStackSize += m_vecArgTypes[i].size; } return iArgStackSize; @@ -116,17 +130,42 @@ void** x86MsThiscall::GetStackArgumentPtr(CRegisters* pRegisters) return (void **)(pRegisters->m_esp->GetValue() + 4); } +int x86MsThiscall::GetArgRegisterSize() +{ + int iArgRegisterSize = 0; + + for (unsigned int i = 0; i < m_vecArgTypes.length(); i++) + { + if (m_vecArgTypes[i].custom_register != None) + iArgRegisterSize += m_vecArgTypes[i].size; + } + + return iArgRegisterSize; +} + void* x86MsThiscall::GetArgumentPtr(int iIndex, CRegisters* pRegisters) { if (iIndex == 0) { + // TODO: Allow custom this register. return pRegisters->m_ecx->m_pAddress; } + // Check if this argument was passed in a register. + if (m_vecArgTypes[iIndex-1].custom_register != None) + { + CRegister *pRegister = pRegisters->GetRegister(m_vecArgTypes[iIndex-1].custom_register); + if (!pRegister) + return NULL; + + return pRegister->m_pAddress; + } + int iOffset = 4; for(int i=0; i < iIndex-1; i++) { - iOffset += m_vecArgTypes[i].size; + if (m_vecArgTypes[i].custom_register == None) + iOffset += m_vecArgTypes[i].size; } return (void *) (pRegisters->m_esp->GetValue() + iOffset); diff --git a/DynamicHooks/conventions/x86MsThiscall.h b/DynamicHooks/conventions/x86MsThiscall.h index 167abd1..5ce2dea 100644 --- a/DynamicHooks/conventions/x86MsThiscall.h +++ b/DynamicHooks/conventions/x86MsThiscall.h @@ -69,8 +69,9 @@ public: virtual ke::Vector GetRegisters(); virtual int GetPopSize(); - virtual int x86MsThiscall::GetArgStackSize(); + virtual int GetArgStackSize(); virtual void** GetStackArgumentPtr(CRegisters* pRegisters); + virtual int GetArgRegisterSize(); virtual void* GetArgumentPtr(int iIndex, CRegisters* pRegisters); virtual void ArgumentPtrChanged(int iIndex, CRegisters* pRegisters, void* pArgumentPtr); diff --git a/DynamicHooks/registers.cpp b/DynamicHooks/registers.cpp index e6fc4d7..c9d28d3 100644 --- a/DynamicHooks/registers.cpp +++ b/DynamicHooks/registers.cpp @@ -378,4 +378,128 @@ void CRegisters::DeleteRegister(CRegister* pRegister) { delete pRegister; } +} + +CRegister* CRegisters::GetRegister(Register_t reg) +{ + switch (reg) + { + case AL: + return m_al; + case CL: + return m_cl; + case DL: + return m_dl; + case BL: + return m_bl; + case AH: + return m_ah; + case CH: + return m_ch; + case DH: + return m_dh; + case BH: + return m_bh; + + case AX: + return m_ax; + case CX: + return m_cx; + case DX: + return m_dx; + case BX: + return m_bx; + case SP: + return m_sp; + case BP: + return m_bp; + case SI: + return m_si; + case DI: + return m_di; + + case EAX: + return m_eax; + case ECX: + return m_ecx; + case EDX: + return m_edx; + case EBX: + return m_ebx; + case ESP: + return m_esp; + case EBP: + return m_ebp; + case ESI: + return m_esi; + case EDI: + return m_edi; + + case MM0: + return m_mm0; + case MM1: + return m_mm1; + case MM2: + return m_mm2; + case MM3: + return m_mm3; + case MM4: + return m_mm4; + case MM5: + return m_mm5; + case MM6: + return m_mm6; + case MM7: + return m_mm7; + + case XMM0: + return m_xmm0; + case XMM1: + return m_xmm1; + case XMM2: + return m_xmm2; + case XMM3: + return m_xmm3; + case XMM4: + return m_xmm4; + case XMM5: + return m_xmm5; + case XMM6: + return m_xmm6; + case XMM7: + return m_xmm7; + + case CS: + return m_cs; + case SS: + return m_ss; + case DS: + return m_ds; + case ES: + return m_es; + case FS: + return m_fs; + case GS: + return m_gs; + + case ST0: + return m_st0; + case ST1: + return m_st1; + case ST2: + return m_st2; + case ST3: + return m_st3; + case ST4: + return m_st4; + case ST5: + return m_st5; + case ST6: + return m_st6; + case ST7: + return m_st7; + + default: + return NULL; + } } \ No newline at end of file diff --git a/DynamicHooks/registers.h b/DynamicHooks/registers.h index 6b7193d..049d66b 100644 --- a/DynamicHooks/registers.h +++ b/DynamicHooks/registers.h @@ -43,6 +43,9 @@ // ============================================================================ enum Register_t { + // No register at all. + None, + // ======================================================================== // >> 8-bit General purpose registers // ======================================================================== @@ -263,6 +266,8 @@ public: CRegisters(ke::Vector registers); ~CRegisters(); + CRegister* GetRegister(Register_t reg); + private: CRegister* CreateRegister(ke::Vector& registers, Register_t reg, int iSize); void DeleteRegister(CRegister* pRegister); diff --git a/dynhooks_sourcepawn.cpp b/dynhooks_sourcepawn.cpp index e4e4c99..ae0a980 100644 --- a/dynhooks_sourcepawn.cpp +++ b/dynhooks_sourcepawn.cpp @@ -189,12 +189,15 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup) DataTypeSized_t type; type.type = DynamicHooks_ConvertParamTypeFrom(info.type); type.size = info.size; + type.custom_register = info.custom_register; vecArgTypes.append(type); } DataTypeSized_t returnType; returnType.type = DynamicHooks_ConvertReturnTypeFrom(setup->returnType); returnType.size = 0; + // TODO: Add support for a custom return register. + returnType.custom_register = None; ICallingConvention *pCallConv = nullptr; switch (setup->callConv) @@ -213,6 +216,32 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup) return pCallConv; } +bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup) +{ + // The registers the arguments are passed in might not be the same size as the actual parameter type. + // Update the type info to the size of the register that's now holding that argument, + // so we can copy the whole value. + ICallingConvention* callingConvention = pDetour->m_pCallingConvention; + ke::Vector &argTypes = callingConvention->m_vecArgTypes; + int numArgs = argTypes.length(); + + for (int i = 0; i < numArgs; i++) + { + if (argTypes[i].custom_register == None) + continue; + + CRegister *reg = pDetour->m_pRegisters->GetRegister(argTypes[i].custom_register); + // That register can't be handled yet. + if (!reg) + return false; + + argTypes[i].size = reg->m_iSize; + setup->params[i].size = reg->m_iSize; + } + + return true; +} + ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour) { DetourMap *map; @@ -536,24 +565,43 @@ HookParamsStruct *CDynamicHooksSourcePawn::GetParamStruct() HookParamsStruct *params = new HookParamsStruct(); params->dg = this; - size_t paramsSize = this->m_pDetour->m_pCallingConvention->GetArgStackSize(); - ke::Vector &argTypes = m_pDetour->m_pCallingConvention->m_vecArgTypes; + ICallingConvention* callingConvention = m_pDetour->m_pCallingConvention; + size_t stackSize = callingConvention->GetArgStackSize(); + size_t paramsSize = stackSize + callingConvention->GetArgRegisterSize(); + ke::Vector &argTypes = callingConvention->m_vecArgTypes; int numArgs = argTypes.length(); params->orgParams = (void **)malloc(paramsSize); params->newParams = (void **)malloc(paramsSize); params->isChanged = (bool *)malloc(numArgs * sizeof(bool)); - size_t offset = 0; - for (int i = 0; i < numArgs; i++) + // Save old stack parameters + if (stackSize > 0) { void *pArgPtr = m_pDetour->m_pCallingConvention->GetStackArgumentPtr(m_pDetour->m_pRegisters); - memcpy(params->orgParams, pArgPtr, paramsSize); - - *(void **)((intptr_t)params->newParams + offset) = NULL; - params->isChanged[i] = false; + memcpy(params->orgParams, pArgPtr, stackSize); + } - offset += argTypes[i].size; + memset(params->newParams, NULL, paramsSize); + memset(params->isChanged, false, numArgs * sizeof(bool)); + + int firstArg = 0; + // TODO: Support custom register for this ptr. + if (callConv == CallConv_THISCALL) + firstArg = 1; + + // Save the old parameters passed in a register. + size_t offset = stackSize; + for (int i = 0; i < numArgs; i++) + { + // We already saved the stack arguments. + if (argTypes[i].custom_register == None) + continue; + + int size = argTypes[i].size; + void *regAddr = callingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters); + memcpy(params->orgParams + offset, regAddr, size); + offset += size; } return params; @@ -565,23 +613,34 @@ void CDynamicHooksSourcePawn::UpdateParamsFromStruct(HookParamsStruct *params) if (!params) return; - ke::Vector &argTypes = m_pDetour->m_pCallingConvention->m_vecArgTypes; + ICallingConvention* callingConvention = m_pDetour->m_pCallingConvention; + size_t stackSize = callingConvention->GetArgStackSize(); + ke::Vector &argTypes = callingConvention->m_vecArgTypes; int numArgs = argTypes.length(); int firstArg = 0; + // TODO: Support custom register for this ptr. if (callConv == CallConv_THISCALL) firstArg = 1; - size_t offset = 0; + size_t stackOffset = 0; + size_t registerOffset = stackSize; + size_t offset; for (int i = 0; i < numArgs; i++) { - int size = argTypes[i].size;; + int size = argTypes[i].size; if (params->isChanged[i]) { + offset = argTypes[i].custom_register == None ? stackOffset : registerOffset; + void *paramAddr = (void *)((intptr_t)params->newParams + offset); - void *stackAddr = m_pDetour->m_pCallingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters); + void *stackAddr = callingConvention->GetArgumentPtr(i + firstArg, m_pDetour->m_pRegisters); memcpy(stackAddr, paramAddr, size); } - offset += size; + + if (argTypes[i].custom_register == None) + stackOffset += size; + else + registerOffset += size; } } \ No newline at end of file diff --git a/dynhooks_sourcepawn.h b/dynhooks_sourcepawn.h index e0cd1cb..fd81522 100644 --- a/dynhooks_sourcepawn.h +++ b/dynhooks_sourcepawn.h @@ -33,6 +33,7 @@ public: }; ICallingConvention *ConstructCallingConvention(HookSetup *setup); +bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup); ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour); bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback); bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction *pCallback); diff --git a/natives.cpp b/natives.cpp index a4c0d22..a61b143 100644 --- a/natives.cpp +++ b/natives.cpp @@ -119,7 +119,7 @@ cell_t Native_SetFromConf(IPluginContext *pContext, const cell_t *params) } //native bool:DHookAddParam(Handle:setup, HookParamType:type); OLD -//native bool:DHookAddParam(Handle:setup, HookParamType:type, size=-1, DHookPassFlag:flag=DHookPass_ByVal); +//native bool:DHookAddParam(Handle:setup, HookParamType:type, size=-1, DHookPassFlag:flag=DHookPass_ByVal, DHookRegister custom_register=DHookRegister_Default); cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params) { HookSetup *setup; @@ -142,6 +142,23 @@ cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params) info.flags = PASSFLAG_BYVAL; } + if (params[0] >= 5) + { + PluginRegister custom_register = (PluginRegister)params[5]; + info.custom_register = DynamicHooks_ConvertRegisterFrom(custom_register); + + // Stay future proof. + if (info.custom_register == None && custom_register != DHookRegister_Default) + return pContext->ThrowNativeError("Unhandled DHookRegister %d", params[5]); + + if (info.custom_register != None && info.type == HookParamType_Object) + return pContext->ThrowNativeError("Can't pass an object in a register."); + } + else + { + info.custom_register = None; + } + if(params[0] >= 3 && params[3] != -1) { info.size = params[3]; @@ -195,6 +212,8 @@ cell_t Native_EnableDetour(IPluginContext *pContext, const cell_t *params) { ICallingConvention *pCallConv = ConstructCallingConvention(setup); pDetour = pDetourManager->HookFunction(setup->funcAddr, pCallConv); + if (!UpdateRegisterArgumentSizes(pDetour, setup)) + return pContext->ThrowNativeError("A custom register for a parameter isn't supported."); } // Register our pre/post handler. diff --git a/sourcemod/scripting/dynhooks-test.sp b/sourcemod/scripting/dynhooks-test.sp index ee86969..b9b7697 100644 --- a/sourcemod/scripting/dynhooks-test.sp +++ b/sourcemod/scripting/dynhooks-test.sp @@ -6,7 +6,7 @@ Handle hFlashbangDetonateDetour; Handle hFlashbangDeafen; -Handle hPercentageOfFlashForPlayer; +//Handle hPercentageOfFlashForPlayer; public void OnPluginStart() { @@ -40,7 +40,7 @@ public void OnPluginStart() if (!DHookSetFromConf(hFlashbangDeafen, temp, SDKConf_Signature, "Deafen")) SetFailState("Failed to load Deafen signature from gamedata"); - DHookAddParam(hFlashbangDeafen, HookParamType_Float); + DHookAddParam(hFlashbangDeafen, HookParamType_Float, .custom_register=DHookRegister_XMM1); if (!DHookEnableDetour(hFlashbangDeafen, false, Detour_OnDeafen)) SetFailState("Failed to detour Deafen."); @@ -51,7 +51,7 @@ public void OnPluginStart() PrintToServer("CCSPlayer::Deafen detoured!"); - hPercentageOfFlashForPlayer = DHookCreateDetour(Address_Null, CallConv_CDECL, ReturnType_Float, ThisPointer_Ignore); + /*hPercentageOfFlashForPlayer = DHookCreateDetour(Address_Null, CallConv_CDECL, ReturnType_Float, ThisPointer_Ignore); if (!hPercentageOfFlashForPlayer) SetFailState("Failed to setup detour for PercentageOfFlashForPlayer"); @@ -68,7 +68,7 @@ public void OnPluginStart() if (!DHookEnableDetour(hPercentageOfFlashForPlayer, true, Detour_OnPercentageOfFlashForPlayer_Post)) SetFailState("Failed to detour PercentageOfFlashForPlayer post."); - PrintToServer("PercentageOfFlashForPlayer detoured!"); + PrintToServer("PercentageOfFlashForPlayer detoured!");*/ } public MRESReturn Detour_OnFlashbangDetonate(int pThis) diff --git a/sourcemod/scripting/include/dhooks.inc b/sourcemod/scripting/include/dhooks.inc index 5c617f9..5c9e9c7 100644 --- a/sourcemod/scripting/include/dhooks.inc +++ b/sourcemod/scripting/include/dhooks.inc @@ -98,6 +98,45 @@ enum DHookPassFlag DHookPass_OASSIGNOP = (1<<4), /**< Object has an assignment operator */ }; +enum DHookRegister +{ + // Don't change the register and use the default for the calling convention. + DHookRegister_Default, + + // 8-bit general purpose registers + DHookRegister_AL, + DHookRegister_CL, + DHookRegister_DL, + DHookRegister_BL, + DHookRegister_AH, + DHookRegister_CH, + DHookRegister_DH, + DHookRegister_BH, + + // 32-bit general purpose registers + DHookRegister_EAX, + DHookRegister_ECX, + DHookRegister_EDX, + DHookRegister_EBX, + DHookRegister_ESP, + DHookRegister_EBP, + DHookRegister_ESI, + DHookRegister_EDI, + + // 128-bit XMM registers + DHookRegister_XMM0, + DHookRegister_XMM1, + DHookRegister_XMM2, + DHookRegister_XMM3, + DHookRegister_XMM4, + DHookRegister_XMM5, + DHookRegister_XMM6, + DHookRegister_XMM7, + + // 80-bit FPU registers + DHookRegister_ST0 +}; + typeset ListenCB { //Deleted @@ -198,7 +237,8 @@ native bool DHookDisableDetour(Handle setup, bool post, DHookCallback callback); * @error Invalid setup handle or too many params added (request upping the max in thread) * @noreturn */ -native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal); +native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal, DHookRegister custom_register=DHookRegister_Default); +//native void DHookAddParam(Handle setup, HookParamType type, int size=-1, DHookPassFlag flag=DHookPass_ByVal); //native DHookAddParam(Handle:setup, HookParamType:type); /* Hook entity diff --git a/util.cpp b/util.cpp index 898f50b..b25dfc2 100644 --- a/util.cpp +++ b/util.cpp @@ -13,23 +13,62 @@ void * GetObjectAddr(HookParamType type, unsigned int flags, void **params, size } -size_t GetParamOffset(HookParamsStruct *paramStruct, unsigned int index) +size_t GetStackParamOffset(HookParamsStruct *paramStruct, unsigned int index) { + assert(paramStruct->dg->params[index].custom_register == None); + size_t offset = 0; for (unsigned int i = 0; i < index; i++) { + // Only care for arguments on the stack before us. + if (paramStruct->dg->params[i].custom_register != None) + continue; + #ifndef WIN32 - if (paramStruct->dg->params.at(i).type == HookParamType_Object && (paramStruct->dg->params.at(i).flags & PASSFLAG_ODTOR)) //Passed by refrence + if (paramStruct->dg->params[i].type == HookParamType_Object && (paramStruct->dg->params[i].flags & PASSFLAG_ODTOR)) //Passed by refrence { offset += sizeof(void *); continue; } #endif - offset += paramStruct->dg->params.at(i).size; + offset += paramStruct->dg->params[i].size; } return offset; } +size_t GetRegisterParamOffset(HookParamsStruct *paramStruct, unsigned int index) +{ + // TODO: Fix this up and get a pointer to the CDetour + assert(paramStruct->dg->params[index].custom_register != None); + + // Need to get the size of the stack arguments first. Register arguments are stored after them in the buffer. + size_t stackSize = 0; + for (int i = paramStruct->dg->params.size() - 1; i >= 0; i--) + { + if (paramStruct->dg->params[i].custom_register == None) + stackSize += paramStruct->dg->params[i].size; + } + + size_t offset = stackSize; + for (unsigned int i = 0; i < index; i++) + { + // Only care for arguments passed through a register as well before us. + if (paramStruct->dg->params[i].custom_register == None) + continue; + + offset += paramStruct->dg->params[i].size; + } + return offset; +} + +size_t GetParamOffset(HookParamsStruct *paramStruct, unsigned int index) +{ + if (paramStruct->dg->params[index].custom_register == None) + return GetStackParamOffset(paramStruct, index); + else + return GetRegisterParamOffset(paramStruct, index); +} + size_t GetParamTypeSize(HookParamType type) { return sizeof(void *); @@ -99,3 +138,68 @@ DataType_t DynamicHooks_ConvertReturnTypeFrom(ReturnType type) return DATA_TYPE_VOID; } + +Register_t DynamicHooks_ConvertRegisterFrom(PluginRegister reg) +{ + switch (reg) + { + case DHookRegister_Default: + return None; + + case DHookRegister_AL: + return AL; + case DHookRegister_CL: + return CL; + case DHookRegister_DL: + return DL; + case DHookRegister_BL: + return BL; + case DHookRegister_AH: + return AH; + case DHookRegister_CH: + return CH; + case DHookRegister_DH: + return DH; + case DHookRegister_BH: + return BH; + + case DHookRegister_EAX: + return EAX; + case DHookRegister_ECX: + return ECX; + case DHookRegister_EDX: + return EDX; + case DHookRegister_EBX: + return EBX; + case DHookRegister_ESP: + return ESP; + case DHookRegister_EBP: + return EBP; + case DHookRegister_ESI: + return ESI; + case DHookRegister_EDI: + return EDI; + + case DHookRegister_XMM0: + return XMM0; + case DHookRegister_XMM1: + return XMM1; + case DHookRegister_XMM2: + return XMM2; + case DHookRegister_XMM3: + return XMM3; + case DHookRegister_XMM4: + return XMM4; + case DHookRegister_XMM5: + return XMM5; + case DHookRegister_XMM6: + return XMM6; + case DHookRegister_XMM7: + return XMM7; + + case DHookRegister_ST0: + return ST0; + } + + return None; +} diff --git a/util.h b/util.h index 7bf5e42..7d131a0 100644 --- a/util.h +++ b/util.h @@ -4,6 +4,45 @@ #include "vhook.h" #include "convention.h" +enum PluginRegister +{ + // Don't change the register and use the default for the calling convention. + DHookRegister_Default, + + // 8-bit general purpose registers + DHookRegister_AL, + DHookRegister_CL, + DHookRegister_DL, + DHookRegister_BL, + DHookRegister_AH, + DHookRegister_CH, + DHookRegister_DH, + DHookRegister_BH, + + // 32-bit general purpose registers + DHookRegister_EAX, + DHookRegister_ECX, + DHookRegister_EDX, + DHookRegister_EBX, + DHookRegister_ESP, + DHookRegister_EBP, + DHookRegister_ESI, + DHookRegister_EDI, + + // 128-bit XMM registers + DHookRegister_XMM0, + DHookRegister_XMM1, + DHookRegister_XMM2, + DHookRegister_XMM3, + DHookRegister_XMM4, + DHookRegister_XMM5, + DHookRegister_XMM6, + DHookRegister_XMM7, + + // 80-bit FPU registers + DHookRegister_ST0 +}; + size_t GetParamOffset(HookParamsStruct *params, unsigned int index); void * GetObjectAddr(HookParamType type, unsigned int flags, void **params, size_t offset); size_t GetParamTypeSize(HookParamType type); @@ -11,4 +50,5 @@ size_t GetParamsSize(DHooksCallback *dg); DataType_t DynamicHooks_ConvertParamTypeFrom(HookParamType type); DataType_t DynamicHooks_ConvertReturnTypeFrom(ReturnType type); +Register_t DynamicHooks_ConvertRegisterFrom(PluginRegister reg); #endif diff --git a/vhook.h b/vhook.h index 14fc1fc..413397b 100644 --- a/vhook.h +++ b/vhook.h @@ -5,6 +5,7 @@ #include #include #include +#include enum CallingConvention { @@ -92,6 +93,7 @@ struct ParamInfo size_t size; unsigned int flags; SourceHook::PassInfo::PassType pass_type; + Register_t custom_register; }; #ifdef WIN32 @@ -216,6 +218,11 @@ public: this->callback = nullptr; }; ~HookSetup(){}; + + bool IsVirtual() + { + return this->offset != -1; + } public: unsigned int returnFlag; ReturnType returnType;