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