-
-
Save gmh5225/ab00f831ffdf4ef608ab3b6eb0d37250 to your computer and use it in GitHub Desktop.
Create process from KernelMode via APC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typedef struct _STARTUPINFOW { | |
UINT32 cb; | |
LPWSTR lpReserved; | |
LPWSTR lpDesktop; | |
LPWSTR lpTitle; | |
UINT32 dwX; | |
UINT32 dwY; | |
UINT32 dwXSize; | |
UINT32 dwYSize; | |
UINT32 dwXCountChars; | |
UINT32 dwYCountChars; | |
UINT32 dwFillAttribute; | |
UINT32 dwFlags; | |
UINT16 wShowWindow; | |
UINT16 cbReserved2; | |
PVOID lpReserved2; | |
HANDLE hStdInput; | |
HANDLE hStdOutput; | |
HANDLE hStdError; | |
} STARTUPINFOW; | |
typedef struct _PROCESS_INFORMATION { | |
HANDLE hProcess; | |
HANDLE hThread; | |
UINT32 dwProcessId; | |
UINT32 dwThreadId; | |
} PROCESS_INFORMATION; | |
typedef struct _LDR_DATA_TABLE_ENTRY { | |
LIST_ENTRY InLoadOrderLinks; | |
LIST_ENTRY InMemoryOrderLinks; | |
LIST_ENTRY InInitializationOrderLinks; | |
PVOID DllBase; | |
PVOID EntryPoint; | |
ULONG SizeOfImage; | |
UNICODE_STRING FullDllName; | |
UNICODE_STRING BaseDllName; | |
ULONG Flags; | |
USHORT LoadCount; | |
USHORT TlsIndex; | |
LIST_ENTRY HashLinks; | |
ULONG TimeDateStamp; | |
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; | |
typedef enum _KAPC_ENVIRONMENT { | |
OriginalApcEnvironment, | |
AttachedApcEnvironment, | |
CurrentApcEnvironment, | |
InsertApcEnvironment | |
} KAPC_ENVIRONMENT; | |
typedef VOID(*PKNORMAL_ROUTINE)( | |
IN PVOID NormalContext, | |
IN PVOID SystemArgument1, | |
IN PVOID SystemArgument2); | |
typedef VOID(*PKKERNEL_ROUTINE)( | |
IN PKAPC Apc, | |
IN OUT PKNORMAL_ROUTINE* NormalRoutine, | |
IN OUT PVOID* NormalContext, | |
IN OUT PVOID* SystemArgument1, | |
IN OUT PVOID* SystemArgument2); | |
typedef VOID(*PKRUNDOWN_ROUTINE)( | |
IN PKAPC Apc); | |
extern "C" void KeInitializeApc( | |
PRKAPC Apc, | |
PRKTHREAD Thread, | |
KAPC_ENVIRONMENT Environment, | |
PKKERNEL_ROUTINE KernelRoutine, | |
PKRUNDOWN_ROUTINE RundownRoutine, | |
PKNORMAL_ROUTINE NormalRoutine, | |
KPROCESSOR_MODE ProcessorMode, | |
PVOID NormalContext); | |
extern "C" BOOLEAN KeInsertQueueApc( | |
PRKAPC Apc, | |
PVOID SystemArgument1, | |
PVOID SystemArgument2, | |
KPRIORITY Increment); | |
extern "C" PVOID RtlFindExportedRoutineByName( | |
PVOID ImageBase, | |
PCCH RoutineName); | |
CHAR CreateProcessWShell[]{ | |
0x48, 0x83, 0xEC, 0x58, // sub rsp,0x58 | |
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // movabs rax,_PROCESS_INFORMATION | |
0x48, 0x89, 0x44, 0x24, 0x48, // mov QWORD PTR [rsp+0x48],rax | |
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // movabs rax,_STARTUPINFOW | |
0x48, 0x89, 0x44, 0x24, 0x40, // mov QWORD PTR [rsp+0x40],rax | |
0x48, 0xC7, 0x44, 0x24, 0x38, 0x00, 0x00, 0x00, 0x00, // mov QWORD PTR [rsp+0x38],0x0 | |
0x48, 0xC7, 0x44, 0x24, 0x30, 0x00, 0x00, 0x00, 0x00, // mov QWORD PTR [rsp+0x30],0x0 | |
0xC7, 0x44, 0x24, 0x28, 0x00, 0x00, 0x00, 0x00, // mov DWORD PTR [rsp+0x28],0x0 | |
0xC7, 0x44, 0x24, 0x20, 0x00, 0x00, 0x00, 0x00, // mov DWORD PTR [rsp+0x20],0x0 | |
0x45, 0x31, 0xC9, // xor r9d,r9d | |
0x45, 0x31, 0xC0, // xor r8d,r8d | |
0x31, 0xD2, // xor edx,edx | |
0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // movabs rcx,lpApplicationName | |
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // movabs rax,CreateProcessW | |
0xFF, 0xD0, // call rax | |
0x31, 0xC0, // xor eax,eax | |
0x48, 0x83, 0xC4, 0x58, // add rsp,0x58 | |
0xC3 // ret | |
}; | |
VOID ApcKernelRoutine(PKAPC Apc, PKNORMAL_ROUTINE* NormalRoutine, PVOID* NormalContext, PVOID* SystemArgument1, PVOID* SystemArgument2) { | |
if (Apc) | |
ExFreePoolWithTag(Apc, 0); | |
} | |
NTSTATUS RunUsermodeProcess(const wchar_t* Path) { | |
NTSTATUS Status = STATUS_SUCCESS; | |
UINT64 Process, ProcessHead; | |
Status = PsLookupProcessByProcessId((HANDLE)0x4, (PEPROCESS*)&ProcessHead); | |
if (!NT_SUCCESS(Status)) | |
return Status; | |
Process = ProcessHead; | |
bool Found = false; | |
do { | |
if (strncmp("explorer.exe", (const char*)(Process + 0x5a8), 12) == 0 && // Process->ImageFileName | |
*(UINT64*)(Process + 0x840) == 0) { // Process->ExitTime | |
Found = true; | |
break; | |
} | |
Process = *(UINT64*)(Process + 0x448) - 0x448; // Process->ActiveProcessLinks.Flink | |
} while (Process != ProcessHead); | |
ObDereferenceObject((PEPROCESS)ProcessHead); | |
if (!Found) | |
return STATUS_NOT_FOUND; | |
UINT64 Thread, ThreadHead = *(UINT64*)(Process + 0x5e0) - 0x538; // Thread->ThreadListHead.Flink | |
Thread = ThreadHead; | |
Found = false; | |
do { | |
if (*(UINT32*)(Thread + 0x74) & (1 << 4)) { // Thread.Tcb.MiscFlags & Alertable | |
Found = true; | |
break; | |
} | |
Thread = *(UINT64*)(Thread + 0x538) - 0x538; // Thread->ThreadListEntry.Flink | |
} while (Thread != ThreadHead); | |
if (!Found) | |
return STATUS_NOT_FOUND; | |
KAPC_STATE ApcState; | |
KeStackAttachProcess((PKPROCESS)Process, &ApcState); | |
PLDR_DATA_TABLE_ENTRY Module, ModuleHead = (PLDR_DATA_TABLE_ENTRY)(*(UINT64*)(*(UINT64*)(Process + 0x550) + 0x18) + 0x10); // Process->Peb->Ldr.InLoadOrderModuleList.Flink; | |
Module = ModuleHead; | |
UNICODE_STRING Kernel32Str = RTL_CONSTANT_STRING(L"kernel32.dll"); | |
Found = false; | |
do { | |
if (RtlCompareUnicodeString(&Module->BaseDllName, &Kernel32Str, TRUE) == 0) { | |
Found = true; | |
break; | |
} | |
Module = (PLDR_DATA_TABLE_ENTRY)Module->InLoadOrderLinks.Flink; | |
} while (Module != ModuleHead); | |
if (!Found) { | |
KeUnstackDetachProcess(&ApcState); | |
return STATUS_NOT_FOUND; | |
} | |
PVOID CreateProcessW = RtlFindExportedRoutineByName(Module->DllBase, "CreateProcessW"); | |
if (!CreateProcessW) { | |
KeUnstackDetachProcess(&ApcState); | |
return STATUS_NOT_FOUND; | |
} | |
PVOID BaseAddress = 0; | |
SIZE_T RegionSize = 0x1000; | |
Status = ZwAllocateVirtualMemory(ZwCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); | |
if (!NT_SUCCESS(Status)) { | |
KeUnstackDetachProcess(&ApcState); | |
return Status; | |
} | |
RtlZeroMemory(BaseAddress, RegionSize); | |
wcscpy((wchar_t*)BaseAddress, Path); | |
STARTUPINFOW* si = (STARTUPINFOW*)((UINT64)BaseAddress + (wcslen(Path) + 1) * 2); | |
si->cb = sizeof(STARTUPINFOW); | |
PROCESS_INFORMATION* pi = (PROCESS_INFORMATION*)((UINT64)si + sizeof(STARTUPINFOW)); | |
PVOID ShellEntry = (PVOID)((UINT64)pi + sizeof(PROCESS_INFORMATION)); | |
*(UINT64*)&CreateProcessWShell[6] = (UINT64)pi; | |
*(UINT64*)&CreateProcessWShell[21] = (UINT64)si; | |
*(UINT64*)&CreateProcessWShell[78] = (UINT64)BaseAddress; | |
*(UINT64*)&CreateProcessWShell[88] = (UINT64)CreateProcessW; | |
memcpy(ShellEntry, CreateProcessWShell, 105); | |
PKAPC Apc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC)); | |
if (!Apc) { | |
ZwFreeVirtualMemory(ZwCurrentProcess(), &BaseAddress, 0, MEM_RELEASE); | |
KeUnstackDetachProcess(&ApcState); | |
return STATUS_NO_MEMORY; | |
} | |
KeInitializeApc(Apc, (PKTHREAD)Thread, OriginalApcEnvironment, ApcKernelRoutine, 0, (PKNORMAL_ROUTINE)ShellEntry, UserMode, BaseAddress); | |
if (!KeInsertQueueApc(Apc, 0, 0, IO_NO_INCREMENT)) { | |
ExFreePoolWithTag(Apc, 0); | |
ZwFreeVirtualMemory(ZwCurrentProcess(), &BaseAddress, 0, MEM_RELEASE); | |
Status = STATUS_INVALID_PARAMETER; | |
} | |
KeUnstackDetachProcess(&ApcState); | |
return Status; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment