DLL Redirection — debugging techniques for Windows Applications
Just how exactly should that API be called?
When you’re dealing with a simple Windows API call such as MessageBox, you can probably deduce what you should be doing via an experiment or two, but some API calls are non-trivial and involve a lot of set up, particularly the likes of Volume Shadow Copy, and some more obscure, undocumented APIs.
Luckily, there is a way to trivially work out how applications use these APIs, if you can identify one that does what you think it should. Firstly, dependency walker should be used to profile the calls an application is making and which DLLs are being made.
The next thing you need to know is that it is possible to redirect DLL function calls in Windows. This technique means you can effectively replace a system DLL with your own DLL, provided you redirect all of the symbols in it to the original.
So the next thing you need to do is to list the functions exported by a DLL. The SDK gives you a utility to do this — here’s an example:
C:> dumpbin /exports c:windowssystem32kernel32.dll
Microsoft (R) COFF/PE Dumper Version 11.00.50214.1
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file c:windowsSystem32kernel32.dll
File Type: DLL
Section contains the following exports for KERNEL32.dll
4E20FCBC time date stamp Sat Jul 16 03:51:40 2011
1 ordinal base
1390 number of functions
1390 number of names
ordinal hint RVA name
138 89 00023190 CreateFileA
139 8A 0000EAD0 CreateFileMappingA
140 8B 00064FB0 CreateFileMappingNumaA
141 8C 0004C550 CreateFileMappingNumaW
142 8D 0000F9F0 CreateFileMappingW
143 8E 000759C0 CreateFileTransactedA
144 8F 00075820 CreateFileTransactedW
145 90 00011870 CreateFileW
Since I detest the very sight of VBScript, I chose to write the next part in Python. This essentially processes the raw output from dumpbin, producing a header which includes linker pragmas to set up DLL redirection.
funcs = 
exports = re.compile('s+d+s+[A-Fa-f0-9]+s+'
redirexps = re.compile('s+d+s+[A-Fa-f0-9]+s+(?P<functionname>S+)'
's+(forwarded to '
with open(file_path, "rb") as f:
line = f.readline()
if not line:
matches = exports.match(line)
matches = redirexps.match(line)
def convert_to_pragma(funcs, orig_dll):
return ["#pragma comment(linker, "/export:%s=%s.%s,@%d")" %
(func, orig_dll, func, i) for i, func in enumerate(funcs, 1)]
def write_defs(funcs, output_file):
deffile_text = "LIBRARY vssapi.dllnn"
deffile_text += "EXPORTSn"
for func in funcs:
special processing is needed for C++ redirects
deffile_text += " %s=Redirected%sn" % (func, func)
deffile_text += "nn"
with open(output_file, "wb") as f:
def write_full_header(pragma_lines, output):
header_text = "/* DLL Redirection Header */ nn"
header_text += "#pragma oncenn"
for p in pragma_lines:
header_text += "%sn" % (p)
header_text += "nn"
with open(output, "wb") as f:
if __name__ == "__main__":
input_file = sys.argv
target_dll = sys.argv
output_prefix = sys.argv
output_header = "%s.h" % (output_prefix)
output_defs = "%s.def" % (output_prefix)
If you include this header in a project named after the DLL you want to intercept, in our case kernel32.dll, and rename the original dll kernel32_0.dll, paste these into the application directory, depends.exe will show you this:
In other words, all the calls to kernel32.dll (ours) are being redirected to the original - note we've some interesting behaviour going on, because our kernel32.dll uses the real kernel32.dll...
Now, here's the magic. We do not have to redirect those functions - we could export symbols matching the names of those functions ourselves, and do whatever we felt like doing.
This is how you work out how an obscure API call is used - replace it with a stub which does two things:
- Writes the arguments somewhere useful, e.g. a log file
- Calls the original
It's that simple. The possibilities extend way beyond this, of course. You can write any code you like in place of the existing function call. A brief function would look like this:
typedef HANDLE (WINAPI *pCreateFileW)(LPCTSTR,DWORD,DWORD,LPSECURITY_ATTRIBUTES,
DWORD, DWORD, HANDLE);
extern "C" HANDLE WINAPI RedirectedCreateFileW (
HMODULE hOrigLib = LoadLibrary(L"kernel32_0.dll");
pCreateFileW orig_func = (pCreateFileW)
// do something here
HANDLE h = orig_func(lpFileName, dwDesiredAccess, dwShareMode, lpSA,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
Of course, this method is quite intrusive, requiring copying DLLs into place. On the plus side, it works with delay-loaded DLLs via LoadLibrary, for which IAT Hooking fails. Since we're not needing to hide with this technique, for what we want it makes perfect sense.