免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
如果看不懂、不知道现在做的什么,那就跟着做完看效果
现在的代码都是依据数据包来写的,如果看不懂代码,就说明没看懂数据包
内容参考于: 易道云信息技术研究院VIP课
上一个内容:87.技能名称显示的逆向分析
码云版本号:78786d2409eedb5fb9d2fde216118ca08c0f6415
代码下载地址,在 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的分享
以 86.解析游戏技能数据包中的内容 它的代码为基础进行修改
上一个内容逆向分析找到了游戏找中文名的过程,接下里就要利用它们显示。
首先整理一下东西
下图是得到语言表指针的位置,下图红框可以看出只要给0x3F1C060函数一个局部变量,它就一定能给我写成 76 00 00 00 84 02 00 00
![]()
然后0x3F1C060函数还有两个参数,如下图,上一个内容里看着这个函数里面没用什么this指针就忽略了这俩参数,一个是字符串一个是eax
![]()
eax 的值来自于0x3E1A6C0函数的返回值
![]()
0x3E1A6C0函数有一个参数也是个字符串
![]()
通过gui和TextManager,这俩字符串可以猜测,0x3E1A6C0函数是获取一个指针,TextManager意思是从0x3E1A6C0函数得到的指针里得到TextManager结构指针或者函数,也就是说TextManager指的可能是函数也可能是结构内存地址,然后0x3F1A6B0函数的返回值是一个可以找名字的基址,为了后面方便这里称它为语言表或者表或者名字表
![]()
不过0x3F1C060函数给局部变量的值是死的,也就是关闭游戏重新打开之后它的值没有变化
然后进入0x3F1A6C0函数里看一看,它的参数有不同的字符串,如下图,这可能把0x3F1A6C0函数拦截掉可以得到游戏中所有的基址
![]()
![]()
然后函数地址可能汇编,需要根据基址进行计算,如下图函数在fxgamelogic.dll里
![]()
fxgamelogic.dll的基址3910000,0x3F1A6C0-0x3910000=0x60A6C0,用的时候要用fxgamelogic.dll的基址+0x60A6C0这样(0x60A6C0这种数字被称为偏移),然后0x3F1C060函数与0x3F1A680函数也都是fxgamelogic.dll里的,所以都需要用fxgamelogic.dll里基址+偏移(其它dll里的函数也是同理),通过 LoadLibraryA函数可以得到模块基址(dll文件的基址,也就是现在的fxgamelogic.dll的基址) LoadLibraryA("fxgamelogic.dll");
![]()
如果上图的符号没有的话,在视图中找,如下图
![]()
获取基址的代码
03E1B73B | 68 58120304 | push fxgamelogic.4031258 | 4031258:"gui"
03E1B740 | E8 7BEF0F00 | call fxgamelogic.3F1A6C0 |
03E1B745 | 83C4 04 | add esp,4 |
03E1B748 | 85C0 | test eax,eax |
03E1B74A | 0F84 10090000 | je fxgamelogic.3E1C060 |
03E1B750 | 68 4C120304 | push fxgamelogic.403124C | 403124C:"TextManager"
03E1B755 | 50 | push eax |
03E1B756 | 8D4C24 64 | lea ecx,dword ptr ss:[esp+64] |
03E1B75A | 51 | push ecx |
03E1B75B | E8 00091000 | call fxgamelogic.3F1C060 |
03E1B760 | 8D5424 68 | lea edx,dword ptr ss:[esp+68] |
03E1B764 | 52 | push edx |
03E1B765 | E8 16EF0F00 | call fxgamelogic.3F1A680 | 111111111111
03E1B76A | 83C4 10 | add esp,10 |
03E1B76D | 85C0 | test eax,eax |
03E1B76F | 894424 14 | mov dword ptr ss:[esp+14],eax | [esp+14]:CD3DDDIDX10_DrawIndexedPrimitive+113
然后分析通过基址、序号得到名字的算法,现在的模块是在fxgui.dll里,它的地址都是死的,可以看到它的地址都非常大是10开头的,这种的基址都是死的可以不用基址+偏移这样调用它里面的东西
来到下图位置
![]()
进入0x10296050函数里分析
![]()
首先从语言表结构偏移0x80位置得到了一个指针
![]()
然后用这个指针+一个序号*4,得到一直指针
![]()
然后又从这个指针+0x8位置得到了字符串
![]()
然后通过断点查看,与上方分析的逻辑一样
![]()
这个字符串结构,也就是edx+0x8的这个edx的结构,如下图,我们用到的只有下图红框位置
![]()
测试代码随便截取一个id
![]()
可以正常把名字打出来
![]()
CUIWnd_0.cpp文件的修改:修改了 OnBnClickedButton2函数
// CUIWnd_0.cpp: 实现文件
//
#include "pch.h"
#include "htdMfcDll.h"
#include "CUIWnd_0.h"
#include "afxdialogex.h"
#include "extern_all.h"
#include "GameOBJECTDef.h"
// CUIWnd_0 对话框
float _xNext = 0.0f;
float _yNext = 0.0f;
void _stdcall loops(HWND, UINT, UINT_PTR, DWORD) {
PAIM aim = Client->GetAimByName(L"r");
if (aim == nullptr) {
return;
}
//AfxMessageBox(aim->Name);
float xDis = fabs(Client->Player.x - aim->x);
float hDis = fabs(Client->Player.h - aim->h);
float yDis = fabs(Client->Player.y - aim->y);
float xNext, yNext, thisx, thisy;
int v[2]{ -1, 1 };
if (xDis > 12) {
// 强制修改角色x坐标的值
thisx = Client->Player.x;
Client->Player.x = Client->Player.x + 6 * v[Client->Player.x < aim->x];
xNext = Client->Player.x;
}
else {
xNext = aim->x;
}
if (yDis > 12) {
// 强制修改角色y坐标的值
thisy = Client->Player.y;
Client->Player.y = Client->Player.y + 6 * v[Client->Player.y < aim->y];
yNext = Client->Player.y;
}else{
yNext = aim->y;
}
if ((xDis < 2)&&(hDis < 2)&&(yDis < 2)) {
Client->MoveStop(aim->x, aim->h, aim->y, 0.0f);
}
else {
Client->MoveWalk(Client->Player.x,aim->h, Client->Player.x, 0.0f, 0.0f, xNext, yNext);
}
}
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)
ON_BN_CLICKED(IDC_BUTTON2, &CUIWnd_0::OnBnClickedButton2)
END_MESSAGE_MAP()
// CUIWnd_0 消息处理程序
void CUIWnd_0::OnBnClickedButton1()
{
// 发送坠落数据包
//Client->Fall();
设置移动速度
float Speed = 30.0;
Client->SetProperty(Client->Player.lId, INDEX_MoveSpeed, &Speed);
/*
// 修改血量
int HP = 10000000;
Client->SetProperty(Client->Player.lId, INDEX_HP, &HP);*/
/*CString txt;
txt.Format(L"通过AIM类获取角色信息 名字:%s,x坐标:%f", Client->Player.Name, Client->Player.x);
AfxMessageBox(txt);*/
// Client->HeartBeep();
// Client->TalkTo(L"r", L"打架吗?");
// Client->Talk(L"[欢迎来到麟科思]");
// Client->SelectRole(L"今晚打老虎");
/*Client->CreateRole(L"am4", 1.0, 2.0, 4.0, 8.0, "gui\BG_team\TeamRole\Teamrole_zq_humF_001.PNG",
"Face,0;Hat,0;Eyes,0;Beard,0;Ears,0;Tail,0;Finger,0;Cloth,0;Pants,0;Gloves,0;Shoes,0;Trait,0;HairColor,0;SkinColor,0;SkinMtl,0;Tattoo,0;TattooColor,16777215;",
"", 0.0);*/
//Client->SelectCamp("xuanrenZQ");
//Client->StartCreateRole();
//Client->DelRole(L"ranzhi11111");
/*
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));
*/
/*char buff[] = {
0x27, 0x46, 0x92, 0x02, 0x00, 0x00, 0x89, 0x02, 0x00, 0x00, 0x06, 0x00, 0x06, 0x05,
0x00, 0x00, 0x00, 0x63, 0x68, 0x61, 0x74, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x07,
0x0A, 0x00, 0x00, 0x00, 0x34, 0x00, 0x33, 0x00, 0x39, 0x00, 0x39, 0x00, 0x00, 0x00,
0x07, 0x5A, 0x02, 0x00, 0x00, 0x31, 0x00, 0x32, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31,
0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x31, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32,
0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32,
0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32,
0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32,
0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32, 0x00, 0x32,
0x00, 0x32, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,
0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,
0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,
0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,
0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,
0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33,
0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x33, 0x00, 0x35,
0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35,
0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35,
0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35,
0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35,
0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35,
0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x35, 0x00, 0x34,
0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34,
0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34,
0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34,
0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34,
0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34,
0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x34, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36,
0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36,
0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36,
0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x36, 0x00, 0x37,
0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00, 0x37, 0x00,
0x38, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00
};
WinSock->OnRecv(buff, sizeof(buff));*/
}
void CUIWnd_0::OnBnClickedButton2()
{
// 根据语言表获取文字
CString txt = PGameProc->GetTextName("npc_GRZJ_0001");
AfxMessageBox(txt);
// 瞬移
//float decX = 3843.776123f;
//float decH = 11.731983f;
//float decY = -2005.533813f;
//float face = 0.0f;
//Client->Teleport(decX, decH, decY, face);
//PAIM aim = Client->GetAimByName(L"r");
//if (aim == nullptr) {
// return;
//}
//Client->Teleport(aim->x, aim->h, aim->y, aim->face);
// 修正坐标
/*PAIM aim = Client->GetAimByName(L"r");
if (aim == nullptr) {
return;
}
Client->SetCoord(Client->Player.lId, aim->x, aim->h, aim->y, aim->face);*/
// 面向
// Client->FaceTo(L"r");
// 飞天
// Client->HideMode = true;
// 遁地
//Client->MoveStop(Client->Player.x, Client->Player.h - 5, Client->Player.y, 0.0f);
// 跟随
// ::SetTimer(m_hWnd, 0x1000, 2000, loops);
//
// Client->Backtoroles();
}
GameProc.cpp文件的修改:修改了 LoadBase函数、新加 GetTextName函数
#include "pch.h"
#include "GameProc.h"
#include "extern_all.h"
// typedef bool(GameWinSock::* U)(char*, unsigned);
bool _OnComprase(HOOKREFS2) {
return WinSock->OnRecv((char*)_EDI, _EBP);
}
bool _OnRecv(HOOKREFS2) {
_EAX = WinSock->RecvPoint;
return true;
}
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");
hlogic = LoadLibraryA("fxgamelogic.dll");
// 如果fxgamelogic.dll里用到了其它dll里面的东西,在这赋值可能会有问题
// 最好在游戏网络连接成功哪里赋值,或者进入到游戏中之后再搞
GetClassByName = (PGetClassByName)((unsigned)hlogic + 0x60A6C0);
GetClassModByName = (PGetClassModByName)((unsigned)hlogic + 0x60C060);
GetClassObject = (PGetClassObject)((unsigned)hlogic + 0x60A680);
}
void GameProc::Init()
{
#ifdef anly
anly = new CAnly();
#endif
/*
这里的 WinSock 是0没有创建对象,但是还是能调用Init函数
这是因为Init函数里面没有用到this,没用到就不会报错
*/
Client = new NetClient();
GameAnlyer = new GameAnly();
init_datadesc();
}
void GameProc::InitInterface()
{
LoadBase();
// MessageBoxA(0, "1", "1", MB_OK);
// 只会HOOK一次,一次性的HOOK
hooker->SetHook((LPVOID)0x10617046, 0x1, _OnConnect, 0, true);
/*
第一个参数是HOOK的位置
第二个参数是HOOK的位置的汇编代码的长度(用于保证执行的汇编代码完整)
第三个参数是HOOK之后当游戏执行到第一个参数的位置的时候跳转的位置
第四个参数是 _OnRecv 函数返回 false 之后跳转的位置
*/
hooker->SetHook((LPVOID)0x10618480, 0x1, _OnRecv, 0);
hooker->SetHook((LPVOID)0x1061161D, 0x3, _OnComprase, (LPVOID)0x10611602);
/*
在这里绑定游戏处理数据包函数(0x10618480函数)
然后0x10618480函数在上面一行代码已经进行了HOOK
所以在调用_OnRecv函数指针时,它就会进入我们HOOK
*/
InitClassProc(&GameWinSock::_OnRecv, 0x10618480);
}
wchar_t* GameProc::GetTextName(const char* configId)
{
CLASS_OFFSET offSet;
void* classPointer = GetClassByName("gui");
if (classPointer) {
GetClassModByName(&offSet, classPointer, "TextManager" );
PTextManger textManger = GetClassObject(&offSet);
unsigned callProc = 0x10295FB0;
/*CString txt;
txt.Format(L"%X", textManger);
AfxMessageBox(txt);*/
int index;
_asm {
push ebx
mov ebx, textManger
push configId
call callProc
mov index, eax
pop ebx
}
if (index < 0)return nullptr;
PTextTable* _table = textManger->TextTable;
return _table[index]->Txt;
}
return nullptr;
}
GameProc.h文件的修改:新加 TextTable类、TextManger类、CLASS_OFFSET结构体、PGetClassByName函数指针、PGetClassModByName函数指针、PGetClassObject函数指针、GetClassByName指针变量、GetClassModByName指针变量、GetClassObject指针变量、hlogic变量、GetTextName函数
#pragma once
#include <htdHook2.h>
#include "GameWinSock.h"
/*
03E1B73B | 68 58120304 | push fxgamelogic.4031258 | 4031258:"gui"
03E1B740 | E8 7BEF0F00 | call fxgamelogic.3F1A6C0 |
03E1B745 | 83C4 04 | add esp,4 |
03E1B748 | 85C0 | test eax,eax |
03E1B74A | 0F84 10090000 | je fxgamelogic.3E1C060 |
03E1B750 | 68 4C120304 | push fxgamelogic.403124C | 403124C:"TextManager"
03E1B755 | 50 | push eax |
03E1B756 | 8D4C24 64 | lea ecx,dword ptr ss:[esp+64] |
03E1B75A | 51 | push ecx |
03E1B75B | E8 00091000 | call fxgamelogic.3F1C060 |
03E1B760 | 8D5424 68 | lea edx,dword ptr ss:[esp+68] |
03E1B764 | 52 | push edx |
03E1B765 | E8 16EF0F00 | call fxgamelogic.3F1A680 | 111111111111
03E1B76A | 83C4 10 | add esp,10 |
03E1B76D | 85C0 | test eax,eax |
03E1B76F | 894424 14 | mov dword ptr ss:[esp+14],eax | [esp+14]:CD3DDDIDX10_DrawIndexedPrimitive+113
*/
typedef class TextTable {
public:
int id;
int un;
wchar_t* Txt;
}*PTextTable;
typedef class TextManger {
public:
int un[0x20];// 0x20 * 0x4 = 0x80
PTextTable* TextTable;
}*PTextManger;
typedef struct CLASS_OFFSET {
int offSet[2];
}*PCLASS_OFFSET;
typedef void* (*PGetClassByName)(const char* name);
typedef void (*PGetClassModByName)(PCLASS_OFFSET _offset, void* classPointer, const char* name);
typedef PTextManger(*PGetClassObject)(PCLASS_OFFSET _offset);
// GameProc类 负责游戏功能与模块的对接,也就是HOOK、获取游戏数据这种操作
class GameProc
{
htd::hook::htdHook2* hooker;
private:
// void InitClassProc(LPVOID proc_addr, unsigned value);
PGetClassByName GetClassByName;
PGetClassModByName GetClassModByName;
PGetClassObject GetClassObject;
HMODULE hlogic;
public:
GameProc();// 初始化 hooker
/*
*/
void LoadBase();
void Init();// 初始化
void InitInterface(); // 接口初始化
wchar_t* GetTextName(const char* configId);
};