Wednesday, November 23, 2005

Porting PBPM from 9x to NT

This has been quite a nice project as i had to rewrite everything from scratch
and since BPM works (as we know) per thread i wanted it to handle all threads
seperated just like i had it done back then on 9x in icedump...

1. Problem there was no VMMCall _AllocateThreadDataSlot

which turned out to be quite a problem at first

later i found out that in the r0 TEB (which is located in PCR:0x124)

was a field that contains always 0 on all threads

mov eax,fs:[124h] ; -> TEB!
mov eax,[eax+4h]
or eax,eax
jnz memory_allocated

so i used that DWORD to store all snapshots...

2. after figuring that part out it also turned out that it wasn't as easy as i thought at first to hook
the necessary code deep enough.... hooking the point where the context gets restored (setthreadcontext)
was no problem at all, but finding a good point where i could hook the "snapshot" process was kinda tricky and this code changes heavily with each service pack and maybe even with security updates...

(i guess it was the main reason for me to never publish anything of it till today)

so i had 2 parts

the more "generic one" // where i hooked zwsetthreadcontext using the keservicedescriptortable

; SEH! stuff

mov ebx,keservicedescriptortable ; grab the fucking table
mov ebx,[ebx] ; pointer to real table
add ebx,020h*4h ; point to our really interesting
; context entry!
; service number 0x20
; -> setthreadcontext | SEH!
mov eax,[ebx] ; -> grab handler rva!
mov pOldCTXHandlerSEH,eax ; store the rva!
mov pOldCTXHandlerSEHP,ebx

mov [ebx],offset myXXsetcontextthreadseh ; install my handler!


and second the part where i hooked the snapshot process:

(therefore i disabled the supervisor bit for a short amount of time and written my hook directly into ntoskernel's code section... afterwards reenable the supervisor bit and exit)

mov ecx,cr0
mov edi,ecx
and ecx,0fffeffffh
mov cr0,ecx

pushad
mov esi,ntosbase
add esi,HARDC0DED
cmp word ptr [esi],0a5f3h
jne failed_at_signature

mov pOldKiUserHandlerP,esi

; save orig_byte_sequence
pushad
mov ecx,08h
lea edi,offset orig_bytes_buffer
db 0f3h, 0a4h ;repz movsb
mov al,068h
stosb ;store push
xchg esi,eax
stosd
mov al,0c3h
stosb
popad

lea eax,offset orig_bytes_buffer
mov my_fucking_destination,eax

xchg esi,edi
mov al,068h
stosb
lea eax,offset myXXkiuser
stosd
mov al,0c3h
stosb
popad

mov ecx,edi
mov cr0,ecx

failed_e:
popad
ret

failed_at_signature:
popad

mov ecx,edi
mov cr0,ecx

popad
ret

3. the hook itself

("kiuser" (snapshot) hook)

;Ä[MY HOOK]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
myXXkiuser equ $
pushfd
pushad
mov eax,fs:[124h]
mov eax,[eax+4h]
or eax,eax
jz dont_fill_the_context

lea edi,dword ptr [esi+4]
mov esi,eax
mov ecx,06h
db 0f3h,0a5h ; repz movsd

Invoke DbgPrint, OFFSET life_sux

dont_fill_the_context:
popad
popfd

db 068h ; push
my_fucking_destination dd ?
ret
myXXkiuserend equ $
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

and the way bigger zwsetcontextthread hook
(btw. i find it pretty confusing to name the ring3 part setthreadcontext and the ring0 part zwsetCONTEXTthread, must be one of a naming genius ;) or someone just noticed bit too late like "doh, we mixed it, damn!")

;Ä[MY HOOK]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
myXXsetcontextthreadseh equ $
pushfd
pushad

mov eax,[esp+028h] ; -> ctx storage buffer
cmp eax,010000000h
jae i_dont_trust_the_kernel

cmp dword ptr [eax+018h],0155h ; most of the time used!
je reset_now

cmp dword ptr [eax+018h],024FFh ; ... :> the evil one
jne i_dont_trust_the_kernel

reset_now:
; and dword ptr [eax+018h],0 ; reset -> dr7


mov eax,fs:[124h] ; -> TEB!
mov eax,[eax+4h]
or eax,eax
jnz memory_allocated

pushad
push 018h
push 4 ; NonPagedPool
iWin32 ExAllocatePool ; allocate buffer
; eax == pointer to allocated
; memory

or eax,eax
jnz proceed_
popad
jmp i_dont_trust_the_kernel

proceed_: mov dword ptr [esp+01ch],eax ; store it!
popad

memory_allocated: mov ebx,fs:[124h]
mov [ebx+4h],eax ; install buffer!

mov edi,eax
mov esi,[esp+028h] ; -> ctx storage!
add esi,04h
mov ecx,06h
mov edx,offset mdr0

grab_regs:
lodsd

push eax
push ecx
call convert
add edx,09h+4h
pop ecx
pop eax

and dword ptr [esi-4],0 ; -> kill it!
stosd ; save value in my buffer!
loop grab_regs

mov eax,fs:[124h] ; -> TEB!
push eax
mov edx,offset kteb_
call convert
pop eax

Invoke DbgPrint, OFFSET shit_happens

i_dont_trust_the_kernel:

popad
popfd
jmp dword ptr [pOldCTXHandlerSEH]
;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Thursday, November 03, 2005

Just another stupid method of "Anti DLL Injection..."

The IDEA behind it

The Problem normally is that you can’t avoid DLL injection into Processes, there’s a way to scan the module list via a few Apis, Module32First/Module32Next, these could easily get hooked and fooling the detection wouldn’t be too hard. To make the cracker’s life a bit harder there’s a non API based method to get the loaded MODULES (*.dll) inside your process.


The PEB aka Process Environment Block

PEB means Process Environment Block and is nothing else than a complex structure containing information needed by Windows to handle processes, there’s another structure called TEB (Thread Environment Block) which describes each running Thread (as Windows normally just administrates Threads), but we will concentrate on the PEB structure.

To get a pointer to the PEB structure all you need to do is grabbing PCR (Processor Control Register) 0x30, or using the TEB first by using PCR (Processor Control Register) 0x18 and then grab struc member +0x30 as it points also to the actual PEB (pPEB).

Processor Control Register means fs:[x].

i.e. mov reg,dword ptr fs:[30h] -> reg = pPEB



PEB STRUCT ;
dwFlags DWORD ? ;00
Unknown04 DWORD ? ;04 == -1
ImageBaseAddress DWORD ? ;08
PebLdrData DWORD ? ;0C == *PEB_LDR_DATA
ProcessParameters DWORD ? ;10 == *PROCESS_PARAMETERS
SubSystemData DWORD ? ;14 == 0
ProgramHeap DWORD ? ;18
LockingContext DWORD ? ;1C == FastPebLock
LockRoutine DWORD ? ;20 == RtlEnterCriticalSection
UnlockRoutine DWORD ? ;24 == RtlLeaveCriticalSection
DirChange DWORD ? ;28 == 1
Unknown2C DWORD ? ;2C == apfnDispatch
Unknown30 DWORD ? ;30 == 0
Unknown34 DWORD ? ;34 == 0
Unknown38 DWORD ? ;38 == 0
Unknown3C DWORD ? ;3C == 0
Unknown40 DWORD ? ;40 == TlsBitMap
Unknown44 DWORD ? ;44 == 3FH
Unknown48 DWORD ? ;48 == 0
ProgramHeap02 DWORD ? ;4C
ProgramHeap02a DWORD ? ;50
InProgramHeap02 DWORD ? ;54
AnsiCodePage DWORD ? ;58
OemCodePage DWORD ? ;5C
UnicodeCodePage DWORD ? ;60
NumberProcessors DWORD ? ;64
GlobalFlag DWORD ? ;68
Unknown6C DWORD ? ;6C == 0
CritSectTimeout DWORD ? ;70
Unknown74 DWORD ? ;74
HeapSegmentReserve DWORD ? ;78
HeapSegementCommit DWORD ? ;7C
HeapDeCommitTotalFreeTreshold DWORD ? ;80 == 10000H

HeapDeCommitFreeBlockTreshold DWORD ? ;84 == 1000H
Unknown88 DWORD ? ;88
Unknown8C DWORD ? ;8C == 386H
Unknown90 DWORD ? ;90 == RtlpProcHeapsListBuffer
Unknown94 DWORD ? ;94
Unknown98 DWORD ? ;98 == 0
Unknown9C DWORD ? ;9C == 14H
UnknownA0 DWORD ? ;A0 == LoaderLock
dwMajorVersion DWORD ? ;A4
dwMinorVersion DWORD ? ;A8
dwBuildNumber WORD ? ;AC
CSDVersion WORD ? ;AE
dwPlatformId DWORD ? ;B0
Subsystem DWORD ? ;B4
MajorSusbsytemVersion DWORD ? ;B8
MinorSusbsytemVersion DWORD ? ;BC
ProcessAffinityMask DWORD ? ;C0
UnknownC4 DWORD 044H DUP (?) ;C4
SessionId DWORD ? ;1D4
Unknown1D8 DWORD ? ;1D8
Unknown1DC DWORD ? ;1DC
Unknown1E0 DWORD ? ;1E0
Unknown1E4 DWORD ? ;1E4
PEB ENDS ;size 1E8H, NT4 size 150H


Interesting is the following field:

PebLdrData DWORD ? ;0C == *PEB_LDR_DATA

This field contains a pointer to another structure called PEB_LDR_DATA, let’s have a look at it.

PEB_LDR_DATA STRUCT ;
cbsize DWORD ? ;00 == 24H
Flags DWORD ? ;04
Unknown8 DWORD ? ;08
InLoadOrderModuleListHead DWORD ? ;0C
PreviousInLoadOrderLdrEntry DWORD ? ;10
InMemoryOrderModuleListHead DWORD ? ;14
PreviousInMemoryOrderLdrEntry DWORD ? ;18
InInitializationOrderModuleListHead DWORD ? ;1C
PreviousInInitializationOrderLdrEntry DWORD ? ;20
PEB_LDR_DATA ENDS ;size 24H

The PEB_LDR_DATA structure contains a field called InLoadOrderModuleListHead this field is what is needed, it points again to another structure called LDR_ENTRY.

LDR_ENTRY STRUCT ;
NextInLoadOrderLdrEntry DWORD ? ;00
PreviousInLoadOrderLdrEntry DWORD ? ;04
NextInMemoryOrderLdrEntry DWORD ? ;08
PreviousInMemoryOrderLdrEntry DWORD ? ;0C
NextInInitializationOrderLdrEntry DWORD ? ;10
PreviousInInitializationOrderLdrEntry DWORD ? ;14
ModuleBase DWORD ? ;18
EntryPoint DWORD ? ;1C
ModuleSize DWORD ? ;20
ModuleFileName UNICODE_STRING <> ;24
ModuleBaseName UNICODE_STRING <> ;2C
Flags DWORD ? ;34
LoadCount WORD ? ;38
TlsIndex WORD ? ;3A
LdrpHashTableEntry0 DWORD ? ;3C
LdrpHashTableEntry1 DWORD ? ;40
TimeStamp DWORD ? ;44
LDR_ENTRY ENDS ;size 48H



And here it is a pointer to the loaded ModuleFileName (ANSI VERSION). The very first Entry in this field points to ourself, means the first module is always our actual *.exe name (GetModuleFileName does the same). Using the field NextInLoadOrderLdrEntry you can walk the list of loaded Modules, it’s getting terminated by pointing to the first entry again.

;**************************************************************************
; ANTI DLL INJECTION USING PEB
;**************************************************************************
pushad
mov ecx,cs
xor cl,cl
cmp ecx,0
jnz no_9x_for_it_tiger_style

mov eax,fs:[30h] ;// ALLOC PEB BASE!
or eax,eax
je no_9x_for_it_tiger_Style
mov eax,[eax+0Ch] ;// MOD LIST
or eax,eax
je no_9x_for_it_tiger_Style
mov eax,[eax+PEB_LDR_DATA.InLoadOrderModuleListHead]
mov esi,eax
loop_all_modules:
cmp esi,[eax+PEB_LDR_DATA.NextInLoadOrderLdrEntry]
je no_9x_for_it_tiger_style
mov ecx,[eax+LDR_ENTRY.MODULEFILENAME+4]
;///////////////////////////////////////////////////////////////
;// CHECK MODULE NAME NOW!
;// SINCE WE HAVE TO DEAL WITH ANSI STRINGS GET IT IN A PROPER WAY
;// FIRST
;///////////////////////////////////////////////////////////////
push esi
push ecx
mov esi,ecx
lea edi,dword ptr [ebp+module_name]
call normalize_string
pop ecx
pop esi

cmp dword ptr [ebp+first_loop],1
jae dont_save_current_directory
mov dword ptr [ebp+first_loop],1
;///////////////////////////////////////////////////////////////
;// SAVE CURRENT DIRECTORY
;///////////////////////////////////////////////////////////////
push ecx
push esi
push eax
lea esi,dword ptr [ebp+module_name]
call strlen_x2
mov ecx,eax
pop eax
pop esi

push esi
lea esi,dword ptr [ebp+module_name]
add esi,ecx
call getdirectory
pop esi
pop ecx
mov byte ptr [edi+2],0 ;// SET TERMINATOR

pushad
lea esi,dword ptr [ebp+module_name]
call strlen_x2
mov ecx,eax
inc ecx
lea edi,dword ptr [ebp+current_dir]
repz movsb
popad

dont_save_current_directory:
;///////////////////////////////////////////////////////////////
;// GET ACTUAL DIRECTORY AND COMPARE BOTH DIRECTORIES!
;///////////////////////////////////////////////////////////////
cmp dword ptr [ebp+first_loop],2
jne set_flag_and_loop
push ecx
push esi
push eax
lea esi,dword ptr [ebp+module_name]
call strlen_x2
mov ecx,eax
pop eax
pop esi

push esi
lea esi,dword ptr [ebp+module_name]
add esi,ecx
call getdirectory
pop esi
pop ecx
mov byte ptr [edi+2],0 ;// SET TERMINATOR

pushad
lea esi,dword ptr [ebp+module_name]
call strlen_x2
mov ecx,eax
inc ecx
lea edi,dword ptr [ebp+current_dir]
repz cmpsb
or ecx,ecx
jne fine_puh
;///////////////////////////////////////////////////////////////
;// INJECTED DLL FOUND!
;// PUT YOUR CODE HERE
;///////////////////////////////////////////////////////////////

fine_puh:
popad
set_flag_and_loop:
mov dword ptr [ebp+first_loop],2
mov eax,[eax+PEB_LDR_DATA.NextInLoadOrderLdrEntry]
jmp loop_all_modules

strlen_X2:
pushad
xor ecx,ecx
count_next_char2:
lodsb
or al,al
je con_a2
inc ecx
jmp count_next_char2
con_a2: mov dword ptr [esp+1ch],ecx
popad
ret

getdirectory:
push ecx
push esi
push eax
mov edi,esi
std
mov al,'\'
repnz scasb
cld
pop eax
pop esi
pop ecx
ret

normalize_string:
pushad
normalize_string2:
lodsb
stosb
inc esi
or al,al
jne normalize_string2
popad
ret

first_loop dd ?
module_name db 0FFh dup (00h)
current_dir db 0FFh dup (00h)

no_9x_for_it_tiger_style:
mov ecx,offset no_9x_for_it_tiger_style-offset first_loop
lea edi,dword ptr [ebp+first_loop]
mov al,00
repz stosb
popad

w00t

ready for take off!

This page is powered by Blogger. Isn't yours?