作者:重楼 
时间:2009-08-23 


======================send函数的调用==================== 

P: 用模拟器拿到当教程,是因为模拟器比较简单,讲一些原理方面的东西比较好.我们学习的是原理而不是方法,很多人抱怨说模拟器根本就没用,其实不然,模拟器给我们提供了学习原理最好的途径.不要只学习方法,比如说下bp send 然后返回 ,然后就急冲冲的去找游戏里的CALL,这样你会摔的很狠.你要懂得为什么要这样做,游戏是怎么调用的?算法结构如何?系统是怎么调用函数的?等等的一切,等你了解之后自然而然就会恍然大悟,当然一切的基础就是 汇编基础

      上回说了,游戏大部分都是用send  或者是 WSASend  来像服务器发送 数据的.现在封包没有加密的游戏越来越少了,可以说快绝种了,现在存在封包没有加密的游戏有  星尘传说 (最近加入了 心跳包 )  问鼎  等等 


*心跳包 是指 每隔一段时间 像服务器 发送一个数据 一般用于 验证 是否掉线 因为像心跳一样,每隔一段时间动一次 就比喻为 心跳包




  


这个是我们用到的 模拟器 .  一个服务端 一个客户端 

封包 没有进行加密 ,今天 我们来找 send  CALL来达到发送 封包的目的


老样子,打开OD 载入 


bp  send    点 一下  进入 

OD开始断下 



  

堆栈窗口 显示出 send 的 函数 所需要的参数

我们打开 MSDN 查一下 send所需要的参数 
(MSDN 是微软 发布的 WINDOWS API 函数的开发手册 里面有所有 函数的解释和细说



  


send  (socket(套接字),封包数据,封包长度,标识

这个就是send 函数所用到的 参数了 

套接字每次跟服务器连接后 都会返回一个 类似于 端口 的一个数字  用来双方互相通信.你可以把它想象成一个通道

封包数据:就是 发送封包的内容 

封包长度:封包内容的长度 

标识这个无需管他,默认为 


好了  我们返回一层 就能看到 send函数了




  

按照调用约定  参数 是从  右边开始 压入堆栈的 

首先是 标识    0 
然后是 大小 
接着是 数据内容 
最后是 套接数 也就是 socket 


我们在  CALL EBP  下断 (F2) 

然后 运行 起来 

点一下  加血 就会断下来 


send 相关值 是  



  


套接数 =EC 
封包内容 ="jx50" 
长度 =4 
标识 =0 
call 71A24C27 


好了  我们用 CALL注入器 写一个试试 



  


push 40300E 

这个是如何来的呢

因为我们要发一个封包数据 但是 代码注入器 无法给内存写入 所以 我们可以用CE找 一个空白的地址 然后往里面写入我们需要的封包数据 





  

搜索 0  会出来 一大堆 随便选一个  然后 把  类型改成文本  值 改成 jx50 

然后把这个地址压入到  堆栈中  就可以调用成功了~~  当然 CALL之前别忘了把 send 断点给去掉 



=====================socket的调用====================== 


这个时候你可能会注意到.这里 socket 的值是 EC . 如何取到这个值呢

这个时候我们可以参考下 window 函数socket 的那部分 




  

创建 一个 通信连接 并返回 一个套接数值


好了 我们来 找一下 这个值吧

从模拟器我们可以看到 ,这个模拟器 在打开的时候 会连接到 服务器段.这个时候我们从 套接数下手 

打开CE  搜索  EC (此次 套接数的 值 


  

出来17个 ,绿色的 是 基址可以排除了 .因为 套接数 的地址不可能不会发生变化

把剩余的7个都选中  

这个时候我们如何确认 7个中是我们要找的呢



  

  所有的地址改成不同的值  这个时候 我们开始断 加血



  
断下来以后 我们发现 EC的值 变成了 EC2了 

这个表明 用CE修改成 EC2的地址就是我们要找的 



  

在命令行输入  dd 009E1AE0  (每个人的地址都不一样

就会以 地址 的形式 显示出 数据的类型 

*da  是汇编代码类型 

*dc  是 文本类型 

*dx 是短行 16进制 

*db 16位显示 

其他的我就不列举了 网上有很多的

然后我们下硬件断点 ,然后重新运行 (因为只有重新运行的时候才会重新连接,才会往写入套接字

断在了程序入口处  我们按F9  断在了 一个 代码里  但是 我们并没有发现 有套接字的写入操作 

看来这步 是行不通的.我们换一个方法 我们来断 socket  像 send 一样 



下 bp socket 


选择  运行 重新开始  来重启程序  为什么要重启呢?因为我们要找写入 谁写入了套接数地址的值 

重新运行后 断在 程序 开始的地方  按下 F9  运行 


  


程序会立马断在这里 .这里堆栈显示了  socket  函数 和 他所需要的参数

这里 我们按 ALT+F9  返回 程序领空.  (CTRL+F9 是返回上一层  这里我们可以用ALT+F9直接返回到程序段






  


好了  返回到这里  .这里就是 SOCKET 的代码了 .CALL这里下段 

然后 在 重新运行 一次    断在程序入口处  按运行  断在了刚刚我们断的CALL地方 


  bp socket 的断点 删了 

在按F8  单步运行  


这个时候 CALL  返回了  SOCKET套接数  放在EAX寄存器里 




  


这个就是我们所需要的东西... 


好了 我们用代码注入器  调用 socket()  取到一个套接数值 


push 0 
push 1 
push 2 
call 71A24211 

这个CALL比较简单  所以我不做多的分析了 


接下来 我们把  EAX的值 读出来 放入一个空白的内存里 




  

0  随便选一个 空白内存 

我这里 是    40300C 

把这个地址写入  EBX 
mov ebx,40300c 
然后把 EAX的值传入到这个指针里 
mov [ebx],eax 



  

好了 套接数的值 读取出来了 每点一次都会得到一个新的值


我们回顾 前面 send  函数 把新的套接数代替 send里的套接数 发现 数据发送不成功 服务器没有反应 
看来每次连接 都是固定的值 .新的套接数并不能用于旧的链接



这里可以看出来  socket()  函数 调用的过程  有兴趣的可以跟进去看看 WINDOWS是如何操作的


或者 跟踪 socket()  后面 看看程序时如何 运行的  在对比下 源代码  你就会有新的认识



====================send在易语言里的编写================== 


  

在易语言插入 DLL命令,这样便可以使用send函数了.当然 直接使用是没效果的,我们还没连接目标




=====================recv函数的调用==================== 

recv是用来接收封包的函数 

我们先来看看 MSDN recv的解释 



  

int recv( SOCKET s,    char FAR *buf,      int len,    int flags    ); 

第一个参数 socket  很熟悉吧 套接字 
第二个参数  用来存放接收到的数据.指针类型 
第三个参数  是长度 
第二个参数 是标志 


*注意协议接收到的数据可能大于buf的长度,所以 在这种情况下要调用几次recv函数才能把s的接收缓冲中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的 

我们来看看 recv 在堆栈里的形式  bp recv  点加血 断下来后我们看看堆栈窗口 
(记住把send 断点取消了要不然容易搞混了


  


套接字是 F0 
数据存放指针地址是 10eeef4 
接收到大小 
标志 



  

右键选中 堆栈里的 数据地址  选中 数据窗口跟随 



*数据窗口跟随  在数据窗口 显示 选中地址的内存里的值 


  

我们接收到的 数据就是 jx27 


  

在服务端可以看到 当前血量是27 


在以前弄加血挂的时候 一般都会用一个时钟来循环处理 ,但这种方法总会有没来得及处理的状况发生,有一句话,监视不如自觉.外挂的最基本的一个功能 就是保证角色不死,即使用1MS检测一次也会有不少的漏过加血的机会,特别是去血比较大的情况下,这个时候 HOOK recv遍可以解决这个问题.如何hook recv  请看后面的hook api 教程 


总结

*send 函数的应用 
*recv 函数的应用 
*socket 函数的应用 
*调用系统函数是一种比较方便的方法 ,它在于比较方便写入只要知道封包的结构,只要调用一个函数便能实现所有的功能
*多用OD跟一下系统某些常用的函数,这会加深你对函数的理解及应用.

posted on 2011-10-17 12:00  巅枫  阅读(5135)  评论(0编辑  收藏  举报