Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Anti-debugging in Win32

Lord Julus
1999

[Back to index] [Comments]

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 ;-)

[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxheaven.org aka vx.netlux.org
deenesitfrplruua