In my last post we found all the Easter Eggs. Each egg was another quote from the movie Pulp Fiction and when we found the most famous quote from the film:
we knew we found all the eggs.
At the end of our hunt, I wondered if there might be more to this challenge. There was a lot more code that I haven’t even analyzed yet and some of the code appeared obfuscated to hide its functionality. And this is a crack me puzzle after all. When we first discovered what to put in each stage box:
we were alerted that we did not “do it.” Since this challenge has an ongoing Pulp Fiction theme, and the Stage 2 text is not a quote from the movie, this may indicate that another Pulp Fiction quote might unlock the puzzle. But which quote is the correct quote? There are lots of memorable quotes from the film so a brute force approach is not likely practical. Where to begin next?
After some thinking, I realized that the CrackMe text box above didn’t appear until the start (WinMain) function ran. But, as we have seen in my previous posts, there is a lot of activity that happens before the start function runs. There were several threads that ran before the main function. I decided to put a break point on CreateThread and examine the corresponding call stack. After setting the break point and hitting F9 to run, we encountered our first break:
in the call stack window we can see the thread function starts at 0x404A60. If we go to that address and put a break point there, we will be able to examine what that piece of code does. But before I do that, I hit F9 (run) again to catch the next CreateThread call:
this thread’s function starts at 0x404680. If we go to that location:
huh! Olly is confused and is having a hard time analyzing this code; it thinks these are data bytes. If we highlight all these data bytes to the nearest RETN instruction (at 0x404B1E), then right-click –> Analyze –> During next analysis, treat selection as –> Commands:
we can start to see that this is the part that sets up the named pipe server that we already analyzed in ESET CrackMe Challenge Part 3. We can let this thread go; we already know what it does.
Lets return to the thread function from our CreateThread break at 0x405A60.
When this tread spawns, the process enters a sleep loop until the CrackMe text boxes are enabled and ready for input. When that happens, the process sends us to a function at 0x405CD0. So I put a break point at that function, let the program run (F9) and waited for a break to step into 0x405CD0. Its a pretty big function but eventually we get to another CreateThread call:
this new thread has a function at 0x405CC0. We set a break point at this new thread function to see what that does:
it takes us to 0x405B10:
This is a huge function but the most interesting stuff happens here:
First, this function calls LoadLibrary and loads a number of user32.dll functions. But as you can see in the Registers window, the function are not names but addresses (e.g., user32.7E41D60F). This makes it harder for us to understand what is going on. How can we resolve these address location calls in user32.dll to their actual function names? There is a tool called DLL Export Viewer and it will load all of the Windows/System32 DLL’s mapping the addresses to function names. I sorted on addresses and searched for what was being called at 0x405C7A and at 0x405C83:
In the example above, the CALL ESI is really a call to user32.7E41D60F, which is between the two addresses highlighted in the screen shot above. So this call must be a call to a SetWindowLong function. I did the same for the FindWindowsEx call that came before the SetWindowLong call. After painstakingly stepping through this function and re-labeling all the user32.dll functions, I finally stumbled upon a key piece as illustrated in the following snippet of code:
what this is doing is finding our CrackMe text box and setting the Stage 2 textbox to include this new procedure. This means that the Stage 2 textbox will have two routines to check the input. One will check for the “I did it!”, which will give us the “Nope. You didn’t!” dialog box, and the other checks for some other text — the correct text presumably. We will need to set a break point at this new textbox procedure which is at:
Actually, through trial and error, I discovered that if we place a BP at 0x405F50, the CrackMe text boxes don’t finish rendering yet, and when you click on the CrackMe box, it breaks the program at 0x405F50. I discovered that if we place a BP further down, say at 0x406023, the text box is fully rendered, and we can input text in the Stage 2 box, which will cause us to break at 0x406023. If we do that, and place in any text other than the “I did it!”, we can trace this part of the code to try and figure out what the real message should be:
We see that at 0x406023, ECX contains my bogus input and then a call is made to 0x4041D0. What does that do? If we go to 0x4041D0:
Ack — we see that Olly hasn’t disassembled this piece correctly; it is fooled into believing that these are just data bytes. So if we highlight all these data bytes until we get to the next RETN instruction (to 0x40429A), then right-click on the highlighted section, select Analysis –> During next analysis, treat selected as –> Commands:
The above two screen shots show the entire routine as supposedly correct commands. This routine is rather complicated but my gut tells me that this is some kind of encryption routine. I am rather lazy, so instead of analyzing the above mess, I am going to try and find an easier way by observing the behavior of stepping over this routine and see what the program does. Back to our current breaking point:
when we return from the 0x4041D0 encryption routine, we note that some data at 0x4227EC is being loaded into a pointer to a data segment. It looks like the program will compare that data with my encrypted input of “sfsf”. If we follow 0x4227EC in the dump window (highlighted in grey in the bottom left window), we can see that this data looks encrypted. Naturally, my input is not going to match whatever is in 0x4227EC:
hence, the program will sit here waiting for the correct input from the Stage 2 textbox. If we let the program resume (F9), we should be able to enter some other text into Stage 2. It is likely that the encryption routine is symmetric since that is computationally cheaper than an asymmetric scheme. To test my theory, I entered the word “cat” and hit the check button. When we broke again, I stepped over the encryption routine and observed the encrypted result of “cat”. I copied this encrypted “cat”, then resumed the program again (F9) and pasted the encrypted version of cat into the Stage 2 textbox and hit the check button to return to our current break point. When I stepped over the encrypted routine again, I got back the word “cat”; this confirms my hunch. So, we should be able to apply the same trick to the data at 0x4227EC. Copy and paste that encrypted data into the Stage 2 textbox and let the program run again:
Did you see it? In the stack window??
“Zed’s dead, baby” — not only another quote from Pulp Fiction (uttered by Bruce Willis’ character Butch), but this must be the correct quote to unlock this puzzle!
After entering the correct input, it looks like the code will now take us to:
0x4060C0, like the previous thread routine, is loading a number of functions but this time from kernel32.dll; and like the previous thread, it is using address locations and not the names of the functions from kernel32.dll to hide the true functionality. So again, I used the DLL Export Viewer tool to resolve the names. We eventually come to an interesting part of the routine as observed in the above screen shot. Another base64 encoded string. The string is sent to the base64 decoder function and I already decoded it as noted above: it looks like this routine is going to do something with userinit.exe. This must be the “malware” part of the CrackMe puzzle. No legitimate program has any business hooking into userinit.exe; this is typical malware behavior.
Userinit, according to Microsoft, “Specifies the programs that Winlogon runs when a user logs on. By default, Winlogon runs Userinit.exe, which runs logon scripts, reestablishes network connections, and then starts Explorer.exe, the Windows user interface.” Let us see what CrackMe intends to do with userinit:
at 0x406348, we see that in EAX, new memory was allocated in userinit.exe’s process space at address 0x90000. This is writing some sort of data, I presume. Then…
at 0x406380, more memory is allocated in userinit.exe’s process space at location 0xA0000. Continuing a little further…
we observe a call to CreateRemoteThread with EAX = 0xA0000. So what was written at 0xA0000 must be code because CreateRemoteThread creates a thread that runs in the virtual address space of another process.
Before stepping over the CreateRemoteThread, I fired up FakeNet and ProcMon tools to capture any events that might happen:
this new process used wget to post an index.php on port 8080 localhost. That is interesting, but here is where my trail (or thread) goes cold. When I look for this process, I can not find it. I don’t see this new process spawned by CreateRemoteThread listed in the active processes in OllyDbg even though it is clearly running somewhere:
There is a PID of 2276 but I don’t even see it in Process Explorer or the task manager. This leaves me somewhat stumped as to how I can attach to this new process. If I can find it, and attach, then I might be able to figure out what to do next. I invite the community to share any hints or tips as to how I might attempt to locate this process. I am so close to solving this thing — I can feel it. I would expect that the patched userinit is supposed to generate my next dialog box after entering the correct quote, “Zed’s dead, baby” in the Stage 2 textbox. But it must be missing a key piece to finish the job. What was sent to localhost?
it looks like there is a key of some kind. My guess is index.php must somehow use the code injected into userinit.exe at 0xA0000 to decrypt the data at 0x90000 (???) but I won’t know this for sure until I figure out how to find and attach to the process spawned at 0xA0000.
I will keep playing with it to see if I can figure it out. If I come up with anything new, I will be sure to post those results here. Stay tuned…
EDIT TO ADD February 18, 2014: After several debug sessions, I did manage to find the userinit process in Windows Task Manager and Sysinternal’s Process Explorer.
However, I still can not locate the userinit thread in OllyDbg to attach to it. The problem seems to be that when the thread is spawned, it immediately goes into a suspended state, which would explain why I can’t find it in Olly’s active process window. Hmmmmmm…. I will keep trying…