EPOlution
The Evolution of Entry Point Obscuring
by roy g biv
                                  EPOlution
                                The Evolution
                                      of
                            Entry Point Obscuring
                              roy g biv / defjam

                                 -= defjam =-
                                  since 1992
                     bringing you the viruses of tomorrow
                                    today!


Former  DOS/Win16  virus writer, author of several virus  families,  including
Ginger  (see Coderz #1 zine for terrible buggy example, contact me for  better
sources  ;),  and Virus Bulletin 9/95 for a description of what   they  called
Rainbow.   Co-author  of  world's first virus using circular  partition  trick
(Orsam, coded with Prototype in 1993).  Designer of world's first XMS swapping
virus  (John Galt, coded by RT Fishel in 1995, only 30 bytes stub, the rest is
swapped  out).   Author of world's first virus using Thread Local Storage  for
replication  (Shrug, see Virus Bulletin 6/02 for a description, but they  call
it Chiton), world's first virus using Visual Basic 5/6 language extensions for
replication  (OU812), world's first Native executable virus (Chthon),  world's
first  virus  using process co-operation to prevent termination  (Gemini,  see
Virus  Bulletin 9/02 for a description), world's first virus using polymorphic
SMTP  headers (JunkMail, see Virus Bulletin 11/02 for a description),  world's
first viruses that can convert any data files to infectable objects (Pretext),
world's  first  32/64-bit  parasitic  EPO .NET  virus  (Croissant,  see  Virus
Bulletin  11/04  for a description, but they call it Impanate), world's  first
virus  using  self-executing HTML (JunkHTMaiL, see Virus Bulletin 7/03  for  a
description), world's first virus for Win64 on Intel Itanium (Shrug, see Virus
Bulletin 6/04 for a description, but they call it Rugrat), world's first virus
for  Win64 on AMD AMD64 (Shrug), world's first cross-infecting virus for Intel
IA32  and  AMD  AMD64  (Shrug),  world's  first  viruses  that  infect  Office
applications  and  script  files  using the same  code  (Macaroni,  see  Virus
Bulletin  11/05  for  a description, but they call it Macar),  world's   first
viruses  that  can infect both VBS and JScript using the same code (ACDC,  see
Virus  Bulletin 11/05 for a description, but they call it Cada), world's first
IDA  plugin virus (Hidan), world's first viruses that use the Microsoft Script
Encoder  to  dynamically  encrypt the virus body (Screed), and  world's  first
virus for StarOffice and OpenOffice (Starbucks).  Author of various retrovirus
articles  (eg  see Vlad #7 for the strings that  make  your code invisible  to
TBScan).  Went to sleep for a number of years.  I am awake now. ;)


What is it?

Entry Point Obscuring techniques have been developing for a long time already,
since  even  the  days of DOS and 16-bit Windows.  We have seen  code  tracing
using  interrupt  1, changing of relocation items, call/jmp  replacement,  and
stack frame replacement.

We saw all of the same techniques on the 32-bit Windows platform, as we saw on
the  DOS and 16-bit Windows platforms, and no really big jumps in  techniques.
Some  people  might  say that the Mistfall engine was a big  jump  because  it
allowed  the code insertion, but is it so very different from the interrupt  1
method?   Also,  since it did not preserve the flags, it did not  support  two
branch instructions in a row that we see sometimes in programs, like this:

    jl label1
    jle label2

One  interesting  technique that is a funny kind of EPO was the  Thread  Local
Storage  callback that I found.  With normal EPO techniques, it is not  always
possible  to know when our code will be called, or even if it will be  called.
This  was  an advantage of the Thread Local Storage callback, since we  always
know that we will be called at the start of process execution (before the main
entry  point),  and  at  the end of process execution  (after  ExitProcess  is
called).   We  are  also called at the start of thread execution  (before  the
thread  entry point), and at the end of thread execution (after ExitThread  is
called).

The  disadvantage  of  the Thread Local Storage callback is that if  you  know
about  it,  it is easy to look for it.  The solution to that is to do  only  a
little  bit in the TLS callback, maybe decrypt a little bit of code, or change
the main entry point to somewhere else.

It  is safest to execute at the end of process execution, because then we  can
alter  all  registers without any problems.  However, it is important to  know
that  heap-memory allocation functions can fail, if the host has destroyed the
heap before calling the exit function.

Besides  the  TLS technique, some people just search the process for calls  to 
ExitProcess,  and change those to point to our code, but now I present another
way.


Introducing the Bound Import Table

For  some  reason,  Microsoft has chosen to never document the format  of  the
Bound  Import table.  This is not a problem for us, though, because the format
is really very simple.  It looks like this:

Offset  Size    Field                   Description
0x00    4       TimeDateStamp           Same as TimeDateStamp in PE header
0x04    2       Name RVA                Address of DLL name string
0x06    2       Forwarder               Flag is set if bound by forwarder

That's all there is.  The TimeDateStamp value must match the same value in the
PE  header  of  the DLL that is named.  Then the binding is considered  to  be
valid.   If all bindings match, then no changes are made to the import  table.
For  any  binding that does not match, only the imports from that DLL will  be
reloaded.

The Name RVA is relative to the start of the Bound Import Table.
The table is terminated by Name RVA field is zero.


What's the point?

The  interesting thing about the Bound Import Table is that it can be used  to
prevent  alterations  to the Import Table.  If all of the bindings are  valid,
then  we have a cavity equivalent to the size of the Import Address Table!  Of
course, we would need to run before the host does, and load the imports on our
own.

The  more  interesting  thing is that we can hook any import by  changing  the
address  in one place.  No need to search anymore.  With only one entry point,
now  it's also easy to prevent our code from being called too often, since  we
just put the original address back in one place.

We can also use this technique to create a system dependency, particularly for
DLLs  that are known to contain vulnerabilities.  If a vulnerable DLL is bound
to  an  application, we can remove that DLL from the import table, so that  if
the DLL is ever patched, the file will not run anymore.  That way, we can keep
a vulnerable DLL to be forever required on the system.


How to use it?

Let us imagine that we want to hook ExitProcess.  First, we look at each entry
in  the Bound Import Table for the kernel32.dll.  If we find it, then we check
if  there is an Import Address Table.  Binding is not possible if the table is
not there.  If the table is there, then we look at each entry in there for the
kernel32.dll.   If we find it, then we use GetProcAddress(ExitProcess) to  get
the virtual address of ExitProcess.  Then we search in the kernel32.dll Import
Lookup  Table for that address.  If we find it, we change that address to  the
virtual address of our code.  That's it.  Now when the host calls ExitProcess,
our  code is called.  Since the address is no more found in the import  table,
no need for an infection marker, either.


Greets to friendly people (A-Z):

Active - Benny - Obleak - Prototype - Ratter - Ronin - RT Fishel -
sars - SPTH - The Gingerbread Man - Ultras - uNdErX - Vallez - Vecna -
VirusBuster - Whitehead


rgb/defjam jun 2006
iam_rgb@hotmail.com