看流星社区

 找回密码
 注册账号
楼主: userchm

CALL是如何炼成的之三:寻踪篇

[复制链接]

该用户从未签到

发表于 2013-3-7 04:58:20 | 显示全部楼层
是怎么练成的

该用户从未签到

发表于 2013-3-14 15:59:26 | 显示全部楼层
CALL是如何炼成的

该用户从未签到

发表于 2013-4-9 19:22:10 | 显示全部楼层
谢谢楼主分享

该用户从未签到

发表于 2013-4-15 04:02:25 | 显示全部楼层
啊啊啊啊啊啊

该用户从未签到

发表于 2013-4-15 14:47:50 | 显示全部楼层
CALL是如何炼成的之三:寻踪篇

该用户从未签到

发表于 2013-4-22 12:13:00 | 显示全部楼层
CALL是如何炼成的之三:寻踪篇

该用户从未签到

发表于 2013-5-3 20:57:38 | 显示全部楼层
学习学习啦

该用户从未签到

发表于 2013-5-4 14:03:23 | 显示全部楼层
回复 1# userchm


    看看有没有图

该用户从未签到

发表于 2013-5-11 10:56:05 | 显示全部楼层
前言:遇到一个CALL应该如何写?

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

写CALL的步骤!

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

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

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

什么是适当的参数?

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

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


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

例子一:

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

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

push ecx
call 5FA410

然后看调用的寄存器.

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

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

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


那么 调用这个CALL的时候 寄存器 都是0了.  当然2个特殊的寄存器除外,一个是ESP 一个是EIP.
好了 现在CPU执行 call 5FA410  后  

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

这个时候,假设所有寄存器值都为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
call 5FA410

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

例子二:
  
从图中我们可以看出这个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
call   5BD150
add esp,4

我们来看看ECX的值,1615d00

那么是不是就是 push 1615d00呢 ?

的确,压入这个值CALL是不会崩溃,但这个绝对不是我想要的答案.
记住:调用CALL就是传入适当的参数.也就是需要我们构造一个CALL所需要的参数环境

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

mov al,[esp+8]

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

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

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

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

所以写成CALL就是  

push 0
call   5BD150
add esp,4

该用户从未签到

发表于 2013-5-11 23:30:40 | 显示全部楼层
看看什么东西
点击按钮快速添加回复内容: 支持 高兴 激动 给力 加油 苦寻 生气 回帖 路过 感恩
您需要登录后才可以回帖 登录 | 注册账号

本版积分规则

小黑屋|手机版|Archiver|看流星社区 |网站地图

GMT+8, 2024-4-20 02:26

Powered by Kanliuxing X3.4

© 2010-2019 kanliuxing.com

快速回复 返回顶部 返回列表