domenica 31 luglio 2011

Defcon 19 (2011) - BINARY L33tness 400 - Writeup

For original hint and executable file see:


Preliminary analysis
This is a Windows 32bit PE binary file. It shows the string "hello world" inside a shell and it exits.
b400 output

It is packed: PEiD reports: tElock 0.98b1 -> tE!
If you open it with Ollydbg, it will say you that b400 executable is packed. This message can be quite annoying, if you wish you can patch Ollydbg itself to skip it :-)


Configuring Ollydbg
When you run it inside Ollydbg, a lot of different errors appear. You can ignore them all:
Debugging options --> Exceptions --> "Ignore also the following exceptions or ranges" --> add 00000000-FFFFFFFF range. Set also: "Ignore memory access violations in KERNEL32" and unset all other options.
If you press F9 you will get a message "Don't know how to bypass...", you can skip it by pressing Shift+F9.
Since this program is heavily packed (probably twice), it is useful to have a breakpoint inside VirtualAlloc API, in order to track memory region creations. You can put it here:
When this breakpoint is hit, in EAX you can see the base address of the memory region allocated
If you try to change b400 memory or to place a hardware breakpoint, you will get the following error message:
A hardware breakpoint (or a memory modification) has been detected!
This is not a big deal since this check is done only before the first call to VirtualAlloc API, just remember that, when you need to place a hardware breakpoint, you have to do it after that VirtualAlloc has been called at least one time.


Finding original executable file
You can try to find the original executable file in memory. Run the program, when it terminates you can still search inside its memory for the string "hello world". You will find it in three different locations. The "hello world" string at 0x00415000 is the most interesting since it is located inside b400 memory. It is dinamically decrypted (in fact, when b400 is going to start, memory at 0x00415000 is filled with zeros).
You can understand when it is generated by placing a hardware breakpoint on write on 0x00415000 (Remember: hardware breakpoints can be set only after that VirtualAlloc has been called once).
This breakpoint is hit twice. The first time some zeros are written, the second time the "hello world" string is written from instruction at: 0x0042E1FB.

Single stepping at this location you can easily identify a decryption function. The code is extremely complex, however you only need to know that:
  • Most of the time data are copied from [ESI] to [EDI] one byte at a time.
  • Under "some circumstances" data written to [EDI] are retrieved in different ways
For instance, "hello world" is copied from "he? world" (where ?=0x11), 0x11 character is substituted with "llo" string copied from "FlsAlloc" string at 0x40D6EC :-)
If you wish, you can dump code from 0x0042E1F8 to 0x0042E2B1 and try to analyze it with IDA Pro, but this is not necessary at all.
The decryption function

It is useful to understand the range of data copied by this function. You can place a conditional log on 0x0042E1FB and log the value of EDI. You cannot place this breakpoint when the program starts, because the code of this decryption function is written during the execution of b400. So, place a hardware breakpoint on execution on 0x0042E1FB and when it is hit, place the conditional log on 0x0042E1FB.
What you will get is a log of memory locations written by the decryption function. It is not 100% complete because, as I said before, not all the data are copied with the MOV BYTE PTR DS:[EDI],AL instruction. However, you can see that this function writes memory from 0x00401000 to 0x0042DDCA.

You can change the conditional log settings, in order to make it stop the program execution when EDI==0x0042DDCA, in this way you can see that, when this function finishes, the following code is executed:
Going to Original Entry Point...
Then:
  • IAT is rebuild
  • Memory access is reset (this is an anti-unpacking technique)
  • The execution jumps to the Original Entry Point at 0x00401560
At 0x00401560 we have the OEP.
The Original Entry Point
If you wish, now you can dump the process (using LordPE) and fix the IAT (using ImpREC, OEP RVA=0x1560, IAT RVA=0xC000, IAT size=0xF7C). If you do so, you will get a valid PE file. (But it will crash, because some values are read from memory allocated by the packer, I don't know why... ).
Once you have a valid PE file, you can load it in IDA Pro. IDA will correctly understands that code at 0x00401000 is the real "main" of this program.
IDA Pro analysis of the "main"

And now?
We have the unpacked binary, we know where it is decrypted (but it seems that no key is used by the decryption function), so where is the key?
Now you can lose hours reversing other decryption functions or the fprintf function (as I did), but it is useless. :-)

The decryption function writes data up to 0x0042DDCA, so, let's see the memory at this location.
There is a PE header!
There is a PE header, if you want, you can see it using Ollydbg integrated PE header parser (you need to paste it inside a full PE header). This PE header is coherent (OEP, IAT, and IAT size) with the original executable we have found, so it is the original PE header of it.
Let's see if there are other PE headers (you can search for "PE" string).

At 0x00432046 there is another PE header, section names are: "ddtek", "rules", "rsrc" :-)
In my opinion, this means that the original executable file has been packed (at least) twice and this is the PE header of the intermediate step. According to this PE header OEP=0x00426000, IAT RVA=0x30014, IAT size=0x8F. If you want to analyze this intermediate step, you can place an hardware breakpoint on execution on 0x00426000

Searching for "PE" string you will find also this string (in the middle of hundreds of API names):
HowCanThisPossiblyBeAValidPEFile?
which is the solution!


How I was suppose to know that?
Solving this challenge can be very simple. You just need to run the program until it terminates, dump the memory and search the "PE" string inside the dump. (There is also an online tool that unpacks an executable file and extracts all the strings it founds [http://eureka.cyber-ta.org])

The problem is: how to know which is the string to look for?
Maybe you can notice that all APIs name are in reverse alphabetical order, except for the "HowCanThisPossiblyBeAValidPEFile?" string.
Another possibility is to realize that the program makes a lot of modifications inside PE header and it hides them from memory breakpoints using VirtualProtect API.
b400 is removing memory breakpoints from PE header using VirtualProtect API.

So you can understand that PE headers are, in some way, important for solving this challenge and you can have the idea of searching for the "PE" string.

Defcon 19 (2011) - BINARY L33tness 500 - Writeup

For original hint and executable file see:


Preliminary analysis
This is a standard Windows 32bit PE binary file.
When you open it, a random sentence appears in a MessageBox. If you press OK, the program closes.
While the MessageBox is open, CPU utilization goes to 100%. Using ProcessExplorer you can see that, inside the b500 process, there are 4 threads using the CPU.

"Standard" b500 executable behavior
If you try to open it using Ollydbg and press F9, you will get an exception and the process ends. This means that there are some anti-debugging checks.



Main thread
Let's start analyzing the main thread.
  • The import table is almost empty, imports are retrieved dynamically (LoadLibrary/GetProcAddress) using the function at 0x00401170. Fortunately, Ollydbg is able to understand the destination address of a dynamic call, at least when the EIP is on it.
  • At 0x004015EC VirtualAlloc is used to allocate a memory region (at 0x00390000), then memset is used to fill with zeros this region.
  • 4 threads are created (0x00401872), for every thread a region in the heap is allocated and inside it the addresses of some APIs are written. The entry point of all these threads is 0x00401930 (this is a parameter of CreateThread API).
  • Then the following APIs are called:
    • WaitForMultipleObjects
    • CloseHandle This is an anti-debugging check [1 (5) kernel32!CloseHandle]
    • VirtualFree 


Secondary threads
First of all, we have to take into consideration that threads are scheduled in a non deterministic way, so we can have different results during different execution of b500.
Ollydbg helps us showing the thread ID of the currently debugged thread on the main window caption, moreover, we can see a list of all currently active threads pressing the T button.
Ollydbg and threads
So, let's place a breakpoint at 0x00401930 and restart the program. While debugging the secondary threads, keep in mind that, if the breakpoints at 0x00401930 is hit again, this means that a new thread is started.
The code of secondary threads is quite complex, however we can easily understand that:
  • The addresses of some APIs are retrived.
  • RDTSC is called (inside function at 0x00401F10), this instruction writes in EDX:EAX the current value of the number of ticks since reset [2], basically this is used for some time-based anti-debugging checks.
  • ZwSetInformationThread is called (0x00401AEC) with flag ThreadHideFromDebugger (push 11). This is an anti-debugging trick [1 (4) NtSetInformationThread].
  • PEB!NtGlobalFlags is checked. This is another anti-debugging check [1 (3) PEB!NtGlobalFlags].
  • Some memory operations are performed.
  • CloseHandle API is called. This is another anti-debugging check [1 (5) kernel32!CloseHandle].

ZwSetInformationThread call and PEB!NtGlobalFlags check


Defeating anti-debugging checks

CloseHandle
We can patch the API code in order to return to the caller without performing any action. There could be a problem if CloseHandle would be called even for legitimate reasons, but, in this executable, this is not the case. Since this function takes one argument, we have to restore the stack with a RETN 4 instruction.
CloseHandle patch

PEB!NtGlobalFlags
We can change the value of this flag before executing any other instruction. I have patched the original b500 executable file. The new b500 changes the value of PEB!NtGlobalFlags (and PEB!IsDebugged, that is used by IsDebuggerPresent API), then it jumps to the original entry point.
You can use Ollydbg to patch the code and save the modifications to the executable. Then, use a tool such as LordPE to change the executable entry point to the address where the patch is located.
PEB check patch

RDTSC
Just do not place breakpoints inside the code of secondary threads. Of course you need breakpoints and single-step while debugging these threads, but, once you have understood how they work, you can skip them.

ZwSetInformationThread
Since this API is called (with flag ThreadHideFromDebugger) hardware breakpoints will not work in the thread that shows the MessageBox, but you can still use regular (INT3) breakpoints!

With the CloseHandle patch and the PEB check patch active, the MessageBox will appear even if b500 is open inside Ollydbg. Now we can search for the key.