VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

EPOlution: The Evolution of Entry Point Obscuring

roy g biv
Ready Rangers Liberation Front [7]
June 2006

[Back to index] [Comments]

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:

0x004TimeDateStampSame as TimeDateStamp in PE header
0x042Name RVAAddress of DLL name string
0x062ForwarderFlag 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
[email protected]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! aka