Backdooring a DLL

Howdy!

It’s been a dogs age, but I’m back at it. I had a crazy idea come to me. Backdoor a common DLL. From time to time I’ll download a dll off the net if its required for some other program to run. It hit me, how can I modify a dll to be backdoored for use? and DLL Sidejacking

Modification of a dll isn’t hard – they’re just exes. The main difference is they cannot be invoked directly (double click, createprocess, etc). They can however be loaded with rundll32.exe, or called via one of their exported entry points.

First off, a little on how dll’s work. For those of you who run Linux, think of a dll as a shared object. There are two kinds of library files – dynamic ones and static ones. A static library (.lib file) is just that – a library file that’s compiled into an exe. Dynamic Link Libraries allow a developer to break up their applications into components. That way when a patch is needed, they don’t need to re-compile the whole thing. They also make a program smaller in size when they rely on dll files rather than compiling in a large static library.

dll_files

How do you backdoor a dll? Same way you backdoor any other exe – replace the entry point with your own code and jump back when you’re done. In the case of a dll, you’re overwriting the EXPORTED function code to ensure your code is hit. This works the same way as a dll hijacking attack. When it comes to modification, you can either

A) Try and find code caves and cram what you need inside
B) Add a new code section yourself and cram what you need in there
C) Dynamically allocate the space you want. This implies you already have the space needed to add the code to dynamically add more, but its still an option. This is done via VirtualAlloc / VirtualProtect, and WriteProcessMemory win32 apis.

Once you add your code, you have be mindful of what you call. Exes have what’s called an ‘import address table‘ (IAT) which is a table list of functions and their respective dll’s they’re imported from. If you attempt to call a function without its respective IAT entry, it won’t work. This means you will either have to add an entry to the IAT meaning modify the exe header, or find some other way of calling the code dynamically. If you’ve ever done C development in windows, you know you can pair up LoadLibrary with GetProcAddress() to call an external dll function. This is still an option. Shellcode developers on the other hand like to call functions the fancy way – getting addresses from the Thread Environment Block (TEB) / Process Environment Block (PEB). For the sake of simplicity, I’m going to just call code that’s already inside the executable image.

There are problems you will encounter with attempting to replace code. The obvious problem is finding the space in an exe to place your code. This means we’ll need to find a Code Cave (empty space in the exe to place our code), or add a new executable section. For my example, I only need about 70 bytes, so adding a new section isn’t necessary. I could also string several code caves together. There’s also the problem of function / program checksums – some applications refuse to run if they’ve been modified.

In this example I will be going after Foobar2000 because its my media player of choice.

foobar

First we need to pick a dll import entry to patch.

foobar2

I will be backdooring the file ‘shared.dll’ as it is employed by Foobar2000. Looking at the import table of foobar and export table of shared.dll, I’ve chosen the dll export ‘uGetOpenFileName’ for its playlist file creation capabilities.

shared_export

Now that we’ve selected an export entry to backdoor, we need to find a cave to write to. I’m using http://www.openrce.org/downloads/details/70/Cave and IDA pro.

shared_dll_screen1
40 bytes is good, but its slim pickings

shared_dll_screen2

Here we have 3 caves. 1 in the text section that’s 73 bytes, 1 in .rdata that’s 2811 bytes and 1 in .data that’s 3492 bytes. 73 bytes is just enough a snug fit for me.

If we wanted to use the other 2 caves listed, we would have to change section header code protection flags – .data and .rdata are usually global / local variable storage and their memory spaces marked non executable. This can however be changed with cff explorer.
section_data

We could also, in a pinch, make use several smaller caves (smaller byte number search) within the .text section from alignment bytes and string them together:
caves
These little caves are generated by the compiler for the sole purpose of maintaining stack alignment and are usually either made up of NOP (0x90) instructions or int3 instructions (0xCC) and can be changed to whatever we want. This of course is difficult because you need 5 bytes to jump, leaving you 10 bytes to do whatever before jumping to the next area. Difficult, but not impossible.

Anyways, we have our code cave, we’ll need to perform a long jump to it meaning we need at least 5 bytes of data to perform the jump. Anything we copy over will have to be restored. Looking at the exported entry for ‘uGetOpenFileName’, I see a perfect place for a long jump to our code cave without messing up the sub routine too much.
export_selection

Specifically between 10003422 and 10003427, 5 bytes of space is enough to perform a long jump to our code cave. All we would have to do when we jump back is remember to move ‘2090h’ into the EAX register when we jump back to 10003427. Easy enough right? But what do we call? For this example, I will be calling an entry inside the dll’s import address table. If an entry is missing, we’ll have to resort to other methods (shellcode, PEB ldr method, getprocaddress / loadlibrary, etc) to call our code. For the sake of simplicity, I’m using stuff already in the import address table. Lucky for us, MessageBoxW exists in the IAT:

iat
Take note of the address 1001C2C0 for MessageBoxW, it will come in handy later.

A big problem we run into with adding new code is relocation. Relocation is the process of assigning load addresses to various parts of a program and adjusting the code and data in the program to reflect the assigned addresses. Windows will relocate an image’s base address to something other than what’s defined in the PE header in order to satisfy ASLR (address space layout randomization). For more info on relocation, see http://www.drdobbs.com/rebasing-win32-dlls/184416272. Using the import address table’s Relative Virtual Address, we can call what we want. Position independence is key or this wont work. We have to get creative.

In the following code, we’re going to use the instruction pointer and the Import Address Table’s Relative Virtual Address (RVA) to call what we want, and tell relocation to take a hike.

We can obtain the address of the instruction pointer a number of ways, but in my example I’m using the pointer to ESP call / ret trick.

MOV EAX,DWORD PTR SS:[ESP]
RETN

Remember the value 1001C2C0? The first 16 bits are relocated at run time. The last 16 bits of that Import Address Table entry is the RVA to our function. By adding that to the first 16 bytes of our instruction pointer, we get the address of our function we can call.

call    GetEip 	; mov     eax, [esp]  then ret, place EIP in the EAX register
xor     ebx, ebx ; clear EBX
mov     ax, bx ; store the first 16 bits of e(ax) in bx
;ax should now be the first 16 bits of the relocation address
add     eax, 0C2C0h		; add the RVA of MessageBoxW to the value
call    [eax] ; call it.

Oh wait I’m forgetting something aren’t I? Can’t just up and call MessageBoxW without a few extra arguments can I? Like strings? There are problems with strings when it comes to injecting code into caves or dynamic code for that matter. In assembly, strings are nothing more than arrays of bytes that are stored sequentially in memory. You define them in assembly using the DB / DD / DW directives. We can’t just define bytes because when we reference them, they will be locked to a region and not position independent.

stringz

Note the bytes, locked to a memory region If I want to use this, I have to push the address 00401080 as an argument which will change each time the dll is loaded (thanks relocation).

How do we get around this? We have to use the stack with our strings.

You can speed up the process of writing assembly considerably if you write out what you want in C first, then check out the assembly output later. For example, forcing the compiler to use the stack, here we have C code:

#define _UNICODE
#include <windows.h>
#include <wchar.h>

int main(void)
{
	char kek[] = "joe not hurr";
	MessageBoxA(NULL, kek, kek, 0x00000010);
	register WCHAR s[] = L"Joerox";
	MessageBoxW(NULL, s, s, 0x00000010);
	return 1;
}

Note: I had to use the register keyword for the WCHAR Unicode constant or else the compiler INSISTS on placing the chars in the data segment. I’m not sure if this is a bug or a feature. Here is the assembly output:

PUSH EBP
MOV EBP,ESP
SUB ESP,1C
MOV DWORD PTR SS:[EBP-D],20656F6A
MOV DWORD PTR SS:[EBP-9],20746F6E
MOV DWORD PTR SS:[EBP-5],72727568
MOV BYTE PTR SS:[EBP-1],0
PUSH 10                 ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
LEA EAX,DWORD PTR SS:[EBP-D]             ; |
PUSH EAX                                 ; |Title
LEA EAX,DWORD PTR SS:[EBP-D]             ; |
PUSH EAX                                 ; |Text
PUSH 0                                   ; |hOwner = NULL
CALL DWORD PTR DS:[<&USER32.MessageBoxA>>; \MessageBoxA
MOV WORD PTR SS:[EBP-1C],4A
MOV WORD PTR SS:[EBP-1A],6F
MOV WORD PTR SS:[EBP-18],65
MOV WORD PTR SS:[EBP-16],72
MOV WORD PTR SS:[EBP-14],6F
MOV WORD PTR SS:[EBP-12],78
MOV WORD PTR SS:[EBP-10],0
PUSH 10                   ; /Style = MB_OK|MB_ICONHAND|MB_APPLMODAL
LEA EAX,DWORD PTR SS:[EBP-1C]            ; |
PUSH EAX                                 ; |Title
LEA EAX,DWORD PTR SS:[EBP-1C]            ; |
PUSH EAX                                 ; |Text
PUSH 0                                   ; |hOwner = NULL
CALL DWORD PTR DS:[<&USER32.MessageBoxW>>; \MessageBoxW
MOV EAX,1
MOV ESP,EBP
POP EBP
RETN

Note the difference between ANSI and Unicode strings on how they’re moved onto the stack. ANSI chars are byte aligned, while Unicode chars are word aligned. We can use this with a few minor modifications. Namely, we want to use EAX for other stuff, and we want to save space, but other than that, this will work.

When it comes to patching, I prefer to use immunity debugger. First we look for our exported entry, then we look for the mov eax, 2090h, then we replace with a long jump to our code. Easiest way to find out our exported entry is via the text search command. referenced

The ‘UGetOpenFileName’ entry should lead us to our entry point for editing.

__23

Then we do our business, placing a string on the stack, and calling out IAT entry then move 2090 into eax, then jump back.
_34

Next we save, and boom.

Here is the finished result:
caved_code
Not if I do say so myself. Now, running the thing, we load up Foobar with our dll in the same directory, play a song, click ‘save playlist’ and viola, our messagebox is run. *applause*.
___56

Maybe that’s worth a golf clap? Oh well, it least I got a message box and it at least it didn’t crash.

You can find the files here.. Password is 12345.

Stay tuned for part 2 where we’re going to go after uxtheme.dll because it’s unsigned, and used by everything.

Happy Haxing!

1464967829372

4 thoughts on “Backdooring a DLL

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.