请问下货车ebp是什么意思哪里来的,谢谢

当前位置: >>
中级外挂电子书教程+找CALL+找基址+游戏实例解说
目录1. 关于 ................................................................................................................................................ 3 2. 外挂制作 ........................................................................................................................................ 3 2.1 找怪的数组 .......................................................................................................................... 3 2.2 对游戏中CALL的理解 ...................................................................................................... 13 2.3 找CALL方法 ...................................................................................................................... 16 2.4 找CALL写CALL教程 ....................................................................................................... 19 2.5 50 走路CALL的找法 .......................................................................................................... 32 2.6 50 快手键CAll分析 ............................................................................................................ 38 2.7 找预言明文发包CALL...................................................................................................... 42 2.8 查看发包数据 .................................................................................................................... 45 2.9 找加密算法的方法 ............................................................................................................ 46 2.10 分析封包 .......................................................................................................................... 47 3. 诛仙找基址 .................................................................................................................................. 49 3.1 【KJ】诛仙游戏找地址集合(一) ................................................................................ 49 3.2 【KJ】诛仙游戏找地址集合(二) ................................................................................ 51 3.3 【KJ】诛仙游戏找地址集合(三) ................................................................................ 53 3.4 【KJ】诛仙游戏找地址集合(四) ................................................................................ 56 3.5 【KJ】诛仙游戏找地址集合(五) ................................................................................ 59 3.6 【KJ】诛仙游戏找地址集合(六) ................................................................................ 60 4. 天龙八部找基址 .......................................................................................................................... 62 4.1 1.搜索人物基地址 .............................................................................................................. 62 4.2 2.编写读状态程序 .............................................................................................................. 65 4.3 3.找当前地图数据 .............................................................................................................. 78 4.4 4.找怪物数组地址 .............................................................................................................. 86 5. 武林外传找基址及CALL............................................................................................................ 89 5.1 不开反汇编找武林基址 .................................................................................................... 89 5.2 找人物包裹地址方法 ........................................................................................................ 91 5.3 武林TAB+天博地址 .......................................................................................................... 96 5.4 找武林打坐CALL.............................................................................................................. 96 5.5 找游戏关键CALL.............................................................................................................. 97 5.6 地面物品查找方法及其call的写法................................................................................. 100 5.7 功能函数及明文发包综合分析 ...................................................................................... 114 6. OD使用教程 ............................................................................................................................... 116 6.1 OD使用经验 ..................................................................................................................... 116 6.2 OD常用断点 ..................................................................................................................... 127 6.3 OD断游戏CALL总结 ....................................................................................................... 139 7. NP原理分析 ................................................................................................................................ 140 7.1 NP下用OD调试的方法 .................................................................................................... 140 7.2 反NP监视原理 ................................................................................................................. 150 7.3 NP下读写游戏内存 .......................................................................................................... 1551 8. API函数应用 ............................................................................................................................... 161 8.1 SetWindowsHookEx 函数参数祥解 ................................................................................ 161 8.2 ReadProcessMemory函数游戏功能 ................................................................................. 168 8.3 winio的使用 ...................................................................................................................... 169 8.4 底层技术接管发包 .......................................................................................................... 170 8.5 API HOOK拦截封包原理 ................................................................................................ 171 8.6 通过注入DLL截取明包 .................................................................................................. 174 8.7 用汇编写HOOKAPI的简单例子 .................................................................................... 177 8.8 网络游戏的封包技术 ...................................................................................................... 181 9. DEBUG教程及代码表 ............................................................................................................... 185 9.1 DEBUG使用教程 ............................................................................................................. 185 9.2 80x86 Opcodes .................................................................................................................. 1992 1. 关于www.369777.com本教程内容均来自网络. 其中大部分整理自网络,其内容版权归原作者所有. 未经允许任何组织或个人不得转载或有商业用途!-----------36977.com-重新整理---------2. 外挂制作2.1 找怪的数组今天我们来找一下怪的数组,首先我们来明确一下数组这个概念 数组就是内存中一连串不间断的大小相同的块 现在我们开始先找怪的名字3 我们找大黄蜂这个关键字,有点久。。。我先去趟厕所,梢后回来 好,找好了,但是这么多结果,怎么看呢? 还记得我说的数组的概念吗? 数组就是内存中一连串不间断的大小相同的块 你看前面几个是连在一起的4 看出什么了吗?每个地址间隔 40h,不信拿计算器算一下 typedef struct { //40h 的内容 } * 我们来看看具体内存里的东西好了,现在发挥你的大脑想象、猜测、对比,不管你多蠢,你都能得到下面的结论:从 02D478A8 开始偏移 40h 个字节是第 0 个怪的信息 从 02D478E8 开始偏移 40h 个字节是第 1 个怪的信息 从 02D47928 开始偏移 40h 个字节是第 2 个怪的信息 从。。。还要我罗嗦吗?不要紧,我只要重复做复制、粘贴的动作,而你真的自己踏踏实实 地找一遍。好了,怪物结构我们可以自己定义一下了 typedef struct {5 //40h 的内容 char MonsterName[16]; DWORD L DWORD//总是 0Fh DWORD ID; DWORD none1;//总是 0 DWORD none2;//总是 0 DWORD none3;//未知 DWORD none4;//总是-1 DWORD DWORD none5;//总是 0 DWORD DWORD none6;//总是-1 DWORD none7;总是 0 } * 自己数数够了没有 12*DWORD+16= 接下来最麻烦事情来了,怪物数组是从 02D478A8h 开始的,但这个地址每次启动游戏后都不 一样,那我们该怎么定位呢?这需要我们找到基地址 CE 已经没用了,加上今天是愚人节,它老跟开玩笑,一狠心关掉它。。。(注意不要关掉游 戏) OD 上场,(鼓掌声。。) OD 附加游戏,来到 02D478A8h 看看你看大黄蜂还乖乖地呆在那里没动,在 02D478A8 那里下内存写入断点。游戏几乎瞬间断下6 删除刚才的内存断点,几次 CTRL+F9 执行到返回到 Game 的区域还记得我们先前要找什么吗?你可以往前翻一下。我是有点犯迷糊了。 在 0040700B lea ecx,dword ptr[edi+10]下断7 可以知道 edi+10= 不要紧,我们改一下 typedef struct { //40h 的内容 DWORD none7;总是 0 char MonsterName[16]; DWORD L DWORD//总是 0Fh DWORD ID; DWORD none1;//总是 0 DWORD none2;//总是 0 DWORD none3;//未知 DWORD none4;//总是-1 DWORD DWORD none5;//总是 08 DWORD DWORD none6;//总是-1 } * 仔细检查一下,OK 完全对上了。 下面准备本草稿本,跟我做 草稿本写下 lea ecx, dword ptr [edi+10] ;edi+10=那么 edi= 往上看一下 edi 从哪里来的在草稿本上记下: mov edi,eax call
让我检查一下你草稿本上写了什么 lea ecx, dword ptr [edi+10] ;edi+10=那么 edi= mov edi,eax call
我劝你倒过来看好一点 call
mov edi,eax lea ecx, dword ptr [edi+10] ;edi+10=那么 edi= 思路清晰多了吧 我们看看函数
里干了什么9 还好函数不是很长,不然头都大,从下面看起 lea eax, dword ptr [eax+ecx+7C] 你可以断一下这句,eax 其实等于 0 那么就可以理解为 lea eax, dword ptr [ecx+7C] 看 ecx 的值从哪里来, 发现不在这个函数里, 去外面找找, 回到函数外面 (还记得在哪里吗?)10 看到 Call
上一句是 mov ecx,ebx,哦原来 ecx 的值是从 ebx 传过来的。 再往上找(在好远的地方 00406D47)有一句 mov ebx,ecx你的草稿本呢?写下 mov ecx,ebx mov ebx,ecx 检查一下你的草稿本是不是很我的一样 lea ecx, dword ptr [edi+10] ;edi+10=那么 edi= mov edi,eax call
{ lea eax, dword ptr [ecx+7C]} mov ecx,ebx mov ebx,ecx 好的,我知道你看得很辛苦,也很烦,不过要坚持哦,快接近胜利了 目标是 ecx 的值,加油 在 00406D47 mov ebx,ecx 下断点,断下后执行到返回 mov ecx,dword ptr [620BC8],在草稿本上记下这最后一句 怎么样,很兴奋吧,620BC8 就基地址了 把电脑关掉(为什么要关掉?答:不要分心啊~~~),研究一下草稿本上的内容 lea ecx, dword ptr [edi+10] ;edi+10=那么 edi=11 mov edi,eax call
{ lea eax, dword ptr [ecx+7C]} mov ecx,ebx mov ebx,ecx mov ecx,dword ptr [620BC8] 草稿本上的是我们逆推的过程,现在我们可以把它倒过来看 mov ecx,dword ptr [620BC8] mov ebx,ecx mov ecx,ebx call
{ lea eax, dword ptr [ecx+7C]} mov edi,eax lea ecx, dword ptr [edi+10] ;edi+10=那么 edi= 如果你的小学数学学得还可以的话,我想你应该和我一样得出下面的公式: [620BC8]+7C+10=怪数组的起始地址)怎么使用: typedef struct { //40h 的内容 DWORD none7;总是 0 char MonsterName[16]; DWORD L DWORD//总是 0Fh DWORD ID; DWORD none1;//总是 0 DWORD none2;//总是 0 DWORD none3;//未知 DWORD none4;//总是-1 DWORD DWORD none5;//总是 0 DWORD DWORD none6;//总是-1 } * pmonster pmonster1; __asm { pushad mov ebx, [620BC8] add ebx,8Ch12 mov pmonster1,ebx } //怪的名字:pmonster1-&MonsterName //怪的 ID: pmonster1-&ID //怪的坐标 X: pmonster1-&x //怪的坐标 Y: pmonster1-&y 后记:愚人节快乐!!!2.2 对游戏中CALL的理解先说下 call 是什么。 call 就是程序调用。熟悉 VB 的朋友,应该熟悉调用函数 call add(a, b)的方法。 在任何程序的编写中都有很多 call。如何找到正确的 call 是比较难的事情。 列一个调用过程: call 鼠标点击 { call 判断是点到怪、物品、地面 { select case 怪 : call 选怪 case 物品 : call 捡取物品 case 地面 : call 走路 case 墙壁 : call ... case ... } } call 选怪(怪物 ID 或标识) { push 明文包 call 加密 } call 捡取物品(物品 ID 或标识) { push 明文包 call 加密 } call 加密1级 { call 加密 n 级 { w32_send()13 //发送给服务器 } } 游戏的大概流程就是这样子的了。 对于找 call 来说,重要的是在 n 层嵌套中找到正确的 call。这方面只能靠经验或猜测,看那 个 push 比较有戏。具体的方法也很简单,在 N 层嵌套的 call 中,看那个参数我们比较熟悉,比 如观 察是否有怪物 ID 等。在多个 call 中找到一个我们熟悉的,然后调用,观看效果,如果不对, 再试 别的。 上次讲过,在找周围怪物列表的时候,通过 call 选怪(怪物 ID 或标识),向上跟踪找到怪物 ID 的 来源。这个怪物 ID 肯定是在周围所有怪物中的其中一个,所以通过这种方法,可以找到怪物 周围 列表。 基本的原理和方法都已经讲出来了。对于初次找 CALL 的朋友,可能对操作系统和编译器生成 的原 理不是很熟悉。我这里大概说一下,也是重点。 首先要明白,windows 是多进程、多线程的操作系统。CPU 轮流切换时间片给每个线程。而每 个进 程都有自己独立的地址空间。具个例子,一排的牢房,CPU 是送餐的,从左到右一直送过去。 每个牢房都是独立的,不会影响其他的牢房。 而 DOS 操作系统是单进程的,每次只能运行一个程序。这里我要说的是,当你面对一个进程 的时 候,就不要考虑其他进程怎么样怎么样了,因为其他的进程和你自己的进程是没有关系的。 这也 是在大学里讲 c 或者汇编只考虑一个进程的原因。 我们继续。 而在一个进程里的多个线程是共享当前进程空间的,如果你写过多线程的程序,就比较容易 理解 call 是怎么回事。我们看代码: function add(a, b) as long { add = } 这是一个加法的 call。 在我们的程序里有2个线程。 function thread1() { while 1 { text1 = }14 } function thread2() { while 1 { text2 = } } 2个线程都可以调用 add 函数,都可以得到正确的结果。同样的概念套到游戏里就是游戏的线 程和 我们自己的线程都可以调用“选怪”这个函数,并且得到正确的结果。call 的原理就是让我 们自 己的程序,去调用游戏里的函数。当然,必须存在我们这个“线程”。注意,这里线程是非 常关 键的。如果不是一个新的线程,就无法得到 CPU 时间片。所以,一定是一个线程在调用1个或 者多 个 call。 明白概念之后,我们就可以考试动手了。首先找到 call 的地址,然后想办法调用他。 这里又需要考虑,我们如何才能调用它。首先第一个概念是要在游戏进程开辟一个线程,在 这个 线程中做我们想要的操作。 那么首先要做的是,把这个线程放在游戏进程中。目前流行的方式有2中,编写钩子 dll。或 者远 程注入一个 dll。 因为 dll 没有自己的独立空间,只能依附在一个 exe 的进程当中。而且 windows 帮我做了很 多 dll 在 exe 空间中定位的问题。所以 dll 就是我们的不二选择。 鉴于钩子和远线程的资料非常多,我就不写了。 我习惯用远线程来注入 dll。按我的习惯,我们继续说。 被注入的 dll,一定要是个标准 dll。不能是 activex dll。两者的调用方式不同,所以不能 用 activex,这也决定了 vb 做的 dll 是不能被注入的。能被注入游戏地址空间中的 dll,几乎都 是用 c 或者 delphi 写的。所以这个 dll,还需要大家去学习这两种语言中的一种。 然后在 dll 里,直接调用。比如我们找到的 call 汇编如下: push 1 push 2 call 123456 这里传递1和2做加法操作。我们在自己的 dll 写下: __asm { push 2 push 5 call 12345615 } 这样,这个 call 中就实现了2+5的操作。如果在123456这个 call 中,输出一个和的消息框, 我们 就能看到结果了。在后面我会给出一个可操作的 exe 和注入 dll 的代码。 我要说的最后一个概念,也是很多人的疑问。已经注入的 dll,我们如何调用它。 可以很明确的告诉你,不能调用(其实也不是不能调用,只是很麻烦,也非常占用资源,就 是利 用远线程调用)。因为你的 dll 已经生存在对方进程中了。你自己的 exe 又是另外一个独立 的进程 。 想像一下, 如果你能调用对方进程里 dll 中的函数, 那不是也可以直接调用游戏 call 了么: ) 这样的话,也就不需要注入了。 然后你肯定又会问,如果不能调用 dll 里的函数,我们让他执行。 这里有2种方法, 1.全部代码都在 dll 中写,包括界面、流程等这些内容。 2.采用进程间交互的方法。windows 虽然不同意你调用其他进程中的数据,但是允许不同的进 程 间做数据通讯。进程间通讯的方法很多,比如消息,共享内存区,映射文件等。百度上资料 很多 。 如果有朋友用过 readProcessMemory API 的话,一定会奇怪,我们可以读写其他进程中的函 数, 为什么你又说 windows 不允许呢。如果你有跟踪过 readProcessMemory 函数的话,你会发现, 该 API 用的是共享内存区的方式获得对方内存中的数据。 就先写这么多吧,打这么点字也用了半个多小时。2.3 找CALL方法方法二: OD,bp send,鼠标选怪,断下后,几个 ctrl+f9,找一个鼠标点击的函数 类似 TAB 的 CALL,push eax ,call XXXXX,进入到 XXXXXX 地址,这里就是鼠标点击的函数头, 在这里下断,你走路吧,步步过,一直跟到函数尾,就能找到我们要找的走路 CALL1、首先要明白你要找什么?先举例,比如你开枪射击,你扣动扳机后,枪会产生 N 个动作: 撞针会后退、前进、子弹的火药要燃烧。。。。。。这些都不要管它。 你扣动扳机的那个动作,就相当于你要找的关键 CALL。 这个概念一定要明确。下断要找准地方。比如上面的例子,你在撞针撞击子弹的地方下断, 断是会断下,但断错了地方。个人觉得,一直向上找,直到你 F2 下断后,不做游戏动作也会 被断下为止。 2、多练、多想,再来一点点的运气,才能找到关键 CALL。不然武林诛仙不玩了,再玩其它游 戏就菜了。 关键 Call 的找法一直都是个不大不小让人头痛的问题,需要大量的汇编代码分析,还需要很 多测试工作,当然还有一种变态的方法,那就是用 OD 断下后,把前前后后所有的 call 都测16 试一边,也能找到关键 call,不过面对大量的 call 和无数次挂游戏,恐怕这个方法只能在理 论上实现了。 那么是否有既不需要看大量的汇编代码,有能够经过有限的几个测试找到关键 call 的方法呢,下面我就把一种另类的找法送给和我一样的懒人和新手吧。 以 50 打坐和普通攻击的 call 查找为例。 启动 OD 加载 50,进入游戏后,和传统方法一样,bp send 下断,然后等待游戏断一 次,按 F9 直到游戏正常运行(这里等待断一次主要是为了去掉游戏定时与服务器信息和其它 信息的干扰),然后马上回到游戏,按 0(默认 0 是打坐),游戏被断下,连续按 4 次 ctrl+F9 (通常游戏的前 3 层都是信息函数等东西,所以直接到第 4 层啦),然后按 F8,此时按 alt+k 打开堆栈窗口,如下: 调用堆栈 地址 堆栈 框架
ElementC.2F538 ElementC.
ElementC.00540E82函数例程 / 参数 004542DB 40E87 包 含调用来自 ElementC. ElementC. ElementC.0049959B ElementC.00540ED01、有很多行,不过我们只需要关系第一行就可以了,其它的不用管,记录下 ,如果 已经知道打坐的 call 地址,一看就知道我们已经找到了,不过现在我们架设是第一次找不知 道关键 call 的地址,所以把
记录下来,继续 ctrl+F9,F8 再进入一层,仍然是按 alt+k, 查看堆栈窗口, 仍然只记录第一行得到 ,还是 ctrl+F9,F8,alt+k 再记录一个 0049959B,一般来说游戏的 call 多在 4-6 层中,很少有再深的,而且还有另外的判断方法, 因为单你再使用 ctrl+F9 进入下一层时,出现的 call 就不是单纯的地址了,而是类似 call [xxxx+xxx]这样的形式,那么也就说明走过了,所以记录 3 层就够了。 2、第一步完成了,此时按 F9 让游戏继续,又断下来了,不过这个时候不用急着按 ctrl+f9 进入,直接按一个 alt+k 看看, 调用堆栈 地址 堆栈 框架 035CFEC8 ElementC.5CFECC CFED0 0CCFED4 5CFED8 CFEE8 ElementC.0056DE34函数例程 / 参数 00568A60 Socket = Data = DataSize = Flags = 0056DE37调用来自 WS2_32.send包含ElementC.00568A6017 第一行显示的是 ws2_32.send,原来是发送函数,所以不用再进入了,看一下 CPU 窗口的标 题, 显示的是 CPU-t 线程 0000000xxxx, 记一下那个 xxxx 的数字, 直接按 F9 运行游戏, 又断下来了,此时看一下 CPU 窗口的标题,如果 xxxx 数字一样,说明还是发送函数一类的东 西不用进入(你可以都打开堆栈窗口看看验证下),继续按 f9 运行游戏,如果游戏断下来了 而且不是发送函数一类的就都进入看一下,和上面的一样记录下地址,最后直到不再连续断, 删除断点,回到游戏,人物已经进入打坐状态,一般简单的操作只会有 1 到 2 个需要跟进的 断,而复杂的操作可能多一些,不过如果你从简单的 call 入手,注意观察,复杂操作的 call 还可以通过总结再去除掉很多无关的断。 3、 第三步, 好了只有三个地址, 而且都没有参数, 直接调用测试吧, 运气不错第一个
就是了。呵呵,没有分析汇编代码找到了打坐的 call 顺便找找取消打坐的 call 吧,仍然 bp send,然后等游戏断一次,按 F9 直到游戏正常,然后 进入游戏,用鼠标在其它地方点一下,游戏断了下来,4 次 ctrl+f9 后按 f8,alt+k,直接记 录第一行, 调用堆栈 地址 堆栈 函数例程 / 参数 框架 0F19FD88 00466D4C ElementC.F19FE2C 00455D8E ElementC.F19FE30 0F19FE7C Arg1 = 0F19FE38
包 含 ElementC. 有了经验就不再继续了,直接测试 ,果然就是取消打坐。调用来自 ElementC. ElementC.ElementC.00455D8E顺便说一下,注意上面的 0F19FE2C 00455D8E ElementC. ElementC.F19FE30 0F19FE7C Arg1 = 这两行,如果是有参数的 call,就是这样的形态,这里也就是 call
含有一个参数。 普通攻击 call 的找法,和上面的类似,先选择一个怪,然后切换到 OD,bp send,等游戏断一 次,按 F9 直到恢复,然后按数字 1(普通攻击默认在 1),游戏断下,然后同样的方法,你 可以找到 调用堆栈 地址 堆栈 框架 0F19FDCC ElementC.F19FDEC函数例程 / 参数 75B8E调用来自 ElementC.0059DC30 ElementC.00475CE018 ElementC.F19FDF0 10B2A500 0F19FE20 ElementC. 0F19FE98 ElementC.0043A56FArg1 = 004639EC 包 包含 含ElementC.00475B8E ElementC.004639EC还是在第一行看到了吗?0059DC30,直接就找到了普通攻击的 call。带参数的 call 的找法, 和普通攻击的相似,无非就是记录下来的地址可能会多一些,需要测试的也多一些,不过如 果你能够对找出来的地址处的汇编代码进行简单的分析,那么也就还可以再排除大部分地址, 减少测试量。 这就是利用堆栈进行关键 call 的另类找法。本来打算弄点图上去的,不过因为我很懒,也就 算了,大家多动手测试下,相信很快就能够掌握一些东西,然后我们多交流共同提高。 比如找怪的 CALL,BP SEND,等游戏断了一下,然后 F9 恢复运行,切换到游戏,用鼠标点任何一 个怪,OD 断下来然后按照上面的方法,马上就可以在堆栈中找到. ElementC. 在第一行,而且这行的下面就在堆栈中显示这个 call 的参数,类似 Arg1= Arg2= 眼睛尖的马上就会发现,其中的一个参数不就是怪的 ID 嘛,另外一个就是相关的偏移,马上就 可以确定这个就是 call 了. 拣物品和使用物品等也是类似的,全都是在第一行出现,其实原理很简单,因为是在堆栈里面, 必须满足堆栈的处理原则,所以么先入后出,后入先出,呵呵.如果是一个新游戏可能一开始会 觉得不太好弄,不过因为大多数程序员都有共同的毛病就是只要功能类似肯定就会选择对某 一类动作调用共同的函数进行操作,只是传入的参数不同,所以看多了,很快就可以对那个才 识我们需要的真正的 call 地址作出判断,有时候还有额外的收获,比如说查找使用技能的 call.由于距离怪还有一定的距离.所以要先移动.然后才打.于是会断下很多,其中大部分是 w32_send,这个直接判断标题栏就剔除了.而剩下的断中,就包含移动.和使用技能的.注意观 察堆栈中调用的参数,只用看第一个调用,很意外的还顺便把移动的 call 找到了。2.4 找CALL写CALL教程首先我们要知道一点,为什么要找 CALL。CALL 是什么?大家知道易里的子程序吧如何调用子 程序的?这里的 CALL 就是调用子程序的意思,那问了为什么要找他的,答案是:当你些个游 戏的外挂用模拟键盘操作的时候,被操作的永远是当前窗口,当窗口切换的时候,你的外挂 就不起作用了, calL 可以解决这点 还有一个是什么暂时我没兴趣不去研究它现在只研究 CALL (萝卜加上)首先说明,这个教程以一个找 CALL 的练习程序为例子。之所以不拿游戏,因为游戏找 CALL 时间长了,不适合做教程,而且本练习涵盖参数。我将说明为什么这么调用,为什么这么写! 好的。偶们好的,偶们这节课需要用到的程序为【wygailf】制作的一个找 CALL 测试程序。 首先感谢他!19 这个就是我们用到的程序,OK,打开他并且用 OD 附加进程!并使其进入“运行”状态 好的,下面我没开始找 CALL,首先说明一下,CTRL+F9这个是“运行到返回”。为什么要按这 个按钮?----就我的理解,假设把程序比做很多层的一个盒子,而 CALL 就是我们要从盒子里 拿出来的东西。 那么,如果我们想拿出来 CALL,怎么办?当然是打开盒子,取出盒子,再打开盒子,取出盒 子.....而这个 CTRL+F9就是这个打开盒子到取出盒子的过程。运行到返回,顾名思义,就是 运行到 RET(返回)截止。 而这个 RET 也正是跳出本层的一个关键点。每一个 RET 都有可能是一层。所以这样也就解释 了为什么有的时候按三下 CTRL+F9和四下 CTRL+F9的原因了。 好,说的就这些。下面 LET'S GO! 我们首先下断点 bp send。20 然后回车。如果不确定自己是否成功的下了断点。可以在 OD 中按 ALT+B 来查看好的,这个就是我们下的断点了。始终就是断点有效,也可以暂停断点。选择一个断点,敲 空格。这个断点就变成了“禁用”。这样就算暂停了断点。OK 这里不再赘述,我们开始。=首先,我们来个 HP 药水试试!在这里选择吃药。然后 OD 会断下!这里是程序断下的地方,我们可以看到下方有如下注释:SEND 来自.....说明这里是 send 函数被断开的地方。 继续,CTRL+F9我每一步都会记录下来,一点一点给新手解释为什么!21 上图是我按下第一次 CTRL+F9之后转到的 RET。 这里再顺便说一句。 看到这里的 RET 10了没有。 这里是 RET 10就是有4个参数的 RET,一个参数占4个字节。那么按照这么说来应该是 RET 16 才对啊。其实 这里的10是16进制的10,那么16=第二次 CTRL+F9,这里的 CALL 还是差不多,还在系统层内。我们继续!22 OK,以上是第三次按 CTRL+F9所看到的信息。 看到这里了吗,已经是程序层了。也就说这里很有可能就是我们需要的 CALL 了。OK。我们来 测试一下好的,我们来看这一段lewei2000提醒:以下几点解释有误,初学者略过,楼主还需深化汇编知识 看第一行:mov dword ptr fs:[eax],edx -------这里的意思是:将指针赋值到 dword,后面 有 FS 就是注释[eax],edx 其实就是将 edx 中的值复制到 eax 中,使 eax 和 edx 相等(由于版 主的指正, 这里要声明, 此处的理解为自己的理解。 并不是正规的解释方法, 仅供参考而已) 。 看第二行:push 入栈,入栈就是把一个数值放到寄存器中,其实跟 mov 是一样的,那么这里 push 到哪里了呢?因为第一行 eax 已经被占用,那么这里就应该是 ebx。也就说这里是赋值 EBX。 看第三行:lea eax,pword ptr ss:[edp-4]。这里 LEA 指令指将操作结果保存到 eax,好既然 是 eax 我们就不管他了。至于是什么结果,我们一会看。 看第四行:CALL 不解释。就是我们需要的东西。(但其实不是) 看第五行:ret 返回的意思。 好的,假设这段代码是我们需要的代码,那我们该怎么去表达它,在程序中如何去写? 这里留个悬念, 因为我事先测试过, 这里不是我们需要的 CALL, 我就不说了。 等找到正确 CALL 的时候我再讲解如何去写 CALL。23 好继续 CTRL+F9下图看这里,跟上面一样,这个返回没用,我们继续 CTRL+F9。好,这里又出现了一个 CALL,那我们想想是不是这个呢?如何去调用这个 CALL? 首先,我们要测试一下它是不是一个带参数的 CALL,至于怎么测试呢?---靠,那就用程序 CALL 一下呗!但这里的 CALL 是个有参数的 CALL。我们继续。 我们如何知道这个 CALL 调用了什么参数?试想一下, CALL 调用参数, 要在哪里看?当然是在 CALL 中看了,如何看?那就让我们去 CALL 那里了,如何去?--断点~!(周杰伦唱的) 好,在上面 CALL 那里下断点~选择 CALL,按 F2这里前面的地址变成了红色的。 这样就算断点成功了, 这里断了前面就不用断了, 我们在 ALT+B 中删除以前的 SEND 断点。(Delete 键删除) OK,我们让程序恢复到运行状态!24 好,我们看到,测试程序中显示,使用了一个补血药品。OK,我们继续按“吃血”!好的,看到断点了没有,正好断在我们刚才下断点的地方。说明不管这个 CALL 正确与否,我 们吃血的过程都要调用这个 CALL,这样就离正确很接近了。 我们刚才说看 CALL 的参数,CALL 的参数其实就是在调用 CALL 的时候所需要的运行环境,在 什么条件下,CALL 执行之后是吃血,什么情况下是吃蓝。 好的。我们现在利用到了寄存器。看寄存器中的提示,有两个红色,说明当我们调用 CALL 的 时候,它使用了寄存器中的两个地址。那么这个就是 CALL 的 运行环境了,也就是说,只要在我们调用这个 CALL 的时候,寄存器 EAX 中有值00D51FE4和寄 存器 ECX 中有值0042ABE4就可以运行。这里还有一个特殊 情况,这里我先卖个关子。 这里也解释了上面的那个不是我们用到的那个 CALL 如何看参数! 好,这里我们写一个小程序来调用 CALL。 = 好,不管是不是这个 CALL,我们先来测试一下我是用 delphi 的,所以这里讲解 delphi-----这里我还要多一嘴,其实语言只是工具,只要 学会了道理,就不在乎语言的问题了,其实在我们这个阶段,语言的区分仅仅是命令不同而 已25 我会把如何写的理论告诉给大家。让大家知道------花儿为什么这样红!o(∩_∩)o...哈哈首先,我们要调用一个程序的 CALL,需要干什么。当然是指定这个程序啦!如何指定?如果 这里您不知道,建议您去句柄那里好好修炼一下。 Hwnd:=这里的 Hwnd 是个变量,为窗口句柄。FindWindow 是一个找窗口句柄的命令,这里有 两个参数,我用1和2代替。其中1在命令中应该是窗口类名。 2在这里应该是窗口标题。 GetWindowThreadProcessID(1,2)=这里的 GetWindowThreadProcessID()也是个命令,是找 窗口线程 ID 的一个命令,有两个参数。1代表窗口句柄,2代表赋值变量,这个变量就是我们 要把线程 ID 赋值给什么变量, 可以这么写 GetWindowThreadProcessID(Hwnd,@ThreadID); OpenProcess(1,2,3)=这个命令是打开进程并返回进程 ID,有三个参数,分别为参数类型,句 柄继承符,和线程 ID.可以写为 Pid:= Process_all_access 就是打 开进程的格式,我们这里使用全部格式就可以了。无需理解,这么写就好。 这里写好了,我们可以检测一下是否成功。26 这里就是找线程 ID 了!下面写注入 过程注入函数 function TForm1.InsterGameFun(Hid:FunName:pointer): var {要注入线程的窗口句柄和临时存放的句柄} TmpHandle: TH ThreadID: T ThreadAdd: WriteCount: DWORD; begin ThreadAdd :=在目标进程建立内存空间27 WriteProcessMemory(Hid, ThreadAdd,FunName, 128, WriteCount);//将要注入的过程写 到上面建立的内存空间中 TmpHandle :=获得注入后过程的句柄 ID result:=返回句柄 ID 这里照抄也可以,反正就是这么写的,每步怎么个意思我也标示了。 注入也写了,窗口也获取了,剩下的就是写 CALL 了。好的!我们看这个图片记得我刚才说的 EAX(00D51FE4)和 ECX(0042ABE4)了吗?按照这里来说。只要我们写命令 pushed asm mov eax,$005D1FE4 mov ecx,$0042ABE4 call $00452E98 popad 一般这样的命令就可以了。但是我们这么写的时候却没有生效。那么一定是哪里出错了。我们对比两个图28 我们对比两个图的寄存器中的值。 我们发现 EDX 中,值在返回之后度没有变化。也就是说这里 EDX 也有可能是环境因素之一。 而 ECX 前后却有变化,那 ECX 是不是环境呢? 我们做如下测试。 procedure HP; var Address: begin Address:= asm pushad mov eax,$00D51FE4 mov ecx,$0042ABE4 mov edx,$ call A 我们这么写,测试一下,成功!那么去掉 ECX 呢?也成功! 这里就是 EDX 和 EAX 是真正的参数了。 = 好的,我这已经讲解的超级详细了,如果还有人不明白,那我真吐血了! 以此类推就可以写出蓝,回城的 CALL,呵呵,如果写不出来。那你看来还要重新看我的文章。 = 提问与解答 = Quote:29//吃红 引用第4楼 wshichenyao2于 12:06发表的 : 我们发现 EDX 中,值在返回之后度没有变化。也就是说这里 EDX 也有可能是环境因素之一。 而 ECX 前后却有变化,那 ECX 是不是环境呢? 这句不太明白啊,,call 之前究竟是给变化的寄存器赋值还是给不变的寄存器赋值啊?我被 你搞混了噢。。。 呵呵 谢谢 lz 这么好的文章,希望能解答下我的问题。。。 回答:这里的 ECX 不是环境之一,这个不一定就要一定不变才是因素,具体问题要具体分析, 如果你想知道到底这个寄存器中的值在 call 后是否变化了, 可以进入这个 call 看看这个 call 的具体运算方法。Quote: 引用第10楼 ffzzfcll 于 15:06发表的 : 但是我们这么写的时候却没有生效。那么一定是哪里出错了。我们对比两个图 ....... 回答:这里的两幅图不是没有添加,因为跟前面的图一样,所以附件并没有显示出来,这里 的两幅图中对对比仅仅为了证明 ECX 的值前后不等~其实没有别的却别。并不影响学习。Quote: 引用第22楼 leonta 于 21:50发表的 LZ 断点 你简直无敌了 是张敬轩 当然有点还是要给你提出来 唱的 不是周杰伦 周杰伦 唱的是 我一定给你顶起 断了的弦 最后希望 楼主多写这么好的教程 : 我一直都没看到过对新人来说如此好的教程回答:感谢您的指正,我对明星不怎么感冒,感觉上貌似是周董的歌,呵呵,弄差了!Quote: 引用第24楼 flycat 于 02:59发表的 通过这么详细的解说,终于 CALL 成功了!!! -------用 VB 写 回城与使用冰系 CALL 的代码 Sub HOME() '回城 Dim asm As New clsASM30: ....... 回答:谢谢您的分享!您的支持是我前进的动力!Quote: 引用第32楼黑爵士于 16:50发表的 : 以自己的方式来理解定义汇编语句?会误导不少人的。 不过思路上具有一定参考价值,文章风格很生动哦,楼主辛苦了,可申精就是不可能的啦:-) 回答:~~55!版主啊版主,我发帖可不容易呢,一个上午的努力还换不来一个精 华,真是对我积极性的打击呢 o(∩_∩)o...不过您指正的错误我虚心接受!!!学无先后达 者尊!Quote: 引用第40楼 nasuer 于 14:59发表的 : 建立 remoteThread 跟你的 procedure 吃红有什么关系呢? 回答:这里的 remoteThread 应该是很多大大们称之为&远程注入&的命令.只有注入了,才能对 所注入程序中的汇编进行操作~(个人意见而已)Quote: 引用第41楼 lccyy 于 11:50发表的 : 楼主 非常感谢你的指点!我这里帮你更正一下! 断在 call 前时 EAX 中的值应该是这样: call 是连续按5次 Ctrl+F9 EAX 00D51FEC ECX 0042ABE4 游戏找 CA.0042ABE4 .......回答:这位朋友的信息贴出来以后我发现和我的差距着实非常的大,不仅很多寄存器中的值不 相同,甚至连 CALL 都不一样.不知道您给我的指正您测试了没有?我这可是亲自测试的.并且有 源代码等等.如果您并没有做相关的测试就来指正的话,恐怕难以服众啊~!不过也谢谢您的指 正,人无完人嘛,我帖子里的错误也会很多的,希望各位大人多多指正!31 Quote: 引用第56楼 lewei-04-29 22:09发表的 : 提醒过楼主错误的地方,但是依然没纠正,为免误导初学者,先取消精华. 错误处看32楼指出的,及另外几处汇编基础性的错误. 回答:谢谢版主您的指正,我的偏离的方向正需要您无私的拨正!Quote: 引用第58楼 liujiangshu 于 00:03发表的 : 胡说八道回答:这位兄弟~有错误我绝对虚心接受,我本身也是菜鸟,不是什么权威,错误是一定有的.但 是您的这个评论未免有点武断!Quote: 引用第60楼 hzyhaa 于 09:16发表的 拿来开刀的那个程序,在那可以下到啊 :回答:针对于这个朋友的提问,我将附加上程序,以及 delphi 源代码!最后我来提问:我看到过这个同样有这个教程的 E 语言的源代码,E 语言的源代码中 mov eax 并我和我的格式一样,我的是直接传递值,而那位大师的则是 mov eax,eax.....类似这样的格 式.我想知道的是这些都是怎么来的?希望各位能多多指点!2.5 50 走路CALL的找法'ce 找到鼠标点击的坐标 0047188A . 894E 28 mov dword ptr [esi+28], ecx32 1、随机找到 2 点的坐标,如图,药师这里的 Y 坐标是 137 左右;红点那里的坐标是 110 左右 2、打开 CE,搜索浮点数,选择在数值―和----之间,输入 100~~120 '3、点击红点处,人物跑起来,马上切换到 CE,搜索 4、跑到红点后,再回来点击药师,数值输入 120~~~140 之间搜索 来回几次找到 0985AF50 这个地址,染后看水修该了这个地址可以看到,是这里 0047188A . 894E 28 mov dword ptr [esi+28], ecxOD 加载后,我们在这里 F2 下断:33 '0047188A '0047188D ' ' ' ' '0047189C '0047189F ' ' ' '.894E 28mov mov mov mov mov mov mov pop mov pop retn 84DB mov push mov mov call test 4dword ptr [esi+28], ecx edx, dword ptr [edi+34] dword ptr [esi+34], edx eax, dword ptr [edi+38] dword ptr [esi+38], eax ecx, dword ptr [edi+3C] dword ptr [esi+3C], ecx edi al, 1 esi;鼠标点 Y 坐标击点下断. 8B57 34 . 8956 34 . 8B47 38 . 8946 38 . 8B4F 3C . 894E 3C . 5F . B0 01 . 5E . C2 0400 |.'CTR+f9 到 0046D67E ' ' ' ' ' '0046D67B '0046D67E ' 'CTR+F9 到
' '0046676E ' ' ' ' '0046677D ' ' ' '0046676B |. |. |. |. |. |. |. |. |. |& \8B4F 30 |. |. |. |. 56testbl, blecx, dword ptr [edi+30] esi ecx, dword ptr [ecx+ebp*4] edx, dword ptr [ecx] dword ptr [edx+20] bl, bl dword ptr [9024E0], 1 ;CALL 的返回点8B0CA9 8B11 FF52 20|. 84DB |.833D E0249000&cmp mov mov mov push push push lea call fld fsub fld fsub fld fmul fld fmul faddp fsqrt fstp fstp st(2) st|& \8B4B 44 8B53 40 51 52 50 8D4C24 24 E8 B3D5F9FF D424 18 D424 20 D9C0 D8C9 D9C2 D8CB DEC1 D9FA DDDA DDD8 |. 8B43 3Cecx, dword ptr [ebx+44] edx, dword ptr [ebx+40] eax, dword ptr [ebx+3C] ecx edx eax ecx, dword ptr [esp+24] 00403D30 dword ptr [esp+50] dword ptr [esp+18] dword ptr [esp+58] dword ptr [esp+20] st st, st(1) st(2) st, st(3) st(1), ST2*ST3 ; st(1) &- st(1) + st(0); ; ; ; 平方根 距离计算: ; ST*ST1 ; ; ; ; 装入浮点到到 ST= ST-(目标坐标)-----ST0 装入浮点到到 ST= ST-(目标坐标)-》-ST0' |.'0046678D |. '0046678F |. ' ' ' ' ' '0046679B |. |. |. |. |. |.然后执行一次出栈操作 SQR[(X-X1)^2+(Y-Y1)^2] 出栈操作 出栈操作34 '0046679D ' ' ' '004667AE ;|. |. |. |.D81D
fcomp DFE0 F6C4 41 fstsw testdword ptr [844998] ax ah, 41 00466BEA ecx, dword ptr [ebx+908] 1
eax, dword ptr fs:[0] -1 0081CAB6 eax eax, dword ptr [esp+10] dword ptr fs:[0], esp esi eax, 11 esi, ecx
dword ptr [eax*4+46D5F8] 30 64 006E7D20 esp, 4 dword ptr [esp+14], eax eax, eax dword ptr [esp+C], 1
esi ecx, eax
ecx, dword ptr [esp+4] dword ptr fs:[0], ecx esi esp, 0C 4 48 push;ST 比较 》 ;[844998]=保存状态字的值到AX&0.5 返回 0 ;与测试 ; 移动距离&1 0F85 3C040000 jnz|. 8B8B
mov 6A 01 E8 156A0000 下面 12 个分支 /$ 64:A1 0000000&mov 6A FF 68 B6CAB 83F8 11 8BF1 push push callebx= ECX =基址]+$24]+$908] |.' |. ' '{F7 跟进 ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '} ' 0046D3BC |.
|. 0046D1DD |. 0046D1DE |.
|. 0046D1EA |. 0046D1ED |. 0046D1EF |.
|. 0046D1FC
|& |&push push mov push cmp mov64:&mov;Switch (cases 0..11)0F87 EF030000 ja FF&jmp 6A 30 6A 64 E8 E5AA 04
85C0; ;Case 0 of switch Case 1 of switch0046D1EA push call add mov test 0046D1EA 走路跳转 |. 0046D23B |. 0046D23E |.
|. 0046D24C |.
|. 0046D25A |. 0046D25E |.
|.C0&mov 0F84
je 56 8BC8 E8 B4C24 04 5E 83C4 0C C2 0400 push mov call mov pop add retn push64:890D 00000&mov|& \6A 48;Case 8 of switch0046D1EA寻路35 ' '004667BB '{ ' ' ' ' ' ' 址 ' ' ' ' ' 址 ' '} ' '004667BF ' ' ' ' ' '004667DB '004667DC '004667DE |. |. |. |. |. |. |. |. 8BF0 33FF 51 57 8BCE E8 04B10000 mov xor push push mov call esi, eax edi, edi ecx edi ecx, esi
edx, dword ptr [esp+90] eax, dword ptr [esp+84] edx eax ecx, esi 00471A00 ecx, dword ptr [ebx+908] 1 edi 1 esi 1
dword ptr [9024E0], 1 mov eax al, 1 ;单 CALL ; /Arg1; Case E0 /Arg2 ; |Arg1 ;| ; \elementc.00471A00 ;ECX =基址]+$24]+$900] ; /Arg2 ; |Arg1 = ;| ; \elementc. ; 保存 46D1D0 的返回值 ' |.
|. 0F84 CB000000 je 66683 |.
|. 0046668B |. 0046668F |.
|. D94424 1C DC24 54 DC24 58 fld fadd fstp fadd fstp dword ptr [esp+1C] dword ptr [esp+60] dword ptr [esp+54] dword ptr [esp+64] dword ptr [esp+58] ; 目标坐标的 Y 的首地 往上翻看看看 esp+50 里是当前 X 坐标 0046666F |.
|. 0046667B |. 0046667F |. D95C24 1C D84C24 4C D424 5C D95C24 50 fstp fmul fld fadd fstp dword ptr [esp+1C] dword ptr [esp+4C] dword ptr [esp+18] dword ptr [esp+5C] dword ptr [esp+50] ; 目标坐标的 X 的首地 |. 8D4C24 50 lea ecx, dword ptr [esp+50] ; 目标坐标的 X 的首地址'004667CC |. '004667DA |.8D&lea 8D&lea 52 50 8BCE push push mov call push push push push push call|. E8 1DB' |. 8B8B
mov ' |. ' '004667EC '004667EF ' ' 'CTR+F9 到 0045549E ' '55417 & \50 push . B0 01|. 57 |. 56 |. |. E8 4C6E0000'004667EA |. 6A 01 '004667ED |. 6A 01833D E0249000&cmp36 ' '0045549E ' ' '. E8 120D0100 . B0 01 . 5E . C2 0400call mov pop retn al, 1 esi 4; \elementc.'var Address1, Address2, Address3: X,Y,Z :S begin Address1 :=函数入口地址 Address2 := Address3 := X := Y := Z := asm pushad mov eax, dword ptr [$0012F82C] mov ebx, dword ptr [eax+$24] mov ecx, dword ptr [ebx+$908] //ebx 为人物首地址,+8CC 做为第一个函数的指针参数 push 1 //压入 1 call Address1 //调用函数 lea ecx, dword ptr [esp+$50] //得到存放目标坐标的 X 的首地址 mov esi, eax //保存上一个函数的返回值 push ecx //X 坐标的首地址 push 0 //0 mov ecx, esi //上一个函数的返回值 call Address2 mov ecx, dword ptr [ebx+$908] push 0 //这里面是 0 ,push edi push 1 push esi //第一个函数返回值 push 1 call Address3 //到这里人物可以跑起来了,下面是修改跑路目的地坐标 mov eax, dword ptr [$0012F82C] mov eax, dword ptr [eax+$24] mov eax, dword ptr [eax+$908] //ebx 为人物首地址,+8CC 做为第一个函数的指针参数 mov eax, dword ptr [eax+$30] mov ecx, dword ptr [eax+4] mov eax, x mov [ecx+$20], eax mov eax, y mov [ecx+$28],Sub Call_RunTO(dx As Single, dy As Single) Dim asm As New clsASM '自动寻路 37 With asm .Pushad .Mov_EAX_DWORD_Ptr &H12F82C .Mov_EBX_DWORD_Ptr_EAX_Add &H24 .Mov_ECX_DWORD_Ptr_EBX_Add &H908 .Push 1 .Mov_EAX &H46D1D0 .Call_EAX .Lea_ECX_DWORD_Ptr_ESP_Add &H50 .Mov_ESI_EAX .Push_ECX .Push 0 .Mov_ECX_ESI .Mov_EAX &H4718D0 .Call_EAX .Mov_ECX_DWORD_Ptr_EBX_Add &H908 .Push 0 .Push 1 .Push_ESI .Push 1 .Mov_EAX &H46D640 .Call_EAX .Mov_EAX_DWORD_Ptr &H12F82C .Mov_EAX_DWORD_Ptr_EAX_Add &H24 .Mov_EAX_DWORD_Ptr_EAX_Add &H908 .Mov_EAX_DWORD_Ptr_EAX_Add &H30 .Mov_ECX_DWORD_Ptr_EAX_Add &H4 //=这里不对还没写,类里没,还要自己加。。郁闷 .Mov_EAX Float2Int(dx) ‘.Mov_EBX_EAX .Mov_EAX Float2Int(dy) ‘.Mov_DWORD_Ptr_EAX &H28 //= .Popad .Ret End With END SUB ' mov eax, y ' mov eax, x2.6 50 快手键CAll分析 |. FF52 08 call dword ptr [edx+8] 0054654A |& 5F pop edi 上面一句就是我们要找的快捷键 CALL,; 如下图38 图1 前 6 次中间分析过程略过。。。。我们直接分析快捷键 CALL 各参数的由来 1、由 得知,我们要找 EAX 的来源;往上看,EAX 是由 传递来的;下断后 F7 跟进:图2 上面可以看到,EAX= 也就是说:公式 1:EAX= 接下来我们首先跟 ECX 里是什么了,分析好了再分析 EAX,CTR+F9 返回程序调用 可以看到:ECX=39 跟 EAX,可以看到 EAX 由下面跳上来的图3 很明显 EAX=,既 ECX= 由上面的分析可以知道: EAX= 代入公式 1:EAX= 这里又分支了,暂时放开[EBX+EAX*4+8F8]里的 EAX,我们先找 EBX 的来历,顺着 OD 的跳转红 线一路找上去;很快就到了图4 EBX= ECX=] EAX= 到这里我们的一个分支已经有了,先整理一下:我们快捷键 CALL 的第一个参数 EAX 的数值= *[[[901C3C]+1C]+24]+EAX*4+8F8]+C]+EAX*4] 这样一个地址值40 2、找上面 2 个 EAX 的由来: 首先看第一个 EAX,回到图 2,按 F1 断下后观察 EAX 的值是调用堆栈中是值观察堆栈 ESP+4 的值=图5 可以看到 而 ESI= H70 很明显可以想象到是 F1 的 ASC 码,由此可见 F1~F8 对应栈中的 0~7 再一次带入上面的公式: EAX=(0~7)*4] 公式 23、找最后一个 EAX: 由图 5 可以看到:EAX 是由 CALL 503BD0 返回的,在此下断,F1 断住后 F7 进入:常数,可以看到 EAX= OK:代入公式 2:EAX=(0~7)*4] 附件:VB 调用 123 版本测试41 2.7 找预言明文发包CALL根据 China 著作权第二章第二节第十二条、第四节第二十二条第九点,特此声明: 分析此文件,仅属于用户阅读其合法拥有的文件,并与其他拥有者分享阅读经验,其版权属 于发行者。 ------------------------------------------------------------------------------注:本文涉及的数值,因版本不同,实际值肯定是会不同的,只介绍方法,本文针对一些对 逆向一知半解的读者,大牛请绕行。 废话不多,OD 附加游戏进程,或直接打开(直接打开会出现异常,忽略即可)。42 BP SEND,CTRL+F9一次,已回到游戏主程序。再 CTRL+F9,到 CALL 005CA2E0(此值只限1.23 版,记得是两次 CTRL+F9就可以了),在005CA2E0下断,发现一直会断下,回车进去看看,会 看到一句 CMP DWORD PTR DS:[EAX+12010],0 应该是判断是否发包的,因为没有包的情况下,就直接跳到下面去了。 接下来一层一层分析 EAX 来源(只列出修改关键值的语句): 005CB6B9 MOV DWORD PTR SS:[EBP-4],ECX 005CB6BC MOV EAX,DWORD PTR SS:[EBP-4] 005CB6BF CMP DWORD PTR DS:[EAX+12010],0 //EBP-4来自 ECX //EAX 来自[EBP-4]回到上层 005C8B7C MOV EAX,DWORD PTR SS:[EBP-14] 005C8B7F MOV ECX,DWORD PTR DS:[EAX+10]//EAX 来自 EBP-14 //ECX 来自 EAX+10看看函数开头处 MOV DWORD PTR SS:[EBP-14],ECX 再上一层,看 ECX= MOV ECX,00823D08 OK,在内存区域找到[823D08+10]+12010的值,下断:哪个在写它 断下后,CTRL+F9三次,你会看到一个类似:
LEA ECX,DWORD PTR SS:[EBP-424]
CALL Aclient.005C7CA0 这里的 ECX 就是明文包,在他上面一个 CALL,进去看看,呵呵,有经验的都看的出来是构造 包了吧。 下面是对激活 NPC 明文结构的分析:
8F 7C 00 10 00 EF 07 D4 08 00 00 00 00 00 00 //激活 NPC 武师
64 8F 7C 00 10 00 EF 07 5F 07 00 00 00 00 00 00 //激活 NPC 管理员
8F 7C 00 10 00 EF 07 5F 07 00 00 00 00 00 00 重开游戏 管理员
8F 7C 00 10 00 EF 07 9A 24 00 00 00 00 00 00 //激活 NPC 西门广 ------执行命令? - 定值10、7EF,2字节-NPC 编号?----写段代码测试下,此代码可成功激活竞技场管理员,由于该文件公司 BOSS 很反对此类阅读, 所以分析就此结束,谢谢观赏。 procedure TForm1.Button1Click(Sender: TObject); var prOpenNPC:TCallP begin prOpenNPC.head :=43 prOpenNPC.wd1 := prOpenNPC.wd2 := prOpenNPC.ID := prOpenNPC.wd3 := prOpenNPC.wd4 := prOpenNPC.wd5 := InjectFunc(GameHwnd,@fabao,@prOpenNPC,sizeof(prOpenNPC)); procedure fabao(P:PCallParam); Type TParam = tou : D un1,un2 : W //$10,$7EF NPCID,un3 : D un4,un5 : W PParam = var Address: P aa : TP len : baoaddr : PP begin aa.tou := aa.un1 := aa.un2 := aa.NPCID := aa.un3 := aa.un4 := aa.un5 := baoAddr := Address :=发包 CALL 地址 asm pushad mov ecx,baoaddr ca44 2.8 查看发包数据游戏的每一个动作都会向服务器端发送数据。截获发包数据可以知道每个动作都 向服务器发送什么数据。 用 OD 附加游戏 输入命令 bp Send 例如。 先扔地下件物品。然后输入命令 bp Send 。这时用鼠标去捡物品。OD 会中断。按 三次 Ctrl+F9,F8 就会回到游戏捡物的发包函数。 005A7C8A 005A7C8C 005A7C8D 005A7C90 6A 0A 56 8B4A 20 E8 BBA2FDFF PUSH 0A PUSH ESI MOV ECX,DWORD PTR DS:[EDX+20] CALL elementc.00581F500A 是包的字节大小。16进制的0A 转十进制就是10 ESI 中的值就是发包数据。 这时可以跳到 ESI 数据窗口跟随。 大小为10. 0E25BD48 06 00 79 3E 02 C0 37 09 00 00 BC 0B 0A 00 00 00 .y&?...?....从左查10个字节就是06 00 79 3E 02 C0 37 09 00 00这就是检物的发包数据。如果需要找走路。打怪等的发包数据。可以在00581f50下跟进此 CAll 中下断点 0889FDA8 0889FDAC 0889FDB0 005A7C95 0E25BD48 0000000A 返回到 elementc.005A7C95 来自 elementc.00581F50上是堆栈窗口 0889FDB0右面的0000000A 就是发包的大小 0889FDAC 处是存储包发内容的地址0889FDB0这样所有的动作只要在发包函数里下断点。看堆栈就行了。 不用在每个动作的汇 编语句上下断了。45 2.9 找加密算法的方法继上次我发的那篇文章《......找 CALL 原理》之后,里面要最重要的是确定游戏加密算法, 可有的朋友不知道怎么去找它。并且,想写出真正功能完善的外挂,不了解游戏的数据结构 和协议,是不可能实现的,即使你用超强的算法利用找到的 CALL 去实现一个外挂,那意味着 你的更新工作会很大。 而游戏的加解密算法一般是很少会去改动的,所以,外挂,使用封包去实现,意义很多。 另外,想写脱机的你,不通过封包,是写不成的(有些功能可以调用游戏 DLL 里的东西)。 好了,我来说说找算法的原理和方法吧。 首先,我们还是要了解游戏是怎么来操作数据的: 最基本的大家应该知道,就是:客户端生成明文包-->调用加密函数加密->交给 SEND 函数去发给服务器。而复杂的话可能就是:客户端生成明文包-->调用加密函数一加密->交调用加密函数二加密->给 SEND 函数 去发给服务器。再复杂的可能是:游戏启动是接服务器发来一个密钥-->客户端生成明文包-->调用加密函数一(利用 密钥)加密-->调用加密函数二->给 SEND 函数去发给服务器。基本上就是那样,当然更复杂和变态的可能还有:服务器发来密钥后,客户端对密钥进行 一次加密,然后才可以用,不管怎么说这要看游戏编写者想怎么来保护数据了。 不过,最其码你知道了这些方法,那就你就有个思路去跟踪了。 另外,大家要了解的就是,发包和接包函数: 有的游戏是用 SEND、RECV,有的是用 WSASEND、WSARRECV,也可能混用,这你可要找对了。 (小方法:可以用 WPE 拦截看一下,包括游戏启动时。) 上 MSDN 查看资料后,我们了解到: SEND 有个参数 BUF,它是用来存将要发送数据的缓冲区。 RECV 也有这么个参数,它是用来接收的缓冲区。 WSASEND 有个参数是 lpBuffers,它是一个指向 WSABUF 结构数组的指针。记住,是指针!46 WSARECV 也一样。 然后,进入游戏,开 OD,我这里就先不找例子了,光给大家说说原理和方法,这是我发这 个主题的原因(你会了方法,哪个游戏都一样,正所谓那个什么什么鱼,不如什么什么渔来 着,忘了!) 以下是跟踪数据的方法(就是看数据 SEND.BUF 中的数据是从哪里来的,其中 SEND 的断不 要取消,同时要多看数据区的数据变化): 1、开 OD,下断:BP SEND,游戏里说句话。断下后,在 OD 的数据区里看一下 BUF 里的东西 和 BUF 的地址。 2、然后,给 BUF 下硬件写入 WORD 断点。F9运行一下。再说一句话,这时就能断下是谁给 这个 BUF 写了数据。 3、你可能看到是:REP MOVS [EDI],[ESI],对了,这里 ESI 就是数据的来源,而 EDI 就是 数据要存放的地方,也就是它的下一级 SEND.BUF。 4、这时注意数据区 EDI 的数据。取消硬件断点,F9一下会断到 SEND,看一下 EDI 也就是这 时指向的 SEND.BUF 中的数据是否有变化,如果有,那么调用这个 REP MOVS 指令的 CALL 就是 加密 CALL。 5、如过没有,再对 ESI 指向的空间下硬件写入 WORD 断,运行游戏,再说一句话。断下另 一个地方的 REP MOVS,然后和第4步一样,注意数据区的数据变化。 整个过程就是4-5步这样的。你也可以一次就追下所有的 REP MOVS,原理都一样! 提示:整个过程都要注意看数据区的数据变化。 而对于 WSASEND, 它的参数是一个指向 WSABUF 结构数组的指针。 大家上 MSDN 看一下它的参 数。和找 SEND 的方法一样。 另外大多数游戏的加密和解密都是用的都是同一个,而跟踪的方法都一样,不同的是一个 是往回找,所以叫逆向,一个是往下找。找到任意一个就行了。 自我感觉跟接包的方法要方便一些,因为它接包后才要调用解密,这样往下找感觉要比往 上找好,呵呵,再提示一下,要是跟 RECV,断下 RECV 后一定要注意先 F8一下,要让这条指 令执行了,它的 BUF 中的数据才是服务器发来的数据。 好了,这次就说这么多吧,也不知道说清楚了没有,高手看了不要笑,如果我说的有不对 的地方,请指证,我怕误人子弟,呵!2.10 分析封包我是用 OD 直接解密的,不提倡用 wpe 看,看的累,而且看半天看不出来东西。 首先是确保游戏运行文件没有加壳。再看看启动后的游戏进程名是否跟你运行的 exe 名一样, 如果不一样那么我们先来看他是如何启动的游戏进程,用 od 取你运行的 exe 文件,然后在命 令里面输入 bp CreateWindowW 和 bp CreateWindowExW,然后按 F9运行,点你连接的服务器, 这时会中断下来,然后看他启动的文件和参数,先在启动文件创建个快捷方式,然后把参数47 填到快捷方式里,以后直接运行这个快捷方式即可。 用 od 取实际的游戏执行文件,然后在命令行输入 bp send,bp recv,bp WSASend, bp WSARecv 四个命令,再点 od 的调试-》参数,把刚才记录的参数写进去。按 CTRL+F2重新取。按 F9运 行。随便输入个帐号和密码点进入,这时会中断到 send 或者 WSASend,按 CTRL+F9即可回到 游戏领域,然后像上看,加密可能就在这上面。首先我们来判断这个函数的开始,如何判断 函数入口那,就是看 PUSH 语句,od 一般把一个函数用蓝线扩起来了,比较容易分清。看函数 入口到调用 send 或 WSASend 前面有没有 call 语句,如果有我们需要跟进去,如果发现离函 数入口很近而且没有 call 语句那直接按 CTRL+F9再回上一个领域,照这样的方法就可以找到 加密算法了。其实很简单。 接下来是 recv 和 WSARecv,首先讲 recv,中断这里后我们在堆栈窗口右键点 buffer,然后选 内存中显示。再按 CTRL+F9,发现内存中有了接收的数据,然后在内存的第一个字节右键点读 硬件中断,继续按 F9运行吧,很快会中断到读取内存的地方,很简单这里有可能就是加密的 地方,如果看不出来那么在内存第5个字节同样做读硬件内存中断,很快就能找到解密地方。 WSARecv 的 buffer 不一样,他是个缓存指针,如果中断到这里我们一样在堆栈窗口右键点 buffer, 然后选内存中显示。 这是个结构, 前4个是 buffer 大小, 后面的才是数据, 按 CTRL+F9, 发现接收数据,我们直接在第5个地方下读硬件中断,以后就跟 recv 一样了。呵呵一切都不 难,只要会汇编就 ok。 6 找写屏函数的方法 我用 si 来分析的,因为 od 我不知道怎么搜索内存。。。 在游戏的交谈栏里写一句话,先不要发送,然后用 si 的 s 命令搜索你要发的这句话比如话是 ‘我要搜索的内存’,s ds: l ffffffff '我要搜索的内存',有可能会找到多个地 址,这个跟 fpe 的搜索差不多,一个一个修改试试,用“d 地址”命令可以查看找到的地址, 然后光标移动到内存页面上面就可以修改了。找到正确的后就要下内存断点了,&bpm 地址 r& 命令就可以了,返回游戏把话发出去,这时就会中断到读这段内存的语句了,一般是 lea 汇 编指令,意思是把这个内存地址副给积存器,然后 PUSH,然后就是 call 了,至于如何分析 call 有几个参数可以看 win32asm 教程。 有时候也可能复杂点, 就是游戏把这个内存拷贝到另 一个内存然后再输出,这样就是多了一个步骤而已,只要在拷贝到另一个内存的地址下个内 存中断即可。找到函数如何利用哪?在你的 hook dll 中可以直接调用这个函数,例如这个写 屏函数有2个参数,1个是 buf,第2个是 buf 的长度,汇编语句是 mov ebx, ds[????] push ebx lea eax,ds[????] push eax call ?????? //用 vc 写个函数,不用怀疑就是那么简单 __declspec(naked) Out(char* buf,int len) { mov ebx, len push ebx lea eax,buf push eax call ?????? } 一般我都做利用 recv 或 WSARecv 函数返回失败后做这些功能。48 DefHookApi(recv,int,(SOCKET s,char *buf,int len,int flags)) { int ret= if(ret&1&&strcmp(outbuf,&&)) { Out(outbuf,strlen(outbuf)); ZeroMemory( outbuf, sizeof(outbuf) ); //记得清空不然会一直发送 } } 这样就 ok 了。3. 诛仙找基址3.1 【KJ】诛仙游戏找地址集合(一)1. 找人物血量,最大血量,蓝量,最大蓝量这里我们的血=699(2BB) 蓝= (首先强调人物的血,蓝,那些基础信息,在客服端应该有一个循环在不停的扫描) 首先我们用 OD,载入游戏。进到游戏画面。然后打开 CE。搜索,当前的血值(非最大),比 如,我们现在的血值是:699 对应的 16 进制应该是:2BB. 好我们用 CE 搜索这个 699,第 一次搜索,可能会有上千条该值。然后,我们打一个小怪让血值减少,之后,我们又根据“数 值改变了”进行第二次搜索。结果可能会剩下 200 多个。然后继续循环搜索“数值改变了”, 到最后,就会只剩下一条记录。改记录就是我们当前的血地址。记录该地址,我们到 OD 里面去下“内存写入断点”,当我们一下断,就会立刻断在(如图) 的地址处:49 (图一) 到这里之后,觉得很奇怪。怎么这么多数据。看着很顺眼。 00459D9F |. 898E
mov dword ptr [esi+254], ecx 这里的 ecx 的值,我们看寄存器窗口(如图)刚好 ECX = 00459DA8 |. 0 mov dword ptr [esi+258], edx 执行到这行,我们看寄存器的 edx 的值这里的 EDX 等于 180,刚好等于我们的蓝量,所以,我们可以肯定蓝的偏移是:258 这样。我们就找到我们的血和蓝的偏移。继续找最大值血和最大值蓝。我们进游戏把角色人 物的血值减少之后到达这行: 00459DBA |. 898E 6C020000 mov dword ptr [esi+26C], ecx 我们在寄存器里看到 ECX 的值还是 2BB, 但是我们人物角色的血已经改变不是这个值了。 所以。 我们能判断这个 ECX 的值,就是我们的最大血量。当然 26c 就是我们的偏移地址。 同理,我们一样能找出最大蓝量的偏移地址。 00459DC3 |. 0 mov dword ptr [esi+270], edx OK。到这里我们的血蓝的偏移地址,就找到了。50 2. 找人物经验,等级这里找这些数据,其实,我们在上一步,就已经看到了。 好。哪我们对(图一)最开始的那行数据进行下断 00459D84 |. 898E 4C020000 mov dword ptr [esi+24C], 下断之后,发现,没有任何反映。那我们回到游戏里面去打个怪。发现立刻断了下来。 看寄存器窗口的 ECX 的值:Ecx =转 10 进制刚好是 22。刚好是我们的人物等级。那这个偏移肯定就是 24C 下面我找人物当前经验地址: 找经验地址。我们通过模糊搜索的方法(由于诛仙的游戏的经验是 Double 类型,为什么是 Double 呢。可以试验一下。分别用 4 位,8 位,float 进行查找,看能不能找出经验值)。经 过测验最后,只能是 DOUBLE 类型找到了经验地址。 查找方法(CE 查找):第一次,我们会找出上千万的数据。我们进游戏打死一个怪之后,再查找。数字增加了。反 复多次,我们找到了地址:然后记录该地址,在 OD 里面下内存写入断点。之后,我们被断在了,如(图一)的 00459D8D |. 0 mov dword ptr [esi+260], 由此,我们可以断定 260 就是人物的经验的偏移地址。(下一节,讲怎么找人物的攻击,防御属性)3.2 【KJ】诛仙游戏找地址集合(二)用 OD 载入游戏。看游戏攻击属性(如图):51 好,我们打开 CE。搜索 15,第一次,会搜索出上千条甚至上万条记录。好我们不管它。继续 切换到游戏里面。我们换一个武器,这时,攻击变成 17-21,这里(我们搜索最小攻击)17, 这时,CE 里只剩下 3 条记录。循环第二步,我们最后找到地址(我这里是:06B006C0),对 该地址,在 OD 里面下内存读入断点(为什么是读入呢,之前在第一节开始,就说了游戏会有 个大循环在读取这些基础信息)。我们一下断。OD 立刻断在了(如图):然后,我们看数据窗口,是否等于我们的攻击数字(如图):这里 16 进制 11 刚好等于我们的最小攻击 17。 由此我们判断 2a4 是我们最小攻击的偏移地址。 同理 2a8 是我们最大攻击的偏移地址。 同理,我们用相同的方法,找出了防御的地址: 004BDD62 |. 8B97 B0020000 mov edx, dword ptr [edi+2B0] 当然,偏移地址是 2B0 同理,找命中,躲闪,也可以用同样的方法,只不过我这里没有这样的装备,就不掩饰了。 如果没装备,其实也可以通过查看上下文的方法,进行跟踪。 在 OD 断下来的防御这行(004BDD62),我们向上翻,在不远处,能找到命中的地址 004BDB4C |. 8B8F AC020000 mov ecx, dword ptr [edi+2AC] ;四.找人物金钱,坐标找金钱的方式,与找攻击的是一样的下内存访问断点,很容易就断到 004E0D29 |. 8BB8 D4020000 mov edi, dword ptr [eax+2D4] 偏移地址:2D4 找坐标诛仙坐标数据是 float 类型的(为什么,大家可以测试,用 DOUBLE 或整型,看能不能找到) 好,我们在 CE 里面搜索 FLOAT 范围为:15-17。第一次,会有上千条数据。第二步,进游戏 走动一下改变 Y 坐标的值。到 CE 里面继续搜索改变了的值。反复多次,到最后只剩下 20 多 记录之后,无论怎么查,始终是这么多。好,我们小退一下。再进游戏。这时,我们发现 CE 里面的真是数据只剩下三条了(如图)。我们分别查看这三天数据,是什么在写入。之后发现前两条记录,没什么动静。只有第三条, 我们能看到数据有数据在写入。好。那我们记录下该地址。到 OD 里面去下内存写入断点。最 后被断在了。如图:52 Ecx+38 正是我们的坐标地址。 好。 我们往上查找 ECX 的值是哪里来的。 下面我把它复制过来。仔细查看,我们不难看出坐标偏移地址是: [[[[91BB74]+4]+A14]+10]+38 OK。同理 X 的坐标也用同样的方法找出来了。下一节,讲如何查找目标 ID。和数组。3.3 【KJ】诛仙游戏找地址集合(三)找目标 ID 的偏移,打开 CE 第一次,用模糊搜索(在这里我们可以分别用不同类型进行搜索, 结果发现最后只有怪物 ID 是 4 字节),一样的情况,第一次,有几百上千万条记录。不管它, 我们换怪搜索,不停的换,不停的搜(或者打死怪)。到最后,应该只剩下四条记录OK。我们分别对这四个地址下内存写入断点。前面三个都没反映。只有 071DD7D4 被断了下 来(如图)53 由此,我们知道了目标怪物的 ID 偏移是:7C4 在看寄存器窗口,我们发现 ECX 是我们的二级 基址的值。那当然不用说了。我们的目标 ID 就出来了。 现在我们思考一下。如果我们选中目标。不打它。但是如果被其它玩家杀死之后。就只动的 失去了这个交点。那我们可以肯定,有一个循环在判断我们当前选中的目标是否已经存在。 OK。那我们对该目标地址下内存读入断点。被断在了如图的位置。(图一) 我们仔细看了一下,下面有两个 CALL。OK 我们单步往下走。
|. /75 10 jnz short
到这里的时候,直接跳了。好。我们按流程不管这个 CALL。继续往下走。走到了
|. E8 47630F00 call
进这个 CALL。54 好。我们先测试一下这个函数,是否在被循环调用。 对
下断,断下之后。继续 F9,会不停的被断下。这下,我们断定肯定是一个被循 环调用的函数。 注意看这三行:
|. F771 24 div dword ptr [ecx+24] 0056038C |. 8B41 18 mov eax, dword ptr [ecx+18] 0056038F |. 8B1490 mov edx, dword ptr [eax+edx*4] 然后,再看
|& /3972 08 /cmp dword ptr [edx+8], esi 我们知道 ESI 是被传入的怪物 ID。CMP 这里刚好是比较(我的判断是这里从循环里面取出的 怪物 ID(edx+8)和我们当前选种的怪物 ID 比较是否相等。那我们可以判断+8 是其中一个偏 移。OK。我们往上看。 0056038F |. 8B1490 mov edx, dword ptr [eax+edx*4] 这里 EDX 又等于 eax+edx*4 而 0056038C |. 8B41 18 mov eax, dword ptr [ecx+18] Eax =
|. 8BC6 mov eax, esi
|. 33D2 xor edx, edx
|. F771 24 div dword ptr [ecx+24] Edx 等于怪物 ID 除以 ecx+24 的余数。55 这里 ECX 的值。我们回溯到上一层,去看到底是多少。 看上(图一) 00469FFD |. 8B0D 74BB9100 mov ecx, dword ptr [91BB74]
|. 8B51 1C mov edx, dword ptr [ecx+1C] 0046A00E |. 8B52 08 0046A02E |. 8B4A 20 mov mov edx, dword ptr [edx+8] ecx, dword ptr [edx+20]从这里我们可以看出: Ecx =[[[[91BB74]+1C]+8]+20] -&怪物地址 我们的 ECX 的值肯定就是怪物地址 同上我们判断出: 0056038F |. Edx = 0056038C |. Edx =
|. Edx =8B 18 F771 24mov mov divedx, dword ptr [eax+edx*4] eax, dword ptr [ecx+18] dword ptr [ecx+24]数组里面的怪物 ID 就应该是: |& /3972 08 /cmp dword ptr [edx+8], esi最后得出数组得怪物 ID: [[ecx+18] + [目标 ID MOD [ECX+24]]*4]+83.4 【KJ】诛仙游戏找地址集合(四)现在我们得物品是 30 个。我们打开 CE 搜索 30.OK.很快得速度出来了上千条数据。 接下来,我们改变数量,继续搜索。很快,我们找到了这个物品得地址:02DA78A4 OK。我们到 OD 里面去下内存写入断点。分别对“数量增加”“数量减少”两种方法测试。我 们发现,对该物品“数量减少”。OD 断在了如图位置:56 看图,我们很容易能判断出偏移地址是 14。这里的 ECX 也是待解决的。 然后,“数量增加”断在如图:好。我们先来分析这个数量增加得函数。 由上,我们已经知道 dword ptr [ecx+14]就是我们的数量的地址。那么 ESI 就是更改后的数量。 往上一步一步的看。 00496DDE |. 3BFA cmp edi, edx 这行,明显就是在比较当前物品,是否到了最大值。那么我们可以肯定。物品的最大值偏移 就是 18。Ecx+14 就是当前物品的数量。好。这里的 ECX 的值,是函数外就被复值了的。那这 里。我们要回溯到上一级调用的地方。如图:57
|. E8 B7670000 call 00496DC0 往上看。中途,有许多 CALL。会不会是那个 CALL 调用了 ECX 或改变过 ECX 的值呢。 通过分析,我们发现。程序在这行的时候。
|. /75 29 jnz short 004905FB 就直接跳到了58 004905FB |& \8B5C24 1C mov ebx, dword ptr [esp+1C] 所以,我们可以放心的直接上去找 ECX 的值
|. 8B4E 0C mov ecx, dword ptr [esi+C]
|. 8B04A9 mov eax, dword ptr [ecx+ebp*4]
|. 8B0CB9 mov ecx, dword ptr [ecx+edi*4] 经过分析:发现 ecx = 这里的 EDI,我们通过分析寄存器,发现是第几格(从 0 开始计数)。 004905BC |. 3BF8 cmp edi, eax 看这行在做格子的比较。那 EAX 肯定就是格子的最大数量。那么 004905AD |. 8B46 10 mov eax, dword ptr [esi+10] 10 就是格子的最大数量的偏移。 好,接下来,我们只需要找到 esi 的值就 OK 了。往上看。发现 esi=Ecx = 看寄存器,刚好,esi 就等于我们的人物基址。那还用说了。地址就出来了。3.5 【KJ】诛仙游戏找地址集合(五)首先,我们应该明确,我们下面要找的应该是地面物品的数量。根据这个数量来找值。 刚开始,我们找一个地面没有物品的地方。往地面丢一个物品。然后打开 CE 搜索 1。第一次 肯定也被搜索了很多个东西出来。然后再往地面丢东西。继续搜索。最后,我们得到了一个 地址:02BB43AC。好。我们进 OD 对该地址下内存写入断点。 这里要注意了。我们分别对两种情况进行测试。一是往地上丢物品。二是往地上拣取物品。 往地面丢物品,如图:往地面拣物品(或物品消失),如图:好。首先我们对拣物品进行分析。59 我们往上看。这段代码,我们能很容易的判断出。他就是减少我们地面物品数量的方法。 那么我们地面物品的数量的偏移就应该是:14 好。我们继续去查看这个 ESI 的值。大概在这个函数入口处,我们能看到 Mov esi,ecx 好。我们继续去找 ECX。又发现 ECX 的值是上级调用进来哦。OK。我们回到上级。 如图:一步一步的分析。我们得出了 ECX 得值为:Ecx =3.6 【KJ】诛仙游戏找地址集合(六)走到卖药的 NPC 前面.打开窗口,准备买药.第一步,先到 NPC 前面去下网络通讯断点 Bp send 切到游戏里面去点击买药按钮.OK.OD 被断在了通讯的位置,然后我们执行到返回.继续找.我 们很容易的找到了位置(由于这节主要讲物品结构找法.所以这些过滤掉),如图:这里的 CALL 就是我们的买物 CALL.而 ecx 和 eax 的参数,就是我们要传入的参数60 我们通过寄存器窗口,不难看出这个 EAX 就是我们买物品的组数 主要就是这里的 ECX 的值.往上分析.
|. 8B4C24 2C mov ecx, dword ptr [esp+2C] Ecx = 我们知道 esp 是我们的堆栈指针,看寄存器窗口 esp= 好.这里我们继续往上看,有一断很特别,如图:这里有一行: esp+2c= 而这里的 ebp = 再看寄存器的 ESP 也等于 12f424 到这里.我们可以很肯定的是.这是在做初始划工作. 哪对这个结构复值,肯定就是在这两断代码之前. 再这里.我们一定要记住的是 esp+2c= 经过上下文的察看。我们发现这段代码:.这里的 ESP= 加上 30 刚好等于之前的 esp+2c 等于我们的结构地址。那么这里的 ECX,我们可以肯定就是 之前的结构首地址。好。我们再看一个很奇怪的一行:
|. 8D1481 |lea edx, dword ptr [ecx+eax*4] 这里把 ecx+eax*4 的地址传给了 EDX。主要就是这里的 EAX。我们看寄存器窗口,我们发 现在我们第一次循环得时候 eax=当然这里得我们说得循环三次.是我在游戏里面买了三样物 品).如果没有买物品.程序还是会循环 18 次.我们可以通过下面这两行知道.
|. 3B59 14 |cmp ebx, dword ptr [ecx+14] 0046B19A |.^ 0F8C 4EFFFFFF \jl 0046B0EE 程序在买物品得时候.会遍历买东西得格子次数.判断当前格子是否有物品.如:
|. 3BFD |cmp edi, ebp
由上我们发现这个结构应该是有三个整型组成得数据结构.再往下看.我们就很容易明白了这 个结构里面包含得都是些什么数据,如下: 0046B14C |. 891A |mov dword ptr [edx], ebx61 0046B14E |. 896A 04 |mov dword ptr [edx+4], ebp
|. 8942 08 |mov dword ptr [edx+8], eax 经过分析.我们可以很容易知道这里得 ebx,ebp,eax 都是些什么值.4. 天龙八部找基址4.1 1.搜索人物基地址游戏:天龙八部 版本:0.13.0402 系统:windows xp 工具:CE5.2+OD1.10 目标:搜索人物基地址 第一步,用 CE 搜索人物 HP,得到一堆地址,掉血后继续搜索,得到唯一地址0ABDC360(HP 地 址) 第二步,切换地图后发现该地址里的值已经不是 HP,是动态地址,重复第一步搜索出新的 HP 地址(地址省略) 第三步,这时候不再切换地图,用 CE5.2对找到的 HP 地址下写访问内存断点,此步也可用 OD 下写内存断点,找到汇编语句如下 4B281 4B284 4B289 44B292
8BEC 56 8BF1 8B4E 04 8B01 PUSH EBP MOV EBP,ESP PUSH ESI MOV ESI,ECX ; 1.2 esi= MOV ECX,DWORD PTR DS:[ESI+4] MOV EAX,DWORD PTR DS:[ECX] PUSH EDI CMP EAX,2 83F8 02FF90
CALL DWORD PTR DS:[EAX+114] 8B3D
MOV EDI,DWORD PTR DS:[&&tEngine.?tThrowS&; JNZ SHORT Game. PUSH 56362tEngine.?tThrowStringException@@YAXPBDZZ
FFD7 83C4 10 8B4E 04 8B11 83F8 01 75 19PUSH Game.; ASCII ; ASCII &CT_MONSTER& ; ASCII &Character must&.\DataPool\GMDP_CharacterData.cpp& PUSH Game. PUSH Game.not %s,(File:%s Line:%d)& CALL EDI ADD ESP,10 MOV ECX,DWORD PTR DS:[ESI+4] MOV EDX,DWORD PTR DS:[ECX] CMP EAX,1 JNZ SHORT Game.0044B2DF PUSH 564 PUSH Game. PUSH Game. ; ASCII ; ASCII ; ASCII &Character mustFF92
CALL DWORD PTR DS:[EDX+114]68 68
&.\DataPool\GMDP_CharacterData.cpp& &CT_PLAYEROTHER& PUSH Game. not %s,(File:%s Line:%d)& 0044B2DA FFD7 0044B2DC 0044B2DF
第一个参数
0044B2FA 0044B2FD 0044B2FE 0044B2FF 8 B8060000 MOV DWORD PTR DS:[EAX+6B8],ECX 8B0D 9C975B00 MOV ECX,DWORD PTR DS:[5B979C] 8B11 6A 19 FF52 4C 5F 5E 5D C2 0400 MOV EDX,DWORD PTR DS:[ECX] PUSH Game. CALL DWORD PTR DS:[EDX+4C] POP EDI POP ESI POP EBP RETN 4 ; ASCII &player& PUSH 19 68 B4545700 ; 1.1 血被写入 83C4 10 8B46 08 8B4D 08 CALL EDI ADD ESP,10 MOV EAX,DWORD PTR DS:[ESI+8] MOV ECX,DWORD PTR SS:[EBP+8] ; 1.2 eax= ; 01.1 血来自父函数这是完整的子函数,实际血被写入的那句代码是红色那句,由此可得知血被存在[eax+6b8] 中,6b8是个偏移量,HP 指针地址其实存在 eax 中,根据该段代码的分析,得知 eax= 第四步,让自己掉一次血,发现 HP 地址没变,OD 中行代码处下断点,发现此时的 eax,ecx 也没变,猜测 HP 地址切换地图时才可能重新分配63 第五步:切换一次地图后代码中断,发现此时的 eax,ecx 与上次又不一样了,上步的猜测可 能正确,因为 eax= 004D7A10 004D7A11 004D7A13 004D7A14 004D7A19 004D7A1F 004D7A20 004D7A21 004D7A27 004D7A30 004D7A33 004D7A35 004D7A36 004D7A39 004D7A3D 004D7A43 004D7A45 004D7A48 004D7A49 004D7A4F 004D7A52 004D7A55 004D7A57 55 8BEC 51 PUSH EBP MOV EBP,ESP PUSH ECX MOV EAX,DWORD PTR DS:[5B97F0]A1 F 56 8B75 08 8B46 08 8B11 50 FF52 44 8BD83B05 E4975B00 CMP EAX,DWORD PTR DS:[5B97E4] PUSH EBX PUSH ESI MOV ESI,DWORD PTR SS:[EBP+8] MOV EAX,DWORD PTR DS:[ESI+8] MOV EDX,DWORD PTR DS:[ECX] PUSH EAX CALL DWORD PTR DS:[EDX+44] MOV EBX,EAX TEST EBX,EBX XOR EAX,EAX MOV AL,BYTE PTR DS:[ESI+C] PUSH EDI ; 2.3 edi= AND EAX,1 MOV DWORD PTR SS:[EBP-4],EAX JE SHORT Game.004D7A82 MOV ECX,DWORD PTR DS:[ESI+18] PUSH ECX MOV ECX,EDI CALL Game.00449A40 ; 2.4 ebx= ; 2.5 eax 是该函数的返0F85 AB080000 JNZ Game.004D82D2004D7A2A 8B0D 78695B00 MOV ECX,DWORD PTR DS:[5B6978]回值,该函数返回一个重要的地址 004D7A3B 85DB 33C0 8A46 0C 57 83E0 01 8945 FC 74 2B 8B4E 180F84 8F080000 JE Game.004D82D28BBB 2C010000 MOV EDI,DWORD PTR DS:[EBX+12C]004D7A5A 51 004D7A5B 8BCF 004D7A5D 004D7A62 004D7A68 004D7A6D 004D7A70 004D7A76 004D7A79 004D7A7CE8 DE1FF7FF 3B5A 44 8B57 08 8B52 70 8B018B15 78695B00 MOV EDX,DWORD PTR DS:[5B6978] CMP EBX,DWORD PTR DS:[EDX+44] JNZ SHORT Game.004D7A82 MOV EDX,DWORD PTR DS:[EDI+8] MOV EDX,DWORD PTR DS:[EDX+70] MOV EAX,DWORD PTR DS:[ECX] PUSH EDX004D7A6B 75 158B0D 10985B00 MOV ECX,DWORD PTR DS:[5B9810]004D7A7B 52FF90 A0000000 CALL DWORD PTR DS:[EAX+A0]64 004D7A82 004D7A84 004D7A87 004D7A8C 004D7A90 004D7A93 004D7A94 004D7A9633C0 8A46 0C 83E0 02 85C0 8B46 20 50 8BCFXOR EAX,EAX MOV AL,BYTE PTR DS:[ESI+C] AND EAX,2 SHR EAX,1 TEST EAX,EAX JE SHORT Game.004D7A9B MOV EAX,DWORD PTR DS:[ESI+20] PUSH EAX MOV ECX,EDI CALL Game. XOR EAX,EAX ; 02.1 eax 里存放了血,给子函数使用 ; 2.2 ecx= ; 2.1 ecx 影响了子函数004D7A8A D1E8 004D7A8E 74 0BE8 E537F7FF004D7A9B 33C0CALL Game.即第三步找到的子函数,调用子函数时血量值作为参数传进去,具体 的子函数功能我也没搞清楚,大体感觉上可能是拿到数据包后给内存中的 HP 地址赋值。 继续分析这段代码,2.1,2.2,2.3这三句发现 ecx= 第六步:CE 中查找0b387708存在什么地址里,找到两个地址013D2BD8和013D6064,随后切换 地图发现这两个地址里的值都改变了,但还是相同,用这个新值进行[[[新值+12c]+8]+6b8] 运算,终于得到了 HP 值。 感觉这两个地址有可能是个不变的值,重开游戏后确认,的确同样的运算还能得到 HP 值。 姑且任务第一个值013D2BD8为要查找的基地址,而血是经过偏移3次后找到的,偏移量分别是 12c,8,6b8 目标基本完成,OVER!4.2 2.编写读状态程序游戏:天龙八部 版本:0.13.0402 系统:windows xp 工具:CE5.2+OD1.10+C# 2005 目标:编写获取分析到内存偏移地址的游戏属性的程序 按照学习笔记1中的方法继续查找到了 MP,HP 上限,HP 上限,人物 ID,人物姓名等属性,接 下来编写一个简单的状态读取程序,语言用 C# 2005,程序运行界面如下65 项目文件布局如下以下为各文件简单说明: 1. 内存地址配置文件 AddressListConfig.xml,用来存放各级基地址,以及人物各属性的偏 移地址 1&?xml version=&1.0& encoding=&utf-8& ?& 2&Configs& 3 &AddressList Key=&Base1& Offset=&0x013D2BD8& ValueType=&System.Int32& ValueLength=&4&&66 4 5 6 7 8 9 10 11 12 13 14&AddressList Key=&Base1.Base2& Offset=&0x12C& ValueType=&System.Int32& &AddressList &Address &Address &Address &Address &Address &Address &/AddressList& &/AddressList& &/AddressList& Key=&Base1.Base2.MyPlayer& Key=&Base1.Base2.MyPlayer.UserId& Key=&Base1.Base2.MyPlayer.Name& Key=&Base1.Base2.MyPlayer.Hp& Key=&Base1.Base2.MyPlayer.Mp& Offset=&0x8& Offset=&0&ValueLength=&4&& ValueType=&System.Int32& ValueLength=&4&& ValueType=&System.String& ValueLength=&4& /& Offset=&0x10& Offset=&0x6B8& Offset=&0x6BC& Offset=&0x81C& Offset=&0x820& ValueType=&System.String& ValueLength=&12& /& ValueType=&System.Int32& ValueLength=&4& /& ValueType=&System.Int32& ValueLength=&4& /& Key=&Base1.Base2.MyPlayer.MaxHp& Key=&Base1.Base2.MyPlayer.MaxMp& ValueType=&System.Int32& ValueLength=&4& /& ValueType=&System.Int32& ValueLength=&4& /&15&/Configs& 1) AddressList 为嵌套的基地址 Key 为全局的读取键名,Offset 为学习笔记1中查到的偏移量,ValueType

我要回帖

更多关于 esp ebp 的文章

 

随机推荐