Skip to content

Commit bcea09e

Browse files
authored
Added the possibility to access pre-registers in a post-hook (#384)
* Remove redundant cpp files * Updated dynamic hooks * Disable caching * Added the possibility to access pre-registers in a post-hook * Added context manager to temporarily set use_pre_registers * Updated DynamicHooks
1 parent 56645a6 commit bcea09e

File tree

14 files changed

+101
-425
lines changed

14 files changed

+101
-425
lines changed

addons/source-python/packages/source-python/memory/hooks.py

+52-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
'PreHook',
2727
'set_hooks_disabled',
2828
'get_hooks_disabled',
29-
'hooks_disabled'
29+
'hooks_disabled',
30+
'use_pre_registers',
3031
)
3132

3233

@@ -86,6 +87,56 @@ class PostHook(_Hook):
8687
# =============================================================================
8788
# >> FUNCTIONS
8889
# =============================================================================
90+
@contextmanager
91+
def use_pre_registers(stack_data, value=True):
92+
"""Temporarily set ``StackData.use_pre_registers`` to the given value.
93+
When the context ends, the previous value is restored.
94+
95+
Some functions overwrite CPU registers during their execution with values
96+
from their internal calculations. In a post-hook, you have access to the
97+
modified CPU registers, but in some cases you might want to access the
98+
registers that were saved before the pre-hook was called. In that case you
99+
can use this context manager to get access to the previous state of the
100+
registers. On Windows this is often required when hooking THISCALL
101+
functions, because the this-pointer is saved in the CPU register ``ECX``,
102+
but gets overwritten during the execution of the hooked function. So, in a
103+
post-hook you won't have access to the this-pointer anymore.
104+
105+
Example (CS:S/Windows):
106+
107+
.. code:: python
108+
109+
from entities.hooks import EntityCondition
110+
from entities.hooks import EntityPostHook
111+
from entities.hooks import EntityPreHook
112+
113+
from memory.hooks import use_pre_registers
114+
115+
@EntityPreHook(EntityCondition.is_player, 'drop_weapon')
116+
def pre_on_drop_weapon(stack_data):
117+
print(f'PRE: this = {stack_data[0].address}')
118+
119+
@EntityPostHook(EntityCondition.is_player, 'drop_weapon')
120+
def post_on_drop_weapon(stack_data, ret_val):
121+
print(f'POST FALSE: this = {stack_data[0].address}')
122+
with use_pre_registers(stack_data):
123+
print(f'POST CORRECT: this = {stack_data[0].address}')
124+
125+
Output:
126+
127+
.. code::
128+
129+
PRE: this = 546778280
130+
POST FALSE: this = 16439007
131+
POST CORRECT: this = 546778280
132+
"""
133+
old = stack_data.use_pre_registers
134+
stack_data.use_pre_registers = value
135+
try:
136+
yield
137+
finally:
138+
stack_data.use_pre_registers = old
139+
89140
@contextmanager
90141
def hooks_disabled(disabled=True):
91142
"""Temporarily disable or enable all hook callbacks. By default hooks are

src/core/modules/memory/memory_hooks.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,10 @@ object CStackData::GetItem(unsigned int iIndex)
173173
BOOST_RAISE_EXCEPTION(PyExc_IndexError, "Index out of range.")
174174

175175
// Argument already cached?
176-
object retval = m_mapCache[iIndex];
177-
if (retval)
178-
return retval;
176+
object retval;
177+
//object retval = m_mapCache[iIndex];
178+
//if (retval)
179+
// return retval;
179180

180181
switch(m_pHook->m_pCallingConvention->m_vecArgTypes[iIndex])
181182
{
@@ -196,7 +197,7 @@ object CStackData::GetItem(unsigned int iIndex)
196197
case DATA_TYPE_STRING: retval = GetArgument<const char *>(m_pHook, iIndex); break;
197198
default: BOOST_RAISE_EXCEPTION(PyExc_TypeError, "Unknown type.") break;
198199
}
199-
m_mapCache[iIndex] = retval;
200+
//m_mapCache[iIndex] = retval;
200201
return retval;
201202
}
202203

@@ -206,7 +207,7 @@ void CStackData::SetItem(unsigned int iIndex, object value)
206207
BOOST_RAISE_EXCEPTION(PyExc_IndexError, "Index out of range.")
207208

208209
// Update cache
209-
m_mapCache[iIndex] = value;
210+
//m_mapCache[iIndex] = value;
210211
switch(m_pHook->m_pCallingConvention->m_vecArgTypes[iIndex])
211212
{
212213
case DATA_TYPE_BOOL: SetArgument<bool>(m_pHook, iIndex, value); break;

src/core/modules/memory/memory_hooks.h

+12-2
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,30 @@ class CStackData
5151
void SetItem(unsigned int iIndex, object value);
5252

5353
CRegisters* GetRegisters()
54-
{ return m_pHook->m_pRegisters; }
54+
{ return m_pHook->GetRegisters(); }
5555

5656
str __repr__()
5757
{ return str(tuple(ptr(this))); }
5858

5959
void* GetReturnAddress()
6060
{
61-
void* pESP = m_pHook->m_pRegisters->m_esp->GetValue<void*>();
61+
void* pESP = m_pHook->GetRegisters()->m_esp->GetValue<void*>();
6262
if (m_pHook->m_RetAddr.count(pESP) == 0) {
6363
return NULL;
6464
}
6565
return m_pHook->m_RetAddr[pESP].back();
6666
}
6767

68+
bool GetUsePreRegister()
69+
{
70+
return m_pHook->m_bUsePreRegisters;
71+
}
72+
73+
void SetUsePreRegisters(bool value)
74+
{
75+
m_pHook->m_bUsePreRegisters = value;
76+
}
77+
6878
protected:
6979
CHook* m_pHook;
7080
std::map<int, object> m_mapCache;

src/core/modules/memory/memory_wrap.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,11 @@ void export_stack_data(scope _memory)
635635
.add_property("registers",
636636
make_function(&CStackData::GetRegisters, reference_existing_object_policy())
637637
)
638+
639+
.add_property(
640+
"use_pre_registers",
641+
&CStackData::GetUsePreRegister,
642+
&CStackData::SetUsePreRegisters)
638643
;
639644
}
640645

src/thirdparty/DynamicHooks/include/conventions/x86MsCdecl.cpp

-129
This file was deleted.

src/thirdparty/DynamicHooks/include/conventions/x86MsCdecl.h

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class x86MsCdecl: public ICallingConvention
7777

7878
private:
7979
void* m_pReturnBuffer;
80+
int* m_pOffsets;
8081
};
8182

8283
#endif // _X86_MS_CDECL_H

src/thirdparty/DynamicHooks/include/conventions/x86MsFastcall.h

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class x86MsFastcall: public ICallingConvention
7878

7979
private:
8080
void* m_pReturnBuffer;
81+
int* m_pOffsets;
8182
};
8283

8384
#endif // _X86_MS_FASTCALL_H

0 commit comments

Comments
 (0)