Log in

View Full Version : Run-time determination of VC++ virtual member function addresses: Take II


Ring3 Circus
February 6th, 2008, 04:11
I wrote about this ("http://www.ring3circus.com/gameprogramming/run-time-determination-of-vc-2005-virtual-member-function-addresses/") tricky little problem a while ago and wasn’t too happy with the desperate methods that seemed necessary. Since then, I’ve been shown a much cleaner way to do the same thing, by manipulating the vTable manually. It seems that Microsoft haven’t changed their vTable implementation since Visual Studio 6 (at least) and so with a little modification, the following piece of inline-assembly will do the trick: no muss, no fuss.

Code:
__declspec(naked) void* ResolveVirtualFunction
(IDirect3DDevice9* pDevice, ...)
{
_asm
{
mov eax, dword ptr ss:[esp+0x0C]
add eax, 0x8
cmp byte ptr ds:[eax-1], 0xA0
mov eax, dword ptr ds:[eax]
je normal_index
and eax, 0xFF
normal_index:
mov ecx, eax
mov eax, dword ptr ss:[esp+0x8]
mov eax, dword ptr ds:[eax]
mov eax, dword ptr ds:[eax+ecx]
retn
}
}

// ...

// The function should be invoked like this:
void* address_device_present = ResolveVirtualFunction(
device, &IDirect3DDevice9::Present);
Thanks go to Vuurvlieg for this function. The beauty (or horror), here, is the use of a variadic parameter-list to overcome C++’s strong-typing that would otherwise make this operation very difficult. Obviously, this implementation will only work for objects of type IDirect3DDevice9, but the method extends to any other class by simply replacing the class name in the function declaration. Don’t be tempted to generalise this function to IUnknown or some other common base-class, as you’ll quickly run into problems with object-slicing. A final warning to those still using Visual Studio 6 (not that you deserve any help for such a crime): you’ll need to drop the ampersand from the second argument in the function call, as VS6 handles function pointers slightly differently.



http://www.ring3circus.com/gameprogramming/run-time-determination-of-vc-virtual-member-function-addresses-take-ii/

disavowed
February 7th, 2008, 00:07
Not to be too nitpicky, but... I think you mean VC++6, not VS6. (In other words, it's the compiler that handles the function pointers differently, not the IDE.)
Love your blog! Keep up the great work!

Admiral
February 9th, 2008, 12:56
For the sake of the archive, I should probably explain that the code up there doesn't actually work . I made last-minute alterations/hash-ups and it all went pear-shaped. The fixed code:

Code:
__declspec(naked) void* ResolveVirtualFunction(IDirect3DDevice9* pDevice, ...) {
__asm {
mov eax, dword ptr ss:[esp+0x08]
add eax, 0x8
cmp byte ptr ds:[eax-1], 0xA0
mov eax, dword ptr ds:[eax]
je normal_index
and eax, 0xFF
normal_index:
mov ecx, eax
mov eax, dword ptr ss:[esp+0x4]
mov eax, dword ptr ds:[eax]
mov eax, dword ptr ds:[eax+ecx]
retn
}
}


And you're quite right, disavowed. All fixed now

JMI
February 9th, 2008, 14:30
Thanks for the update!

Regards,