外挂制作CALL是如何炼成的之二:实践篇

外挂制作CALL是如何炼成的之二:实践篇

学习各种外挂制作技术,马上去百度搜索"魔鬼作坊"点击第一个站进入、快速成为做挂达人。

前言:遇到一个CALL应该如何写?

这个是写一个内挂不可避免的问题.刚初学的朋友可能会不知道如何入手.想起刚学这方面的时候,绕过很多弯路,现在把一些经验写出来给大家参考参考吧,不是很高深的东西,但我觉得对某些人很有帮助.

写CALL的步骤!

我之前说过写一个程序的CALL其实就2个步骤,第一:找到相关地址,第二:传入适当参数.只要这2点你做到了这个CALL便能调用了.

其实写CALL就更简单了.只要传入适当的参数调用这个地址便可以了.

这里地址我们找到了,所以我们所做的就是传入适当的参数.

什么是适当的参数?

就是CALL所需要的数据.大家都知道,在WINDOW系统里,数据的传递是靠寄存器和堆栈.其中寄存器用的最多的指令就是MOV指令.

而堆栈则是用PUSH指令.通过[esp+*]或者先mov ebp,esp然后[ebp+*]指向堆栈数据.

学习各种外挂制作技术,马上去百度搜索"魔鬼作坊"点击第一个站进入、快速成为做挂达人。

说了那么多其实本文就是围绕着一个中心点来讲解,那就是教你如何构建一个CALL所需要的参数环境.

例子一:

这是某游戏的一个CALL.我们来看看CALL的内部

写一个CALL,首先要写堆栈.这里从调用CALL的图中我们可以看出只有一个堆栈,那么就是

push ecx

call5FA410

然后看调用的寄存器.

如何看CALL内部调用了哪些寄存器呢?

首先,明确一点,寄存器本身是空的.他并没有数据,只是一个用来存放数据的空间.

假如我们直接调用这个CALL那么,寄存器中,数据不是为0就是运行上一个CALL残留的数据.这些残留的数据我们暂且把他看成0.

那么调用这个CALL的时候寄存器都是0了.当然2个特殊的寄存器除外,一个是ESP 一个是EIP.

好了现在CPU执行call5FA410后

首先把当前的EIP压入堆栈,也就是call5FA410当前地址的下一条指令的地址.然后JMP5FA410

这个时候,假设所有寄存器值都为0

有哪些指令会读取寄存器的值呢?最常见的就是mov,push,lea,其实很多汇编指令都会读取寄存器比如说add ebx,eax

读取EAX的值加上EBX所得的值放入EBX里.

第一条指令为push ebx

我们刚刚说过push也是传递寄存器的一种指令.它读取了EBX的值开辟一个堆栈空间也就是指令sub esp,4然后存放.

这里EBX是不是我们所说的CALL所需要寄存器呢?

其实这里不是的.这里涉及到一个寄存器环境保护的机制.

什么是寄存器环境保护机制?

当ECX存放着一个重要的数据时候,这个时候需要运行一个CALL,而CALL的内部需要用ECX存放东西.那么原有的ECX重要数据该怎么办?

这个时候,肯定要找一个空间存放起来,等CALL内部临时用完寄存器后在放回.

这就好像你家里有一个仓库,堆满了玉米,但你邻居家要用你的仓库临时存放大米.你没办法,只好先将玉米放入一个临时空间.然后给你邻居家使用.用完之后你在放回去.

这里的临时空间就是指window系统里的堆栈.首先PUSH EBX把数据保存到堆栈里,等下面的指令使用完寄存器,然后POP EBX.

在尾部我们可以看到有POP EBX对应上面的PUSH EBX.

这里我们发现下面也有几个PUSH指令

push ebx

push ebp

push esi

push edi

在CALL尾部我们可以看到

pop edi

pop esi

pop ebp

pop ebx

这里的4个寄存器就是我上面指的寄存器环境保护.所以这4个寄存器就可以被排除了.

然后是第二句,mov ebx,[esp+8]

讲调用CALL之前的最后一个堆栈读取并存放到EBX.呵呵,刚刚把寄存器里的数据存放这里就被用到了,指令执行完后原有的EBX数据被覆盖.

所以这里的EBX是被用来当做临时空间来使用的.

mov esi,[ebx+a8]

这里的EBX,上面那条指令已经赋值了,所以这里的EBX就不用理会了,[EBX+A8]读取后存放到ESI,这里的ESI也是用来当做临时空间使用.

XOR EBP,EBP

EBP置0.即使没有上面的PUSH EBP只要遇到这种指令EBP也是被用来当做临时空间的而不是当做参数传递的.你都清0了还怎么传递参数?

下面就是一个对比,然后一个CALL了.

这些都不是我们改理会的东西.

最后我们来看看MOV[ESP+14],EAX

这一句调用了EAX的值.如果之前没有赋值的情况下,也就是我们假设等于0的情况下,那么EAX就是一个参数传递的寄存器.而这里我们在上面发现了

lea eax,[EBX+c]执行完这条指令后EAX的值便不是空的了.既然不是空的也就是不是参数传递的寄存器.

下面的MOV[ESP+14],ECX也是如此.

上面有一条指令给寄存器赋值了.

可以这么说,在假设寄存器都是空的情况下,CALL内部调用了空的寄存器那么这个寄存器就是参数传递的指令.

从这里我们可以看出,整个CALL的内部都没有调用寄存器.也就是没有用寄存器传递参数,故这个CALL的写法就是

push ecx

call5FA410

=============================

例子二:

从图中我们可以看出这个CALL是一个比较好写的CALL

首先我们来看堆栈部分.拿到一个CALL,首先处理堆栈,从图中我们可以看出这个CALL只有一个堆栈.

从mov al,[esp+8]我们可以看出这里的[ESP+8]指向了CALL上面压入的堆栈

PUSH ECX

处理完堆栈后,我们来看看寄存器的处理.

首先PUSH ESI我们可以看到尾部有POP ESI相对应.所以这个ESI是环境数据保护的寄存器,用来被CALL内部作为临时寄存器使用.

下面的MOV ESI,EAX中的EAX则是上面一个CALL的返回值.所以不必要做考虑

而mov[esi+2],al中EAX则是由上面的指令mov al,[esp+8]赋值.所以这里是临时寄存器.

而mov ecx,[ecx+20]中的ECX则由上面的指令赋值了.所以这里也不用考虑.

从上面的分析得到,这里我们不需要任何寄存器.

然后我们来看看,CALL尾部,是RETN,后面没有跟随数字,这里没有自动平衡堆栈.所以这里需要我们来加上恢复指令恢复堆栈

所以这个CALL的写法是

push ecx

call5BD150

add esp,4

我们来看看ECX的值,1615d00

那么是不是就是push1615d00呢?

的确,压入这个值CALL是不会崩溃,但这个绝对不是我想要的答案.

记住:调用CALL就是传入适当的参数.也就是需要我们构造一个CALL所需要的参数环境

这里我们只有一个参数.我们来看看CALL内部中调用这个参数的指令

mov al,[esp+8]

al大家看过汇编都知道,这个是EAX的低位1个字节.也就是最大数字是FF

从这句话我们可以得知,这里读取了PUSH ECX的低位数的1个字节的数据!

既然只调用了一个字节的数据,我们为何要压入4字节的数据呢?

所以这里ECX数据是1615d00低位1字节数据也就是00

所以写成CALL就是

push0

call5BD150

add esp,4

学习各种外挂制作技术,马上去百度搜索"魔鬼作坊"点击第一个站进入、快速成为做挂达人。

相关文档
最新文档