自动创建您的代理 DLL






4.91/5 (45投票s)
2006年11月27日
2分钟阅读

459857

5724
这是一个小程序,它将基于另一个 DLL 的导出项创建代理 DLL 的 CPP 和 DEF 文件。 您可以使用它来生成一个模板,然后编辑该模板以满足您的需求。
引言
我们许多人都尝试创建代理 DLL 来替换现有的 DLL 并监视其他程序的调用。 这是一个小程序,它将基于另一个 DLL 的导出项创建代理 DLL 的 CPP 和 DEF 文件。 您可以使用它来生成一个模板,然后编辑该模板以满足您的需求。
背景
创建代理 DLL 时,您必须精确地导出与原始 DLL 导出的名称相同的名称。 这可能很麻烦,原因有两个
- 导出项太多。
- 有些函数您不知道它们的作用;您只想监视一个特定的函数调用。
第二个问题可以通过汇编和 __declspec(naked)
属性来解决。 该程序创建函数存根,这些存根除了 JUMP
(不是调用)到导出的地址外,什么也不做,因此堆栈保持原样。 这允许您仅为确实知道其作用的函数创建代码。
使用程序
WRAPPIT <dll> <txt> <convention> <point dll name> <cpp> <def>
<dll>
是您要创建的新 DLL 名称。 该程序可以使用 VC++ 或 BC++ 编译 DLL,具体取决于您如何注释或编辑第 233-237 行// // _stprintf(ay,_T("BCC32 -o%s.obj -c %s\r\n"),argv[5],argv[5]); _stprintf(ay,_T("CL.EXE /O2 /GL /I \".\" /D \"WIN32\" /D \"NDEBUG\" /D" "\"_WINDOWS\" /D \"_WINDLL\" /FD /EHsc /MT /Fo\".\\%s.obj\" " "/Fd\".\\vc80.pdb\" /W3 /nologo /c /Wp64 /TP " "/errorReport:prompt %s\r\n"),argv[5],argv[5]); system(ay); // _stprintf(ay,_T("ILINK32 -c -Tpd %s.obj, // %s,,,%s\r\n"),argv[5],argv[1],argv[6]); _stprintf(ay,_T("LINK.EXE /OUT:\"%s\" /INCREMENTAL:NO /NOLOGO /DLL" " /MANIFEST /DEF:\"%s\" /SUBSYSTEM:WINDOWS /OPT:REF " "/OPT:ICF /LTCG /MACHINE:X86 /ERRORREPORT:PROMPT " "%s.obj kernel32.lib user32.lib gdi32.lib winspool.lib " "comdlg32.lib advapi32.lib shell32.lib ole32.lib " "oleaut32.lib uuid.lib odbc32.lib odbccp32.lib\r\n"), argv[1],argv[6],argv[5]); system(ay); //
<txt>
是一个包含原始 DLL 导出项的文本文件。 您可以使用dumpbin
创建此文件dumpbin /exports original.dll > exports.txt
或使用
tdump
tdump original.dll -ee > exports.txt
<convention>
是您希望函数拥有的调用约定。 您通常希望使用__stdcall
,但使用什么几乎无关紧要,因为存根函数会立即跳转到现有代码,因此它们应该适用于任何调用约定。<point dll name>
是您的代理 DLL 将尝试加载的 DLL 名称。 确保使用 C++ 转义字符,例如\\
。<cpp>
是生成的 CPP 文件。<def>
是生成的 DEF 文件。
示例
您有 WSOCK32.DLL,并且您想为其创建一个代理,将其替换为 WSOCK32_.DLL。 你会怎么做?
move wsock32.dll wsock32_.dll
dumpbin /exports wsock32_.dll > exports.txt
wrappit wsock32.dll exports.txt __stdcall .\\wsock32_.dll wsock32.cpp wsock32.def
这将
- 解析文本文件中的导出项并创建 DEF 文件。 仅支持按序号导出的函数。
- 创建示例 CPP 代码。 在 DLL 的代码
DllMain
中,将使用LoadLibrary()
加载原始的wsock32_dll
。 然后,所有原始导出的函数的地址将通过GetProcAddress
返回并存储在内部指针中。 然后将为每个函数创建存根。
一个 CPP 文件将如下所示
//
#include <windows.h>
#pragma pack(1)
HINSTANCE hLThis = 0;
HINSTANCE hL = 0;
FARPROC p[75] = {0};
// -----------
BOOL WINAPI DllMain(HINSTANCE hInst,DWORD reason,LPVOID)
{
if (reason == DLL_PROCESS_ATTACH)
{
hLThis = hInst;
hL = LoadLibrary(".\\wsock32_.dll");
if (!hL) return false;
p[0] = GetProcAddress(hL,"AcceptEx");
p[1] = GetProcAddress(hL,"EnumProtocolsA");
p[2] = GetProcAddress(hL,"EnumProtocolsW");
...
}
if (reason == DLL_PROCESS_DETACH)
{
FreeLibrary(hL);
}
return 1;
}
// AcceptEx
extern "C" __declspec(naked) void __stdcall __E__0__()
{
__asm
{
jmp p[0*4];
}
}
// EnumProtocolsA
extern "C" __declspec(naked) void __stdcall __E__1__()
{
__asm
{
jmp p[1*4];
}
}
// EnumProtocolsW
extern "C" __declspec(naked) void __stdcall __E__2__()
{
__asm
{
jmp p[2*4];
}
}
...
//
一个 DEF 文件将如下所示
EXPORTS
AcceptEx=__E__0__ @1141
EnumProtocolsA=__E__1__ @1111
EnumProtocolsW=__E__2__ @1112
...
您现在可以编辑 CPP/DEF 文件并重复使用它们来创建您自己的代理 DLL!
重要!
一旦 cpp 准备就绪,您应该替换您知道如何使用的函数。 例如,如果您想监视 Wsock32.send()
// send, created by wrappit
extern "C" __declspec(naked) void __stdcall __E__69__()
{
__asm
{
jmp p[69*4];
}
}
// If you want to manipulate it, change to:
extern "C" int __stdcall __E__69__(SOCKET x,char* b,int l,int pr)
{
// manipulate here parameters
.....
// call original send
typedef int (__stdcall *pS)(SOCKET,char*,int,int);
pS pps = (pS)p[63*4];
int rv = pps(x,b,l,pr);
return rv;
}
历史
- 2007 年 5 月 14 日 - 修复了当 dumpbin.exe 也生成 RVA 信息时发生的问题