1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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;
}
|