diff options
Diffstat (limited to 'samples/member/member.cpp')
-rw-r--r-- | samples/member/member.cpp | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/samples/member/member.cpp b/samples/member/member.cpp new file mode 100644 index 0000000..585ef98 --- /dev/null +++ b/samples/member/member.cpp @@ -0,0 +1,116 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Test a detour of a member function (member.cpp of member.exe) +// +// Microsoft Research Detours Package +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// By default, C++ member functions use the __thiscall calling convention. +// In order to Detour a member function, both the trampoline and the detour +// must have exactly the same calling convention as the target function. +// Unfortunately, the VC compiler does not support a __thiscall, so the only +// way to create legal detour and trampoline functions is by making them +// class members of a "detour" class. +// +// In addition, C++ does not support converting a pointer to a member +// function to an arbitrary pointer. To get a raw pointer, the address of +// the member function must be moved into a temporary member-function +// pointer, then passed by taking it's address, then de-referencing it. +// Fortunately, the compiler will optimize the code to remove the extra +// pointer operations. +// +// If X::Target is a virtual function, the following code will *NOT* work +// because &X::Target is the address of a thunk that does a virtual call, +// not the real address of the X::Target. You can get the real address +// of X::Target by looking directly in the VTBL for class X, but there +// is no legal way to 1) get the address of X's VTBL or 2) get the offset +// of ::Target within that VTBL. You can of course, figure these out for +// a particular class and function, but there is no general way to do so. +// +#include <stdio.h> + +#include <windows.h> +#include <detours.h> + +#include "..\slept\verify.cpp" + +//////////////////////////////////////////////////////////////// Target Class. +// +class CMember +{ + public: + void Target(void); +}; + +void CMember::Target(void) +{ + printf(" CMember::Target! (this:%p)\n", this); +} + +//////////////////////////////////////////////////////////////// Detour Class. +// +class CDetour /* add ": public CMember" to enable access to member variables... */ +{ + public: + void Mine_Target(void); + static void (CDetour::* Real_Target)(void); + + // Class shouldn't have any member variables or virtual functions. +}; + +void CDetour::Mine_Target(void) +{ + printf(" CDetour::Mine_Target! (this:%p)\n", this); + (this->*Real_Target)(); +} + +void (CDetour::* CDetour::Real_Target)(void) = (void (CDetour::*)(void))&CMember::Target; + +////////////////////////////////////////////////////////////////////////////// +// +int main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + ////////////////////////////////////////////////////////////////////////// + // + + void (CMember::* pfTarget)(void) = &CMember::Target; + void (CDetour::* pfMine)(void) = &CDetour::Mine_Target; + + Verify("CMember::Target ", *(PBYTE*)&pfTarget); + Verify("*CDetour::Real_Target", *(PBYTE*)&CDetour::Real_Target); + Verify("CDetour::Mine_Target ", *(PBYTE*)&pfMine); + + printf("\n"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&(PVOID&)CDetour::Real_Target, + *(PBYTE*)&pfMine); + + LONG l = DetourTransactionCommit(); + printf("DetourTransactionCommit = %ld\n", l); + printf("\n"); + + Verify("CMember::Target ", *(PBYTE*)&pfTarget); + Verify("*CDetour::Real_Target", *(&(PBYTE&)CDetour::Real_Target)); + Verify("CDetour::Mine_Target ", *(PBYTE*)&pfMine); + printf("\n"); + + ////////////////////////////////////////////////////////////////////////// + // + CMember target; + + printf("Calling CMember (w/o Detour):\n"); + (((CDetour*)&target)->*CDetour::Real_Target)(); + + printf("Calling CMember (will be detoured):\n"); + target.Target(); + + return 0; +} + |