内容参考于:易道云信息技术研究院VIP课
上一个内容:游戏底层功能对接类GameProc的实现
码云地址(master 分支):https://gitee.com/dye_your_fingers/titan
码云版本号:44c54d30370d3621c1e9ec3d7fa1e2a028e773e9
代码下载地址,在 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的分享
以 游戏底层功能对接类GameProc的实现 它的代码为基础进行修改
HOOK下图红框位置:0x10617046(通过之前分析找到的)
然后在注入的时候做HOOK发现,会崩溃,然后发现hook的点没有被游戏加载,解决办法我们在HOOK之前手动的把模块加载进入,不等游戏加载了
黑兔sdk升级:首先点击属性
找到下图红框位置,主要时看$(htd)\indude,如果下图红框位置不显示 $(htd)\indude
而显示不同选项,如下图红框
这时把配置这一行设置成跟下图一样,就好了
下载完升级版的黑兔std头文件可能无法正常加载到项目中,所以要手动加,首先检查它的目录对不对,如下图红框,我这里是对的,我的头文件就放在了那里
如果不对,首先点击下图红框位置
选择头文件所在目录,这样就把头文件设置好了
然后设置dll库,库目录是下图红框位置,手动设置方法与上方设置头文件一样
全部搞完之后,选择下图重新扫描解决方案,就不会报红了(就算报红也能编译通过)
这里补充一个东西:就是当执行了黑兔SDK,但是在创建项目的时候下图红框里的东西不存在
首先不打开项目启动 Visual Studio 然后选择选项:
然后看下图红框里的目录
查看目录中是否有下图红框里的两个文件,如果没有就复制到上图红框目录下
如下图
GameProc.cpp文件的修改:新加 _OnConnect函数,修改了 InitInterface函数、LoadBase函数
#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;/*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]);CString str;str.Format(L"===vtable:%X", vtable[0x34 / 4]);AfxMessageBox(str);DWORD oldPro,backProc;VirtualProtect(vtable, 0x100, PAGE_EXECUTE_READWRITE, &oldPro);vtable[0x34 / 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);hooker->SetHook((LPVOID)0x10617046, 0x1, _OnConnect, 0, true);
}
新加GameWinSock.h文件:
#pragma once
class GameWinSock
{typedef bool(GameWinSock::* PROC)(char*, unsigned);
public:static PROC _OnConnect;bool OnConnect(char* ip, unsigned port);
};
新加GameWinSock.cpp文件:
#include "pch.h"
#include "GameWinSock.h"
#include "extern_all.h"GameWinSock::PROC GameWinSock::_OnConnect{};
// 这个函数拦截了游戏的连接
bool GameWinSock::OnConnect(char* ip, unsigned port)
{// this是ecx,HOOK的点已经有ecx了WinSock = this;MessageBoxA(0, ip, ip, MB_OK);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, 0x100, PAGE_EXECUTE_READWRITE, &oldPro);vtable[0x34 / 4] = vproc.value;VirtualProtect(vtable, 0x100, oldPro, &backProc);*/return b;
}
htdMfcDll.cpp文件的修改:修改了 InitInstance函数
// htdMfcDll.cpp: 定义 DLL 的初始化例程。这是一个MFC的dll
//#include "pch.h"
#include "framework.h"
#include "htdMfcDll.h"
#include "extern_all.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif// 注释掉下方宏,以入口点注入的方式注入
// #define WNDHOOK
#ifdef WNDHOOK
typedef struct htdDll
{HHOOK keyHook;unsigned KbdProc;unsigned SetDll;}*PHtdDll;
void htdSetDll(htdDll hDll);
htdDll mDll;
#endifBEGIN_MESSAGE_MAP(ChtdMfcDllApp, CWinApp)
END_MESSAGE_MAP()// ChtdMfcDllApp 构造ChtdMfcDllApp::ChtdMfcDllApp()
{}ChtdMfcDllApp theApp;
ChtdMfcDllApp* PtheApp;HHOOK keyHook;
LRESULT CALLBACK KeyCallBack(int nCode, WPARAM w, LPARAM l);BOOL ChtdMfcDllApp::InitInstance()
{CWinApp::InitInstance();PtheApp = this;
#ifdef WNDHOOKmDll.KbdProc = (DWORD)(KeyCallBack);mDll.SetDll = 0;
#elsekeyHook = SetWindowsHook(WH_KEYBOARD, KeyCallBack);// 代码一开始,在这注册一个键盘事件的钩子
#endifPGameProc = new GameProc();return TRUE;
}// 钩子处理事件
LRESULT CALLBACK KeyCallBack(int nCode, WPARAM w, LPARAM l)
{if (nCode == 0){if ((l & (1 << 31)) == 0){switch (w){case VK_HOME:if (PtheApp->wndMain == NULL){PtheApp->wndMain = new CUI();PtheApp->wndMain->Create(IDD_MAIN);}PtheApp->wndMain->ShowWindow(TRUE);break;}}}return CallNextHookEx(keyHook, nCode, w, l);
}
#ifdef WNDHOOK
void htdInit(htdDll* hDll)
{hDll->KbdProc = mDll.KbdProc;hDll->keyHook = mDll.keyHook;hDll->SetDll = mDll.SetDll;
}void htdSetDll(htdDll hDll)
{mDll = hDll;
}
#else
void htdInit()
{
}
#endif
新加extern_all.h文件:
/*此文件是用来存放全局变量、全局函数(通用函数)
*/
#pragma once
#include "GameWinSock.h"
#include "GameProc.h"extern GameWinSock* WinSock;
extern GameProc* PGameProc;
extern void InitClassProc(LPVOID proc_addr, unsigned value);
新加extern_all.cpp文件
/*此文件是用来存放全局变量、全局函数(通用函数)
*/
#include "pch.h"
#include "extern_all.h"
GameWinSock* WinSock = nullptr;
GameProc* PGameProc = nullptr;void InitClassProc(LPVOID proc_addr, unsigned value)
{unsigned* writer = (unsigned*)proc_addr;writer[0] = value;
}