You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DLL注入后如何调用目标进程的静态库静态类成员及未导出单例函数

咱们一个一个来解决你的问题:

问题1:如何从DLL注入的目标进程中调用静态库的静态类成员函数?

首先得明确一个核心误区:如果你直接在注入的DLL里链接同一个静态库并调用成员函数,本质是让DLL自带了一份静态库的代码副本——这和目标进程里的静态库实例是完全独立的,根本不是一回事。要调用目标进程里原本的静态库成员函数,核心思路是找到该函数在目标进程内存中的实际地址,通过函数指针来调用。

具体步骤如下:

  • 获取函数的相对虚拟地址(RVA):你手里有目标进程的目标文件(.obj/.pdb等资源),可以用工具解析符号:
    • 用dumpbin /symbols命令从.obj文件里提取函数符号对应的RVA;
    • 如果有.pdb文件,用调试工具(比如x64dbg、WinDbg)或者dbghelp库直接解析符号地址。
  • 计算函数的实际内存地址:在注入的DLL中,用GetModuleHandle获取目标进程中加载静态库的模块基地址(如果静态库是直接链接到主EXE的,那主EXE的模块就是基地址),然后用「基地址 + RVA」得到函数的实际内存地址。
  • 通过函数指针调用:定义匹配的函数指针类型,将计算出的地址强制转换后调用即可。

举个代码例子,假设静态类成员函数是StaticLibClass::DoStaticWork(int):

// 定义函数指针类型,要和目标函数的签名完全匹配
typedef void(*StaticWorkFuncPtr)(int);

void CallTargetStaticFunc() {
    // 获取目标主程序的模块基地址
    HMODULE hTargetModule = GetModuleHandle(L"YourTarget.exe");
    if (!hTargetModule) return;

    // 替换成你实际解析到的RVA
    uintptr_t funcRva = 0x12345;
    StaticWorkFuncPtr pTargetFunc = (StaticWorkFuncPtr)((uintptr_t)hTargetModule + funcRva);

    // 调用目标进程里的静态成员函数
    pTargetFunc(42);
}
问题2:调用目标进程未导出的单例函数是否可行?怎么操作?

当然可行,但你之前的做法确实会出问题——原因你猜的没错:静态变量是每个模块(EXE/DLL)独立存储的,你在注入的DLL里调用VictimSingleton::Get(),创建的是DLL自己数据段里的单例,和目标进程EXE里的单例完全是两个不同的内存对象,自然地址不一样。

解决思路和问题1一致:找到目标进程中VictimSingleton::Get()的实际内存地址,通过函数指针调用它,这样拿到的就是目标进程的单例实例了。具体步骤:

  1. 获取VictimSingleton::Get()的内存地址:

    • 利用你手里的目标文件/.pdb,用调试工具(x64dbg/WinDbg)找到该函数的RVA;
    • 或者用dbghelp库的SymInitialize+SymFromNameAPI自动解析符号地址,避免手动找RVA的麻烦。
  2. 在注入的DLL中通过函数指针调用:
    注意:如果DoThing()是非虚函数,你同样需要获取它的地址并用函数指针调用;如果是虚函数,直接通过单例指针调用就行(因为虚表在目标进程的实例内存里)。

代码示例:

// 前向声明类,不需要完整定义,只要能声明指针类型就行
class VictimSingleton;

// 定义Get()函数的指针类型
typedef VictimSingleton*(*VictimSingletonGetPtr)();
// 如果DoThing()是非虚函数,定义它的指针类型
typedef void(*VictimDoThingPtr)(VictimSingleton*);

void SomeFuncInHook() {
    HMODULE hTargetExe = GetModuleHandle(L"YourTarget.exe");
    if (!hTargetExe) return;

    // 替换成实际的Get()函数RVA
    uintptr_t getFuncRva = 0x67890;
    VictimSingletonGetPtr pGetTargetSingleton = (VictimSingletonGetPtr)((uintptr_t)hTargetExe + getFuncRva);

    // 调用目标进程的Get(),拿到真正的单例实例
    VictimSingleton* vs = pGetTargetSingleton();

    // 调用DoThing()的两种情况:
    // 情况1:DoThing()是虚函数,直接调用
    vs->DoThing();

    // 情况2:DoThing()是非虚函数,需要获取它的地址
    uintptr_t doThingRva = 0xABCDE;
    VictimDoThingPtr pDoThing = (VictimDoThingPtr)((uintptr_t)hTargetExe + doThingRva);
    pDoThing(vs);
}

额外提醒:如果用dbghelp库解析符号,记得要初始化符号库,并且确保目标进程的.pdb文件路径能被正确找到,这样可以避免手动计算RVA的错误,适配不同的编译版本。

内容的提问来源于stack exchange,提问作者Hinchy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:35:35