插件开发手册

插件产品介绍
Game-Plug 是一款功能强大的 Windows 逆向开发插件,兼容 VC++、Delphi、VB、按键精灵、火山 PC、等多种编程语言调用。它面向编程人员提供窗口、内存、线程、汇编、HOOK、注入、Call、按键、封包、驱动防检测等全方位操作命令,并配有对应的使用案例示范,简单易学、上手快、实用性强。
目录导航

调用目标进程函数 - Call

接口 ID 115 | 分类:DLL 注入与远程执行 | 收费功能

作用说明

在目标进程里按地址调用一个函数,并取回该函数的返回值。目标进程是 32 位还是 64 位会自动适配;参数用逗号分隔的字符串传入,最多 6 个。

参数说明
参数名方向类型说明
pid[in]long目标进程 ID(十进制整数);可用 GetWindowProcessId 从窗口句柄取得。不能为 0。
addr[in]__int64 (int64)目标进程内的函数地址(64 位整数,可写 0x 十六进制)。32 位目标的地址不能超过 0xFFFFFFFF,超过会直接返回 0。
params[in]string (BSTR)逗号分隔的参数列表字符串,最多 6 个;每个参数可写十进制、0x 十六进制或负数,例如 "1,0x100,-8"。没有参数时填空串。
conv[in]long调用约定:0=stdcall、1=cdecl、2=thiscall(第一个参数作 this 指针)。目标为 64 位进程时本参数不生效。
timeout[in]long等待执行完成的毫秒数;填 0 表示使用默认值 5000 毫秒。超时返回 0。
VC++ 调用示例(x64,控制台工程)
// 说明:本示例为完整 x64 控制台工程,整段复制覆盖新建控制台工程的 main.cpp 即可编译运行。
//   1. VS2019 新建「控制台应用」,项目属性 -> 平台选 x64,才能加载 64 位 DLL。
//   2. 项目属性 -> C/C++ -> 预编译头 -> 改为「不使用预编译头」,否则默认找 pch.h 会报 C1010。
//   3. 把 x64Game-Plug.dll 放到 exe 同目录(#import 与免注册加载都需要)。
//   4. 源码保存为 UTF-8 带 BOM,避免中文乱码;全站用 regsvr32 注册也可(需管理员)。
#include <iostream>
#include <clocale>
#include <windows.h>
#include <comdef.h>

// 免注册加载:用 IGamePlug 智能指针装载
// rename 是为避开 windows.h 的 FindWindow 宏冲突,接口里的 FindWindow 在 C++ 侧改名为 FindWindowGP
#import "x64Game-Plug.dll" no_namespace rename("FindWindow", "FindWindowGP")

static HMODULE      g_hDll = NULL;
static IGamePlugPtr g_plug;

// ---------- 免注册:加载 DLL 并创建对象(发布时把 DLL 放 exe 同目录)----------
static bool LoadPlug() {
    const wchar_t* paths[] = {
        L"x64Game-Plug.dll",
        L"..\\x64Game-Plug.dll"
    };
    for (int i = 0; i < (int)(sizeof(paths) / sizeof(paths[0])); ++i) {
        g_hDll = ::LoadLibraryW(paths[i]);
        if (g_hDll) break;
    }
    if (!g_hDll) {
        std::cout << "LoadLibrary failed: put x64Game-Plug.dll next to the exe" << std::endl;
        return false;
    }
    typedef HRESULT (__stdcall *GamePlugCreateFn)(IGamePlug**);
    GamePlugCreateFn fn = (GamePlugCreateFn)::GetProcAddress(g_hDll, "GamePlugCreate");
    if (!fn) { std::cout << "GetProcAddress GamePlugCreate failed" << std::endl; return false; }
    HRESULT hr = fn(&g_plug);
    if (FAILED(hr)) { std::cout << "GamePlugCreate failed: 0x" << std::hex << hr << std::endl; return false; }
    return true;
}
int main() {
    if (!LoadPlug()) { system("pause"); return 1; }
    // 授权(收费功能需先传入授权码,去 https://www.game-plug.cn/ 获取)
    g_plug->SetUsername(_bstr_t(L"U12-XXXXXXXXXXXXXXXX"));

    // ---------- 调用插件本命令方法如下 ----------
    try {
        long pid = 1234;  // 换成目标进程 ID
        __int64 addr = 0x12345678;  // 换成目标进程内的函数地址
        _bstr_t params = L"1,0x100,-8";  // 逗号分隔,最多 6 个参数;无参数写 L""
        long conv = 0;  // 0=stdcall 1=cdecl 2=thiscall(64 位目标不生效)
        long timeout = 0;  // 0=默认 5000 毫秒
        __int64 v = g_plug->Call(pid, addr, params, conv, timeout);
        std::cout << "函数返回值: " << v << std::endl;
    } catch (_com_error& e) {
        std::wcout << L"COM error: " << e.ErrorMessage() << std::endl;
    }

    g_plug->Release();
    system("pause");
    return 0;
}

返回值

返回被调用函数的返回值:64 位目标取 8 字节整数,32 位目标取 4 字节整数。函数地址为 0、参数解析失败、执行超时或未授权都返回 0,不抛异常。

常见注意事项
  • pid 是目标进程 ID(十进制整数),可用 GetWindowProcessId 从窗口句柄取得;传 0 会直接返回失败。
  • 目标程序以管理员权限运行时,调用方程序也必须以管理员权限启动,否则打不开目标进程、会返回失败。
  • 本分类全部为收费功能,调用前需先执行 SetUsername 传入有效授权码(示例开头已写,发布时换成你自己的授权码);未授权时返回 0,不抛异常。
  • addr 是目标进程内的地址,不是本进程地址;32 位目标的地址不能超过 0xFFFFFFFF,超过会直接返回 0。
  • params 最多识别前 6 个参数,超出部分忽略;每个参数支持十进制、0x 十六进制和负数,参数之间用逗号分隔。
  • conv 只对 32 位目标有效;64 位目标无论填什么都按 64 位统一调用约定执行。选 2(thiscall)时第一个参数作为 this 指针。
  • 同一时刻只允许一个线程调用本方法,占用期间其它线程的调用会直接返回 0,不会排队等待;多线程脚本请自己错开调用。
  • timeout 填 0 使用默认 5000 毫秒,超时返回 0。返回值无法区分「函数本身返回 0」和「执行失败」,需要区分时请让被调用函数返回非 0 标志。
  • 函数地址可以用「内存读写与搜索」分类里的取模块导出函数地址方法取得。