From: Port Angeles, WA, USA
|i know often these is complaint on this board of not enough posts regarding technical so i decided to post this post i made for somewhere else also here.
i've been working lately on making different algorithms for calling C++ methods using pointers and all manner of things, dealing with normal methods and virtual methods..
just wanna post some of my examples here, and see if anybody likes them (though they are inline assembler examples that can easily be modified to call in memory C++ objects from ASM code in the same process, also maybe people might be able to point out some errors in my logic or understanding. b.t.w these are MSVC++ specific as other compilers probably implement things differently.. one thing to note is i haven't tested/made allowances for classes that use multiple inheritence
first issue is getting a pointer to the method. The folowing inline assembly will do it for virtual and non virtual methods, however it won't do it if you only have an empty "shell interface" definiton of the class (i.e virtual BOOL Shutdown() = 0;
If you just have a 'shell interface' though, that won't compile, and maybe you want to rather get that address from C/C++, or actually maybe you know its a virtual method, and you want to rather get it from the pointer to the instance of the class. well first lets try getting it with C++ code..
now we have a pointer to a method (but we can't actually just use that as a function pointer because of difference in calling convention. b.t.w if the function pointer is pointing to a nonvirtual method the address is the actual address of the method , however if its a virtual method.. its a pointer to a stub, that looks up the instance, and calls an entry in the virtual table (calling either this address of the actual address will both work.)
that stub always (as far as i've seen) looks like this
the only difference between each time, is the +4 or the 5th byte which is an index into the virtual table..
so i've this routine here that call be called on the address we got from the method pointer to see if it points to a virtual or non virtual method
the next thing is maybe we already know the virtual table index (quite easy to calculate by looking at the class definition since msvc++ puts everything in the order it was declared, also you can altneratively do
myobj->doit(1); in a test app, and see the Assembly that msvc++ produces (or debug the app to see it).also the offset is goign to be DWORD aligned so first method be at offset 4, 2nd at offset 8 etc..
anyhow i made this function to go inside the virtual table and get the adddress of a virtual method based on the instance and offset.
now that we can get the address of a method in many different ways.. How about calling this method..
nonstaTIC C++ methods use the THISCALL calling convention which is basically the STDCALL (called method cleans up the stack) with the hidden 'this' instance pointer also being sent, with MSVC++ the 'this' pointer is passed in ECX register.. and all the parameters like STDCALL are pushed on the the stack in right to left order. (but since the stack goes downwards, basically in memory in left to right order ) so if you want to call
this particular method manually you could do.. the return value is normally returned in eax, but 8 bit structures are returned in eax:edx, and floats are returned in ST0 - so will have to be accessed seperately, not covered in this article
however we want to make a more generic technique to call functions.. so this is the solution..
first this is how it is called.
and that is all. now here the actual code for callmethod. basically we copy the structure to the stack (as if we had pushed the parmeters backwards), put the instance of the object into ECX and call the address. and return what is returned in EAX
also if we are just calling a virtual method, and we know the offset, i combined my getvirtualaddress method with the one here to produce this
which enables you do do the following
which is really useful, but often you might get the pointer directly using other methods so "callmethod" itself is useful. There is one more technique i have done so far.. ussually it wouldn't be of use to anybody, but in my case of HOOK methods, it is absolutely essential. Early on in the article i showed getting an address to a method pointer. I also pointed out that if that method pointer points to a virtual method, it doesn't point directly to it, but rather to some stub code that looks up the actual address from the virtual table based on an offset specified in the stub code as below
for hooking purposes there isn't enough bytes (6) for me to install a safe hook, and also if i hooked this function then it would only hook calls to the method that were called through a method pointer rather that any other way. so i made a function that checks the address, and if it starts with the faith bytes 60FF018B as above it knows its this stub, and then it grabs the 5th byte as the offset, and then manually looks up the vtable itself and gets the actual address of the function. that code is below. (it has alot of comments in this one)
any comments, thoughts from you C++ types lurking in the shadows?
From: Melbourne, FL USA
|Nothing to say except that there IS a reason I blocked assembly from my memory...
Though I sort of had to get back into it for graphics.
From: Port Angeles, WA, USA
|hehe, well this is at least basic asm, not MMX,SSE2
the purpose though of this library i am building is so that C++ can use functions to achieve these things (leave the asm up to the library)..
other than maybe just having to do a simple copy and paste of say
you can do anything.
|just thought i'd say almost everysingle word of that was 10ft over my head...i could get into programming and all if there wasn't so much to it. that and the books i see are either way too beginner style, or way too complicated...anywho...later
From: Stony Plain, Alberta, Canada
|Years ago I had to write code like some of the above to allow some old Fortran code to hook into some C functions. Thanks so much for reminding me of what I never wanted to remember again.
Seriously, you have some really good stuff there, even though a lot of it is somewhat esoteric and not something I'll be using everyday. Definitely going into my "cool code" file.