CreateProcess in KernelMode
2009-05-25 21:38
330 查看
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()
{
}
相关文章推荐
- CreateProcess in KernelMode!
- CreateProcess in KernelMode[转]
- fatal error in launcher:unable to create process using 解决办法
- Pip - Fatal error in launcher: Unable to create process using '"'
- pip install 出现 Fatal error in launcher: Unable to create process using '"'
- 002-Fatal error in launcher: Unable to create process using '""
- (转载)DLLs in Kernel Mode
- Fatal error in launcher: Unable to create process using '"'
- Remote Thread Execution in System Process using NtCreateThreadEx for Vista & Windows7
- Linux kernel boot process——从实模式(real mode)到保护模式(protected mode),再到分页(paging)(转)
- pip报错解决方法--Fatal error in launcher: Unable to create process using
- python pip使用报错:Fatal error in launcher: Unable to create process using '"'
- Fatal error in launcher: Unable to create process using '"'解决办法
- Create a new Database Instance (in SILENT mode)
- hadoop mkdir: Cannot create directory /usr. Name node is in safe mode.
- 【Python错误】windows下使用pip/easy_install提示Fatal error in launcher: Unable to create process using...
- Linux kernel boot process——从实模式(real mode)到保护模式(protected mode),再到分页(paging)
- Python-Fatal error in launcher: Unable to create process using '"'
- Hadoop "Cannot create directory .Name node is in safe mode."解决方案
- How to debug user-mode process using kernel-mode windbg in Win7