[原创] 从零开始教你做辅助(二) –攻击怪物功能

a1辅助网提供[原创] 从零开始教你做辅助(二) –攻击怪物功能的下载地址,长期提供破解软件,各种线报福利等,54391是一个很好的福利资源网站

fanvalen 发表于 2021-2-6 20:21
你还是回山里去吧

要不你来上台表演一下,发了帖子记得@我 谢谢了

谢谢分享
可以感谢分享

大家好,我是山里猴,我又回来了.
作为一个打工人,目前只能保证一周更新一次,更新可能会迟到,但绝不会不来.
这次主要讲解下怎么找到攻击怪物的函数调用地址,及完成辅助中的攻击模块,大家如果看完觉得有哪些写的不好的,可以留言或者提issue,我后面再把文档更新下.

这期内容的markdown我同样也会同步放到我的gayhub项目中的https://github.com/shanlihou/hack_warspear,的tutorial文件夹下面

实现打怪功能

0x01:找到打怪的调用堆栈

方法选择

跟上次我们讲的内容差不多,都是先要找到调用堆栈(其实上次没用到,哈哈,这次是肯定要用到了)
找攻击的调用堆栈,有两种方法.
方法一:我们注意到每次玩家点击怪物之后会多出一个攻击目标,所以至少内存中会存在一块数据用来保存当前攻击目标,我们首先就是找到是哪里会改写这块内存.
方法二:我们可以通过在send函数上加断点,并输出调用堆栈来查找,毕竟每次攻击行为最终还是要把数据发送给服务器的(不过可能因为和服务端通信并不是每次直接发数据,而先把要发送内容放在队列里,下一帧才进行发送,这种情况追踪堆栈可能是追不到的).
方法三:还记得我们上一课讲过怎么找到怪物列表吗,在攻击时候可能会访问到怪物列表,所以可以通过ce在怪物上查看什么访问了怪物地址来找调用堆栈.
我们这里就使用第二种方法来

开始查找

首先我们打开immunity debugger, 然后再在下方命令窗口输入b send(这个命令会在win api send上面加断点),然后我们通过打开断点窗口就能得到send的调用地址

[原创] 从零开始教你做辅助(二) --攻击怪物功能  

上图中75324CF0 WS2_32.send 就是send函数调用地址
有了这个地址就可以打开ce,并编写如下

function print_stack(ebp, deep)     if deep == 0     then         return ""     end     local ebp_4 = readInteger(ebp + 4)     local str_ret = string.format("%x->", ebp_4)     local next_ebp = readInteger(ebp)     str_ret = str_ret .. print_stack(next_ebp, deep - 1)     return str_ret end  function clear_debug()     local tbl = debug_getBreakpointList()     if tbl == nil     then         return     end     for i,v in ipairs(tbl) do         print(string.format("%4d 0x%X",i,v))         debug_removeBreakpoint(v)     end end  function debugger_onBreakpoint()          if EIP == 0x75324CF0          then              print(string.format("up frame:0x%X", readInteger(ESP)))              local stack_str = print_stack(EBP, 10)              print(string.format("stack:%s", stack_str))          end     return 1 end  clear_debug() print(1) --debug_setBreakpoint(0x75324CF0)

得到如下打印
up frame:0x883C82
stack:86eee6->87c587->86052b->763547ab->76332aac->763344db->763341e0->8602c6->85fb76->4e4558->
其中0x883c82 调用send的地址
stack后面的是调用堆栈,这里大家可能会有疑问,为什么调用堆栈第一层是86eee6,而不是0x883C82.
这是因为,我们这种获取堆栈的方式,针对的是汇编函数开头一定要先进行push EBP, MOV EBP ESP这种操作的函数,这种通常是为了定义很多局部变量,为了不污染上层堆栈空间,所以先把EBP push进堆栈.但是对于没有这两步操作的就无能为力了.
并且其实我们断点加在了send函数的头位置,这里还没来得及push,所以也没法获取

[原创] 从零开始教你做辅助(二) --攻击怪物功能
上图是0x883c7c位置汇编代码截图,就是调用send函数的位置,这里重点关注下EAX寄存器,这个寄存器里存了send数据的长度,我们可以通过这个长度来大致判断调用到send这里时候,是否为攻击的调用过程,这里我就补贴代码了,否则看起来有点乱.
从我加的打印来看,游戏的心跳包长度为6,攻击包长度为14
限于ce获取堆栈比较麻烦,现在还是回归immunity debugger吧,编写如下python代码.

from immlib import * import rec_down import utils  class HookStack(LogBpHook):     def __init__(self, desp):         LogBpHook.__init__(self)         self.desp = desp      #########################################################################     def run(self, regs):         imm = Debugger()         data_len = regs['EAX']         imm.log('eax is:{}'.format(data_len)) # 打印出send函数将要发送数据长度          if data_len != 6: # 如果send函数发送数据长度不为6,我们就打印堆栈             stacks = imm.callStack() # 获取堆栈列表             for stack in stacks:                  imm.log(str(stack)) # 打印堆栈到log窗口  def main(args):     imm = Debugger()      utils.clear_hooks(imm)     opr = args[0]     if opr == 'hook':         # ---------------------------- send start ------------------------------------         addr = '883c7c' # 在调用send函数处下断点         h = HookStack(addr)         ret = h.add(h.desp,  int(addr, 16))         if ret == -1:             imm.log("hook send failed!")      return "ok"

现在我们得到如下调用堆栈

0BADF00D   0x0019F970 warspear.00883BD0 0x0086EEE3 0x0019F96C [0x00559CCF 0x009A5798 0x00000000]
0BADF00D   0x0019F988 warspear.0086EEB0 0x0087C56A 0x0019F984 [0x000A09E4 0x80006010 0x00000001]
0BADF00D   0x0019F9B8 ? warspear.0087C460 0x00860526 0x0019F9B4 [0x00000001 0x0019FAC4 0x008D58DA]
0BADF00D   0x0019F9D0 warspear.00860490 0x763547A9 0x0019F9CC [0x000A09E4 0x00000113 0x00000000]
0BADF00D   0x0019F9D4   Arg1 = 000A09E4 0x763547A9 0x0019F9CC [0x00000000 0x00000000 0x00000000]
0BADF00D   0x0019F9D8   Arg2 = 00000113 0x763547A9 0x0019F9CC [0x00000000 0x00000000 0x00000000]
0BADF00D   0x0019F9DC   Arg3 = 00000000 0x763547A9 0x0019F9CC [0x00000000 0x00000000 0x00000000]
0BADF00D   0x0019F9E0   Arg4 = 00559CCF 0x763547A9 0x0019F9CC [0x00000000 0x00000000 0x00000000]  

哈哈,很遗憾,找到这里我发现堆栈中不包含攻击操作,因为这个调用堆栈是从消息队列里面取出攻击包然后发给服务器.
那么我们现在要换个思路了  

0x02:找到消息封装的函数位置

因为之前的方法行不通,那就只能找到封装攻击包的位置了.
我们先在调用send函数的位置下断点,然后查看buf地址,找到是谁改写了这个地址.

[原创] 从零开始教你做辅助(二) --攻击怪物功能
如上图所示,用ida查看第一个位置代码,并转c++查看
[原创] 从零开始教你做辅助(二) --攻击怪物功能
从上图可以看出,对目的buf的写入用了同个字符,那这个函数大概就是个类似memset的函数了,这肯定不是我们要找的.
[原创] 从零开始教你做辅助(二) --攻击怪物功能
从上图可以看出,应该是拷贝操作了,这就是我们要的,那么我们找到调用这个函数位置,加个断点,找到入参地址(也就是拷贝的原地址),并找到是谁改写了这个地址

这次又找到两个地址.
[原创] 从零开始教你做辅助(二) --攻击怪物功能  

我们先来查看地址1这个位置,发现这里既不是buf拷贝操作,也不是memset操作,那么这里可能是封装点.然后写出如下lua代码
[原创] 从零开始教你做辅助(二) --攻击怪物功能  

function print_str(src, len)          local ret = readBytes(src, len, true)  --- 下面要调用的读缓冲区的函数          local str_ret = ""          for k,v in ipairs(ret) do              str_ret = str_ret .. string.format("%x ", v)          end          return str_ret end  function debugger_onBreakpoint()          if EIP == 0x0050e35c and EDX > 4 --这个是我测得时候发现,如果是心跳包,dex一定小于等于4,所以这里过滤掉          then             -- 因为上面,是从dl中读取值,所以我们这里打印EDX的值              print(string.format("eax:0x%X", EDX))              local stack = print_stack(EBP, 10)              print(stack) -- 打印堆栈          elseif EIP == 0x00883c7c -- send函数调用位置          then              local len = EAX -- send 的缓冲区大小              local src = readInteger(ESI + 0x44) -- send 缓冲区指针              local ret = print_str(src, len) -- 这个函数 从缓冲区地址src中读出len个字符到ret中              print(ret)           end      return 1 end  clear_debug() print(1) debug_setBreakpoint(0x0050e35c) -- 猜测的封装函数地址,查看用于封装的值 debug_setBreakpoint(0x00883c7c) -- send函数的调用地址,打印出buff的信息,用来对比

下面是攻击时候的打印,可以看到,进行了两次复制0xc到缓冲区的操作,刚好是缓冲区前两字节,这时候基本已经找到我们需要的调用堆栈了,我们一层一层网上搜寻

eax:0xC, arg0:0xC   //写入攻击buff第一个字节
50dd1c->7a714e->7a22aa->769cae->76a77c->76a5c6->5c72b5->7af2f9->7e8c79->5c77df->
eax:0xC, arg0:0xC  //写入攻击buff第二字节
50dd22->7a714e->7a22aa->769cae->76a77c->76a5c6->5c72b5->7af2f9->7e8c79->5c77df-> // 攻击调用堆栈
c c f 7 5a d8 f6 5 0 0 1 77 69 80  // 这个是打印出来的攻击buff里面的内容

通过对上面调用堆栈的跟踪,我们发现0x76a777这个位置就有我们要找的攻击调用地址

[原创] 从零开始教你做辅助(二) --攻击怪物功能  

如上图, 这个switch应该就是玩家操作最终走到的选择的switch
图1位置case 10001:就是0x76a777这个位置,调用了一个0x769c50.
图2位置case 10006:这个还没仔细分析,不过在玩家拾取怪物掉落物品时候会走到这个逻辑  

然后就是分析0x769c50的传参了,通过打印传参并对比我们之前获取的怪物列表发现.
[原创] 从零开始教你做辅助(二) --攻击怪物功能
图1位置:这里edi的值为要攻击的实体列表中怪物地址
图2位置:这里ecx的值为实体列表(之前叫错了,不应该叫怪物列表)中玩家的地址  

0x03:编写辅助攻击函数

代码位置 $(ROOT)/hackWarspear/StructGame.cpp  

void EntityBase::attack(DWORD monsterPtr) {     log_debug("enter attackn");     try     {         DWORD selfPtr = this->basePtr;         log_debug("will attack %p, %pn", selfPtr, monsterPtr);         __asm         {             mov eax, monsterPtr             push eax //怪物的地址             mov ecx, selfPtr //自己的地址             mov eax, 0x00769c50 //我们辛辛苦苦找到的攻击call地址(这里一定不能直接调用,要先存入某个寄存器中)             CALL eax         }     }     catch (...)     {     } }  EntityBase::EntityBasePtr EntityMgr::getEntityByHp(DWORD hp) {     for (auto ptr : this->entities)     {         if (ptr.second->HP == hp)         {             log_debug("find hpn");             return EntityBase::EntityBasePtr(ptr.second);         }     }      return EntityBase::EntityBasePtr(); }  EntityBase::EntityBasePtr EntityMgr::getEntityByType(DWORD type) {     for (auto ptr : this->entities)     {         if (ptr.second->type == type)         {             return EntityBase::EntityBasePtr(ptr.second);         }     }     return EntityBase::EntityBasePtr(); }  void EntityMgr::attack() {     try     {         log_debug("avatar attackn");         //这里默认我们已经获取到怪物列表了.上期有讲到过,最后会把怪物列表内容存到一个map里面         auto avatar = this->getEntityByType(EntityType::SELF);//根据类型找到玩家地址         auto mon = this->getEntityByHp(470);//找到一个血量为470的怪物         if (mon) {             log_debug("avatar :%dn", avatar->HP, mon->basePtr);             avatar->attack(mon->basePtr);         }     }     catch (...)     {         log_debug("error happened!n");     } }

[原创] 从零开始教你做辅助(二) --攻击怪物功能
如上图,编译运行后,点击攻击就会对怪物发起攻击了.

其实仔细想想,如果直接就根据怪物在内存中实体列表中的地址来找,可能一下就找到了.
下面是上期内容导航
从零开始教你做辅助(一)

部分文章来自互联网,侵权删除www.a1fz.com/

www.a1fz.com A1fz网专注于福利分享,各种破解软件学习资料,视频教程等等,如有侵权告知管理员删除
A1fz.com,福利吧,宅男福利,宅男,福利社,福利,有福利 » [原创] 从零开始教你做辅助(二) –攻击怪物功能

发表评论