免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
内容参考于:易道云信息技术研究院VIP课
上一个内容:接管游戏连接服务器的操作
码云地址(master 分支):染指/titan
码云版本号:00820853d5492fa7b6e32407d46b5f9c01930ec6
代码下载地址,在 titan 目录下,文件名为:titan-接管游戏发送数据的操作.zip
链接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg
提取码:q9n5
--来自百度网盘超级会员V4的分享
HOOK引擎,文件名为:黑兔sdk升级版.zip
链接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw
提取码:78h8
--来自百度网盘超级会员V4的分享
以 接管游戏连接服务器的操作 它的代码为基础进行修改
首先通过 通过逆向分析确定游戏明文发送数据过程 分析得出数据发送的位置,然后它与connect用的是同一个对象,所以还是可以用虚函数表:如下图虚函数表3C位置里的函数里调用了send函数

然后它的参数,第一个参数是发送的数据包,第二个数据是发送的数据包的长度,它的返回值是一个bool类型,如下图它的返回值是al,al寄存器是1字节

然后通过下图两个红框位置的赋值操作,也能看出这是一个bool类型(true是1,false是0)

它的函数原型:
bool GameWinSock::Send(char* buff, int len);
模拟游戏发送数据:首先现在无法制作游戏的数据包,所以用游戏生成一个数据包,复制出来

通过按钮发送聊天数据:

资源视图新加按钮:

CUIWnd_0.cpp文件的修改:新加新加按钮点击事件
- // CUIWnd_0.cpp: 实现文件
- //
-
- #include "pch.h"
- #include "htdMfcDll.h"
- #include "CUIWnd_0.h"
- #include "afxdialogex.h"
- #include "extern_all.h"
-
- // CUIWnd_0 对话框
-
- IMPLEMENT_DYNAMIC(CUIWnd_0, CDialogEx)
-
- CUIWnd_0::CUIWnd_0(CWnd* pParent /*=nullptr*/)
- : CDialogEx(IDD_PAGE_0, pParent)
- {
-
- }
-
- CUIWnd_0::~CUIWnd_0()
- {
- }
-
- void CUIWnd_0::DoDataExchange(CDataExchange* pDX)
- {
- CDialogEx::DoDataExchange(pDX);
- }
-
-
- BEGIN_MESSAGE_MAP(CUIWnd_0, CDialogEx)
- ON_BN_CLICKED(IDC_BUTTON1, &CUIWnd_0::OnBnClickedButton1)
- END_MESSAGE_MAP()
-
-
- // CUIWnd_0 消息处理程序
-
-
- void CUIWnd_0::OnBnClickedButton1()
- {
- char buff[] = {
- 0xA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x4, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 00 ,0x00,
- 0x00, 0x07, 0x0E, 0x00, 0x00, 0x00, 0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x31, 0x00, 0x32 ,0x00,
- 0x33, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- WinSock->OnSend(buff, sizeof(buff));
- }
GameWinSock.cpp文件的修改:新加 OnSend函数、_OnSend函数指针变量
- #include "pch.h"
- #include "GameWinSock.h"
- #include "extern_all.h"
-
- GameWinSock::PROC GameWinSock::_OnConnect{};
- GameWinSock::PROC GameWinSock::_OnSend{};
- // 这个函数拦截了游戏的连接
- bool GameWinSock::OnConnect(char* ip, unsigned port)
- {
- // this是ecx,HOOK的点已经有ecx了
- WinSock = this;
- bool b = (this->*_OnConnect)(ip, port);
- // 下方注释的代码时为了防止多次注入,导致虚函数地址不恢复问题导致死循环,通过一次性HOOK也能解决
- /*unsigned* vtable = (unsigned*)this;
- vtable = (unsigned*)vtable[0];
- union {
- unsigned value;
- bool(GameWinSock::* _proc)(char*, unsigned);
- } vproc;
- vproc._proc = _OnConnect;
- DWORD oldPro, backProc;
- VirtualProtect(vtable, 0x10x00, PAGE_EXECUTE_READWRITE, &oldPro);
- vtable[0x34 / 4] = vproc.value;
- VirtualProtect(vtable, 0x10x00, oldPro, &backProc);*/
-
- return b;
- }
-
- bool GameWinSock::OnSend(char* buff, unsigned len)
- {
-
- /*
- 这里就可以监控游戏发送的数据了
- */
- return (this->*_OnSend)(buff, len);;
- }
GameWinSock.h文件的修改:新加 OnSend函数、_OnSend函数指针变量
- #pragma once
- class GameWinSock
- {
- typedef bool(GameWinSock::* PROC)(char*, unsigned);
- public:
- static PROC _OnConnect;
- static PROC _OnSend;
- bool OnConnect(char* ip, unsigned port);
- bool OnSend(char* buff, unsigned len);
- };
GameProc.cpp文件的修改:修改了 _OnConnect函数
- #include "pch.h"
- #include "GameProc.h"
- #include "extern_all.h"
-
- // typedef bool(GameWinSock::* U)(char*, unsigned);
-
-
-
- bool _OnConnect(HOOKREFS2) {
- /*
- 根据虚函数表做HOOK的操作
- 截取 ecx 获取 winsock 的值(指针)
- */
- unsigned* vtable = (unsigned*)_EDX;
- //WinSock = (GameWinSock *)_ECX;
- /*
- 联合体的特点是共用一个内存
- 由于 GameWinSock::OnConnect 的 OnConnect函数是 GameWinSock类的成员函数
- 直接 vtable[0x34 / 4] = (unsigned)&GameWinSock::OnConnect; 这样写语法不通过
- 所以使用联合体,让语法通过
- */
- union {
- unsigned value;
- bool(GameWinSock::* _proc)(char*, unsigned);
- } vproc;
- DWORD oldPro, backProc;
- VirtualProtect(vtable, 0x100, PAGE_EXECUTE_READWRITE, &oldPro);
- /*
- vproc._proc = &GameWinSock::OnConnect; 这一句是把我们自己写的调用connect函数的地址的出来
- */
- vproc._proc = &GameWinSock::OnConnect;
- /*
- InitClassProc函数里做的是给指针赋值的操作
- InitClassProc(&GameWinSock::_OnConnect, vtable[0x34/4]);这一句的意思是把
- GameWinSock类里的_OnConnect变量的值赋值成vtable[0x34/4],这个 vtable[0x34/4] 是虚表里的函数
- vtable[0x34/4]是游戏中调用connect函数的函数地址,经过之前的分析调用connect是先调用了虚表中的
- 一个函数,然后从这个函数中调用了connect函数
- */
- InitClassProc(&GameWinSock::_OnConnect, vtable[0x34/4]);
- vtable[0x34 / 4] = vproc.value;
-
-
- vproc._proc = &GameWinSock::OnSend;
- InitClassProc(&GameWinSock::_OnSend, vtable[0x3C / 4]);
- vtable[0x3C / 4] = vproc.value;
-
-
- VirtualProtect(vtable, 0x100, oldPro, &backProc);
- return true;
- }
-
- GameProc::GameProc()
- {
- hooker = new htd::hook::htdHook2();
- Init();
- InitInterface();
- }
-
- void GameProc::LoadBase()
- {
- LoadLibraryA("fxnet2.dll");
- }
-
- void GameProc::Init()
- {
- }
-
-
-
- void GameProc::InitInterface()
- {
- LoadBase();
- MessageBoxA(0, "1", "1", MB_OK);
- // 只会HOOK一次,一次性的HOOK
- hooker->SetHook((LPVOID)0x10617046, 0x1, _OnConnect, 0, true);
- }
