The challenge contains three files.
MyFirstMalware.exe is an executable
notdroids.jpg looks compressed or encrypted
config.jpg looks compressed or encrypted
When we execute MyFirstMalware it does nothing for the first 90 seconds and starts then a new svchost.exe process and closes afterwards. It looks like it’s injecting something into another process.
Let’s start with MyFirstMalware.exe and load that in IDA Pro. Loaded in IDA Pro we will see that some API calls are dynamically resolved, for example “call dword_417354” which gets called right before the FreeConsole call.
We can follow that call using cross references and find which function sets that value. If we look at the modifier function we can see that it looks like a hashing function which enumerates the exports of a PE module and creates a hash of each export and compares that with 0x5B8D5E53.
Using cross references again we can see that it’s not the only one function which receives a given hash as argument but there are a many of them and each of them resolves the API dynamically for just one API hash.
The fastest way so solve that would be to load into a debugger and follow them and rename them correctly.
Let’s start a debugger and set a breakpoint at the WinMain entry point. Now we can follow the first call and see that the API pointers have already been resolved and our first API call is CreateMutexA. Fun fact: API hashes have been resolved at the initialization, even before WinMain has been called.
After renaming some useful API pointers to the real API names we can read the code a little easier:
We can skip the CreateMutex and 90 second Sleep calls and simply set our instruction pointer to the call of the real entry point (at call sub_12D4060).
At real entry point it uses a two anti-debugging tricks to make the analysis harder. The first anti-debugging trick calls GetProcessHeap and CloseHandle and measures the time that it takes to call these functions. If the time is over 10 milliseconds then it will return “c:\config.jpg” and else it would return “c:\notdroids.jpg”. We shouldn’t set any breakpoints in that function so that it returns “c:\notdroids.jpg”. We also should copy notdroids.jpg and config.jpg to c:\.
The second anti-debugging check is using IsDebuggerPresent and we could bypass that check by manipulating the return of the function or by using your favorite anti-debugger plugin (e.g.: IDAStealth).
After that it will initialize the string “C:\Windows\System32\svchost.exe” which is going to be the remote process for injection. It will also initialize the string “7ZfKiuNbDcmXJvzRuVHRiD4pH6EEApCmb4ciUmzbH6TXEh7nmuQ3LghuGx38t2BT” which is going to be decryption key. If it detects a debugger it would use a wrong key and the decryption would fail.
After that it calls the decryption function with three arguments:
c:\notdroids.jpg in ECX
Pointer to a allocated memory in EDX
7ZfKiuNbDcmXJvzRuVHRiD4pH6EEApCmb4ciUmzbH6TXEh7nmuQ3LghuGx38t2BT pushed on stack (push esi)
Decryption function opens the file given in ECX register using CreateFileW and reads its content. For decryption, it uses Microsoft’s Crypt APIs with the provider “Microsoft Enhanced Cryptographic Provider v1.0”. We can simply set a breakpoint at the end of the function and let it decrypt.
We can see that the decrypted file is a PE file. After that it will call the final function and that looks like typical RunPE function. It initializes NtUnmapViewOfSection, calls CreateProcessW, GetThreadContext, WriteProcessMemory, SetThreadContext and ResumeThread. That means it will execute svchost.exe in suspended mode, unmap its memory at the ImageBase, write the new decrypted PE to its memory and resume its execution.
We can dump the decrypted PE file now with the debugger (save memory region) or we can use some external tools like pd32 or process hacker. I have used process hacker to search for “DOS” string and saved the memory region and removed the unnecessary data.
After we have successfully extracted the PE file we can load the second stage in IDA Pro. The second stage looks like the first one. It uses again FreeConsole, some long strings which looks like keys and anti-debugging tricks.
Because we already know how this is going to end we can run a debugger and set a breakpoint before the last call because that looks like a free memory call. Now we can execute it and wait until it hits that breakpoint.
Now we can read the memory at lpMem we can see our flag has been decrypted there: