Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

DLL function forwarder(s) by ordinal

414 views
Skip to first unread message

Marcel van Brakel

unread,
Jan 7, 2000, 3:00:00 AM1/7/00
to
Hi all,

I am writing a dll to temporarily "replace" a system dll for debugging
purposes. I need to "hook" into only a few functions and want to forward all
others using the #pragma comment(linker, ...). The trouble is that the
functions are only exported by ordinal and not by name from the original
system dll. The question: is it possible to forward by ordinal? If so, could
you please give me an example...

regards,
Marcel

Jeff Partch

unread,
Jan 9, 2000, 3:00:00 AM1/9/00
to
Hi, Marcel!

If you have an import library for the dll, use that in step 1 instead. The
dumpbin output will list all of the function names, ordinals and prototypes.
But in the worst case, you have only the *.dll file available -- no headers,
no import libraries no nothing, so I'll start from that premise. For named
functions, the MS supplied imagehlp library supplies a function that will
decode the mangling back into a true prototype, but I don't know an easy way
to recreate the ordinal-only export hook without an import library. You can
certainly do it, if you know the prototype of the function. It's not the
ordinal-only that's the problem. Anyway...

This example assumes the existence of a dll called "hello.dll" that exports
the following...

Exports

ordinal name

1 ?Hello@@YAXXZ (void __cdecl Hello(void))
2 ?nHello@@3HA (int nHello)
3 ?Goodbye@@YAXXZ (void __cdecl Goodbye(void))
4 ?Bogus@@YAXPBD@Z (void __cdecl Bogus(char const *))

And a calling application that links to it implicitly and calls its exported
functions like so...

void CUsehelloApp::OnUseDllMenuItem()
{
typedef void (__cdecl *PFNHELLO)(void);
PFNHELLO pfnHello;
CString strValue;
HMODULE hMod;

strValue.Format("Imported = %d\n", nHello);

Hello();
Goodbye();
Bogus((LPCSTR)strValue);

if ((hMod = GetModuleHandle("HELLO")) &&
(pfnHello = (PFNHELLO)GetProcAddress(hMod, "?Hello@@YAXXZ")))
{
(*pfnHello)();
}
}

And lastly, that we have created a Win32 Dynamic-Link Library project in
ClassWizard. Our goal is to create a wrapper dll with the same name and
module name as the original and that implicitly links to the original under
an assumed name. So our project in this example is called "hello" and our
wrapper will be called "hello.dll", and the original will be renamed to
"hellow.dll".

Okay, here's the steps...

1. Use Dumpbin /Exports on the original "hello.dll" to get a list of them.
The example dll produces this...

ordinal hint RVA name

1 0 00001014 ?Hello@@YAXXZ
2 1 00032A60 ?nHello@@3HA
3 00001005 [NONAME]
4 0000100A [NONAME]

2. Turn this into a mock .Def file called "hellow.def" and save it to the
base project directory. If you add the file to the project, make sure that
the Settings->exclude from build box is checked. Note that we rename the
module in the def file as well. Like this...

LIBRARY hellow
DESCRIPTION "Phony def file for hello.dll wrapper"
EXPORTS
?Hello@@YAXXZ @1
?nHello@@3HA @2
ExpFunc3 @3 NONAME
ExpFunc4 @4 NONAME

Assuming that we don't know the names of the ordinal-only exports we just
make one up for internal use. If we do know the name of an export, we
preserve it. In both cases, the original ordinal values are preserved.

3. Now run this through LIB to create an import library

LIB /MACHINE:IX86 /DEF:hellow.def

You can add this line to the Pre-Link step in the project settings.

4. Now for the real fun! Add a new cpp file to your project called
"hellow.cpp", and fill it in like so...

#include "stdafx.h"

#pragma comment(lib, "hellow.lib")

#pragma comment(linker, "/EXPORT:?Hello@@YAXXZ,@1=HELLOW.@1")
#pragma comment(linker, "/EXPORT:?nHello@@3HA=HELLOW.?nHello@@3HA,@2")
#pragma comment(linker, "/EXPORT:_ExpFunc3,@3=HELLOW.@3,NONAME")
#pragma comment(linker, "/EXPORT:_ExpFunc4,@4=HELLOW.@4,NONAME")

5. Building this, we get a true pass-through wrapper -- no functions are
hooked yet. To accomplish this for say the "Hello()" export, we must first
modify our mock DEF file, by changing the name of the function like so...

EXPORTS
?FwdHello@@YAXXZ @1

Note that all of the name-mangling stuff is left intact. Now run this
through LIB again like we did in step 3.

6. Now add this code to the end of "hellow.cpp" to create a replacement
exported function with the same name, ordinal and prototype as the original
(none of the previous lines from step 4 above are modified)...

#pragma comment(linker, "/EXPORT:?FwdHello@@YAXXZ=HELLOW.@1")
void __cdecl FwdHello(void);

void __cdecl Hello(void)
{
OutputDebugString(" Hello -- Intercepted!\n");
FwdHello();
}

By preserving the original function name and ordinal in our hook function,
we also get to hook GetProcAddress calls as well. Just so there'll be no
uncertainty here, neither the original DLL or the application that uses it
gets modified or rebuilt in the above steps. All we did to the original dll
was rename it, and place our wrapper dll into it's path.

Lastly, I have not done alot of this on alot of different dll's, so there's
no telling where the gotcha's are hiding. Good luck, and...

HTH,

Jeff...

0 new messages