65.9K
CodeProject 正在变化。 阅读更多。
Home

自动创建您的代理 DLL

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (45投票s)

2006年11月27日

2分钟阅读

viewsIcon

459857

downloadIcon

5724

这是一个小程序,它将基于另一个 DLL 的导出项创建代理 DLL 的 CPP 和 DEF 文件。 您可以使用它来生成一个模板,然后编辑该模板以满足您的需求。

引言

我们许多人都尝试创建代理 DLL 来替换现有的 DLL 并监视其他程序的调用。 这是一个小程序,它将基于另一个 DLL 的导出项创建代理 DLL 的 CPP 和 DEF 文件。 您可以使用它来生成一个模板,然后编辑该模板以满足您的需求。

背景

创建代理 DLL 时,您必须精确地导出与原始 DLL 导出的名称相同的名称。 这可能很麻烦,原因有两个

  1. 导出项太多。
  2. 有些函数您不知道它们的作用;您只想监视一个特定的函数调用。

第二个问题可以通过汇编和 __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 信息时发生的问题
© . All rights reserved.