22授人以鱼不如授之以渔●写CALL篇二:寄存器的处理找到一个CALL如何去写?这是很多人都想知道的问题.我觉得写一个call首先处理的顺序是如下的这里我写出我自己的想法,当然如果你有更好的方法或者意见就请提出来第一首先处理堆栈第二如果堆栈有寄存器,那么处理寄存器值的来源第三看看CALL有没有需要某个寄存器第四看看有没有往指针地址写值的代码第五是否需要堆栈平衡==========================第三章寄存器的处理=========================写完堆栈后,我们就需要写,CALL需要的寄存器.在之前的几篇找CALL中我都使用过这种方法.这个方法难就难在如何看出是否是堆栈环境保护,还是需要的寄存器.为何不给寄存器赋值就会出错呢?我们拿概念篇:出错分析一文中的例子我们知道汇编里指针指向地址,可以直接往内存里写入或者读取地址里的值.这个时候如何指向一个不能读的地址呢?如上图所示.那么就出错了,这里前面是执行代码的地址,中间是出错的内存地址,后面是出错的原因.这里的错误信息是执行4030a7这处地址的代码时无法读取147172E的内存.从OD里可以看出147172E指向的是一个不存在的内存区域.在这里要说下,很多朋友写C语言用指针读取内存时也会发生这样错误,比如说读血的值,在游戏中可以正常读取,但小退的时候却出错了,原因就是小退的时候,那里的内存值未分配.这里我拿来了剑侠三中喊话CALL的原型汇编代码.这里是喊话的CALL这里是CALL的内部想要知道CALL内部需要什么寄存器当然得去内部找了.图中的第一行pushecx//这里需要压入ECX的值那么这里需不需要给ECX的值赋值呢?其实是不需要的,因为CALL的内部有时候需要调用寄存器来存放数据那么原有的数据就会保存到堆栈里.执行完后在弹出来.也就有了CALL尾部的POPECX来对应.从这里我们便可以看出如果尾部有对应的POP的话那么这里就是CALL内部的环境保护.我们可以发现尾部一共是5个分别是ediesiebpebxecx那么我们是不是这些就不用处理了呢?其实也不对.这里的原因我后面再说然后是第三行,movebx,[esp+14]按照上面写CALL篇一中的来说这里就是取出刚刚压入的参数,所以也不需要管EBX的值了第八行XORESI,ESIESI清零,即使有数据也会被清0的所以也不需要管第十一行这里需要一个ECX的值用来传入到EBP第十二行这里的ESI其实上面已经被处理过了所以也不需要第十三行到了第一个CALL了,其实绝大部分来说只要看前面一部分就可以了.这里我们可以看到CALL给ECX赋值为522FB8这里是正常情况下ECX值的跟踪,如果到最后一步值变成0或者100之类的无法读取的内存地址那么游戏变会出错,当然也有可能走不到这里.这个就要对比赋值和未赋值的代码执行方向.这里我对比了下发现,未赋值ECX的值中途会跳到出错CALL去.写到这里,不知不觉有点跑题了,我们来拉回正题这里是走路的CALL第二行读取参数赋值到EBX里那么下面的BL的值就有着落了.第六行这里把ECX的值传入到ESI,前面我们可以看到没有给ECX赋值的代码故我这里先写上ECX第七行和第八行给ECX和EDX赋值,来给下面那个CALL使用.这里EDX也可以排除了.好了分析到这里我们就可以发现CALL可能需要ECX的值.要找出CALL所需要的寄存器,不是几天就可以熟悉的,需要不断的寻找和测试.