//=====================================================================================// //Name: void RunUserModeProcess() // // // //Descripion: This routine retrieves the list of all processes running on the machine, // // searches for 'explorer.exe', gets one thread from it's PEPROCESS struct, // // then it queues an APC to that thread // //=====================================================================================// void RunUserModeProcess(char* command_line) { PEPROCESS pTargetProcess = NULL; //self explanatory PKTHREAD pTargetThread = NULL; //thread that can be either alerable or non-alertable PKTHREAD pNotAlertableThread = NULL; //non-alertable thread PEPROCESS pSystemProcess = NULL; //May not necessarily be the 'System' process PETHREAD pTempThread = NULL; PLIST_ENTRY pNextEntry, pListHead, pThNextEntry; if(strlen(command_line)>300) return; //name not longer than 300 characters pSystemProcess = PsGetCurrentProcess(); //make sure you are running at IRQL PASSIVE_LEVEL if(!pSystemProcess) { DbgPrint("lzplhq -> Cannot find 'System' process!"); return; } if(IsListEmpty(&pSystemProcess->ActiveProcessLinks)) DbgPrint("lzplhq -> No processes found!"); else { pListHead = &pSystemProcess->ActiveProcessLinks; pNextEntry = pListHead->Flink; while(pNextEntry != pListHead) //start looping through the available processes { pSystemProcess = CONTAINING_RECORD(pNextEntry,EPROCESS,ActiveProcessLinks); if(pSystemProcess->ActiveThreads) { if(!IsListEmpty(&pSystemProcess->ThreadListHead)) { //Is this explorer.exe? if(_strnicmp(pSystemProcess->ImageFileName,"explorer.exe",12)==0) { pTargetProcess = pSystemProcess; //Yes,we have found it! pTargetThread = pNotAlertableThread = NULL; pThNextEntry = pSystemProcess->ThreadListHead.Flink; //Now we loop through it's threads, seeking an alertable thread while(pThNextEntry != &pSystemProcess->ThreadListHead) { pTempThread = CONTAINING_RECORD(pThNextEntry,ETHREAD,ThreadListEntry); if(pTempThread->Tcb.Alertable) //Tcb is the KTHREAD of this ETHREAD and stands for 'Thread Control Block' { //Good, an alertable thread was found. pTargetThread = &pTempThread->Tcb; DbgPrint("lzplhq -> Found alertable thread"); //We will be using this one, so break now break; } else { //Didn't find an alertable thread yet, so we'll keep this one //just in case we won't find ANY alertable threads pNotAlertableThread = &pTempThread->Tcb; } pThNextEntry = pThNextEntry->Flink; //check next thread } break; } } } pSystemProcess = NULL; pNextEntry = pNextEntry->Flink; //get next process } } if(!pTargetProcess) { DbgPrint("lzplhq -> Couldn't find Explorer.exe!"); return; } if(!pTargetThread) { //No alertable thread was found, so let's hope we've at least got a non-alertable one (we'll set its alertable flag ON) //There's no problem with non-alertable threads, except for the fact that it takes //a little longer for them to return from KernelMode. (that means our process execution will be delayed) pTargetThread = pNotAlertableThread; } if(pTargetThread) { DbgPrint("lzplhq -> Targeted thread: 0x%p",pTargetThread); //We have one thread (alertable or n/a), now install the APC InstallUserModeApc(command_line, pTargetThread,pTargetProcess); } else DbgPrint("lzplhq -> No thread found!"); //Explorer exe with NO threads (???) } PMDL pMdl = NULL; //===================================================================// //Name: VOID ApcKernelRoutine() // // // //Descripion: This routine gets called after the APC routine returns // // (our process should have been executed by then) // // It frees all the memory allocated by InstallUserModeApc// // (APC and MDL) // //===================================================================// void ApcKernelRoutine( IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 ) { PKEVENT pEvent; if (Apc) ExFreePool(Apc); pEvent = (PKEVENT)*SystemArgument1; KeSetEvent (pEvent,IO_NO_INCREMENT,FALSE); } //===================================================================// //Name: // // NTSTATUS InstallUserModeApc() // // // //Paramters: // // CommandLine - Full path of the process to be executes // // pTargetThread - This is where we queue our APC // // pTargetProcess - Should point to Explorer's EPROCESS // // // //Descripion: This routine attaches to 'pTargetThread' and it queues // // a UserMode APC that will be excuted next time the // // thread returns from KernelMode // //===================================================================// NTSTATUS InstallUserModeApc(char* CommandLine, PKTHREAD pTargetThread, PEPROCESS pTargetProcess) { PRKAPC pApc = NULL; //Our APC PKEVENT pEvent = NULL; PVOID pMappedAddress = NULL; //This is where the UserMode routine's code will be placed at ULONG dwSize = 0; //Size of code to be executed in Explorer's address space KAPC_STATE ApcState; // Needed for KeStackAttachProcess ULONG *data_addr=0; //just a helper to change the address of the 'push' instruction //in the ApcCreateProcess routine ULONG dwMappedAddress = 0; //same as above NTSTATUS Status = STATUS_UNSUCCESSFUL; if (!pTargetThread || !pTargetProcess) return STATUS_UNSUCCESSFUL; DbgPrint("command_line:%s/n",CommandLine); //Allocate memory for our APC pApc = ExAllocatePool (NonPagedPool,sizeof (KAPC)); if (!pApc) { DbgPrint("lzplhq -> Failed to allocate memory for the APC structure"); return STATUS_INSUFFICIENT_RESOURCES; } pEvent = ExAllocatePool (NonPagedPool,sizeof (KEVENT)); if (!pEvent) { ExFreePool (pApc); return STATUS_INSUFFICIENT_RESOURCES; } //Get the size of our UserMode code dwSize = (unsigned char*)ApcCreateProcessEnd-(unsigned char*)ApcCreateProcess; //Allocate an MDL describing our ApcCreateProcess' memory pMdl = IoAllocateMdl (ApcCreateProcess, dwSize, FALSE,FALSE,NULL); if (!pMdl) { DbgPrint("lzplhq -> Failed to allocate MDL"); ExFreePool (pApc); return STATUS_INSUFFICIENT_RESOURCES; } __try { //Probe the pages for Write access and make them memory resident MmProbeAndLockPages (pMdl,KernelMode,IoWriteAccess); } __except (EXCEPTION_EXECUTE_HANDLER) { DbgPrint("lzplhq -> Exception during MmProbeAndLockPages"); IoFreeMdl (pMdl); ExFreePool (pApc); ExFreePool (pEvent); return STATUS_UNSUCCESSFUL; } //Attach to the Explorer's address space KeStackAttachProcess(&(pTargetProcess->Pcb),&ApcState); //Now map the physical pages (our code) described by 'pMdl' pMappedAddress = MmMapLockedPagesSpecifyCache (pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority); if (!pMappedAddress) { DbgPrint("lzplhq -> Cannot map address"); KeUnstackDetachProcess (&ApcState); IoFreeMdl (pMdl); ExFreePool (pApc); ExFreePool (pEvent); return STATUS_UNSUCCESSFUL; } else DbgPrint("lzplhq -> UserMode memory at address: 0x%p",pMappedAddress); dwMappedAddress = (ULONG)pMappedAddress; // copy commandline memset ((unsigned char*)pMappedAddress + 163, 0, 260); memcpy ((unsigned char*)pMappedAddress + 163, CommandLine,strlen (CommandLine)); //all done, detach now KeUnstackDetachProcess (&ApcState); //Initialize the APC... KeInitializeEvent(pEvent,NotificationEvent,FALSE); KeInitializeApc(pApc,pTargetThread, OriginalApcEnvironment, &ApcKernelRoutine,NULL, pMappedAddress, UserMode, (PVOID) NULL); //...and queue it if (!KeInsertQueueApc(pApc,pEvent,NULL,0)) { DbgPrint("lzplhq -> Failed to insert APC"); MmUnlockPages(pMdl); IoFreeMdl (pMdl); ExFreePool (pApc); ExFreePool(pEvent); return STATUS_UNSUCCESSFUL; } else { DbgPrint("lzplhq -> APC delivered"); } //is this a non-alertable thread? if(!pTargetThread->ApcState.UserApcPending) { //if yes then alert it pTargetThread->ApcState.UserApcPending = TRUE; } // apc is fired, wait event to signal completion KeWaitForSingleObject (pEvent,Executive,KernelMode,FALSE,NULL); DbgPrint("Get the Event/n"); // free event ExFreePool (pEvent); if(pMdl) { MmUnlockPages(pMdl); IoFreeMdl (pMdl); pMdl = NULL; } DbgPrint("lzplhq -> ApcKernelRoutine called. Memory freed."); return 0; } //=====================================================================================// //Name: void ApcCreateProcess() // //=====================================================================================// __declspec(naked) void ApcCreateProcess(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2) { __asm { push ebp mov ebp,esp push ebx push esi push edi jmp __startup; ; these are just functions.... skip __find_kernel32: push esi ; Save esi push 0x30 pop ecx mov eax, fs:[ecx] ; Extract the PEB mov eax, [eax + 0x0c] ; Extract the PROCESS_MODULE_INFO pointer from the PEB mov esi, [eax + 0x1c] ; Get the address of flink in the init module list lodsd ; Load the address of blink into eax mov eax, [eax + 0x8] ; Grab the module base address from the list entry pop esi ; Restore esi ret ; Return __find_function: pushad ; Save all registers mov ebp, [esp + 0x24] ; Store the base address in eax mov eax, [ebp + 0x3c] ; PE header VMA mov edx, [ebp + eax + 0x78] ; Export table relative offset add edx, ebp ; Export table VMA mov ecx, [edx + 0x18] ; Number of names mov ebx, [edx + 0x20] ; Names table relative offset add ebx, ebp ; Names table VMA __find_function_loop: jecxz __find_function_finished ; Jump to the end if ecx is 0 dec ecx ; Decrement our names counter mov esi, [ebx + ecx * 4] ; Store the relative offset of the name add esi, ebp ; Set esi to the VMA of the current name xor edi, edi ; Zero edi xor eax, eax ; Zero eax cld ; Clear direction __compute_hash_again: lodsb ; Load the next byte from esi into al test al, al ; Test ourselves. jz __compute_hash_finished ; If the ZF is set, we've hit the null term. ror edi, 0xd ; Rotate edi 13 bits to the right add edi, eax ; Add the new byte to the accumulator jmp __compute_hash_again ; Next iteration __compute_hash_finished: cmp edi, [esp + 0x28] ; Compare the computed hash with the requested hash jnz __find_function_loop ; No match, try the next one. mov ebx, [edx + 0x24] ; Ordinals table relative offset add ebx, ebp ; Ordinals table VMA mov cx, [ebx + 2 * ecx] ; Extrapolate the function's ordinal mov ebx, [edx + 0x1c] ; Address table relative offset add ebx, ebp ; Address table VMA mov eax, [ebx + 4 * ecx] ; Extract the relative function offset from its ordinal add eax, ebp ; Function VMA mov [esp + 0x1c], eax ; Overwrite stack version of eax from pushad __find_function_finished: popad ; Restore all registers ret 8 __begin: nop pop edi ; Pop address mov ebx, __execute sub ebx, __command_line sub edi, ebx ; filename offset mov esi,edi ; filename to edi call __find_kernel32 ; Find kernel32 address mov ebx, eax ; Save address in ebx jmp short __execute ; Skip data __startup: call __begin ; Fetch our data address __execute: push 0x0e8afe98 ; WinExec hash push ebx ; kernel32 base address call __find_function ; find address xor ecx,ecx inc ecx ; ecx = 1 push ecx ; uCmdShow push esi ; lpCmdLine. We already have the exe path in esi call eax ; call WinExec jmp __end __command_line: ; Space (~300 bytes) for commandline nop ............ ;omit here, total 300 nop instruction nop __end: pop edi ; restore registers pop esi pop ebx pop ebp ret 0x0c } } void ApcCreateProcessEnd(){}
用APC实现在内核模式运行用户程序
最新推荐文章于 2022-09-04 16:36:23 发布