Print Story Creating a shim DLL on Microsoft Windows
Technology
By Rogerborg (Sat Feb 18, 2006 at 07:55:21 AM EST) 1337, virginity, nerd (all tags)
Pip pip, chums.  Ever wanted to replace some functionality in a Windows system DLL with your own, for purposes noble or nefarious?   One way to do it is with a shim DLL, that looks and acts like the real thing but which you can hook your own functionality into on a function by function basis.  Enclosed is some C++ source that will create a shim DLL for any arbitrary DLL, replicating all of its exported functions, and (by default) calling straight through to the real system DLL.


The following code, when compiled and run, will take a specified Windows system DLL, FOO.dll and produce a FOO.cpp and FOO.def file which can then be used to compile a shim DLL (which is an exercise for the reader).

The intended use of the shim DLL is to drop it into the directory of a specific executable.  The executable will (in most cases) load the shim DLL instead of the real one.  By default, all functions in the shim DLL call (actually jmp) straight through to the function in the real DLL in the Windows system directory (system32).  You should do this first, to verify that the basic shim DLL works transparently.

Now you can get up to mischief by replacing individual _I_BAR functions with functions with the correct signatures, and call (rather than jmp) through to the real functions, for which you'll need to replace the _O_BAR() function pointer with one with the correct signature.  This allows you to view or modify both the parameters, and the return value.  The uses for this are practically endless; just for example, you can intercept all IP traffic from an application (which Ethereal already allows) but you can also modify the connections, and the incoming or outgoing data.

If you are feeling particularly confident, you could even replace the real system DLL with the shim one, so that all applications will use it.  I do not recommend that you do this, as if you pooch it, you might completely stuff your Windows install.

The code follows.  Save it out and compile it (modifying the CLONE_DLL and/or INSERT_DEBUG_OUTPUT defines first) and run the resulting console executable.  All being well, it will produce a .cpp and .def file.  Use them to build the actual shim DLL, modifying them as required.  In Microsoft Dev Studio, it's as simple as creating a new empty DLL project and including the FOO.cpp and FOO.def files.

I've tested this by shimming WS2_32.dll, which has a fairly hefty set of exports, and it works as expected.  Bug reports and improvements welcome.



#include <stdio.h>
#include <windows.h>
#include <list>
using namespace std;

// Change this to the name of the DLL that you want to clone
#define CLONE_DLL "WS2_32"

// Define this to insert basic fprintf debug into the cloned DLL
#define INSERT_DEBUG_OUTPUT 1

typedef struct
{
    int ordinal;
    char name[64];
} Symbol;

static list<Symbol> gs_symbols;

main()
{
    char originalDLL[256];
    (void)GetSystemDirectory(originalDLL, sizeof(originalDLL) - 1);
    strcat(originalDLL, "\\" CLONE_DLL ".dll");

    char exportFile[256];
    (void)GetTempPath(sizeof(exportFile), exportFile);
    strcat(exportFile, "exports.txt");

    char dumpbin[512];
    sprintf(dumpbin, "dumpbin /exports %s > %s", originalDLL, exportFile);
    (void)system(dumpbin);

    FILE * exports = fopen(exportFile, "r");
    FILE * cpp = fopen(CLONE_DLL ".cpp", "w");
    FILE * def = fopen(CLONE_DLL ".def", "w");

    while(!feof(exports))
    {
        char line[256];
        Symbol newSymbol;

        if(fgets(line, sizeof(line) - 1, exports))
            if(2 == sscanf(line, "%d %*x %*x %s",
                &newSymbol.ordinal,
                newSymbol.name))
                gs_symbols.push_back(newSymbol);
    }

    fprintf(def, "LIBRARY " CLONE_DLL "\n\nEXPORTS\n");

    for(list<Symbol>::iterator symbol = gs_symbols.begin();
        symbol != gs_symbols.end();
        ++symbol)
        fprintf(def, "\t%s = _I_%s @%d\n",
                symbol->name,
                symbol->name,
                symbol->ordinal);

    fprintf(cpp, "#include <stdio.h>\n");
    fprintf(cpp, "#include <windows.h>\n");
    fprintf(cpp, "static HINSTANCE gs_hDLL = 0;\n\n");

#if INSERT_DEBUG_OUTPUT
    fprintf(cpp, "#if defined (_DEBUG)\n");
    fprintf(cpp, "static FILE * debug;\n");
    fprintf(cpp, "#define DEBUG(x) fprintf x\n");
    fprintf(cpp, "#else // DEBUG\n");
    fprintf(cpp, "#define DEBUG(x)\n");
    fprintf(cpp, "#endif // _DEBUG\n\n");
#endif // INSERT_DEBUG_OUTPUT

    for(symbol = gs_symbols.begin();
        symbol != gs_symbols.end();
        ++symbol)
    {
        fprintf(cpp, "int (__stdcall * _O_%s)();\n", symbol->name);
        fprintf(cpp, "extern \"C\" void __declspec(naked) __stdcall _I_%s()\n", symbol->name);       
        fprintf(cpp, "{\n");
#if INSERT_DEBUG_OUTPUT
        fprintf(cpp, "\tDEBUG((debug, \"%s\\n\"));\n", symbol->name);
#endif // INSERT_DEBUG_OUTPUT
        fprintf(cpp, "\t__asm { jmp _O_%s }\n", symbol->name);
        fprintf(cpp, "}\n\n");
    }

    fprintf(cpp, "BOOL WINAPI DllMain(HINSTANCE hI, DWORD reason, LPVOID notUsed)\n");
    fprintf(cpp, "{\n");
    fprintf(cpp, "    if (reason == DLL_PROCESS_ATTACH)\n");
    fprintf(cpp, "    {\n");

#if INSERT_DEBUG_OUTPUT   
    fprintf(cpp, "#if defined(_DEBUG)\n");
    fprintf(cpp, "        if(!debug)\n");
    fprintf(cpp, "            debug = fopen(\"debug.txt\", \"w\");\n");
    fprintf(cpp, "#endif // DEBUG\n");
    fprintf(cpp, "        DEBUG((debug, \"DllMain\\n\"));\n\n");
#endif // INSERT_DEBUG_OUTPUT

    fprintf(cpp, "        char realDLL[MAX_PATH];\n");
    fprintf(cpp, "        (void)GetSystemDirectory(realDLL, sizeof(realDLL) - 1);\n");
    fprintf(cpp, "        strcat(realDLL, \"\\\\" CLONE_DLL ".dll\");\n");
    fprintf(cpp, "        gs_hDLL = LoadLibrary(realDLL);\n");
    fprintf(cpp, "        if (!gs_hDLL)\n");
    fprintf(cpp, "            return FALSE;\n\n");

    for(symbol = gs_symbols.begin();
        symbol != gs_symbols.end();
        ++symbol)
    {
        fprintf(cpp, "        _O_%s = GetProcAddress(gs_hDLL, \"%s\");\n",
                symbol->name, symbol->name);
    }

    fprintf(cpp, "\n        return TRUE;\n");
    fprintf(cpp, "    }\n");
    fprintf(cpp, "    else if (reason == DLL_PROCESS_DETACH)\n");
    fprintf(cpp, "    {\n");

#if INSERT_DEBUG_OUTPUT
    fprintf(cpp, "#if defined(_DEBUG)\n");
    fprintf(cpp, "        if(debug)\n");
    fprintf(cpp, "            fclose(debug);\n");
    fprintf(cpp, "#endif // DEBUG\n\n");
#endif // INSERT_DEBUG_OUTPUT

    fprintf(cpp, "        FreeLibrary(gs_hDLL);\n\n");
    fprintf(cpp, "    }\n");
    fprintf(cpp, "    return TRUE;\n");
    fprintf(cpp, "}\n\n");

    fclose(exports);
    fclose(cpp);
    fclose(def);

    return 0;
}

< I'm a little teapot | BBC White season: 'Rivers of Blood' >
Creating a shim DLL on Microsoft Windows | 34 comments (34 topical, 0 hidden) | Trackback
Got rootkit? by lb008d (3.00 / 2) #1 Sat Feb 18, 2006 at 08:05:43 AM EST
nt



Good heavens! by Rogerborg (4.00 / 2) #6 Sat Feb 18, 2006 at 08:53:54 AM EST
Now that you point it out, it occurs to me that you could use this technique to replace just about any system DLL and pwown a box.  Lucky I recommended that you not do this, eh?

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

Oh, that's boring by Man (2.00 / 0) #2 Sat Feb 18, 2006 at 08:06:26 AM EST
Real fun: Creating shim COM objects for which you have no method definitions for.



Meh, it's called IUknown for a reason. by Rogerborg (2.00 / 0) #7 Sat Feb 18, 2006 at 08:55:42 AM EST
This is just a generalisation of what I did to replace ddraw.dll / dsound.dll, in order to pass cloned IDirectFoo objects back to the unsuspecting victim.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

So by Man (2.00 / 0) #11 Sat Feb 18, 2006 at 10:28:17 AM EST
Did you have to maintain the original COM object instance?

In my case, we had to have access to in process COM objects outside the process. Fun times.

[ Parent ]

Yes I keep them prisoner in little jars by Rogerborg (4.00 / 3) #14 Sat Feb 18, 2006 at 10:58:36 AM EST
Sometimes I shake the jars and make them fight.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

VSTFP!!!!!!! by georgeha (4.00 / 2) #3 Sat Feb 18, 2006 at 08:11:47 AM EST
I think we need more of these stories to drive up circulation and fight the stereotype that Husi is nothing more than boring old fogies complaining about relationships, councils or their job.




I only write this stuff because my job sucks by Rogerborg (4.00 / 4) #10 Sat Feb 18, 2006 at 08:59:46 AM EST
I'd take it out on my vicious gold digging shrew of a wife, but I'm one ASBO away from cleaning off graffiti as it is.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

What gold have you got? by Idempotent (4.00 / 2) #24 Sun Feb 19, 2006 at 12:40:20 AM EST
I thought you were just a lowly code monkey in a dead end job in a company going nowhere?

[ Parent ]

I have a gold tooth by Rogerborg (4.00 / 1) #28 Sun Feb 19, 2006 at 10:19:33 PM EST
Sometimes I wake up to the sound of pliers being oiled.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

I hear such women like to cut things off... by Idempotent (4.00 / 1) #29 Mon Feb 20, 2006 at 01:11:13 AM EST
... in the night.

I assume the obvious has already gone, not that it's of much value of course.

[ Parent ]

How come by joh3n (4.00 / 3) #4 Sat Feb 18, 2006 at 08:16:22 AM EST
When I read shim dll, I thought you were gonna talk about lesbian prison porn?

----



I may do yet by Rogerborg (4.00 / 3) #15 Sat Feb 18, 2006 at 10:59:43 AM EST
What else would the edit facility be for?

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

That brings back memories. by komet (4.00 / 1) #5 Sat Feb 18, 2006 at 08:47:33 AM EST
Back when I was not yet able to have an ejaculation, I made a Windows 3.0 program that prevented the mouse from moving over any Cancel button in a dialog and installed it on various publically accessable computers. The implementation details escape me, but I do seem to recall diverting some calls within the system layer. Perhaps I used a shim DLL, but I really can't remember any more.

--
<ni> komet: You are functionally illiterate as regards trashy erotica.


Well, that was several hundred years ago by Rogerborg (2.00 / 0) #9 Sat Feb 18, 2006 at 08:57:21 AM EST
I mean, if you'd thought to engrave the technique on stone tablets, you might not have so much trouble remembering.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

I did something like this once... by NoMoreNicksLeft (4.00 / 1) #8 Sat Feb 18, 2006 at 08:57:12 AM EST
Nothing quite as elegant, to be sure. At the time, I was working on something absurd, I think it was a clone of Back Orifice for Mac OS8 (Mac Orifice?), but also trying to hide files from explorer.exe (advapi32.dll maybe?).

At age 31, my quest for world domination is over. I think I'll order pizza.
--
Do not look directly into laser with remaining good eye.


IAWTP by wiredog (4.00 / 2) #12 Sat Feb 18, 2006 at 10:30:36 AM EST
Pizza is much better than world domination. Well, if it's good pizza. From the pie place on the corner, not Pizza Rut or Dominators.

Earth First!
(We can strip mine the rest later.)

[ Parent ]

Papa John's. by NoMoreNicksLeft (4.00 / 1) #13 Sat Feb 18, 2006 at 10:43:31 AM EST
Did carryout, since the pizza guy does not seem to comprehend that delivery is "delivery". Last time, he sat out on the the street, and honked the horn.

This is after I'd paid the tip via internet, the fucker.
--
Do not look directly into laser with remaining good eye.
[ Parent ]

missing functionality by martingale (4.00 / 2) #16 Sat Feb 18, 2006 at 01:52:01 PM EST
Your program also needs to write a makefile, and then you need to write a second program which takes the shim source code and splices into it the contents of a second code file, the latter containing the actual extra shim functionality. Then you can invoke it all like so:

shim_creator && shim_inserter myshimbits.cpp && make

And lo and behold, when the next version of WS_32 is downloaded from Microhard, you don't need to fret about the extra exports they've added because your shim boys don't care.

bonus question: how do you install your system dll while preventing Microblow's dll protection hack from replacing it with the original version?
--
$E(X_t|F_s) = X_s,\quad t > s$


you forgot by dr k (4.00 / 4) #17 Sat Feb 18, 2006 at 02:46:14 PM EST
your unit tests.

:| :| :| :| :|

[ Parent ]

yeah, yeah by martingale (4.00 / 1) #20 Sat Feb 18, 2006 at 04:22:48 PM EST
Do, do, do. That's all you management types can say all day. It's a repetitive song.
--
$E(X_t|F_s) = X_s,\quad t > s$
[ Parent ]

That's in the advanced class by Rogerborg (4.00 / 3) #18 Sat Feb 18, 2006 at 03:25:19 PM EST
Bonus answer: you don't.  I'm using this to confuddle individual applications.  What you get up to with system dlls is between you, the Invisible Sky Giant, and the Department of Homeland Security.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

damn it! by martingale (4.00 / 1) #19 Sat Feb 18, 2006 at 04:21:52 PM EST
I _told_ the ISG not to bring the Homeland people into it. Bernie, I said, those Homeland people are _not_ your chosen people, I said.
--
$E(X_t|F_s) = X_s,\quad t > s$
[ Parent ]

Uh huh. by lb008d (2.00 / 0) #21 Sat Feb 18, 2006 at 04:43:37 PM EST
Which is why someone zeroed comment #1 of mine eh?

[ Parent ]

I think that had more to do with google [nt] by yicky yacky (2.00 / 0) #25 Sun Feb 19, 2006 at 04:01:34 AM EST

----
Vacuity abhors a vacuum.
[ Parent ]

Then hole the diary. by lb008d (2.00 / 0) #26 Sun Feb 19, 2006 at 08:32:21 AM EST
Jeez, the borg is giving instructions for creating them here.

[ Parent ]

Security through obscurity, eh? by Rogerborg (4.00 / 1) #27 Sun Feb 19, 2006 at 10:17:56 PM EST
I cannot see any problems with that approach.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

Oh, wait, that was me by Rogerborg (2.00 / 0) #31 Mon Feb 20, 2006 at 03:42:57 AM EST
Oops, that was completely accidental.  I was probably zeroing a bunch of rmg's posts and you got caught in the blast.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

Microsoft research by sasquatchan (4.00 / 1) #22 Sat Feb 18, 2006 at 04:48:22 PM EST
provides a full API hook library. Not windows hooks (messages), but a hooking of the full win32 API.

http://research.microsoft.com/sn/detours/

and they'll give you the full source. (or at least the last time I downloaded it [win2k] they would.. great stuff.. )

Put that in your sheapherds pie and eat it!




That's... obscene by Rogerborg (4.00 / 2) #23 Sun Feb 19, 2006 at 12:17:58 AM EST
If I wanted to shoot fish in a barrel, I'd go hunting with a lawyer.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

Didn't understand a word of that by nebbish (4.00 / 1) #30 Mon Feb 20, 2006 at 01:11:27 AM EST

--------
It's political correctness gone mad!


It's the Windows equivelant by Rogerborg (4.00 / 3) #32 Mon Feb 20, 2006 at 03:45:06 AM EST
Of sticking a card cloners over the slot of an ATM in order to steal the money and identity of everyone who uses it robustly test the bank's security systems.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

Nice by hulver (4.00 / 1) #33 Mon Feb 20, 2006 at 06:56:59 AM EST
That should come in handy, thanks.
--
Cheese is not a hat. - clock


n/p by Rogerborg (2.00 / 0) #34 Tue Feb 21, 2006 at 02:02:58 PM EST
You might want to remove some of the global data that I've left in there while stripping down and generalising a more complex version.

-
Metus amatores matrum compescit, non clementia.
[ Parent ]

Creating a shim DLL on Microsoft Windows | 34 comments (34 topical, 0 hidden) | Trackback