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