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
- What is ‘Name Mangling’ and ‘Function Decoration’? When and why is it necessary?
- Why is the
declspace(naked)
attribute used for method__encryptString()
? - Why was the shim DLL’s method named
__encryptString()
and notencryptString()
? Could we have named the methodencryptString()
instead of__encryptString()
? - Why could we reference the first argument as
[esp+8]
? - Why would code placed after the
__asm jmp jmpaddr
instruction never execute?