热血传奇(Mir2Client.exe,窗口类TFrmMain,标题legendofmir2)里说的“关键CALL”,指客户端内部触发具体功能函数地址:走路、跑步、普通攻击、释放技能、选怪、吃药、拾取、换装、喊话、寻路、发包。找CALL本质是在游戏进程领空内,从数据变化或网络发包反向回溯到功能函数,再算出“模块基址+RVA偏移”,用远程线程/DLL注入调用。
一、先搞懂基址与偏移关系
每次启动客户端因ASLR或版本不同,函数内存地址会变,但“主模块基址+相对偏移RVA”不变。实战取地址:
uintptr_tbase=(uintptr_t)GetModuleHandle(L"Mir2Client.exe");
void*pFunc=(void*)(base+0x301620);//例:RVA0x301620
老版传奇主模块基址常固定在0x400000,新版用GetModuleHandle取真实基址再相加。
二、必备工具链
x64dbg/OD(OllyDbg):下断、看调用栈、跟汇编
CheatEngine(CE):扫血量、坐标、状态值、找基址
IDAPro:静态反编译,看函数序言/结尾、调用约定
Wireshark+条件断点:配合send/WSASend抓明文包
注入端:CreateRemoteThread+LoadLibrary注入DLL,或WriteProcessMemory调参
三、通用找CALL四条主线
1.发包回溯法(最常用)
在ws2_32.send/send/WSASend下bp断点→回游戏做动作(砍怪、吃药、说话、点地图寻路)→断下后Alt+K看调用堆栈→从send向上Ctrl+F9/F8逐层返回→第3~6层出现的call地址即功能CALL。传奇类动作链:鼠标点击→选怪CALL→走路CALL→攻击CALL→组包→send。
例:释放技能断点返回层:
movedxesi;怪物ID
movecxesi;角色对象(thiscall)
movr8wbx;技能ID
movr9bdil;技能等级
call0x7FF7F9B75260;技能CALL
2.数据写入断点法
CE搜角色坐标(XY)、血量、寻路状态(静止0/移动1/战斗2)→找到稳定地址→x64dbg对该地址下硬件写入断点→触发移动/寻路→断点命中处向上回溯→定位走路CALL/寻路CALL。寻路CALL参数常见:ecx=角色对象指针、edx/xmm=目标X/Y、标志位=寻路模式,调用约定__thiscall。
3.对象结构追踪法
选中怪物→CE搜未知初始值→换怪搜变动值→锁定怪物对象基址→下访问断点→攻击时断下→回溯到攻击CALL。技能ID、目标ID、怪物坐标都从对象结构里取。
4.字符串/消息窗口法
OD加载客户端进领空→Ctrl+N找Send/WSASend/OnLButtonDown/DefMainWndProc→从CGameProcess::OnLButtonDown开始跟鼠标点击逻辑,传奇源码里点击地面→计算坐标→寻路→组包全在这条链上。
四、热血传奇典型关键CALL清单(参数特征)
•走路/跑步CALL:8方向,参数含目标X、Y、方向、跑步标志;走路与跑步是同一CALL不同参数。
•普通攻击CALL:等同技能ID=0(F1),参数怪物ID/对象、技能ID、等级。
-释放技能CALL:技能ID(烈火0x..、冰咆哮..)、目标ID、ecx=角色对象。
•选怪CALL:鼠标点击命中后先选怪再走路再攻击,第一层返回多为选怪CALL。
•吃药CALL:药品背包索引、类型(红/蓝/太阳水)、数量;注意流程是“功能CALL→发包→服务器回包→扣血/加血”,直接追血量地址只能找到表现层,不是吃药CALL本身。
-拾取CALL:地面物品对象指针/索引;回溯send包类型0x0A左右(捡物指令)。
•换装CALL:背包物品基址+装备槽位;先找“物品复制到鼠标”CALL,再找真正穿戴CALL。
•喊话CALL:频道号、字符串指针、长度;发包类型0x1F。
-寻路CALL:目标X/Y、寻路模式、角色对象ecx;状态位1时生效。
•明文发包CALL:缓冲区指针、长度、加密标志;在send上方贴近末尾下断最稳,避开反调试检测。
五、调用约定与参数判定
-__cdecl:参数右→左压栈,调用者平栈(addespx)
•__stdcall:被调用者平栈(retn0Ch)
•__thiscall:ecx=this(角色/对象指针),剩余右→左压栈
-__fastcall:ecx+edx前俩参数,其余压栈
进CALL内部看retn/addespn算参数个数,临时变量看[ebp-xx],传入参数看[esp+xx](注意CALL本身压返回地址占4字节)。
六、经典基址线索(老版1.76客户端参考)
主角色对象指针:[[0x59C7CC]+0x4C]=HP,+0x50=MaxHP,+0x54=MP,+0x58=MaxMP,+0xD8=X坐标,+0xDC=Y坐标;地图名指针:[0x59C7CC+0x10]→字符串地址。
注意:不同补丁/周年版偏移会变,必须本机重扫,不能直接抄老教程地址。
七、定位完整步骤(以“走路CALL”为例)
1.CE搜当前X坐标→微移→搜变动→锁定坐标地址A
2.x64dbg附加Mir2Client.exe,对A下硬件写入断点
3.游戏里点地面移动→断下→看调用栈返回到游戏领空函数FuncA
4.FuncA头部记下RVA=FuncA-模块基址
5.分析FuncA参数:ecx(角色对象)、push目标X、push目标Y、push方向
6.DLL注入测试:构造ecx+参数→call(base+RVA)→角色移动即命中
八、常见坑点
•线程发包:不直接走send,另起线程组包,需先追线程数据来源再回溯功能CALL。
-包体加密:异或/RC4/查表,Wireshark抓到乱码,需在send前找加密函数模拟组包。
•软件断点被检测:换硬件断点(DR0~DR3)、条件断点、隐藏调试器插件。
•状态值误判:追血量找到的是表现函数不是吃药CALL,必须沿“功能→发包→回包→改值”正向链找。
-偏移失效:客户端更新、补丁重打包、ASLR开启,必须重算RVA。
九、调用验证最小代码框架
DWORDbase=(DWORD)GetModuleHandle(L"Mir2Client.exe");
DWORDwalkCall=base+0xABCDEF;//RVA
__asm{
movecxroleObj//角色对象指针
pushdir//方向
pushy//目标Y
pushx//目标X
callwalkCall
addesp0xC
}
角色移动即CALL正确;崩调用约定或ecx错位。
找全CALL后,走路+选怪+攻击+拾取+吃药+寻路组合,就是完整自动打怪闭环,剩下只是计时器与判断逻辑。
一、先搞懂基址与偏移关系
每次启动客户端因ASLR或版本不同,函数内存地址会变,但“主模块基址+相对偏移RVA”不变。实战取地址:
uintptr_tbase=(uintptr_t)GetModuleHandle(L"Mir2Client.exe");
void*pFunc=(void*)(base+0x301620);//例:RVA0x301620
老版传奇主模块基址常固定在0x400000,新版用GetModuleHandle取真实基址再相加。
二、必备工具链
x64dbg/OD(OllyDbg):下断、看调用栈、跟汇编
CheatEngine(CE):扫血量、坐标、状态值、找基址
IDAPro:静态反编译,看函数序言/结尾、调用约定
Wireshark+条件断点:配合send/WSASend抓明文包
注入端:CreateRemoteThread+LoadLibrary注入DLL,或WriteProcessMemory调参
三、通用找CALL四条主线
1.发包回溯法(最常用)
在ws2_32.send/send/WSASend下bp断点→回游戏做动作(砍怪、吃药、说话、点地图寻路)→断下后Alt+K看调用堆栈→从send向上Ctrl+F9/F8逐层返回→第3~6层出现的call地址即功能CALL。传奇类动作链:鼠标点击→选怪CALL→走路CALL→攻击CALL→组包→send。
例:释放技能断点返回层:
movedxesi;怪物ID
movecxesi;角色对象(thiscall)
movr8wbx;技能ID
movr9bdil;技能等级
call0x7FF7F9B75260;技能CALL
2.数据写入断点法
CE搜角色坐标(XY)、血量、寻路状态(静止0/移动1/战斗2)→找到稳定地址→x64dbg对该地址下硬件写入断点→触发移动/寻路→断点命中处向上回溯→定位走路CALL/寻路CALL。寻路CALL参数常见:ecx=角色对象指针、edx/xmm=目标X/Y、标志位=寻路模式,调用约定__thiscall。
3.对象结构追踪法
选中怪物→CE搜未知初始值→换怪搜变动值→锁定怪物对象基址→下访问断点→攻击时断下→回溯到攻击CALL。技能ID、目标ID、怪物坐标都从对象结构里取。
4.字符串/消息窗口法
OD加载客户端进领空→Ctrl+N找Send/WSASend/OnLButtonDown/DefMainWndProc→从CGameProcess::OnLButtonDown开始跟鼠标点击逻辑,传奇源码里点击地面→计算坐标→寻路→组包全在这条链上。
四、热血传奇典型关键CALL清单(参数特征)
•走路/跑步CALL:8方向,参数含目标X、Y、方向、跑步标志;走路与跑步是同一CALL不同参数。
•普通攻击CALL:等同技能ID=0(F1),参数怪物ID/对象、技能ID、等级。
-释放技能CALL:技能ID(烈火0x..、冰咆哮..)、目标ID、ecx=角色对象。
•选怪CALL:鼠标点击命中后先选怪再走路再攻击,第一层返回多为选怪CALL。
•吃药CALL:药品背包索引、类型(红/蓝/太阳水)、数量;注意流程是“功能CALL→发包→服务器回包→扣血/加血”,直接追血量地址只能找到表现层,不是吃药CALL本身。
-拾取CALL:地面物品对象指针/索引;回溯send包类型0x0A左右(捡物指令)。
•换装CALL:背包物品基址+装备槽位;先找“物品复制到鼠标”CALL,再找真正穿戴CALL。
•喊话CALL:频道号、字符串指针、长度;发包类型0x1F。
-寻路CALL:目标X/Y、寻路模式、角色对象ecx;状态位1时生效。
•明文发包CALL:缓冲区指针、长度、加密标志;在send上方贴近末尾下断最稳,避开反调试检测。
五、调用约定与参数判定
-__cdecl:参数右→左压栈,调用者平栈(addespx)
•__stdcall:被调用者平栈(retn0Ch)
•__thiscall:ecx=this(角色/对象指针),剩余右→左压栈
-__fastcall:ecx+edx前俩参数,其余压栈
进CALL内部看retn/addespn算参数个数,临时变量看[ebp-xx],传入参数看[esp+xx](注意CALL本身压返回地址占4字节)。
六、经典基址线索(老版1.76客户端参考)
主角色对象指针:[[0x59C7CC]+0x4C]=HP,+0x50=MaxHP,+0x54=MP,+0x58=MaxMP,+0xD8=X坐标,+0xDC=Y坐标;地图名指针:[0x59C7CC+0x10]→字符串地址。
注意:不同补丁/周年版偏移会变,必须本机重扫,不能直接抄老教程地址。
七、定位完整步骤(以“走路CALL”为例)
1.CE搜当前X坐标→微移→搜变动→锁定坐标地址A
2.x64dbg附加Mir2Client.exe,对A下硬件写入断点
3.游戏里点地面移动→断下→看调用栈返回到游戏领空函数FuncA
4.FuncA头部记下RVA=FuncA-模块基址
5.分析FuncA参数:ecx(角色对象)、push目标X、push目标Y、push方向
6.DLL注入测试:构造ecx+参数→call(base+RVA)→角色移动即命中
八、常见坑点
•线程发包:不直接走send,另起线程组包,需先追线程数据来源再回溯功能CALL。
-包体加密:异或/RC4/查表,Wireshark抓到乱码,需在send前找加密函数模拟组包。
•软件断点被检测:换硬件断点(DR0~DR3)、条件断点、隐藏调试器插件。
•状态值误判:追血量找到的是表现函数不是吃药CALL,必须沿“功能→发包→回包→改值”正向链找。
-偏移失效:客户端更新、补丁重打包、ASLR开启,必须重算RVA。
九、调用验证最小代码框架
DWORDbase=(DWORD)GetModuleHandle(L"Mir2Client.exe");
DWORDwalkCall=base+0xABCDEF;//RVA
__asm{
movecxroleObj//角色对象指针
pushdir//方向
pushy//目标Y
pushx//目标X
callwalkCall
addesp0xC
}
角色移动即CALL正确;崩调用约定或ecx错位。
找全CALL后,走路+选怪+攻击+拾取+吃药+寻路组合,就是完整自动打怪闭环,剩下只是计时器与判断逻辑。

