Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Home NTDEV

Before Posting...

Please check out the Community Guidelines in the Announcements and Administration Category.

More Info on Driver Writing and Debugging


The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.


Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/


How to create process in wdm kernel dirver on win98 system?

Hi! ALl,
Does kernel WDM driver can create user mode process enve on windows98
system?

If the follow code can do the job?

************create process in kernel mode ***********

By: valerino



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+0x4a)=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()
{

}



*********end of create process in kernel
mode*************************************

Thanks!

Best Regards!

momer

Comments

  • Doron_HolanDoron_Holan Member - All Emails Posts: 10,777
    God knows if this will work, I think half the functions you are using
    don't exist on win9x. Just create a process in UM, that is the
    supported way of doing it.

    d

    -----Original Message-----
    From: [email protected]
    [mailto:[email protected]] On Behalf Of momer
    Sent: Friday, March 10, 2006 10:17 PM
    To: Windows System Software Devs Interest List
    Subject: [ntdev] How to create process in wdm kernel dirver on win98
    system?

    Hi! ALl,
    Does kernel WDM driver can create user mode process enve on
    windows98
    system?

    If the follow code can do the job?

    ************create process in kernel mode ***********

    By: valerino



    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+0x4a)=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()
    {

    }



    *********end of create process in kernel
    mode*************************************

    Thanks!

    Best Regards!

    momer



    ---
    Questions? First check the Kernel Driver FAQ at
    http://www.osronline.com/article.cfm?id=256

    To unsubscribe, visit the List Server section of OSR Online at
    http://www.osronline.com/page.cfm?name=ListServer
    d
  • Yes, I know how to create process in user mode.But what I am interest ijn is
    to create process in kernel mode.
    Maybe I need to define those kernel APIs which don't exit on win98 in my
    kernel driver and mimic the way by which win98 create process.
    Thanks!

    momer


    "Doron Holan" wrote in message
    news:xxxxx@ntdev...
    God knows if this will work, I think half the functions you are using
    don't exist on win9x. Just create a process in UM, that is the
    supported way of doing it.

    d

    -----Original Message-----
    From: [email protected]
    [mailto:[email protected]] On Behalf Of momer
    Sent: Friday, March 10, 2006 10:17 PM
    To: Windows System Software Devs Interest List
    Subject: [ntdev] How to create process in wdm kernel dirver on win98
    system?

    Hi! ALl,
    Does kernel WDM driver can create user mode process enve on
    windows98
    system?

    If the follow code can do the job?

    ************create process in kernel mode ***********

    By: valerino



    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+0x4a)=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()
    {

    }



    *********end of create process in kernel
    mode*************************************

    Thanks!

    Best Regards!

    momer



    ---
    Questions? First check the Kernel Driver FAQ at
    http://www.osronline.com/article.cfm?id=256

    To unsubscribe, visit the List Server section of OSR Online at
    http://www.osronline.com/page.cfm?name=ListServer
  • Doron_HolanDoron_Holan Member - All Emails Posts: 10,777
    Why? What's the point? Are you trying to do this for the sake of
    learning or b/c of some perceived need that user mode doesn't provide
    (like security?). IIRC, win9x doesn't have KAPCs fully integrated into
    the OS and that process creations is drastically different then NT. I
    think there are ways as a VXD to create a process.

    d

    -----Original Message-----
    From: [email protected]
    [mailto:[email protected]] On Behalf Of momer
    Sent: Saturday, March 11, 2006 6:35 PM
    To: Windows System Software Devs Interest List
    Subject: Re:[ntdev] How to create process in wdm kernel dirver on win98
    system?

    Yes, I know how to create process in user mode.But what I am interest
    ijn is
    to create process in kernel mode.
    Maybe I need to define those kernel APIs which don't exit on win98 in my
    kernel driver and mimic the way by which win98 create process.
    Thanks!

    momer


    "Doron Holan" <[email protected]> wrote in message
    news:xxxxx@ntdev...
    God knows if this will work, I think half the functions you are using
    don't exist on win9x. Just create a process in UM, that is the
    supported way of doing it.

    d

    -----Original Message-----
    From: [email protected]
    [mailto:[email protected]] On Behalf Of momer
    Sent: Friday, March 10, 2006 10:17 PM
    To: Windows System Software Devs Interest List
    Subject: [ntdev] How to create process in wdm kernel dirver on win98
    system?

    Hi! ALl,
    Does kernel WDM driver can create user mode process enve on
    windows98
    system?

    If the follow code can do the job?

    ************create process in kernel mode ***********

    By: valerino



    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+0x4a)=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()
    {

    }



    *********end of create process in kernel
    mode*************************************

    Thanks!

    Best Regards!

    momer



    ---
    Questions? First check the Kernel Driver FAQ at
    http://www.osronline.com/article.cfm?id=256

    To unsubscribe, visit the List Server section of OSR Online at
    http://www.osronline.com/page.cfm?name=ListServer




    ---
    Questions? First check the Kernel Driver FAQ at
    http://www.osronline.com/article.cfm?id=256

    To unsubscribe, visit the List Server section of OSR Online at
    http://www.osronline.com/page.cfm?name=ListServer
    d
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. Sign in or register to get started.

Upcoming OSR Seminars
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead!
Kernel Debugging 16-20 October 2023 Live, Online
Developing Minifilters 13-17 November 2023 Live, Online
Internals & Software Drivers 4-8 Dec 2023 Live, Online
Writing WDF Drivers 10-14 July 2023 Live, Online