Warning: closedir() expects parameter 1 to be resource, null given in /home/aware/public_html/etc/alpha/index.php on line 23
.aware alpha zine - Exploring RDA
.aware eZine Alpha - Overground Hacking
α
Ω


[=========================================================================]
[----------------------------[ Exploring RDA ]----------------------------]
[=========================================================================]


       _==####==_
     .############.
   .################.
  .##################.__ __ __ __ _ _ __ __ 
  ##############/_`|#\ V  V // _` | '_/ -_)
  ##############\__,|# \_/\_/ \__,_|_| \___|
  ###########**######                                     
  *#########{   }####* 
   ##########._.#####    "Kill! Maim! Kill! Maim! Burn!"
    ################     ./kharn
     *############*
       ==####==



--[ 0 ]-----------------------------------------------[ Introduction ]-----

   The ultimate aim of every VXer is to write a program which is difficult,
   or even impossible to remove from the host after it's been attached.
   This code is then truly viral - it can't be removed without somehow
   harming the host, or the host's environment. Many methods have been
   used to acheive this, but at the heart of them all lies various methods
   of encryption - and RDA is one of them.

   RDA is not some new cipher - it stands for Random Decryption Algorithm,
   and can be used with any encryption algorithm, whether symmetric or
   assymetric. It was first implemented in the RDA.Fighter virus, a virus
   which tried different decryption keys against itself until the
   "decrypted" virus matched a certain checksum - and this was assumed to
   be correct. This is the simplest implementation of RDA.


--[ 1 ]-----------------------------------------------[ Standard RDA ]-----

   Your standard appending virus with encryption, encrypts the body and
   stores the decryption algorithm, key, and ciphertext within the last
   section of the host executable. When the executable is loaded,
   AddressOfEntryPoint has already been hijacked, and points to your
   decryption routine first. The ciphercode is decrypted, executed, and
   control is hopefully returned to the host executable without any major
   hitches.

   The weakness of this is that an AV engine, upon recognizing your
   decryption algorithm, will also recognize your decryption key. Simply
   layering encryption on doesn't help either - the AV engine will simply
   peel away the encryption layers, leading to your decrypted code.

   RDA solves this problem by throwing away the decryption key, but
   leaving the algorithm in the open - if the encryption is immune to
   known-plaintext attacks[1], then the only way an Anti-Virus can look at
   the plaintext code is by brute force. However, the only way YOU can
   reach your own decrypted code is also by brute force. Thus, the
   advantage lies with the virus - the virus can "tolerate" one or two
   executables on a system being corrupted with incorrect decryption, an
   anti-virus cannot.

   The standard RDA implementation (weak XOR, for example):

   setup:
       xor ebx,ebx

   iterate:
       mov esi,[ebp + hostOffset]
       mov edi,esi
       mov ecx,[ebp + host_size]
       inc ebx
   decrypt:
       lodsb
       xor al,bl
       stosb
       loop decrypt

   check:
       mov esi,[ebp + hostOffset]
       push esi
       mov ecx,[ebp + host_size]
       push ecx
       mov eax,[ebp + __ADDR_CheckSum]  ; whatever this happens to be
       call eax
       test eax,eax
       jnz iterate
       mov esi,[ebp + hostOffset]
       jmp esi


   However, this has major flaws which impede it's usability. For example,
   if an anti-virus engine can see this code in the clear and recognizes
   it, it can emulate the virus decryption engine, and call CheckSum for
   itself - revealing the decrypted executable. Also, since the XOR
   algorithm is weak, if a single byte is known in the plaintext, the
   entire ciphertext becomes decrypted.

1) known plaintext attack: where a hostile entity knows part of, or the
   entirety of your plaintext, and uses it to manipulate your encryption.
   for example, bytewise XOR is weak to known plaintext attack - if I
   know one charachter of the plaintext, i know the entire plaintext,
   because the key is the same.


--[ 2 ]-----------------------------------[ Variation: SEH-based RDA ]-----

   With the introduction of structured exception handling in Windows OSes,
   programmers have a good way of catching unexpected errors and handling
   them gracefully, instead of leading the user to a BSoD. This is also
   good for when implementing RDA-based techniques: instead of matching the
   decrypted code to a checksum, we simply run the decrypted code - and use
   a different decryption key if we get an exception.

   Probability is most certainly on our side here - the chance that we'll
   get an incorrect decryption key leading to code which executes, but does
   not lead to an exception, is negligible. Also, the circumstances tilt
   the playing field towards the virus end - as a virus, it can "tolerate"
   a few corrupted executables on a system due to incorrect decryption. An
   anti-virus, on the other hand, cannot. Exception handling is set up with
   the help of SetUnhandledExceptionFilter API, which is called as thus:

       SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER f);

   where 'f' is a function (the exception handler) defined as thus:

       LONG f(STRUCT_EXCEPTION_POINTERS e);

   f is called every time an exception occurs, and is passed the state of
   the machine at the point of exception, in the Context member of e.
   Basically, we just try different decryption keys - and if the end result
   (the plaintext code) is incorrect, it'll most likely throw an exception,
   and we can try a different key.

   Here's the Context member of e, which we're interested in. This may
   differ from machine to machine, and this was taken from an IA32 box.

       CONTEXT STRUCT
         ContextFlags  DWORD      ?
         iDr0          DWORD      ?
         ...
         regEbp        DWORD      ?
         regEip        DWORD      ?
         regCs         DWORD      ?
         regFlag       DWORD      ?
         regEsp        DWORD      ?
         regSs         DWORD      ?
         ExtendedRegisters db MAXIMUM_SUPPORTED_EXTENSION dup(?)
       CONTEXT ENDS

   Basically, Context stores the state of the registers at the moment of
   exception. When we exit from our exception handler, we have the option
   of asking the CPU to return to execution from where it halted. This
   "return point" is taken from regEIP, in the Context structure. So we
   modify regEIP to point to our decryption algorithm again. We also need
   to reset EBP and ESP, to make sure we can still access local variables
   and whatnot when we return to the decryption algorithm.

        pop eax
        assume eax:ptr EXCEPTION_POINTERS
        mov ebx,[eax].ContextRecord
        mov eax,ebx
        assume eax:ptr CONTEXT

    ; reset EIP, so we return to "decrypt:"
        lea ebx,decrypt
        mov [eax].regEip,ebx

        mov ebx,ebpSafe
        mov [eax].regEbp,ebx
        mov ebx,espSafe
        mov [eax].regEsp,ebx

        mov eax,-1
        ret

   NOTE: ebpSafe and espSafe are drawn from values we know (assume) to be
   correct - since there is an initial run of the decryption algorithm
   (what if the key happens to be the first one guessed?) - ebp and esp are
   saved at every iteration of the decryption algorithm. That way, they
   remain static:

    decrypt:
        mov [ebp+espSafe],esp
        mov [ebp+ebpSafe],ebp

   There are problems with this method, however. Firstly, we must make
   sure to recalculate EBP, especially if we work within the confines of a
   virus. This must be done within the exception handler itself - if
   "corrupted" or incorrectly decrypted code modifies EBP before throwing
   an exception and you keep on using the tainted EBP, you'll throw more
   exceptions, leading to an infinite loop and Windows terminating your
   process.

   Also, the encryption algorithm must be simple, and efficient - as a
   virus, you must preserve a reasonable loading time for the host
   executable. something which will take several minuites to brute force
   is unacceptable - thus the XOR cipher. However, other fast ciphers
   exist - for example, the XTEA cipher[2].

2) XTEA cipher: although reasonably fast in it's standard form, using
   a 32-bit key is certainly too long for our brute forcing attempts -
   we don't have time to cover that much keyspace. We can shorten XTEA
   to only use 8 bits of randomness in a 32-bit key, to reduce our
   brute forcing time.


----------------------------------[ EOF ]----------------------------------
This page is part of the .aware network. Content and design © 2004 - 2014 .aware network
Due to certified insanity, we are not responsible for anything, period.