作者:重楼
时间: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 函数所用到的 参数了
套接字: 每次跟服务器连接后 都会返回一个 类似于 端口 的一个数字 用来双方互相通信.你可以把它想象成一个通道.
封包数据:就是 发送封包的内容
封包长度:封包内容的长度
标识: 这个无需管他,默认为 0
好了 我们返回一层 就能看到 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
接收到大小 4
标志 0
右键选中 堆栈里的 数据地址 选中 数据窗口跟随
*数据窗口跟随 在数据窗口 显示 选中地址的内存里的值
我们接收到的 数据就是 jx27
在服务端可以看到 当前血量是27
在以前弄加血挂的时候 一般都会用一个时钟来循环处理 ,但这种方法总会有没来得及处理的状况发生,有一句话,监视不如自觉.外挂的最基本的一个功能 就是保证角色不死,即使用1MS检测一次也会有不少的漏过加血的机会,特别是去血比较大的情况下,这个时候 HOOK recv遍可以解决这个问题.如何hook recv 请看后面的hook api 教程 .
总结:
*send 函数的应用
*recv 函数的应用
*socket 函数的应用
*调用系统函数是一种比较方便的方法 ,它在于比较方便写入只要知道封包的结构,只要调用一个函数便能实现所有的功能.
*多用OD跟一下系统某些常用的函数,这会加深你对函数的理解及应用.