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
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