插件开发手册

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

拦截64位进程send封包 - WPE_GetSendx64

接口 ID 202 | 分类:网络 WPE 封包

作用说明

远程TCP拦截(WPE 系列,64 位目标):hook 64位目标进程 ws2_32.dll 的 send 函数入口,目标每次调 send 时把 套接字、封包数据指针、封包长度 3 个参数回调给宿主子程序。x64 调用约定参数在寄存器(rcx=套接字 rdx=封包指针 r8=长度),插件在 hook 入口直接取寄存器快照;pid 目标进程(必须是 64 位);callback 回调子程序地址,原型 void f(unsigned long long 套接字, unsigned long long 封包指针, unsigned long 长度),回调运行在插件后台线程(要快),封包内容用 读内存 接口按指针+长度自己读。失败用 GetLastError 取原因:-20 目标不是64位进程 -21 找不到send -22 入口指令无法识别 -23 内部消息窗口创建失败 -24 hook安装失败 -25 参数无效

参数说明
参数名方向类型说明
pid[in]long目标进程 ID(十进制整数);可用 GetWindowProcessId 从窗口句柄取得。不能为 0:拦截方法传 0 会得到 -25 参数无效,停止方法传 0 直接返回 0,列表方法传 0 查不到任何套接字
callback[in]__int64 (int64)宿主进程里的回调子程序地址(64 位整数,接口类型为 hyper;不要用 32 位 LONG 存函数地址,高位会被截断)。原型 void f(unsigned long long 套接字, unsigned long long 封包指针, unsigned long 长度);不能为 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;
}

// 封包回调子程序:原型 void f(unsigned long long 套接字, unsigned long long 封包指针, unsigned long 长度)
// 运行在插件后台线程,目标线程会停在 send 入口等它返回,务必尽快结束,不要做耗时操作
static void __stdcall OnSend(unsigned long long s, unsigned long long buf, unsigned long len) {
    // 封包内容请用内存读接口,按 buf + len 到目标进程里读取;buf 不是本进程指针
    std::cout << "sock=" << s << "  buf=0x" << std::hex << buf
              << "  len=" << std::dec << len << std::endl;
}
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(可用 GetWindowProcessId 从窗口句柄取得)
        __int64 callback = (__int64)(ULONG_PTR)&OnSend;  // OnSend 的函数地址,按 64 位整数传
        VARIANT_BOOL v = g_plug->WPE_GetSendx64(pid, callback);
        std::cout << "是否启用: " << (v ? 1 : 0) << std::endl;
    } catch (_com_error& e) {
        std::wcout << L"COM error: " << e.ErrorMessage() << std::endl;
    }

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

返回值

返回 1 表示拦截已启用、0 表示失败(原因用 GetLastError 取);未授权时同样返回 0,且不抛异常。

常见注意事项
  • pid 是目标进程 ID(十进制整数),可用 GetWindowProcessId 从窗口句柄取得。32 位目标用 WPE_GetSend / WPE_StopSend,64 位目标用 WPE_GetSendx64 / WPE_StopSendx64,位数选错会直接失败。
  • 只支持 64 位目标进程;32 位目标请改用 WPE_GetSend,位数选错直接失败并返回 -20。
  • x64 调用约定的前三个参数在寄存器里(rcx=套接字、rdx=封包指针、r8=长度),插件在 send 入口直接取寄存器快照,不读栈参数。
  • 拦截覆盖长度从 send 入口按整条指令累加到至少 5 字节(上限 32 字节);入口指令无法识别会返回 -22。
  • callback 是宿主进程里回调子程序的地址,按 64 位整数传入(接口类型 hyper),不要用 32 位 LONG 存函数地址;原型 void f(unsigned long long 套接字, unsigned long long 封包指针, unsigned long 长度),示例里已给出可直接编译的 OnSend。
  • 回调运行在插件后台线程且目标线程会同步等待,必须尽快结束;封包内容要自己按「目标进程里的封包指针 + 长度」用内存读接口读取,不能直接解引用。
  • 同一进程重复启用会先自动停掉旧的拦截;程序退出前请调用 WPE_StopSendx64 卸载。
  • 失败时用 GetLastError 取原因:0 成功、-20 目标不是 64 位进程、-21 找不到 send、-22 入口指令无法识别、-23 内部消息窗口创建失败、-24 拦截安装失败(含打不开目标进程或读不到内存)、-25 参数无效(pid 或 callback 为 0)。
  • 本方法为收费功能,调用前需先执行 SetUsername 传入有效授权码(示例开头已激活该调用,发布时请改为你自己的授权码);未授权时列表方法返回空串、拦截与停止方法返回 0,都不抛异常。