-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathDetours.cpp
150 lines (115 loc) · 4.87 KB
/
Detours.cpp
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
namespace Detours
{
bool DetourCopyMemory(uintptr_t Target, uintptr_t Memory, size_t Length)
{
auto pvTarget = reinterpret_cast<void*>(Target);
auto pvMemory = reinterpret_cast<void*>(Memory);
DWORD dwOld = 0;
if (!VirtualProtect(pvTarget, Length, PAGE_EXECUTE_READWRITE, &dwOld))
return false;
memcpy(pvTarget, pvMemory, Length);
// Ignore if this fails, the memory was copied either way
VirtualProtect(pvTarget, Length, dwOld, &dwOld);
return true;
}
uintptr_t IATThunkHook(uintptr_t Module, PIMAGE_THUNK_DATA NameTable, PIMAGE_THUNK_DATA ImportTable, const char* API, uintptr_t Detour)
{
for (; NameTable->u1.Ordinal != 0; ++NameTable, ++ImportTable)
{
if (!IMAGE_SNAP_BY_ORDINAL(NameTable->u1.Ordinal))
{
auto importName = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(Module + NameTable->u1.ForwarderString);
auto funcName = &importName->Name[0];
// If this is the function name we want, hook it
if (!strcmp(funcName, API))
{
// Copy the pointer variable itself, not the function bytes
uintptr_t originalFunc = ImportTable->u1.AddressOfData;
uintptr_t newPointer = Detour;
if (!DetourCopyMemory(reinterpret_cast<uintptr_t>(&ImportTable->u1.AddressOfData), reinterpret_cast<uintptr_t>(&newPointer), sizeof(ImportTable->u1.AddressOfData)))
return 0;
// Done
return originalFunc;
}
}
}
return 0;
}
uintptr_t IATHook(uintptr_t Module, const char* ImportModule, const char* API, uintptr_t Detour)
{
auto dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(Module);
auto ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(Module + dosHeader->e_lfanew);
// Validate PE Header and (64-bit|32-bit) module type
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return 0;
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
return 0;
if (ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
return 0;
// Get the load configuration section which holds the imports
auto dataDirectory = ntHeaders->OptionalHeader.DataDirectory;
auto sectionRVA = dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
auto sectionSize = dataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
if (sectionRVA == 0 || sectionSize == 0)
return 0;
// https://jpassing.com/2008/01/06/using-import-address-table-hooking-for-testing/
// https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/interception/interception_win.cc
//
// Iterate over each import descriptor
auto importDescriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(Module + sectionRVA);
for (size_t i = 0; importDescriptor[i].Name != 0; i++)
{
auto dllName = reinterpret_cast<PSTR>(Module + importDescriptor[i].Name);
// Is this the specific module the user wants?
if (!_stricmp(dllName, ImportModule))
{
if (!importDescriptor[i].FirstThunk)
return 0;
auto nameTable = reinterpret_cast<PIMAGE_THUNK_DATA>(Module + importDescriptor[i].OriginalFirstThunk);
auto importTable = reinterpret_cast<PIMAGE_THUNK_DATA>(Module + importDescriptor[i].FirstThunk);
auto originalFunc = IATThunkHook(Module, nameTable, importTable, API, Detour);
if (!originalFunc)
continue;
return originalFunc;
}
}
// API or module name wasn't found
return 0;
}
uintptr_t IATDelayedHook(uintptr_t Module, const char* ImportModule, const char* API, uintptr_t Detour)
{
auto dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(Module);
auto ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(Module + dosHeader->e_lfanew);
// Validate PE Header and (64-bit|32-bit) module type
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return 0;
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE)
return 0;
if (ntHeaders->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
return 0;
// Get the load configuration section which holds the imports
auto dataDirectory = ntHeaders->OptionalHeader.DataDirectory;
auto sectionRVA = dataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress;
auto sectionSize = dataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size;
if (sectionRVA == 0 || sectionSize == 0)
return 0;
// Iterate over each delayed import descriptor
auto importDescriptor = reinterpret_cast<PIMAGE_DELAYLOAD_DESCRIPTOR>(Module + sectionRVA);
for (size_t i = 0; importDescriptor[i].DllNameRVA != 0; i++)
{
auto dllName = reinterpret_cast<PSTR>(Module + importDescriptor[i].DllNameRVA);
// Is this the specific module the user wants?
if (!_stricmp(dllName, ImportModule))
{
auto nameTable = reinterpret_cast<PIMAGE_THUNK_DATA>(Module + importDescriptor[i].ImportNameTableRVA);
auto importTable = reinterpret_cast<PIMAGE_THUNK_DATA>(Module + importDescriptor[i].ImportAddressTableRVA);
auto originalFunc = IATThunkHook(Module, nameTable, importTable, API, Detour);
if (!originalFunc)
continue;
return originalFunc;
}
}
// API or module name wasn't found
return 0;
}
}