Skip to content

Commit 5e076d8

Browse files
committed
Removed memory callbacks (the new method will be allocating some space and then hooking and overwriting it)
Added custom calling conventions Removed 64bit register comments
1 parent 4838111 commit 5e076d8

6 files changed

Lines changed: 395 additions & 185 deletions

File tree

src/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,14 +260,12 @@ Set(SOURCEPYTHON_MEMORY_MODULE_HEADERS
260260
core/modules/memory/memory_tools.h
261261
core/modules/memory/memory_scanner.h
262262
core/modules/memory/memory_hooks.h
263-
core/modules/memory/memory_callback.h
264263
)
265264

266265
Set(SOURCEPYTHON_MEMORY_MODULE_SOURCES
267266
core/modules/memory/memory_scanner.cpp
268267
core/modules/memory/memory_tools.cpp
269268
core/modules/memory/memory_hooks.cpp
270-
core/modules/memory/memory_callback.cpp
271269
core/modules/memory/memory_wrap_python.cpp
272270
)
273271

src/core/modules/memory/memory_hooks.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ class CStackData
2121
public:
2222
CStackData(CHook* pHook);
2323

24-
object GetItem(unsigned int iIndex);
25-
void SetItem(unsigned int iIndex, object value);
24+
object GetItem(unsigned int iIndex);
25+
void SetItem(unsigned int iIndex, object value);
26+
CRegisters* GetRegisters() { return m_pHook->m_pRegisters; }
2627

2728
protected:
2829
CHook* m_pHook;

src/core/modules/memory/memory_tools.cpp

Lines changed: 88 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,7 @@ int GetDynCallConvention(Convention_t eConv)
7272
}
7373

7474
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Unsupported calling convention.")
75-
return 0;
76-
}
77-
78-
std::vector<DataType_t> ObjectToDataTypeVector(object oArgTypes)
79-
{
80-
std::vector<DataType_t> vecArgTypes;
81-
for(int i=0; i < len(oArgTypes); i++)
82-
{
83-
vecArgTypes.push_back(extract<DataType_t>(oArgTypes[i]));
84-
}
85-
return vecArgTypes;
75+
return -1;
8676
}
8777

8878
ICallingConvention* MakeDynamicHooksConvention(Convention_t eConv, std::vector<DataType_t> vecArgTypes, DataType_t returnType, int iAlignment=4)
@@ -103,7 +93,7 @@ ICallingConvention* MakeDynamicHooksConvention(Convention_t eConv, std::vector<D
10393
#endif
10494

10595
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Unsupported calling convention.")
106-
return 0;
96+
return NULL;
10797
}
10898

10999
//-----------------------------------------------------------------------------
@@ -241,17 +231,52 @@ CPointer* CPointer::Realloc(int iSize)
241231
return new CPointer((unsigned long) UTIL_Realloc((void *) m_ulAddr, iSize));
242232
}
243233

244-
CFunction* CPointer::MakeFunction(Convention_t eConv, object args, object return_type)
234+
CFunction* CPointer::MakeFunction(object oCallingConvention, object args, object oReturnType)
245235
{
246236
if (!IsValid())
247237
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Pointer is NULL.")
248238

249-
return new CFunction(m_ulAddr, eConv, args, return_type);
239+
Convention_t _eCallingConvention = CONV_NONE;
240+
int _iCallingConvention = -1;
241+
object _oCallingConvention = object();
242+
ICallingConvention* _pCallingConvention = NULL;
243+
tuple _tArgs = tuple(args);
244+
object _oReturnType = oReturnType;
245+
DataType_t _eReturnType;
246+
247+
// Get the enum return type
248+
try
249+
{
250+
_eReturnType = extract<DataType_t>(oReturnType);
251+
}
252+
catch( ... )
253+
{
254+
PyErr_Clear();
255+
_eReturnType = DATA_TYPE_POINTER;
256+
}
257+
258+
try
259+
{
260+
// If this line succeeds the user wants to create a function with the built-in calling conventions
261+
_eCallingConvention = extract<Convention_t>(oCallingConvention);
262+
_iCallingConvention = GetDynCallConvention(_eCallingConvention);
263+
_pCallingConvention = MakeDynamicHooksConvention(_eCallingConvention, ObjectToDataTypeVector(args), _eReturnType);
264+
}
265+
catch( ... )
266+
{
267+
// If this happens, we won't be able to call the function, because we are using a custom calling convention
268+
PyErr_Clear();
269+
270+
_oCallingConvention = oCallingConvention(args, _eReturnType);
271+
_pCallingConvention = extract<ICallingConvention*>(_oCallingConvention);
272+
}
273+
274+
return new CFunction(m_ulAddr, _eCallingConvention, _iCallingConvention, _oCallingConvention, _pCallingConvention, _tArgs, _eReturnType, _oReturnType);
250275
}
251276

252-
CFunction* CPointer::MakeVirtualFunction(int iIndex, Convention_t eConv, object args, object return_type)
277+
CFunction* CPointer::MakeVirtualFunction(int iIndex, object oCallingConvention, object args, object return_type)
253278
{
254-
return GetVirtualFunc(iIndex)->MakeFunction(eConv, args, return_type);
279+
return GetVirtualFunc(iIndex)->MakeFunction(oCallingConvention, args, return_type);
255280
}
256281

257282
void CPointer::CallCallback(PyObject* self, char* szCallback)
@@ -301,48 +326,51 @@ void CPointer::__del__(PyObject* self)
301326
//-----------------------------------------------------------------------------
302327
// CFunction class
303328
//-----------------------------------------------------------------------------
304-
CFunction::CFunction(unsigned long ulAddr, Convention_t eConv, object args, object return_type)
305-
: CPointer(ulAddr)
329+
CFunction::CFunction(unsigned long ulAddr, Convention_t eCallingConvention,
330+
int iCallingConvention, object oCallingConvention,
331+
ICallingConvention* pCallingConvention, tuple tArgs,
332+
DataType_t eReturnType, object oReturnType)
333+
:CPointer(ulAddr)
306334
{
307-
m_eConv = eConv;
308-
m_Args = tuple(args);
309-
m_oReturnType = return_type;
310-
311-
DataType_t eReturnType;
312-
313-
// Try to get the return type
314-
try
315-
{
316-
eReturnType = extract<DataType_t>(m_oReturnType);
317-
}
318-
catch( ... )
319-
{
320-
PyErr_Clear();
335+
m_eCallingConvention = eCallingConvention;
336+
m_iCallingConvention = iCallingConvention;
337+
m_oCallingConvention = oCallingConvention;
338+
m_pCallingConvention = pCallingConvention;
339+
m_tArgs = tArgs;
340+
m_eReturnType = eReturnType;
341+
m_oReturnType = oReturnType;
342+
}
321343

322-
// It failed, so let's handle it as a pointer
323-
eReturnType = DATA_TYPE_POINTER;
324-
}
344+
bool CFunction::IsCallable()
345+
{
346+
return (m_eCallingConvention != CONV_NONE) && (m_iCallingConvention != -1);
347+
}
325348

326-
m_pCallingConvention = MakeDynamicHooksConvention(eConv, ObjectToDataTypeVector(args), eReturnType);
349+
bool CFunction::IsHookable()
350+
{
351+
return m_pCallingConvention != NULL;
327352
}
328353

329354
object CFunction::Call(tuple args, dict kw)
330355
{
356+
if (!IsCallable())
357+
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function is not callable.")
358+
331359
if (!IsValid())
332360
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function pointer is NULL.")
333361

334-
if (len(args) != len(m_Args))
362+
if (len(args) != len(m_tArgs))
335363
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Number of passed arguments is not equal to the required number.")
336364

337365
// Reset VM and set the calling convention
338366
dcReset(g_pCallVM);
339-
dcMode(g_pCallVM, GetDynCallConvention(m_eConv));
367+
dcMode(g_pCallVM, m_iCallingConvention);
340368

341369
// Loop through all passed arguments and add them to the VM
342370
for(int i=0; i < len(args); i++)
343371
{
344372
object arg = args[i];
345-
switch(extract<DataType_t>(m_Args[i]))
373+
switch(extract<DataType_t>(m_tArgs[i]))
346374
{
347375
case DATA_TYPE_BOOL: dcArgBool(g_pCallVM, extract<bool>(arg)); break;
348376
case DATA_TYPE_CHAR: dcArgChar(g_pCallVM, extract<char>(arg)); break;
@@ -369,23 +397,8 @@ object CFunction::Call(tuple args, dict kw)
369397
}
370398
}
371399

372-
DataType_t return_type;
373-
374-
// Try to get the return type
375-
try
376-
{
377-
return_type = extract<DataType_t>(m_oReturnType);
378-
}
379-
catch( ... )
380-
{
381-
PyErr_Clear();
382-
383-
// It failed, so let's handle it as a pointer
384-
return m_oReturnType(ptr(new CPointer(dcCallPointer(g_pCallVM, m_ulAddr))));
385-
}
386-
387400
// Call the function
388-
switch(return_type)
401+
switch(m_eReturnType)
389402
{
390403
case DATA_TYPE_VOID: dcCallVoid(g_pCallVM, m_ulAddr); break;
391404
case DATA_TYPE_BOOL: return object(dcCallBool(g_pCallVM, m_ulAddr));
@@ -401,7 +414,13 @@ object CFunction::Call(tuple args, dict kw)
401414
case DATA_TYPE_ULONG_LONG: return object((unsigned long long) dcCallLongLong(g_pCallVM, m_ulAddr));
402415
case DATA_TYPE_FLOAT: return object(dcCallFloat(g_pCallVM, m_ulAddr));
403416
case DATA_TYPE_DOUBLE: return object(dcCallDouble(g_pCallVM, m_ulAddr));
404-
case DATA_TYPE_POINTER: return object(ptr(new CPointer(dcCallPointer(g_pCallVM, m_ulAddr))));
417+
case DATA_TYPE_POINTER:
418+
{
419+
CPointer* pPtr = new CPointer(dcCallPointer(g_pCallVM, m_ulAddr));
420+
if (!m_oReturnType.is_none())
421+
return m_oReturnType(ptr(pPtr));
422+
return object(ptr(pPtr));
423+
}
405424
case DATA_TYPE_STRING: return object((const char *) dcCallPointer(g_pCallVM, m_ulAddr));
406425
default: BOOST_RAISE_EXCEPTION(PyExc_TypeError, "Unknown return type.")
407426
}
@@ -410,42 +429,38 @@ object CFunction::Call(tuple args, dict kw)
410429

411430
object CFunction::CallTrampoline(tuple args, dict kw)
412431
{
432+
if (!IsCallable())
433+
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function is not callable.")
434+
413435
if (!IsValid())
414436
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function pointer is NULL.")
415437

416438
CHook* pHook = GetHookManager()->FindHook((void *) m_ulAddr);
417439
if (!pHook)
418440
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function was not hooked.")
419441

420-
return CFunction((unsigned long) pHook->m_pTrampoline, m_eConv, m_Args, m_oReturnType).Call(args, kw);
442+
return CFunction((unsigned long) pHook->m_pTrampoline, m_eCallingConvention,
443+
m_iCallingConvention, m_oCallingConvention, m_pCallingConvention, m_tArgs,
444+
m_eReturnType, m_oReturnType).Call(args, kw);
421445
}
422446

423447
handle<> CFunction::AddHook(HookType_t eType, PyObject* pCallable)
424448
{
449+
if (!IsHookable())
450+
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function is not hookable.")
451+
425452
if (!IsValid())
426453
BOOST_RAISE_EXCEPTION(PyExc_ValueError, "Function pointer is NULL.")
427454

428-
// Generate the argument string
429-
DataType_t return_type;
430-
try
431-
{
432-
return_type = extract<DataType_t>(m_oReturnType);
433-
}
434-
catch ( ... )
435-
{
436-
PyErr_Clear();
437-
return_type = DATA_TYPE_POINTER;
438-
}
439-
440455
// Hook the function
441456
CHook* pHook = GetHookManager()->HookFunction((void *) m_ulAddr, m_pCallingConvention);
442-
457+
443458
// Add the hook handler. If it's already added, it won't be added twice
444-
pHook->AddCallback(eType, (HookHandlerFn *) &SP_HookHandler);
445-
459+
pHook->AddCallback(eType, (HookHandlerFn *) (void *) &SP_HookHandler);
460+
446461
// Add the callback to our map
447462
g_mapCallbacks[pHook][eType].push_back(pCallable);
448-
463+
449464
// Return the callback, so we can use this method as a decorator
450465
return handle<>(borrowed(pCallable));
451466
}

src/core/modules/memory/memory_tools.h

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,11 +140,22 @@ inline void UTIL_Dealloc(void* ptr)
140140
#endif
141141
}
142142

143+
inline std::vector<DataType_t> ObjectToDataTypeVector(object oArgTypes)
144+
{
145+
std::vector<DataType_t> vecArgTypes;
146+
for(int i=0; i < len(oArgTypes); i++)
147+
{
148+
vecArgTypes.push_back(extract<DataType_t>(oArgTypes[i]));
149+
}
150+
return vecArgTypes;
151+
}
152+
143153
//-----------------------------------------------------------------------------
144154
// Convention enum
145155
//-----------------------------------------------------------------------------
146156
enum Convention_t
147157
{
158+
CONV_NONE,
148159
CONV_CDECL,
149160
CONV_THISCALL,
150161
CONV_STDCALL
@@ -233,8 +244,8 @@ class CPointer
233244
virtual CPointer* Realloc(int iSize);
234245
virtual void Dealloc() { UTIL_Dealloc((void *) m_ulAddr); m_ulAddr = 0; }
235246

236-
CFunction* MakeFunction(Convention_t eConv, boost::python::object args, object return_type);
237-
CFunction* MakeVirtualFunction(int iIndex, Convention_t eConv, boost::python::object args, object return_type);
247+
CFunction* MakeFunction(object oCallingConvention, object args, object return_type);
248+
CFunction* MakeVirtualFunction(int iIndex, object oCallingConvention, object args, object return_type);
238249

239250
static void CallCallback(PyObject* self, char* szCallback);
240251
static void PreDealloc(PyObject* self);
@@ -253,7 +264,12 @@ class CPointer
253264
class CFunction: public CPointer
254265
{
255266
public:
256-
CFunction(unsigned long ulAddr, Convention_t eConv, boost::python::object args, object return_type);
267+
CFunction(unsigned long ulAddr, Convention_t eCallingConvention, int iCallingConvention,
268+
object oCallingConvention, ICallingConvention* pCallingConvention,
269+
boost::python::tuple tArgs, DataType_t eReturnType, object oReturnType);
270+
271+
bool IsCallable();
272+
bool IsHookable();
257273

258274
object Call(boost::python::tuple args, dict kw);
259275
object CallTrampoline(boost::python::tuple args, dict kw);
@@ -274,9 +290,20 @@ class CFunction: public CPointer
274290
{ RemoveHook(HOOKTYPE_POST, pCallable); }
275291

276292
public:
277-
boost::python::tuple m_Args;
293+
boost::python::tuple m_tArgs;
278294
object m_oReturnType;
279-
Convention_t m_eConv;
295+
DataType_t m_eReturnType;
296+
297+
// Shared built-in calling convention identifier
298+
Convention_t m_eCallingConvention;
299+
300+
// DynCall calling convention
301+
int m_iCallingConvention;
302+
303+
// Custom DynamicHooks calling convention
304+
object m_oCallingConvention;
305+
306+
// DynamicHooks calling convention (built-in and custom)
280307
ICallingConvention* m_pCallingConvention;
281308
};
282309

0 commit comments

Comments
 (0)