传奇吃药CALL详细步骤与代码实现教程

来源: 作者: 点击:
吃药CALL的查找和调用是传奇类游戏辅助开发中最基础也最关键的一环。角色血量低于设定阈值时自动使用背包中的药品,整个功能的实现依赖于对游戏内部函数调用的精准定位和参数封装。下面把从找CALL到写出可运行代码的完整流程拆开讲清楚。

**一、找吃药CALL之前的准备工作**

在动手找CALL之前,先要把药品放到固定的背包格子。传奇的背包格子是从0开始编号的,第一格是0,第二格是1,以此类推。把一瓶金创药放在背包第四格,那么这瓶药对应的格子编号就是3。记住这个编号,后面的搜索要用到。

打开CE附加游戏进程。先用CE搜索背包格子的数值。使用背包第四格的物品,在CE中首次搜索数值3;然后换用背包第三格的物品,再次搜索数值2。反复搜索几轮,直到只剩下少数几个内存地址。这些地址中,只有一个是真的记录当前使用物品格子的地址,其他可能是临时变量或缓存值。右键点击每个地址,选择“找出是什么改写了这个地址”,然后在游戏中切换使用不同格子的物品,观察哪个地址在你使用物品时发生了变化。那个每次使用物品时都被写入格子编号的地址,就是目标地址。

**二、在OD中定位吃药CALL**

拿到格子地址之后,右键选择“找出访问这个地址的代码”。回到游戏中右键使用背包里的药品,OD会断下来。此时看到的代码是游戏在处理物品使用时对格子编号的读取操作。不要停在这一层,按Alt+K打开调用堆栈窗口,查看返回地址列表。

调用堆栈会列出一串返回地址,前两个通常不是目标。从第三个返回地址开始,逐个在OD中Ctrl+G跳转过去查看。吃药相关的CALL通常出现在第四或第五个返回地址处。找到类似“PUSH 1 / PUSH 物品ID / PUSH 格子编号”这样的参数入栈序列,基本就能确认这就是吃药的功能CALL。

另一个定位思路是从明文封包CALL入手。在明文发包CALL的头部下断点,使用药品让断点断下,然后逐层向上返回。第一层是明文发包CALL,再返一层就到了功能CALL,这一层就是真正的吃药CALL。

**三、解析吃药CALL的参数结构**

不同游戏版本的吃药CALL参数传递方式有差异,32位和64位版本的区别也比较大。以32位版本为例,一个典型的吃药CALL原型是这样的:PUSH 1(固定参数),PUSH 物品ID,PUSH 格子编号,PUSH 0(固定参数),然后LEA ECX取基址相关地址,最后CALL目标函数。

物品ID是游戏中每种药品的唯一标识,比如超级金创药的ID可能是0x21A6。格子编号就是药品在背包中的位置,第一格为0。固定参数1和0在不同引擎中含义不同,有的版本中1代表从主背包使用,0可能是保留字段。实际调试时把这几项参数都记下来,写代码时照着传就行。

64位版本的参数传递通过寄存器完成。rcx传基地址,r9传物品ID,r8传格子编号,edx传背包序号(1表示主背包,2表示装备栏)。代码形式类似:mov r9d, [物品ID地址];mov r8d, 格子编号;mov edx, 1;call 吃药CALL地址。

**四、编写易语言调用代码**

拿到CALL地址和参数结构之后,就可以在易语言中封装调用函数了。核心思路是申请一段内存,把汇编指令写进去,然后远程调用。

先定义必要的变量。总基址是游戏进程的基地址,用CE或OD都能查到。用物CALL地址就是刚才定位到的吃药CALL地址。包裹物品ID和包裹物品格作为函数参数传入。

置代码部分按顺序写入汇编指令:pushad保存寄存器环境,mov_ecx_常数把物品ID放到ecx,mov_eax_常数把格子编号放到eax,push_常数1、push_ecx、push_eax、push_常数0完成参数入栈,然后mov_eax_ptr读总基址,mov_eax_ptr_eax加整数32偏移,mov_esi_eax把结果放到esi,lea_ecx_ptr_eax加整数244取ECX地址,最后call_eax调用目标函数,popad恢复寄存器,ret返回。

这段代码的逻辑和手工在OD中看到的汇编序列完全一致。写完之后调用函数,传入物品ID和格子编号,如果一切正确,游戏角色就会喝下指定格子的药品。

**五、背包遍历与自动吃药逻辑**

吃药CALL本身只是“使用某格物品”的底层函数,要实现自动吃药还需要知道当前背包里哪一格是红药、哪一格是蓝药。这就涉及到背包遍历。

背包遍历的方法是先找到背包数组的首地址。可以借助吃药CALL来调试找物品地址,因为吃药时必然要把药品的ID或者地址传递给CALL,在CALL处下断点查看push的参数值,就能反推出背包数组的结构。

拿到背包数组之后,遍历每个格子,读取格子中物品的ID。把红药ID列表和蓝药ID列表预先写好,遍历时逐个比对。血量低于阈值时,从背包中找到第一个红药所在的格子,把格子编号和对应的物品ID传给吃药函数。蓝药同理。

在实际的自动吃药循环中,还需要处理药品使用后的冷却时间。传奇中药品使用有内置冷却,连续调用吃药CALL如果间隔太短,后面的调用会被游戏忽略。在每次吃药调用之后加一个短暂延时,通常几百毫秒就够。

**六、测试与常见问题**

写好的吃药功能先在安全区测试。把角色血量调到较低状态,观察是否自动使用背包中的药品。如果没反应,检查几个地方:CALL地址是否正确、参数顺序是否搞反、基址是否过期。

基址过期是最常见的问题。游戏每次更新或者换区之后,基址和CALL地址都可能发生变化。可以用特征码搜索的方式来定位CALL,不直接写死地址,而是搜索CALL前面的指令特征。比如吃药CALL前面通常有固定的参数入栈序列,用这些字节作为特征码,启动时动态搜索CALL的实际地址。

格子编号传错也会导致吃药失败。特别注意背包格子从0开始编号,而很多玩家的直觉是从1开始。如果你把第四格的编号写成4而不是3,CALL会去读不存在的格子,药品自然用不出来。

如果吃药CALL调用后游戏闪退或者卡死,大概率是ECX或ESI的值不对。ECX在32位版本中通常需要指向一个有效的内存结构,直接传0会导致CALL内部访问空指针。按照上面代码中的方式,从总基址加偏移逐层取地址,保证ECX指向的是游戏自己的数据结构。