PDA

View Full Version : win32 Anti-Debugging Tricks



Best Programmer
سه شنبه 05 خرداد 1383, 02:21 صبح
The IsDebuggerPresent function indicates whether the calling process is

running under the context of a debugger. This function is exported from

KERNEL32.DLL.

BOOL IsDebuggerPresent(VOID)

- Parameters

This function has no parameters.

- Return Value

þ If the current process is running in the context of a debugger, the return

value is nonzero.

þ If the current process is not running in the context of a debugger, the

return value is zero.

-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú

So, an example for demonstrate this is very simple. Here it goes.

;ÄÄÄ[ CUT HERE ]ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄ

.586p

.model flat

extrn GetProcAddress:PROC

extrn GetModuleHandleA:PROC

extrn MessageBoxA:PROC

extrn ExitProcess:PROC

.data

szTitle db "IsDebuggerPresent Demonstration",0

msg1 db "Application Level Debugger Found",0

msg2 db "Application Level Debugger NOT Found",0

msg3 db "Error: Couldn't get IsDebuggerPresent.",10

db "We're probably under Win95",0

@IsDebuggerPresent db "IsDebuggerPresent",0

K32 db "KERNEL32",0

.code

antidebug1:

push offset K32 ; Obtain KERNEL32 base address

call GetModuleHandleA

or eax,eax ; Check for fails

jz error

push offset @IsDebuggerPresent ; Now search for the existence

push eax ; of IsDebuggerPresent. If

call GetProcAddress ; GetProcAddress returns an

or eax,eax ; error, we assume we're in

jz error ; Win95

call eax ; Call IsDebuggerPresent

or eax,eax ; If it's not 0, we're being

jnz debugger_found ; debugged

debugger_not_found:

push 0 ; Show "Debugger not found"

push offset szTitle

push offset msg2

push 0

call MessageBoxA

jmp exit

error:

push 00001010h ; Show "Error! We're in Win95"

push offset szTitle

push offset msg3

push 0

call MessageBoxA

jmp exit

debugger_found:

push 00001010h ; Show "Debugger found!"

push offset szTitle

push offset msg1

push 0

call MessageBoxA

exit:

push 00000000h ; Exit program

call ExitProcess

end antidebug1

;ÄÄÄ[ CUT HERE ]ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄ

Ain't it nice? Micro$oft did the job for us :) But, of course, don't expect

this method to work with SoftICE, the g0d ;)

[ Win32: Another way of know if we're under the context of a debugger ]

If you take a look into the article "Win95 Structures and Secrets", that was

written by Murkry/iKX, and published in the Xine-3, you'll realize that the-

re is a very cool structure in the FS register. Take a look into the field

FS:[20h]... It's 'DebugContext'. Just make the following:

mov ecx,fs:[20h]

jecxz not_being_debugger

[...] <--- do whatever, we're being debugged :)

So, if FS:[20h] is zero, we're not being debugged. Just enjoy this little

and simple method for detect debuggers! Of course, this can't be applied to

SoftICE...

[ Win32: Stopping Application level debuggers with SEH ]

I still don't know why, but the application level debuggers die simply if

the program uses SEH. And also the code emulators, if we make faults, die

too :) The SEH, as i published in my article in DDT#1 is used for many inte-

resting purposes. Well, as i don' t want to tell you all SEH stuff again, i

will cut'n'paste my old description :)

--[DDT#1.2_6]---------------------------------------------------------------

Well, this is a very simple tutorial about the Structured Exception Handler.

When i saw SEH implemented in a virus, i thought "Well, it does a lot. Must

be very hard to implement". So i simple skipped its use. But, as my Destiny

made General Protection Faults running under NT, as i read in 0BFF70000h, i

realized that i had to do something. And SEH was the only way. Well, we can

do it very complex to understand, or very easy. Of course, i prefer to do it

more easy :)

% Setting up the SEH frame %

ÄÄÄÄÄÄÄÄ&A uml;ÄÄÄÄÄÄÄ&Aum l;ÄÄÄÄÄÄÄÄ ÄÄÄ

Firstly we save it for our own safety with a simple text line.

push dword ptr fs:[0]

And now it's time to make the thingy to point to our handler (for example,

imagine that we used a call for call the setup of the SEH, and our handler

is just after that call instructions: we can use the offset of ret for make

it point there)

push offset SEH_Handler

mov fs:[0],esp

Well, as easy as it gets. What about restore the original SEH? More easy.

Simply do the opposite of the first instruction.

pop dword ptr fs:[0]

It's surprising that that very simple thing for implement if our Windoze vi-

ruses could do for us. For me (as it was the use of SEH i was searching) the

most important one is that i can help us to avoid all that goddamn blue

screens when we run our Win95 virus under NT enviroments. That goddamn blue

screen appears everytime we try to make comparisons over our hardcoded Win95

kernel under NT.

% Example of SEH use %

ÄÄÄÄÄÄÄÄ&A uml;ÄÄÄÄÄÄÄ&Aum l;ÄÄÄÄÄ

Well, you can compile this with:

tasm32 /m3 /ml sehtest,,;

tlink32 /Tpe /aa sehtest,sehtest,,import32.lib

;ÄÄÄ[ CUT HERE ]ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄ

.386p

.model flat ; Good good... 32 bit r0x0r

extrn MessageBoxA:PROC ; Defined APIs

extrn ExitProcess:PROC

.data

szTitle db "Structured Exception Handler example",0

szMessage db "Intercepted General Protection Fault!",0

.code

start:

call setupSEH ; The call pushes the offset

; past it in the stack rigth?

; So we will use that :)

exceptionhandler:

mov esp,[esp+8] ; Error gives us old ESP

; in [ESP+8]

push 00000000h ; Parameters for MessageBoxA

push offset szTitle

push offset szMessage

push 00000000h

call MessageBoxA

push 00000000h

call ExitProcess ; Exit Application

setupSEH:

push dword ptr fs:[0] ; Push original SEH handler

mov fs:[0],esp ; And put the new one (located

; after the first call)

mov ebx,0BFF70000h ; Try to write in kernel (will

mov eax,012345678h ; generate an exception)

xchg eax,[ebx]

end start

;ÄÄÄ[ CUT HERE ]ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄ

[...]

--[DDT#1.2_6]---------------------------------------------------------------

Well, i hope you understood that. If not... Erhm, forget it :) Also, as the

other methods presented before, this cannot be applied to SoftICE

[ Win9X: Detect SoftICE (I) ]

Well, i must greet here Super/29A, because he was the one that told me about

this method. I broke this into two parts: in this one we will see how to

do it from a Ring-0 virus. I won't put a whole example program because it

would fill unnecessary lines, but you must know that this method must be

executed in Ring-0, and the VxDCall must be restored because the call-back

problem (do you remember?).

Well, we are gonna use the Virtual Machine Manager (VMM) service Get_DDB,

so the service will be 00010146h (VMM_Get_DDB). Let's see the information

about this service on the SDK.

-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú

mov eax, Device_ID

mov edi, Device_Name

int 20h ; VMMCall Get_DDB

dd 00010146h

mov [DDB], ecx

- Determines whether or not a VxD is installed for the specified device and

returns a DDB for that device if it is installed.

- Uses ECX, flags.

- Returns a DDB for the specified device if the function succeeds;

- otherwise, returns zero.

þ Device_ID: The device identifier. This parameter can be zero for name-

based devices.

þ Device_Name: An eight-character device name that is padded with blank

characters. This parameter is only required if Device_ID is zero. The

device name is case-sensitive.

-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú

Well, you are wondering why all this shit. Very simple, the Device_ID field

of SoftICE VxD is constant for all programs, as it's registered in Micro$oft

so we have a weapon again the marvelous SoftICE. It's Device_ID is 202h al-

ways. So we should use code like this:

mov eax,00000202h

VxDCall VMM_Get_DDB

xchg eax,ecx

jecxz NotSoftICE

jmp DetectedSoftICE

Where NotSoftICE should be the continuation of virus code, and the label

DetectedSoftICE should handle the action to perform, as we know that our

enemy is alive :) I don't suggest anything destructive because, for example,

would hurt my computer, as i always have SoftICE active :)

[ Win9X: Detect SoftICE (II) ]

Well, here goes another method for detect the presence of my beloved SoftICE

but based in the same concept of before: the 202h ;) Again i must greet to

Super :) Well, in the Ralph Brown Interrupt list we can see a very cool

service in the interrupt 2Fh (multiplex), the 1684h

-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú

Inp.:

AX = 1684h

BX = virtual device (VxD) ID (see #1921)

ES:DI = 0000h:0000h

Return:ES:DI -> VxD API entry point, or 0:0 if the VxD does not support an

API

Note: some Windows enhanced-mode virtual devices provide services that

applications can access. For example, the Virtual Display Device

(VDD) provides an API used in turn by WINOLDAP.

-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú-ú

So, you put in BX a 202h, and execute this function. And you then say...

"Hey Billy... How the fuck i can use interrupts?". My answer is... USE THE

VxDCALL0!!!

[ Win32: Detect SoftICE (III) ]

The definitive and wonderful trick that you was waiting... The global solu-

tion of finding SoftICE in both Win9x and WinNT enviroments! It's very easy,

100% API based, and without "dirty" tricks that go againist compatibility.

And the answer isn't as hidden as you can think... the key is in an API that

you've surely used before: CreateFile. Yes, that API... ain't it charming?

Well, we have to try to open the following:

+ SoftICE for Win9x : ".SICE"

+ SoftICE for WinNT : ".NTICE"

If the API returns us something different than -1 (INVALID_HANDLE_VALUE),

SoftICE is active! Here follows a demonstration program:

;ÄÄÄ[ CUT HERE ]ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄÄÄÄÄÄ&Au ml;ÄÄÄÄÄÄÄ&Auml ;ÄÄÄÄÄÄÄÄ& Auml;ÄÄ

.586p

.model flat

extrn CreateFileA:PROC

extrn CloseHandle:PROC

extrn MessageBoxA:PROC

extrn ExitProcess:PROC

.data

szTitle db "SoftICE detection",0

szMessage db "SoftICE for Win9x : "

answ1 db "not found!",10

db "SoftICE for WinNT : "

answ2 db "not found!",10

db "(c) 1999 Billy Belcebu/iKX",0

nfnd db "found! ",10

SICE9X db ".SICE",0

SICENT db ".NTICE",0

.code

DetectSoftICE:

push 00000000h ; Check for the presence of

push 00000080h ; SoftICE for Win9x envirome-

push 00000003h ; nts...

push 00000000h

push 00000001h

push 0C0000000h

push offset SICE9X

call CreateFileA

inc eax

jz NoSICE9X

dec eax

push eax ; Close opened file

call CloseHandle

lea edi,answ1 ; SoftICE found!

call PutFound

NoSICE9X:

push 00000000h ; And now try to open SoftICE

push 00000080h ; for WinNT...

push 00000003h

push 00000000h

push 00000001h

push 0C0000000h

push offset SICENT

call CreateFileA

inc eax

jz NoSICENT

dec eax

push eax ; Close file handle

call CloseHandle

lea edi,answ2 ; SoftICE for WinNT found!

call PutFound

NoSICENT:

push 00h ; Show a MessageBox with the

push offset szTitle ; results

push offset szMessage

push 00h

call MessageBoxA

push 00h ; Terminate program

call ExitProcess

PutFound:

mov ecx,0Bh ; Change "not found" by

lea esi,nfnd ; "found"; address of where

rep movsb ; to do the change is in EDI

ret

end DetectSoftICE