Log in

View Full Version : Run-time resolution of C++ virtual function addresses


Admiral
December 1st, 2007, 18:54
Perhaps this is a bit of a long-shot, but I don't suppose anybody knows of, or can work out a better way to determine the address of a virtual function than the one I'm currently using. I've searched high and low, and it seems that there is no 'C++' way to do it, via creative casting or suchlike. Of this I'm pretty sure. It's not the inline-assembly I'm scared of, just the hacky nature of my 'simplest' solution:

I have only analysed Visual C++ 2005 EE's output code, but in this case the compiler generates a v-table for each class instance, and the linker resolves the function calls to an effective CALL DWORD PTR. Since there is no need to hang on to the function names after linking, the intermediate data is discarded, making things rather difficult for those of us who want to do the same thing at run-time (as each call reduces to a seemingly arbitrary offset into the v-table, which is liable to change in newer builds).

In all the cases I encountered - and I have no concrete evidence to safely generalise this - the auto-generated code loads the function address into one of the four general-purpose registers and subsequently calls it from there. So my best efforts amount to this:

1. Write some code to ensure that a call to the virtual function gets compiled, but assemble in a JMP to prevent it executing.
2. Make an appropriate call to VirtualProtect and patch over the CALL R32, replacing it with a JMP to a safe location.
3. Using a switch-statement on the operand just patched over, determine which register will now contain the desired address and extract it to a local variable.
4. Remove the patch and reset the access.
5. Restore the stack-pointer to account for any parameters that may have been pushed but not popped (as the thiscall convention requires the callee to balance the stack, when it was never executed in this case).

This works, but that's about all it has going for it. Clearly, it's a nasty hack for a seemingly simple operation, but I can't seem to improve on it. Normally I'd be happy to grin and bear it, but the nature of the patch means that I no longer take advantage of Visual C++'s run-time stack frame checks, as the asymmetric 'call' compromises ESP (albeit innocently and harmlessly) and I inevitably get a run-time error. I've poked around, but there isn't enough room in the disassembly to safely circumvent the sanity check, and even if there were I wouldn't want to have to write extra code to determine whether it needs doing or not.

And so I'm all out of ideas. Any suggestions?

Thanks
Admiral

dELTA
December 4th, 2007, 12:11
Hey Admiral, nice to see you around again.

More exactly in what situation do you want to do this? In your own program or in someone else's where you only have the compiled code?

I don't have very much experience with vtables, just thinking generally here, but do you really need to patch any code to be able to resolve the address? Couldn't you e.g. instead compile in a "signature" before all the calls to different functions you have created (even containing the name of the function in question if you like), and then resolve them all in-memory from a single and completely other place in the program, by scanning the code segment for the signature and then emulating the program's own vtable address resolve code for each of them, thus easily and quickly building a table of all the function addresses without having to patch or prod anything at all inside the program?

I'm quite sure I missed something here, but anyway, let me know what, and I'll gladly come back with some additional stupid ideas...

OHPen
December 4th, 2007, 14:26
Hi admiral,

im not sure whether i get the point but let us take this wikipedia example:

http://en.wikipedia.org/wiki/Virtual_function

if i assume correct that you try to get eat functions address at runtime of class wolf according to the example mentioned above why not simply registering a veh handler during your applications startup which will handle invalid instructions.
Then assemble an invalid instruction at the beginning of each function you need to resolve the address.
Once for example eat function of wolf class is executed the handler will be triggered by the raised exception and you can do nothing more than resolving the address by calculating (exception address - length of your invalid opcode).
This should then be the address of the eat function in wolf class.
The handler should also fix the invalid instruction by nooping it.

dunno whether this is a possible solution for you, but i thought why not give it a try
also dunno whether that stack thingy you were talking of will be still working after such a "trick".
the only thing i know is that the question is kind of complicated

regards,

OHPen aka PAPiLLiON

PS: This technique should be also work with c++ in-house-means. raising an exception and nooping the exception cause should be not problem at all. so no need to use inline assembly.

Admiral
December 5th, 2007, 13:46
Thanks for the replies.

Unfortunately, I'm still at a loss, but that's my fault. I should have given some context, in retrospect. Better late than never:

The virtual functions whose addresses I'm trying to determine are not mine, but belong to the Direct3D library distributed in the DirectX SDK. Moreover, I am attempting to patch them from a DLL injected into an existing process, so compiling invalid instructions is no-go.

My DLL (written in C++) dynamically links to Direct3D, so all my calls to its interfaces are resolved at load-time (i.e. during injection). So there's no problem calling these functions, but the trouble starts when I want to patch in a soft hook. Ideally, there would be some kind of hybrid between C++'s dynamic_cast and reinterpret_cast that I could use but it turns out that C++ forbids this kind of behaviour, and I guess it's right to do so.

The ultimate goal is to produce a Direct3D hooking framework for rendering overlays on existing game's viewports. It's pretty much finished, but I was hoping for something cleaner than hard-coding DLL offsets. If you're interested, take a look here:

http://www.ring3circus.com/gameprogramming/drawing-on-another-direct3d-programs-viewport/

Don't sweat over this one too much, as it's a low-priority problem and I already have a working solution. Thanks for the help all the same.

Admiral

dELTA
December 5th, 2007, 16:24
I'm probably still missing something important here, but looking at your code (here: http://www.ring3circus.com/gameprogramming/run-time-determination-of-vc-2005-virtual-member-function-addresses/) and reading your posts above repeatedly, I still don't understand why my completely static method wouldn't work? Anyway, I think the best way to find out where we I might be misunderstanding the problem would be for you to point out why my method wouldn't work, and at some point during that discussion we will understand each other, and thus be able to better work together to solve the problem.

I really like to solve problems like this, so it's no problem at all, please just tell me where my current suggestion fails, so I can continue the pursuit now.

Oh, btw, you might be interested in skimming through the following threads, in regards to the subject of your project in general:

http://www.woodmann.com/forum/showthread.php?t=10033

http://www.woodmann.com/forum/showthread.php?t=6310

http://www.woodmann.com/forum/showthread.php?t=9600

http://www.woodmann.com/forum/showthread.php?t=7850

Looking forward to your reply.

Admiral
December 5th, 2007, 19:57
Sorry for ignoring you there, dELTA

I did consider your approach, but it turns out to be trickier to get working than you may think. Not to say that it isn't possible, but once you've accounted for all the potential gotchas, there isn't much in the way of improvement:

Code:
// Virtual function call #1
00411808 |. 6A 00 PUSH 0
0041180A |. 6A 10 PUSH 10
0041180C |. 8D45 DC LEA EAX, [LOCAL.9]
0041180F |. 50 PUSH EAX
00411810 |. 8D4D DC LEA ECX, [LOCAL.9]
00411813 |. 51 PUSH ECX
00411814 |. 8B15 78914100 MOV EDX, DWORD PTR DS:[419178]
0041181A |. 8B02 MOV EAX, DWORD PTR DS:[EDX]
0041181C |. 8B0D 78914100 MOV ECX, DWORD PTR DS:[419178]
00411822 |. 51 PUSH ECX
00411823 |. 8B50 44 MOV EDX, DWORD PTR DS:[EAX+44]
00411826 |. FFD2 CALL EDX


// Virtual function call #2
00411828 |. 6A 00 PUSH 0
0041182A |. 51 PUSH ECX
0041182B |. D905 B0784100 FLD DWORD PTR DS:[4178B0]
00411831 |. D91C24 FSTP DWORD PTR SS:[ESP]
00411834 |. 6A 00 PUSH 0
00411836 |. 6A 00 PUSH 0
00411838 |. 8D45 EC LEA EAX, [LOCAL.5]
0041183B |. 50 PUSH EAX
0041183C |. 6A 00 PUSH 0
0041183E |. 8B0D 78914100 MOV ECX, DWORD PTR DS:[419178]
00411844 |. 8B11 MOV EDX, DWORD PTR DS:[ECX]
00411846 |. A1 78914100 MOV EAX, DWORD PTR DS:[419178]
0041184B |. 50 PUSH EAX
0041184C |. 8B8A AC000000 MOV ECX, DWORD PTR DS:[EDX+AC]
00411852 |. FFD1 CALL ECX


The first problem is that unless we hand-code each example, there's no safe way to determine how many parameters the function takes. Even if we knew, we'd also need to be sure of their types and values, as different PUSH instructions have different lengths. This really isn't a big deal though, as we could just as easily put the signature bytes after the call and work backwards.

The next small problem is the discrepancy between release- and debug-builds. If you look at the three MOVs preceding the final PUSH in each case, you'll notice that the first and third are always the same. This is simply the compiler dereferencing the 'this' pointer twice - once to get the vtable address, and again to pass 'this' according to the thiscall convention. The redundant operation is a clear candidate for optimisation, and as it happens, that final MOV is missing in a release-mode assembly. Again, we can fix this with relative ease by handling the two cases separately via '#ifdef _DEBUG', so we're still smiling.

The real problem, though - and it's a very frustrating margin case - is that the assembly changes in a rather nasty way when the function being called is the first in the vtable. The penultimate instruction in the assembly is

MOV EDX, DWORD PTR DS:[R32+OFFSET]

where OFFSET is the index of the virtual function into the vtable. Now, if we knew how these offsets mapped to the functions then there would be no problem, but the compiler keeps them secret and the linker destroys all the evidence .

This instruction can be deconstructed easily enough, but if the first vtable function is being called then OFFSET is zero and we get an entirely different form of MOV - with a different operand size - being assembled. Once again, a switch-statement could sort us out, but it's all starting to get a little complicated, especially considering that we need to account for this by counting backwards from the end of the MOV, not forward from the beginning. All of a sudden, your emulation method starts to look about as complicated as my simulation.

Admittedly, this jiggerypokery is preferable to the nasty SMC approach I came up with, but it's still not exactly elegant. I guess I was hoping there would be an even simpler method. I'm not missing something simple, am I?

Cheers
Admiral

dELTA
December 6th, 2007, 04:03
Ah, I was afraid of something like that. But I also wasn't sure about the obvious "sorting order" for how "simple" or "non-hacky" a solution in this case would be rated as. I assumed that a fully static solution (which thus e.g. doesn't muck up ESP either, which you mention as a problem above) might possibly be considered better than one involving patching and running code, but I'm also aware that this solution might be uglier in other aspects, absolutely. The cleanest solution would of course, as you mention, be a fully compile-time C++ based one, but I'm not really that good at C++, so I can't sadly come with any good suggestions there (and as you say, it might just not be possible at all from there either).

Anyway, another idea that comes to mind is using debug information/symbols? As far as I've understood this, you create your own DLL, which you have full control over, source code-wise and binary-wise, right? Can't you include full debug/symbol data in this DLL, and wouldn't this possibly make the linker not destroy all instances of the desired vtable offset information (or otherwise annotate the calls)? And in that case, couldn't you just parse this debug/symbol information during runtime to easily and robustly get all the information you seek?

_wh_
December 6th, 2007, 06:27
maybe i missed something...

But you can just patch the Vtable pointer.

1)
alloc memory for the VTABLE
2)
copy the org_vtable pinter to this memory
3)
patch the pointer in the d3d device object to your alloced memory
*((DWORD*)this)=VTABLE;
4)
now you can replace there any function.

e.g.
VTABLE[table_offset]=DevicePresentHook;

--

a ready to compile solution is
http://forum.gamedeception.net/showthread.php?t=7681

Admiral
December 6th, 2007, 11:21
_wh_, that's the natural way to redirect virtual functions once you know their offsets into the vtable, but my problem is exactly that: determining the vtable index for a function from its compile-time name.

dELTA, that's the perfect solution provided you have the library definition at hand - and I do . Considering that's what debug symbols were invented for, I'm a little worried that it never even occurred to me . I guess, once a reverser, always a reverser. So sure enough, that's what I'll do. Though I must admit that it feels a little dissatisfying - starting off with a good excuse to hack some code, and ending up with an elementary lesson in symbol-parsing

Thanks for everything. I forgot how helpful the members of this forum really are
Admiral

dELTA
December 6th, 2007, 11:28
Hehe, glad I could help, and sorry to remove the reason for you to do low-level hacks (this time anyway, I'll try to make up for it next time, I promise ).

Oh, and forgetting about us indicates that you're not hanging around here quite enough, so I hope that will change, your contributions are always very welcome.

naides
December 6th, 2007, 12:35
Keep in mind,
and write it in your resumee:

A code reverser is a
highly trained,
fiercely determined,
always creative,
resourceful,
ingenious,

Problem Solver

Vuurvlieg
December 9th, 2007, 18:51
I also had the same problem as Admiral described so I did make some low-level hack for this which is probably very compiler specific. Also it does not work for all classes with virtual functions, I made it specifically to get the D3D virtual function addresses. I am not entirely sure anymore but I believe I tested it on ms visual studio 6 / 2003/ 2005.

Code:

#if _MSC_VER >= 1400
#define _D3DM(m) (&m)
#else
#define _D3DM(m) (m)
#endif

PBYTE __declspec( naked ) GetD3DFunction( IDirect3DDevice9* pDevice, ... )
{
_asm
{
push ebx
mov eax, dword ptr ss:[esp+0x0C]
add eax, 0x8
cmp byte ptr ds:[eax-0x1], 0xA0
mov eax, dword ptr ds:[eax]
je _normal_index
and eax, 0xFF
_normal_index:
mov ebx, eax
mov eax, dword ptr ss:[esp+0x8]
mov eax, dword ptr ds:[eax]
mov eax, dword ptr ds:[eax+ebx]
pop ebx
retn
}
}

//and then in some pseudo you can do like:
HookFunction( GetD3DFunction( g_pD3Ddev, D3DM( IDirect3DDevice9::Present ) ), (PBYTE)&My_IDirectD3D9Present );


Admiral
December 9th, 2007, 20:10
That's very clever, Vuurvlieg

Using a variadic function to avoid typing problems, and declaring the function with __declspec(naked) to prevent a prologue being generated are tricks I would probably never have though of. Also, by means of a simple cast this can be made to work with any class.

Great job
Admiral

JMI
December 9th, 2007, 20:14
And, of course, thanks for sharing it with our readers!

Regards,