
                                        /-----------------------------\
                                        | Xine - issue #4 - Phile 106 |
                                        \-----------------------------/


                        Win32 Anti-Debugging tricks
                        a.k.a. protect your own ass


 
 Here  i will list some  tricks that  could be  used for the purpose of self-
 protect your viruses and/or your programs againist debuggers (of all levels,
 application and system). I hope you will like it.

 [ Win98/NT: Detecting Application level debuggers with IsDebuggerPresent ]

 This API is not present in Win95, so you will have to test for its presence,
 and works with application level debuggers only (such as TD32). And it works
 fine. Let's see what it's written about  it in the Win32 API reference list.

 -ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś-ś

 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 ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

       .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 ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 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 %
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 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 %
 ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 Well, you can compile this with:

 tasm32 /m3 /ml sehtest,,;
 tlink32 /Tpe /aa sehtest,sehtest,,import32.lib

;ÄÄÄ[ CUT HERE ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

        .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 ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 [...]

 --[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 ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

        .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

;ÄÄÄ[ CUT HERE ]ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

 This really works, believe me :) The same  method can  be  applied  to other
 "hostile" drivers, just research a bit on it.

 [ Final Words ]

 Well, some  simple  antidebugging  tricks. I  hope  you can use them in your
 virus without problems. See ya!

 Breaking the law,
 Billy Belcebu/iKX.



