117 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
		
		
			
		
	
	
			117 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C++
		
	
	
	
|  | //////////////////////////////////////////////////////////////////////////////
 | ||
|  | //
 | ||
|  | //  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; | ||
|  | } | ||
|  | 
 |