CBJ 1 2 2006 Kruse Processless Threads
CBJ 1 2 2006 Kruse Processless Threads
2, 2006
Abstract:
The shown technique is able to run on all Windows operation systems. In order to avoid virus creation on it's best,
this technique is shown for W2K/XP/2K3 only. NT4 systems doesnt know several of the used API's, also it is possible
to rewrite them. Non NTbased systems need other techniques to detect the correct process to inject the code.
several placeholders for resolved API function calls and * The reader who understand the shown thread code in
strings (for MessageBox call and additional API Section IX might have seen, that the base address of
functions to resolve). There are several placeholders USER32.DLL is not resolved by our thread code! It’s up
which are not used in our example, but this data part is to you to change it.
prepared for further projects, too.
Knowing this workflow we are able to create the carrier
application general part. It contains needed data and
6 Thread Code Part included functions and is shown in Section X.
We are able to imagine the thread code workflow by The code part shown in Section XI realises exactly what
analyzing this given data part: we want to do. And this code could be used as general
template to create such applications! If you want to use
• resolve GetProcAddress API from KERNEL32.DLL resources later on, simply create another memory region
• resolve GetExitCodeThread API from by using VirtualAllocEx and store the memory address
KERNEL32.DLL inside the thread data ( lpRsrc).
• resolve ExitThread API from KERNEL32.DLL
• resolve MessageBoxA API from User32.DLL 8 Conclusions
• prepare MessageBoxA parameters on stack The shown technique uses one target which executes the
• show the messagebox injected code. But it is also possible to:
• prepare GetExitCodeThread parameter on stack
• inject code in DIFFERENT target applications and
( dwThreadHandle)
communicate between these targets using the
• get the exitcode technique from carrier application to access a process
• exit the tread (thread terminates, process continue!) • WALK from one target application to another,
destroying itself after inject needed parts to new
And again: In order to make ”crackers life” even harder, target by using polymorphic code
we use several tricks to realize this code! The code sown • WALK from one target application to another, leaving
in Section IX needs some ”brain gymnastics”, but it is itself intact and create ”splitted” applications which
documented and as time goes by easy to understand. communicate together
• INTERACT with still running carrier application as
7 Carrier Application kind of ”external” WatchDog from target
application(s)
The prepared thread code is useless without the carrier • all COMBINATIONS of shown examples above
application. Lets have a closer look on what to do:
• check the operating system (do not execute on 9X) In combination with already existing software
• resolve USER32.DLL base address for our thread (*) protections it is possible to avoid ”readable” thread data.
• create a snapshot of running processes By using polymorphic code and crypto algorythms the
reversing approach becomes nearly impossible.
• find the target application (explorer.exe)
• if not found, terminate with error message
• store target processID 9 SourceCode Thread.inc
• free snapshot We use several structures for resolving the export
• grant access to target application via OpenProcess[1] address table from KERNEL32.DLL. These structures
are changed into correct code during compilation and in
• store the target process handle
case of that, we didn’t need to make life harder than it is.
• create two memory areas via VirtualAllocEx
• create a remote thread in suspended mode ; thread.inc (data and code)
• resume the remote thread to become executed via _sizeofInject dd offset _inject_end offset _inject
ResumeThread[1] _sizeofData dd offset _ENDOFDATA offset _dwThreadID
• close the target process handle _dwThreadID dd 0
• terminate the carrier via ExitProcess _dwThreadHandle dd 0
_lpCode dd 0
11 SourceCode inject.asm
mov eax,_myProcessID ; get the process ID
test eax,eax ; is there an ID
; inject.asm jne _goOn ; if so, continue
include inject.inc ; additional data and includes invoke MessageBox,NULL,addr szErrorText,\
addr szErrorCaption, MB_OK
.code jmp _exitApp ; leave application
start: ; application entry point
; carrier application _goOn:
invoke GetModuleHandle,NULL ; get application module invoke
handle OpenProcess,PROCESS_ALL_ACCESS,NULL,_myProcessID
mov hInstance,eax ; and store it mov _myProcessHandle,eax ; store the process handle
assume fs:nothing ; needed for MASM ; create two mem parts: one for code, one for data
mov eax,fs:[18h] ; get TEB self pointer invoke
mov ebx,fs:[30h] ; get PEB pointer VirtualAllocEx,_myProcessHandle,NULL,1000h,MEM_COMM
IT,\
PAGE_EXECUTE_READWRITE
.if eax!=7FFDE000h || ebx!=7FFDF000h ; NT check
mov _lpCode,eax ; store code base in thread data
invoke
VirtualAllocEx,_myProcessHandle,NULL,100h,MEM_COMMI
T,\
PAGE_EXECUTE_READWRITE
mov _lpData,eax ; store data base in thread data