Creating a Proxy/Shim DLL

A while back I found the need for a Win32 shim DLL, so I took the opportunity to create a quick hack-up.

Shim DLLs are normally used to extend or alter the functionality offered by a regular DLL. In my case, I just wanted to observe the data being transmitted from an application to its crypto / hashing library. So we start with an application we’ll call SecProggie and its respective hashing library, SecLibbie.

Now SecLibbie is exporting a few methods but none of them are decorated. As such, we don’t know what argument combination the methods are expecting, unless I take a look at the library’s ASM. I’m avoiding that because I wasnt something I can reuse again later.

One function (exported by SecLibbie) which we are particularly interested in is encryptString(), however, we still don’t know all the arguments.

The Code

We start off by pulling our VC++ tools out of whichever closet we last hid them in, and create a the shim DLL as follows:

#include "windows.h"
#include <stdio.h>

HINSTANCE thisDll = 0;
HINSTANCE realDll = 0;
FARPROC jmpaddr = 0;
long int tmpreg;

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved)
{
	switch (reason)
    {
    	case DLL_PROCESS_ATTACH:
            // {{{ load the library
            thisDll = hModule;
            realDll = LoadLibrary("SecLibbie_.dll");
            if (! realDll) return FALSE;
            // }}}
            
            // get exported method address(es)
            jmpaddr = GetProcAddress(realDll, "encryptString");
            
            break;
            
        case DLL_PROCESS_DETACH:
            // free the real library
            FreeLibrary(realDll);
            break;
    }
    return TRUE;
}

extern "C" __declspace(naked) void __stdcall __encryptString()
{
    // base pointer
    __asm __volatile mov tmpreg, ebp;
    printf("BP  0x%08x | %d | %s \n", tmpreg, tmpreg, tmpreg);

    // stack pointer
    __asm __volatile mov tmpreg, esp;
    printf("SP  0x%08x | %d | %s \n", tmpreg, tmpreg, tmpreg);

    // 1st argument
    __asm __volatile mov eax, dword ptr [esp+8];
    __asm __volatile mov eax, [eax];
    __asm __volatile mov tmpreg, eax;
    printf("A1  0x%08x | %d | %s \n", tmpreg, tmpreg, tmpreg);

    // jump to exported method
    __asm jmp jmpaddr;
}	

We need all calls to encryptString() to be sent to __encryptString() instead, so we setup out exports DEFs to export __encryptString() as encryptString(). DEF file follows:

EXPORTS
encryptString=__encryptString

Once the shim DLL is loaded to run the encryptString() method, the __encryptString() method will be executed instead. Looking at the code, we can see that there is some debug ASM to collect information which could prove to be helpful to determining the arguments.

I will leave you, the reader, the task of inserting your own debug routines which will capture required information for you to view later. (hint: file io?)

Items for you to consider

  1. What is ‘Name Mangling’ and ‘Function Decoration’? When and why is it necessary?
  2. Why is the declspace(naked) attribute used for method __encryptString()?
  3. Why was the shim DLL’s method named __encryptString() and not encryptString()? Could we have named the method encryptString() instead of __encryptString()?
  4. Why could we reference the first argument as [esp+8]?
  5. Why would code placed after the __asm jmp jmpaddr instruction never execute?