josh's answer is a good one, but one thing to note is that there is an alternative scheme that (usually) does not require inline assembly, and which handles the virtual functions case also. This is how I prefer to interact with C++ programs when I'm doing DLL injection/code reuse like your question is asking.
Begin by defining something for the class whose methods you want to call. If you know the full class declaration, recreate it in your calling program. If you know less than that -- say, you only know the size of the class -- you can do something like:
class MyClass {
public:
char mData[0x80]; // sizeof(MyClass) = 0x80
};
(If you don't know the size of the class, pick a large number in place of 0x80
and hope for the best. If the program crashes, pick a larger number and try again. Really though, try to figure out the size of the class, at minimum.)
Now, we can use member function pointers to force the compiler to set ecx
(the this
) pointer for us during the function pointer call. Namely:
typedef void (MyClass::*FuncToCall)(int arg1, void *arg2);
Similarly to josh's answer, now we want to cast the raw address of the member function in the DLL to a member function pointer of that type, and then call it:
#define FUNC_OFFSET 0x4320
FuncToCall f = (FuncToCall)((byte*)pDLL + FUNC_OFFSET);
MyClass *m = new MyClass();
m->*f(123, NULL); // member function pointer invocation syntax
EDITED TO NOTE: in my original answer, I'd forgotten to note that C++ is not as liberal about accepting casts of arbitrary types to member function pointers as C is about casting to ordinary function pointers. That is to say, the code in the below won't work directly; you'll need to basically twist the compiler's arm to make it work, but it is doable. See this StackExchange discussion of the situation. One of the answers proposes using a union
, which is what I've typically done. See these two blog entries by Raymond Chen discussing why C++ is less tolerant about casts involving member function pointers (TL;DR multiple inheritance): one, two. Finally, here's an example of how I used these techniques in a recent project.
ORIGINAL TEXT CONTINUES HERE: You can even wrap this up into a proxy stub function:
#define FUNC1_OFFSET 0x4320
// Global function pointer(s)
// Note: these are GLOBAL variables, not class members
FuncToCall gfp_MemFunc1;
// Relocate all necessary addresses
// Call this once before calling member function pointers
void Init(byte *pDLL) {
gfp_MemFunc1 = (FuncToCall)(pDLL + FUNC1_OFFSET);
}
class MyClass {
public:
char mData[0x80];
// Make stub functions for members you want to call
// Does not affect the layout of the class
void MemFunc1Proxy(int arg1, void *arg2) {
this->*gfp_MemFunc1(arg1, arg2);
};
};
int main() {
MyClass m();
Init(/* address of DLL */);
// Call member functions easily via stubs
m.MemFunc1Proxy(123,NULL);
}
For virtual functions, there are two cases. In both cases, you'll need to add compatible virtual function delcarations (in the proper order) to the mock class declaration. Something like:
class MyClass {
public:
char mData[0x80];
virtual void ~MyClass();
virtual int VFunc0x4(int);
};
Now, as for the two different cases. First case: if you're able to call a function in the DLL to obtain an instantiated instance of your object, that's all you need; call a virtual function as follows:
MyClass *p = fpDLLFuncThatAllocatesMyClass();
int x = p->VFunc0x4(1);
If it's not easy or feasible to obtain a memory instance for MyClass
from the DLL, you can just install its VTable yourself.
#define VTABLE_OFFSET 0x5670
MyClass *m = new MyClass();
void *VTableAddr = (byte*)pDLL + VTABLE_OFFSET;
// Set the VTable pointer to be the VTable address in the DLL
*reinterpret_cast<void *>(m) = VTableAddr;
int x = p->VFunc0x4(1);
This scheme gives you a bit more flexibility, and does not usually require inline assembly. The exception to this happens when the non-virtual member function that you want to call uses a non-standard calling convention, as happens frequently in MSVC-compiled x86. If the compiler determines that the function will not be accessed outside of the DLL, it's under no obligation to use plain __thiscall
as the calling convention, and may use alternative register argument locations. In this situation, you'll have no choice but to use inline assembly language as in josh's answer above.
this
intoecx
this
is passed in RCX.