Chinaunix首页 | 论坛 | 博客
  • 博客访问: 241094
  • 博文数量: 65
  • 博客积分: 2758
  • 博客等级: 少校
  • 技术积分: 725
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-25 00:23
文章分类

全部博文(65)

文章存档

2011年(4)

2010年(1)

2009年(60)

我的朋友

分类: C/C++

2009-12-04 23:06:44

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

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


写CALL的步骤!

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

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

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


什么是适当的参数?

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

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


例子一:




这是某游戏的一个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









未完待续
阅读(1223) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~