-
Notifications
You must be signed in to change notification settings - Fork 445
/
Copy pathwow64layer.h
229 lines (187 loc) · 5.18 KB
/
wow64layer.h
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*
#ifndef CONTEXT_i386
#define CONTEXT_i386 0x00010000 // this assumes that i386 and
#define CONTEXT_i486 0x00010000 // i486 have identical context records
#endif
#define WOW64_CS32 0x23*/
#include <Windows.h>
BOOL XP_GetThreadWow64Context(
__in HANDLE Thread,
__in_opt HANDLE Process,
__inout PWOW64_CONTEXT Ctx32
)
{
THREAD_BASIC_INFORMATION ThreadInfo;
PWOW64_CONTEXT RemoteCtx;
CONTEXT Ctx64;
SIZE_T Transferred;
ULONG ContextFlags;
BOOLEAN CloseProcess;
ULONG LastError;
CloseProcess = FALSE;
Ctx64.ContextFlags = CONTEXT_ALL;
//
// Determine whether the thread is running in 64-bit mode or not. If it is
// running in 64-bit mode then we'll get the saved 32-bit context out of
// the pointer in the 64-bit TEB's TLS slot.
//
// If, however, the thread is running in 32-bit mode, then we'll need to be
// converting the 32-bit halves of the 64-bit registers into the
// appropriate fields of the WOW64_CONTEXT structure.
//
if (!GetThreadContext(
Thread,
&Ctx64))
return FALSE;
if (Ctx64.SegCs != WOW64_CS32)
{
wprintf(L" -- Target is in 64-bit mode, returning saved 32-bit context\n");
//
// The thread is running in 64-bit mode. We'll need to find the base
// address of the thread's TEB and from there, read the remote TLS
// slots and then the actual WOW64_CONTEXT structure residing within
// the target.
//
// Also, if the caller didn't supply a process handle, then we'll
// attempt to open one now using the thread's associated process ID in
// the THREAD_BASIC_INFORMATION structure. This is the typical
// behavior of the Wow64 implementation of GetThreadContext.
//
if (!NT_SUCCESS(NtQueryInformationThread(
Thread,
ThreadBasicInformation,
&ThreadInfo,
sizeof( THREAD_BASIC_INFORMATION ),
0
)))
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
//
// If we don't have a process handle then we'll need to be opening one
// ourselves for the VM read operation.
//
if (!Process)
{
Process = OpenProcess(
PROCESS_VM_READ,
FALSE,
HandleToUlong(ThreadInfo.ClientId.UniqueProcess)
);
if (!Process)
return FALSE;
CloseProcess = TRUE;
}
//
// Fetch the second TLS slot. Wow64 assumes (hardcoded) that the
// second TLS slot is the WOW64_CONTEXT. This is a bit sloppy, but it
// works out as there's not a 64-bit kernel32.dll loaded in a Wow64
// process, so there won't be anyone calling TlsAlloc anyway.
//
if (!ReadProcessMemory(
Process,
&((PTEB)ThreadInfo.TebBaseAddress)->TlsSlots[ 1 ],
&RemoteCtx,
sizeof( PWOW64_CONTEXT ),
&Transferred))
{
if (CloseProcess)
{
LastError = GetLastError();
CloseHandle( Process );
SetLastError( LastError );
}
return FALSE;
}
if (Transferred != sizeof( PWOW64_CONTEXT ))
{
if (CloseProcess)
CloseHandle( Process );
SetLastError( ERROR_PARTIAL_COPY );
return FALSE;
}
//
// Now that we've got the PWOW64_CONTEXT pointer, let's read the memory
// where the actual context is stored.
//
// Note that this is unreliable if the remote thread is still running
// when we make the call.
//
//
// TODO: Pay attention to the caller's requested context flags and
// filter the returned context appropriately.
//
if (!ReadProcessMemory(
Process,
(PUCHAR)(RemoteCtx) + sizeof( ULONG ),
Ctx32,
sizeof( WOW64_CONTEXT ),
&Transferred
))
{
if (CloseProcess)
{
LastError = GetLastError();
CloseHandle( Process );
SetLastError( LastError );
}
return FALSE;
}
if (Transferred != sizeof( WOW64_CONTEXT ))
{
if (CloseProcess)
CloseHandle( Process );
SetLastError( ERROR_PARTIAL_COPY );
return FALSE;
}
//
// All done.
//
}
else
{
wprintf(L" -- Target is in 32-bit mode, truncating 64-bit registers\n");
//
// The requested thread is executing 32-bit instructions and is not in
// the Wow64 layer (e.g. a system call). This means that the 64-bit
// thread context is actually reflective of the Wow64 context, except
// that we need to convert from an x64 context strucuture to the
// WOW64_CONTEXT structure (the high halves of registers are discarded
// here).
//
ContextFlags = Ctx32->ContextFlags | CONTEXT_i386;
ZeroMemory(
Ctx32,
sizeof( WOW64_CONTEXT )
);
Ctx32->ContextFlags = ContextFlags;
if (ContextFlags & CONTEXT_CONTROL)
{
Ctx32->Eip = (ULONG)Ctx64.Rip;
Ctx32->EFlags = (ULONG)Ctx64.EFlags;
Ctx32->Esp = (ULONG)Ctx64.Rsp;
Ctx32->Ebp = (ULONG)Ctx64.Rbp;
}
if (ContextFlags & CONTEXT_INTEGER)
{
Ctx32->Eax = (ULONG)Ctx64.Rax;
Ctx32->Ebx = (ULONG)Ctx64.Rbx;
Ctx32->Ecx = (ULONG)Ctx64.Rcx;
Ctx32->Edx = (ULONG)Ctx64.Rdx;
Ctx32->Edi = (ULONG)Ctx64.Rdi;
Ctx32->Esi = (ULONG)Ctx64.Rsi;
}
//
// TODO: Convert other registers, pay attention to the caller's
// requested context flags. For example, floating point registers
// would need to be handled here if support for them is desired.
//
//
// All done.
//
}
if (CloseProcess)
CloseHandle( Process );
return TRUE;
}