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

全部博文(65)

文章存档

2011年(4)

2010年(1)

2009年(60)

我的朋友

分类:

2009-11-19 15:28:59

作者:重楼
日期:2009-08-26

*所谓的call,其实本质上来说就是一条汇编指令.
*只要找到了关键代码的地址,传入适当参数,就可以借用游戏中已有功能来完成内挂的功能。

当程序被编译以后,便不会存在任何函数,存在的只是0和1.所以我们调用也只是这段机器码而已.


网上找CALL的教程很多,但是却是从一个游戏的某一个功能入手,比如说完美的打坐,剑侠3的技能CALL,等等,那是因为每个游戏的数据结构都是不同的.一个游戏的怪物数组可以用数组结构 也可以用树 可以用链表,所以说
bp send 在返回, 并不是万能的.


P:当我们上手一款游戏,我们一开始如何分析,从哪里开始?


每个人都有不同的想法,而且水平不同,开始寻找的侧重点也不同,寻找多了之后你自然而然的会明白自己该从何入手,而且能确认哪个是真正要找的数据,这个就是经验了.

目标:武易的打坐CALL
目的:以打坐为例子讲解各层CALL的含义



好了,今天就拿 武易 这个游戏做例子,这个游戏的非常简单,有些类似于传奇.

首先分析下,能不能用OD加载,或者看看 有没有启动什么 保护之类的.

加载好以后,我们来试试 游戏的一些功能 (有些朋友一上手就去分析数据了) , 知彼知己,方能做出好的功能的辅助,一个做的好的辅助,他的游戏经验也一定很好,只有玩这个游戏精通的人才能做出最适合的辅助来.
color=Black]玩了一段时间,我们发现,一开始,是需要领取武器和衣服,要不然你会死的很惨.... 好了,玩了下 发现 游戏 按 D 是打坐,  TAB 是选怪,右键是跑,在地图上面点击能自动寻路,任务里面能点击怪物自动寻路. 好了  简单的游戏功能都已经出来了,我们下面从最简单的功能开始,就先寻找打坐的CALL吧


我们下来下 bp send  命令, 然后 返回 游戏 按 D  这个时候 OD就断下来了,(如果不断试试 WSASend或其他发包函数)


既然断下来了 ,我们就能确认他是用send 发包




 

好了 我们又来到了老地方了,这里是 send  函数的头部,前面我们讲过只要CALL这个地方并且传入4个值就能正确调用这个函数了.



 

好了,返回一层我们到了这里 ,这里是游戏 调用 send 函数 发包的地方.


 

这里是我们 加密包后的CALL.  为什么呢?



 

好了 ,我们在断 一次 看看 封包地址内容是什么,  是不是和上面的差不多?
当然这个游戏比较简单, 所以很多东西都比较直观.

我们继续返回


 

这里有一层CALL,比较像 打坐的.我们来看看堆栈地址,发现压入的堆栈是加密后的数据,但是少了一些内容
看来这里还不是打坐CALL的地址,要不然不会压入封包加密后的数据.



 




又返回一层 到了这里,这里我们发现压入了好多东西,我们看看 那个EAX有啥数据,看堆栈...




 


这里 压入的顺序和代码压入堆栈的顺序是一样的.  这里我们可以看到EAX=

 


有经验的人就能看出这里是 封包构造的那一层,  3AAC  是封包内容中  打坐的标志.~

当然了 以我们目前得到的数据来说的话 这一切只是猜的,而且这层里面包含2个CALL


在这里 如果如我们猜想的正确的话 那么就是 明文封包的打坐CALL的封包结构了,而这一层 就是所有构造封包的CALL.

我们先来分析下他的数据...

==============================CALL的分析========================

在第一行 push ebx  下断.  压入了 20 这个值

第二行
004931C1    8A5C24 08      mov    bl, byte ptr [esp+8]

*这里 [esp+8]  是指 上一层CALL所压入的参数.([esp-8] 表示局部变量 详情请看 反汇编原理篇一),不信的话还可以去上一层看看压入的参数是否一样

[esp+8] 指针的内容是 01  bl = 01

第三行 
004931C5    66:0FB6C3      movzx  ax, bl

我们先来看下 movzx 指令的含义

movzx: 
  带0扩展传送指令(注意是通用数据传送指令,所以符合mov一般寻址方式) 
  格式:  movzx  DST,SRC 
  执行操作:(DST)<-0扩展(SRC) 
  两种格式 
   
  movzx  reg1,reg2 
  movzx  reg,mem 
   
  该指令不影响标志位 
  源操作数任意寄存器或内存寻址而目的操作数必须寄存器寻址,且长度一定大于源操作数,将源操作数带0扩展传送 
   
  例如: 
  movzx  dx,al 
  al=8ah,10001010,扩展后dx  00000000  10001010  008a


是不是看的很迷茫?没事 只要我们多实战几次自然就会懂的.
我们先来看看 执行这条指令后的结果.



 

004de150 变成了 004d0001  呵呵 现在应该有点明白 上面指令解说里的意思了吧.

第四行 004931C9    56              push    esi      ESI= 7C80934A    不知道会不会变


004931CA    6A 00          push    0    这一行不解释了 压入了一个0

004931CC    8BF1            mov    esi, ecx    将 ECX的值压入到 ESI, ECX的值从哪来?

004931CE    50              push    eax                    这里就是把前面得到的 4d0001 压入堆栈 也就是说 封包内容(别问我咋知道的 我是猜的)


004931CF    6A 00          push    0
004931D1    6A 00          push    0
004931D3    68 AC3A0000    push    3AAC


压入2个0  然后压入3AAC  (可能是封包标志)

好啦 接下来是CALL       
call    004200B0


现在差一个ECX ,我们多断几次看看他的值 会不会变  当然还有ESI的值.

我们断了几次 发现ECX的值 暂时不会变化 (重新打开游戏可能会变化)

这里顺便提一下 如何 寻找ECX  和ESI 的值的基址.

方法一 用CE查找.


 

我在 找基址一中就说过  在CE中 绿色的就是基址了

以后读取这个地址 就可以取到  ECX的值了



 


用同样的方法就能取到  ESI的值  这里我们发现有好几个绿色的值 我们随便取一个就可以了


==============================CALL分析结束===================

既然CALL已经分析完了 ,那么 我们用代码注入器来写CALL



push 20
mov esi,[600F1FC]
push esi
push 0
mov ecx,[4FA818]
mov esi,ecx
push 4d0001                  '这里我们直接压入 获得的EAX值
push 0
push 0
push 3aac
call 4200b0
add esp,1c                '堆栈平衡 压入了 7个堆栈 7*4=28  =1C    10进制的28=16进制的1C



好了 , 注入远程代码,  发现 游戏人物并未 执行打坐 动作,但是 游戏没有出错,我们的CALL是写正确了.
但可能不是封包结构的CALL,估计我们猜错了

很多时候,我们都在作无用功,但是成功可能在离你不远的地方,就要看你能不能坚持下去了.

我们这时候发现下面还有一一个CALL ,如果继续写的话 还不如直接调用上一层CALL呢。




 


好了 继续返回,  这里有个CALL [EAX+84]  这个是间接地址,我们先断下来看看.




 


=============================CALL 分析======================



 


首先 我们看下 CALL的值

call [eax+84]=[004DE1D4]=004931C0



然后 我们来找下 edx 的值  .....我们多断几次 发现EDX的值 每次都是变化的.

好了 我们进去看看  到底哪个语句调用了  这个参数.




 


进入了[EAX+84] 的内部  也就是 刚刚我们分析的那一层.

我们来找下

004931C1    8A5C24 08      mov    bl, byte ptr [esp+8]            ; 01

这句话 就是 使用了刚刚 PUSH 进来的值.  为啥是这个呢 ,我们在上面说过 [堆栈+*] 这种都是 参数.

也就是在易语言里  子程序 被传入的参数.

BL    是 EBX  EX BX    EX=EH EL  BX=BH BL   

所以 这里不管[ESP+8]  有多少数字 只会传入8个字节 也就是说16进制的2位

那么 这里 除了  个位数和十位数 有用 其他位数的不都没用了么?

回答正确.~

我们多断几次 发现他不管怎么变化 后面2位都是01

也就是说传入EBX的值 就是=1

我们PUSH 1 试试


参数解决了 ,那么 我们来解决寄存器问题 首先进入到 CALL内部 来看看CALL需要哪些寄存器



 


004931C0    53              push    ebx                                  ''这里调用了 EBX
004931C1    8A5C24 08      mov    bl, byte ptr [esp+8]            ; 01
004931C5    66:0FB6C3      movzx  ax, bl                            ''这里的BL 上面已经赋值了 所以不需要我们写了
004931C9    56              push    esi                                      ''调用了ESI
004931CA    6A 00          push    0
004931CC    8BF1            mov    esi, ecx                          ECX未被赋值所以CALL调用了ECX 
004931CE    50              push    eax                              ; 004D0001  ''EAX上面已经赋值了
004931CF    6A 00          push    0
004931D1    6A 00          push    0
004931D3    68 AC3A0000    push    3AAC
004931D8    E8 D3CEF8FF    call    004200B0
004931DD    8B8E 98040000  mov    ecx, dword ptr [esi+498]        ; 4
004931E3    8B96 84040000  mov    edx, dword ptr [esi+484]        ; 9a
004931E9    8B86 80040000  mov    eax, dword ptr [esi+480]        ; 67
004931EF    83C4 14        add    esp, 14


其他都没了~  我们来整理下  一共调用了3个寄存器  一个是 EBX  ESI  ECX


我们来看看 3个值到底多少






 


这里我们断在CALL的时候寄存器的值    EBX=20    ESI =7C80934A  ECX=0DDC01D8


我们在上面分析过了  EBX 和ESI的值都是不会变化的 ,而ECX的值 重新开游戏 就会有变化

我们上面用了CE找基址 这次我们来用另外一个方法



 


00471B7E    8B0D 18A84F00  mov    ecx, dword ptr [4FA818]


这里 传入了 ECX的值 是不是跟我们上面找的一样?


00471B8E    8A91 0E050000  mov    dl, byte ptr [ecx+50E]          ; 打坐状态


这里 有个 ECX的偏移  多次 打坐 站起来后 我发现 打坐的话  就是 1  不打坐就是0 

这里就是 打坐的状态,  大家可能会发现 修改这里的内存值 会直接打坐 ,其实这只是本地的效果,在服务器并没有打坐,也不会有恢复血量的变化,所以你还是老老实实的调用CALL吧



 


================================分析结束==============


好了 分析结束了 我们开始调用CALL



 


好了 调用成功了.

这里 ,我们来找找  mov esi,7c80934a      中 7c80934a  的基址


 

随便挑一个,写成汇编代码就是  mov esi,[600F1FC]


这里我们把CALL换一种写法  我们来写一下CALL 的基址



 

mov ecx,[4fa818]
mov eax,[ecx]
call  [eax+84]


这里 我用红色的框标出来了,这里可以直接找到 基址  (注:这里基址你们的基址可能跟我的不同,我最后会讲这个原因)


好了整合下  测试成功~(这里因为间接地址的原因 (如[EBX+84] ),可能基址会不同.)

mov esi,[600F1FC]
mov ebx,20
mov ecx,[4fa818]
mov eax,[ecx]
mov eax,[eax+84]
push 1
call eax




不过这样写还是太麻烦了 ,所以我们再去上一层看看





 


这里 便是上一层的代码了.我们来分析下



====================CALL分析=========================

首先来看看堆栈的数值 PUSH ESI          esi=09ECA1A8  重开游戏发现这个值变化了.我们来找找这个值从哪来的 ,打开CE 搜ESI的值,找到一个绿色的地址 ,  这个就是ESI的基址


 


好了 接下来我们看看 CALL内部调用什么寄存器.



 


=======================================分析结束================
好了 我们写一下CALL


 




===============================最后分析========================

我们在讲解第二个CALL的时候,你可能会发现你的基址跟我的可能有些不一样.

下面那张图是不同电脑的CALL 原型.



 


后来我发现 很多动作都调用了这个CALL,  比如说打开地图啊  修理啊, 关闭背包 等等.

这里可能是调用了 外部模块 的原因 .这里我无法肯定 ,因为我也没有具体的去研究过.或者是游戏版本的不同

如果有朋友知道 请回帖说下,不甚感激. 

从上面那张图可以敲出  除非用 特征码 来寻找基址 ,估计没有其他办法来确定固定的值了,或者说我不知道.如果用特征码的话那么就太麻烦了.

如果调用这层CALL来做挂的话,我估计也只能你自己用了.~~~~.

好了,花费那么多时间来研究一个自能自己用的CALL 到底值不值呢?这个只有你自己最清楚了.
阅读(1182) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~