Malware Launcher using DLL Search Order Hijacking

Hello again,

Have you ever heard of this? It’s a pretty cool technique to load an arbitrary DLL into a process by taking advantage of the way Windows’ DLL search works. Quite honestly, I’ve never seen it in action on real malware, up until very recently.

There is a “launcher” floating around which uses not only DSOH, but some other pretty cool techniques to host malicious activity into the process of a legitimate (and signed) tool.

Screenshot_4

At a first glance, which one is the malicious one? Yeah, it’s not ccBaa2.exe. Turns out that *.exe is an legitimate Microsoft tool, called srctool.

Screenshot_1

So, what’s the trick? Well, the first part is the DSOH. dbghelp.dll was crafted to export exactly the same functions srctool.exe imports from the original dbghelp.dll, located @ system32.

Screenshot_2

Only this dbghelp.dll’s exported functions do nothing.

Screenshot_3

The original SymGetOptions() looks like this:

Screenshot_5

Also, the rogue dbghelp.dll only exports what srctool needs, not all the functions present in the original dbghelp.dll.

Another important detail, is that, according to MSDN’s Windows DLL Search Order explanation I linked in the beggining of the post, Windows will first look for the DLL referenced by the PE in the directory from which the application loaded. So, when Windows’ PE loading routine starts looking for imported functions, and see that srctool needs dbghelp.dll, it’ll first look to the rogue dbghelp.dll. It’ll also successfully resolve the imported functions, because the referenced functions are all correctly named!

OK. So what exactly happens when srctool (ccBaa2.exe) executes?

Well, every PE has an entrypoint, right? That’s no exception to DLLs. If you ever wrote a DLL in C/C++, you may remember DllMain(). It’s an optional entrypoint, and it exists so you can perform initializations, or whatever you need before any exported function on your DLL gets called.

The important thing is this:

When the system starts or terminates a process or thread, it calls the entry-point function for each loaded DLL using the first thread of the process. The system also calls the entry-point function for a DLL when it is loaded or unloaded using the LoadLibrary and FreeLibrary functions.

During initial process startup or after a call to LoadLibrary, the system scans the list of loaded DLLs for the process. For each DLL that has not already been called with the DLL_PROCESS_ATTACH value, the system calls the DLL’s entry-point function.

That is, upon the execution of ccBaa2.exe, Windows will load the rogue dbghelp.dll, and it’s entrypoint will be called before ccBaa2.exe’s entrypoint. And guess what? Our rogue dbghelp.dll has “initializations” to do. 🙂

Screenshot_7

OK, so first of all, it’ll check if the reason why it’s being called is DLL_PROCESS_ATTACH. That’s part of the standard switch case suggested in DllMain.

Screenshot_8

These distinctions are important when writing DllMain, because this function may be called multiple times (it gets called everytime “the system starts or terminates a process or thread”). If the reason is indeed DLL_PROCESS_ATTACH, evil_stuff() gets called, and this is where things get more interesting.

We can see some_function() is passed as a parameter to it.

Screenshot_10

GetCurrentProcess() + WriteProcessMemory() = something is being modified. We’ll soon find out what. Just for the sake of brievity, let me summarize sub_66081960. Essentially, it’s grabbing the address of entrypoint of the main module (*.exe) – not an offset, the full address. Kinda like this:


DWORD get_entrypoint() {
DWORD base = (DWORD)GetModuleHandleA(NULL);

PIMAGE_DOS_HEADER dos_header =
(PIMAGE_DOS_HEADER)base;
PIMAGE_NT_HEADERS32 nt_header =
(PIMAGE_NT_HEADERS32)(base + dos_header->e_lfanew);

DWORD entry_point =
nt_header->OptionalHeader.ImageBase +
nt_header->OptionalHeader.AddressOfEntryPoint;

return entry_point;
}

If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).

OK, now that we know what sub_66081960 is doing, let’s continue inspecting evil_stuff().

Screenshot_14

After call get_entrypoint, EAX will hold the entrypoint address. We can see a buffer being filled, with its first position being filled with 0xE9, and the last, 0xC3. After that, we see that function that was passed as a param to evil_stuff() being subtracted with 0x5, and later, to the entrypoint we just got @ get_entrypoint(). The result is passed as a DWORD (there’s no byte ptr granularity on that MOV) @ pos[1] in our buffer, making positions [1, 2, 3 4] to be filled (DWORD = 4 bytes).

buffer = [0xE9, _d, _i, _f, _f, 0xC3]

This buffer is then passed to WriteProcessMemory as the source buffer, and the *.exe entrypoint as the destination.

“What’s going on?” – you might ask. Well. What dbghelp.dll is doing here is effectively detouring this *.exe’s usual code flow to start @ some_function, by overwriting the instructions at *.exe’s entrypoint with a “JMP to some_function” instruction.

That buffer contains a valid JMP instruction (more specifically, a Jump near, relative, displacement relative to next instruction, as there are many kinds of JMP). The address after 0xE9 is the distance between the entrypoint and some_function. The resulting offset is then placed right after 0xE9. The buffer ends with 0xC3, which translates to RET.

This is what happens to srctools entrypoint in-memory.

Screenshot_15d

Pretty cool, right?

What happens @ some_function() is not really in the scope of this post, so summing it up, it loads a file hiding in an alternate data stream, and starts decoding it / executing stuff from it – at least that’s what I assume is happening, as I don’t have the ADS file to confirm everything.


Wrap-up

This is what happens when we double-click ccBaa2.exe (srctool):

  1. As part of srctool’s imports and following Windows’ DLL Search Order rules, the rogue dbghelp.dll will be loaded in memory;
  2. dbghelp.dll’s DllMain() routine will execute, and it will execute before srctool’s entrypoint, because Windows is still initializing this process;
  3. dbghelp.dll will patch srctool’s entrypoint to JMP to one of its malicious functions;
  4. After all initialization has taken place, Windows will resume the main thread @ scrtool’s entrypoint;
  5. The main thread will follow the JMP, dbghelp.dll will load the hidden file, and “start” it.

I’ve seen a variant of this launcher where the legitimate signed tool was vprintproxy.exe (from VMware), and the rogue dll was vmwarebase.dll.

Brazilian banking trojans are getting cooler!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s