Skip to content

Commit f912f82

Browse files
committed
Fixed calling a hook callback
- Implemented the new argument/return type system
1 parent c4c61ca commit f912f82

File tree

5 files changed

+177
-101
lines changed

5 files changed

+177
-101
lines changed

src/core/modules/memory/memory_callback.cpp

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -49,20 +49,14 @@ using namespace DynamicHooks;
4949
// ============================================================================
5050
// >> CLASSES
5151
// ============================================================================
52-
CCallback::CCallback(object oCallback, Convention_t eConv, char* szParams)
53-
: CFunction(NULL, eConv, szParams)
52+
CCallback::CCallback(object oCallback, Convention_t eConv, tuple args, ReturnType_t return_type)
53+
: CFunction(NULL, eConv, args, return_type)
5454
{
55-
m_eConv = eConv;
5655
m_oCallback = oCallback;
5756

58-
// Parse the parameter string
59-
m_pParams = new Param_t;
60-
m_pRetParam = new Param_t;
61-
ParseParams(eConv, szParams, m_pParams, m_pRetParam);
62-
6357
// Find the proper callback caller function
6458
void* pCallCallbackFunc = NULL;
65-
switch(m_pRetParam->m_cParam)
59+
switch(return_type)
6660
{
6761
case SIGCHAR_VOID: pCallCallbackFunc = GET_CALLBACK_CALLER(void); break;
6862
case SIGCHAR_BOOL: pCallCallbackFunc = GET_CALLBACK_CALLER(bool); break;
@@ -107,45 +101,51 @@ CCallback::CCallback(object oCallback, Convention_t eConv, char* szParams)
107101
m_ulAddr = (unsigned long) a.make();
108102
}
109103

110-
CCallback::~CCallback()
111-
{
112-
delete m_pParams;
113-
delete m_pRetParam;
114-
}
115-
116104
int CCallback::GetPopSize()
117105
{
106+
/*
107+
Who cleans up the stack?
108+
109+
Linux: Always the caller
110+
111+
Windows:
112+
CDECL: Caller
113+
STDCALL + THISCALL: Callee
114+
*/
115+
118116
#ifdef _WIN32
119-
if (m_eConv == CONV_THISCALL || m_eConv == CONV_STDCALL)
120-
{
121-
Param_t* pParam = GetArgument(GetArgumentCount() - 1);
122-
return pParam->m_iOffset + pParam->m_iSize;
123-
}
117+
if (m_eConv == CONV_CDECL)
118+
return 0;
119+
120+
int i = 0;
121+
122+
// Skip the this pointer. It's passed in an own register (ECX)
123+
if (m_eConv == CONV_THISCALL)
124+
i++;
125+
126+
int size = 0;
127+
for(; i < len(m_Args); i++)
128+
size += GetTypeSize(extract<Argument_t>(m_Args[i]));
129+
130+
return size;
124131
#endif
125132
return 0;
126133
}
127134

128-
int CCallback::GetArgumentCount()
135+
int CCallback::GetArgumentOffset(int iIndex)
129136
{
130-
int count = 0;
131-
Param_t* temp = m_pParams;
132-
while(temp)
133-
{
134-
count++;
135-
temp = temp->m_pNext;
136-
}
137-
return count - 1;
138-
}
137+
int offset = 8;
138+
for(int i=0; i <= iIndex; i++)
139+
{
140+
offset += GetTypeSize(extract<Argument_t>(m_Args[i]));
141+
}
139142

140-
Param_t* CCallback::GetArgument(int iIndex)
141-
{
142-
Param_t* temp = m_pParams;
143-
while(temp && iIndex > 0)
144-
{
145-
iIndex--;
146-
temp = temp->m_pNext;
147-
}
148-
return temp;
143+
// Subtract the this pointer on Windows
144+
#ifdef _WIN32
145+
offset -= sizeof(void *);
146+
#endif
147+
148+
return offset;
149149
}
150150

151151
void CCallback::Dealloc()
@@ -171,18 +171,18 @@ T GetArgument(CCallback* pCallback, unsigned long ulEBP, unsigned long ulECX, in
171171
return *(T *) &ulECX;
172172
#endif
173173

174-
return *(T *) (ulEBP + pCallback->GetArgument(iIndex)->m_iOffset + 8);
174+
return *(T *) (ulEBP + pCallback->GetArgumentOffset(iIndex));
175175
}
176176

177177
object CallCallback(CCallback* pCallback, unsigned long ulEBP, unsigned long ulECX)
178178
{
179+
// TODO: Make this crash proof
179180
BEGIN_BOOST_PY()
180-
181181
list arg_list;
182-
for(int i=0; i < pCallback->GetArgumentCount(); i++)
182+
for(int i=0; i < len(pCallback->m_Args); i++)
183183
{
184184
object val;
185-
switch(pCallback->GetArgument(i)->m_cParam)
185+
switch(extract<Argument_t>(pCallback->m_Args[i]))
186186
{
187187
case SIGCHAR_BOOL: val = object(GetArgument<bool>(pCallback, ulEBP, ulECX, i)); break;
188188
case SIGCHAR_CHAR: val = object(GetArgument<char>(pCallback, ulEBP, ulECX, i)); break;
@@ -199,7 +199,7 @@ object CallCallback(CCallback* pCallback, unsigned long ulEBP, unsigned long ulE
199199
case SIGCHAR_DOUBLE: val = object(GetArgument<double>(pCallback, ulEBP, ulECX, i)); break;
200200
case SIGCHAR_POINTER: val = object(CPointer(GetArgument<unsigned long>(pCallback, ulEBP, ulECX, i))); break;
201201
case SIGCHAR_STRING: val = object(GetArgument<const char*>(pCallback, ulEBP, ulECX, i)); break;
202-
default: BOOST_RAISE_EXCEPTION(PyExc_TypeError, "Unknown type."); break;
202+
default: BOOST_RAISE_EXCEPTION(PyExc_TypeError, "Unknown argument type."); break;
203203
}
204204
arg_list.append(val);
205205
}

src/core/modules/memory/memory_callback.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,16 @@ inline void* CallbackCaller(CCallback* pCallback, unsigned long ulEBP, unsigned
6767
class CCallback: public CFunction
6868
{
6969
public:
70-
CCallback(object oCallback, Convention_t eConv, char* szParams);
71-
~CCallback();
70+
CCallback(object oCallback, Convention_t eConv, tuple args, ReturnType_t return_type);
7271

73-
int GetPopSize();
74-
int GetArgumentCount();
75-
Param_t* GetArgument(int iIndex);
72+
int GetPopSize();
73+
int GetArgumentOffset(int iIndex);
7674

7775
virtual void Dealloc();
7876
virtual void Realloc(int iSize);
7977

8078
public:
81-
// For variadic functions
82-
object m_oCallback;
83-
Param_t* m_pParams;
84-
Param_t* m_pRetParam;
79+
object m_oCallback;
8580
};
8681

8782
#endif // _MEMORY_CALLBACK_H

src/core/modules/memory/memory_tools.cpp

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
#include <string>
3232

3333
#include "dyncall.h"
34-
#include "dyncall_signature.h"
3534

3635
#include "memory_hooks.h"
3736
#include "memory_tools.h"
@@ -177,49 +176,47 @@ CPointer* CPointer::GetVirtualFunc(int iIndex)
177176
return new CPointer((unsigned long) vtable[iIndex]);
178177
}
179178

180-
CFunction* CPointer::MakeFunction(Convention_t eConv, char* szParams)
179+
CFunction* CPointer::MakeFunction(Convention_t eConv, tuple args, ReturnType_t return_type)
181180
{
182181
if (!IsValid())
183182
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Pointer is NULL.")
184183

185-
return new CFunction(m_ulAddr, eConv, szParams);
184+
return new CFunction(m_ulAddr, eConv, args, return_type);
186185
}
187186

188-
CFunction* CPointer::MakeVirtualFunction(int iIndex, Convention_t eConv, char* szParams)
187+
CFunction* CPointer::MakeVirtualFunction(int iIndex, Convention_t eConv, tuple args, ReturnType_t return_type)
189188
{
190-
return GetVirtualFunc(iIndex)->MakeFunction(eConv, szParams);
189+
return GetVirtualFunc(iIndex)->MakeFunction(eConv, args, return_type);
191190
}
192191

193192
//-----------------------------------------------------------------------------
194193
// CFunction class
195194
//-----------------------------------------------------------------------------
196-
CFunction::CFunction(unsigned long ulAddr, Convention_t eConv, char* szParams)
195+
CFunction::CFunction(unsigned long ulAddr, Convention_t eConv, tuple args, ReturnType_t return_type)
197196
{
198197
m_ulAddr = ulAddr;
199198
m_eConv = eConv;
200-
m_szParams = strdup(szParams);
199+
m_Args = args;
200+
m_ReturnType = return_type;
201201
}
202202

203203
object CFunction::Call(tuple args, dict kw)
204-
{
204+
{
205205
if (!IsValid())
206206
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function pointer is NULL.")
207207

208+
if (len(args) != len(m_Args))
209+
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Number of passed arguments is not equal to the required number.")
210+
211+
// Reset VM and set the calling convention
208212
dcReset(g_pCallVM);
209213
dcMode(g_pCallVM, GetDynCallConvention(m_eConv));
210-
char* ptr = (char *) m_szParams;
211-
int pos = 0;
212-
char ch;
213-
while ((ch = *ptr) != '\0' && ch != ')')
214-
{
215-
if (ch == DC_SIGCHAR_VOID)
216-
{
217-
ptr++;
218-
break;
219-
}
220214

221-
object arg = args[pos];
222-
switch(ch)
215+
// Loop through all passed arguments and add them to the VM
216+
for(int i=0; i < len(args); i++)
217+
{
218+
object arg = args[i];
219+
switch(extract<Argument_t>(m_Args[i]))
223220
{
224221
case DC_SIGCHAR_BOOL: dcArgBool(g_pCallVM, extract<bool>(arg)); break;
225222
case DC_SIGCHAR_CHAR: dcArgChar(g_pCallVM, extract<char>(arg)); break;
@@ -236,20 +233,14 @@ object CFunction::Call(tuple args, dict kw)
236233
case DC_SIGCHAR_DOUBLE: dcArgDouble(g_pCallVM, extract<double>(arg)); break;
237234
case DC_SIGCHAR_POINTER: dcArgPointer(g_pCallVM, ExtractPyPtr(arg)); break;
238235
case DC_SIGCHAR_STRING: dcArgPointer(g_pCallVM, (unsigned long) (void *) extract<char *>(arg)); break;
239-
default: BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Unknown parameter type.")
236+
default: BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Unknown argument type.")
240237
}
241-
pos++; ptr++;
242238
}
243239

244-
if (pos != len(args))
245-
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "String parameter count does not equal with length of tuple.")
246-
247-
if (ch == '\0')
248-
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "String parameter has no return type.")
249-
250-
switch(*++ptr)
240+
// Call the function
241+
switch(m_ReturnType)
251242
{
252-
case DC_SIGCHAR_VOID: dcCallVoid(g_pCallVM, m_ulAddr); break;
243+
case DC_SIGCHAR_VOID: dcCallVoid(g_pCallVM, m_ulAddr); break;
253244
case DC_SIGCHAR_BOOL: return object(dcCallBool(g_pCallVM, m_ulAddr));
254245
case DC_SIGCHAR_CHAR: return object(dcCallChar(g_pCallVM, m_ulAddr));
255246
case DC_SIGCHAR_UCHAR: return object((unsigned char) dcCallChar(g_pCallVM, m_ulAddr));
@@ -279,18 +270,29 @@ object CFunction::CallTrampoline(tuple args, dict kw)
279270
if (!pHook)
280271
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function was not hooked.")
281272

282-
return CFunction((unsigned long) pHook->m_pTrampoline, m_eConv, m_szParams).Call(args, kw);
273+
return CFunction((unsigned long) pHook->m_pTrampoline, m_eConv, m_Args, m_ReturnType).Call(args, kw);
283274
}
284275

285-
PyObject* CFunction::AddHook(DynamicHooks::HookType_t eType, PyObject* pCallable)
276+
handle<> CFunction::AddHook(DynamicHooks::HookType_t eType, PyObject* pCallable)
286277
{
287278
if (!IsValid())
288279
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function pointer is NULL.")
289280

290-
CHook* pHook = g_pHookMngr->HookFunction((void *) m_ulAddr, m_eConv, m_szParams);
281+
// Generate the argument string
282+
char* szParams = extract<char*>(eval("lambda args, ret: ''.join(map(chr, args)) + ')' + chr(ret)")(m_Args, m_ReturnType));
283+
puts(szParams);
284+
285+
// Hook the function
286+
CHook* pHook = g_pHookMngr->HookFunction((void *) m_ulAddr, m_eConv, strdup(szParams));
287+
288+
// Add the hook handler. If it's already added, it won't be added twice
291289
pHook->AddCallback(eType, (void *) &SP_HookHandler);
290+
291+
// Add the callback to our map
292292
g_mapCallbacks[pHook][eType].push_back(pCallable);
293-
return pCallable;
293+
294+
// Return the callback, so we can use this method as a decorator
295+
return handle<>(borrowed(pCallable));
294296
}
295297

296298
void CFunction::RemoveHook(DynamicHooks::HookType_t eType, PyObject* pCallable)

src/core/modules/memory/memory_tools.h

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <malloc.h>
3131
#include "memalloc.h"
3232
#include "dyncall.h"
33+
#include "dyncall_signature.h"
3334

3435
#include "utility/wrap_macros.h"
3536
#include "DynamicHooks.h"
@@ -111,6 +112,45 @@ inline int GetDynCallConvention(Convention_t eConv)
111112
return 0;
112113
}
113114

115+
enum Argument_t
116+
{
117+
ARG_BOOL = DC_SIGCHAR_BOOL,
118+
ARG_CHAR = DC_SIGCHAR_CHAR,
119+
ARG_UCHAR = DC_SIGCHAR_UCHAR,
120+
ARG_SHORT = DC_SIGCHAR_SHORT,
121+
ARG_USHORT = DC_SIGCHAR_USHORT,
122+
ARG_INT = DC_SIGCHAR_INT,
123+
ARG_UINT = DC_SIGCHAR_UINT,
124+
ARG_LONG = DC_SIGCHAR_LONG,
125+
ARG_ULONG = DC_SIGCHAR_ULONG,
126+
ARG_LONGLONG = DC_SIGCHAR_LONGLONG,
127+
ARG_ULONGLONG = DC_SIGCHAR_ULONGLONG,
128+
ARG_FLOAT = DC_SIGCHAR_FLOAT,
129+
ARG_DOUBLE = DC_SIGCHAR_DOUBLE,
130+
ARG_POINTER = DC_SIGCHAR_POINTER,
131+
ARG_STRING = DC_SIGCHAR_STRING
132+
};
133+
134+
enum ReturnType_t
135+
{
136+
RET_VOID = DC_SIGCHAR_VOID,
137+
RET_BOOL = DC_SIGCHAR_BOOL,
138+
RET_CHAR = DC_SIGCHAR_CHAR,
139+
RET_UCHAR = DC_SIGCHAR_UCHAR,
140+
RET_SHORT = DC_SIGCHAR_SHORT,
141+
RET_USHORT = DC_SIGCHAR_USHORT,
142+
RET_INT = DC_SIGCHAR_INT,
143+
RET_UINT = DC_SIGCHAR_UINT,
144+
RET_LONG = DC_SIGCHAR_LONG,
145+
RET_ULONG = DC_SIGCHAR_ULONG,
146+
RET_LONGLONG = DC_SIGCHAR_LONGLONG,
147+
RET_ULONGLONG = DC_SIGCHAR_ULONGLONG,
148+
RET_FLOAT = DC_SIGCHAR_FLOAT,
149+
RET_DOUBLE = DC_SIGCHAR_DOUBLE,
150+
RET_POINTER = DC_SIGCHAR_POINTER,
151+
RET_STRING = DC_SIGCHAR_STRING
152+
};
153+
114154
//-----------------------------------------------------------------------------
115155
// CPointer class
116156
//-----------------------------------------------------------------------------
@@ -196,8 +236,8 @@ class CPointer
196236
virtual void Realloc(int iSize) { m_ulAddr = (unsigned long) UTIL_Realloc((void *) m_ulAddr, iSize); }
197237
virtual void Dealloc() { UTIL_Dealloc((void *) m_ulAddr); m_ulAddr = 0; }
198238

199-
CFunction* MakeFunction(Convention_t eConv, char* szParams);
200-
CFunction* MakeVirtualFunction(int iIndex, Convention_t eConv, char* szParams);
239+
CFunction* MakeFunction(Convention_t eConv, boost::python::tuple args, ReturnType_t return_type);
240+
CFunction* MakeVirtualFunction(int iIndex, Convention_t eConv, boost::python::tuple args, ReturnType_t return_type);
201241

202242
public:
203243
unsigned long m_ulAddr;
@@ -207,18 +247,18 @@ class CPointer
207247
class CFunction: public CPointer
208248
{
209249
public:
210-
CFunction(unsigned long ulAddr, Convention_t eConv, char* szParams);
250+
CFunction(unsigned long ulAddr, Convention_t eConv, boost::python::tuple args, ReturnType_t return_type);
211251

212252
object Call(boost::python::tuple args, dict kw);
213253
object CallTrampoline(boost::python::tuple args, dict kw);
214254

215-
PyObject* AddHook(DynamicHooks::HookType_t eType, PyObject* pCallable);
255+
handle<> AddHook(DynamicHooks::HookType_t eType, PyObject* pCallable);
216256
void RemoveHook(DynamicHooks::HookType_t eType, PyObject* pCallable);
217257

218-
PyObject* AddPreHook(PyObject* pCallable)
258+
handle<> AddPreHook(PyObject* pCallable)
219259
{ return AddHook(HOOKTYPE_PRE, pCallable); }
220260

221-
PyObject* AddPostHook(PyObject* pCallable)
261+
handle<> AddPostHook(PyObject* pCallable)
222262
{ return AddHook(HOOKTYPE_POST, pCallable); }
223263

224264
void RemovePreHook(PyObject* pCallable)
@@ -228,8 +268,9 @@ class CFunction: public CPointer
228268
{ RemoveHook(HOOKTYPE_POST, pCallable); }
229269

230270
public:
231-
char* m_szParams;
232-
Convention_t m_eConv;
271+
boost::python::tuple m_Args;
272+
ReturnType_t m_ReturnType;
273+
Convention_t m_eConv;
233274
};
234275

235276

0 commit comments

Comments
 (0)