注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

风雨夜归人

专业收集资料,个人爱好!

 
 
 

日志

 
 

星尘找怪物数组新手教程  

2009-06-19 07:03:39|  分类: 外挂学习 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
本来是想找到怪物的基本的数组和偏移(另外这个偏移是不是26h),但是一直没有成功,于是就找了这个可选怪的call来自己构建可选怪物数组,定位还是比较简单,但是写call还花了一番心思。由于要准备考试了,最近也没有时间弄外挂了,于是就想写一篇文总结一下这一个月来使用od分析程序的经验,也希望这可以对还没有入门的人(应为我也是新人)有所帮助。第一次发长贴写的不好还望见谅。

首先,为了找到一个call我们要知道一些必要的信息。
当前选中目标基址:BASE+134+34  这个就是当前选中怪的基址,论坛里面有各个地址的很全的信息,包括这条,至于怎么找到这条基址,我们可以打怪用CE跟怪物血,还是很简单的,这里就先直奔主题而去了。

《星尘》当前版本号 02.01.0023 base:7b6958h

我们首先开星尘,在开od,附加到星尘,之后F9运行,在数据窗口转到上面的地址。
方法:先将数据窗口显示信息改为 长型-地址。在表达式对话框(Ctrl+G)输入基址7b6958确定(这里第一次用od找地址可能会出错,要细看是不是到了要找的地址,不是在来一遍)。我的是这样的:

007B6958  017A5828
007B695C  00000000
007B6960  1E070413
007B6964  00000100
007B6968  00000000

这里我们找到了基址的地址。之后是一个汇编内容——基址加偏移是怎么运算的,我们在使用od时看到的代码都是反汇编之后的代码,在代码窗口总会有一些这样的值,例如: [7b6958], 这个就是一个固定地址的意思,表示到程序的进程地址空间中的第7b6958个位置上寻址,也就是说加了中括号的数就是表示绝对地址,也就是各种各样的基址(也就是汇编编译过程中伪指令为数据分配的地址,或者说c等语言的全局变量指针等,另外没加中括号的是立即数)。然后在说偏移的算法(偏移是伪指令分配连续数据的位移或高级语言的数组中数据大小、类成员大小等?),就是 值+值=地址, 比如7b6958+134算偏移就是7b6958地址中的值+134,在如代码中[ebp+34]就是ebp的值+34。

然后按照这个算法找到当前选中怪的地址(从7b6958中的值开始我们的数据可能就会微妙的不同,但是没关系),我的在转换回HEX/ASCII是这样,下面那个FF FF FF FF是标志,找到这里就对了。

08CF0E04  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
08CF0E14  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
08CF0E24  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
08CF0E34  00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00  
08CF0E44  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
08CF0E54  00 40 95 43 00 80 21 43 00 00 00 00 C0 0E CF 08  
08CF0E64  00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00  
08CF0E74  02 00 00 00 00 00 00 00 2A 01 00 00 A3 00 00 00  
08CF0E84  00 00 00 00 FF FF FF FF 00 00 00 00 00 00 00 00  

然后我们TAB选怪试一试这里是不是变,怪选了一圈是不是回到原处(操作一次要点一次od,要不他不更新数据)。结果是正确的(废话)。然后我们为这个地址(我的是08CF0E04)下 硬件写入 断点(在右键里),大小当然跟指针一样长最好(DWORD),然后在TAB断下游戏(用鼠标选怪断也可以,我最初这样做,但是进行到了一定地方EBP不太会跟,所以没成功)。在代码运行到得位置的上一句F2下断点(之所以是在上一句,是应为程序运行完了一句代码,各个需要改动的地方才会改动,所以改动那个地址的代码是上一句),然后卸载硬件断点(在调试菜单),然后F9运行游戏,这时我们可以看一下断的这句和数据窗口、cpu窗口的状态。

00421E0B    8941 0C        mov    dword ptr [ecx+C], eax          ; 选定怪物

从cpu窗口看出[ecx+C]正是存放怪物基址(08CF0E04)的地址,所以eax中的值是怪物基址,数据窗口的情况也肯定了这点。

之后我们要找一些相关的call。再TAB断下游戏,之后Ctrl+F9运行到返回(根据od版本不同有的运行到RET,有的运行到CALL的下一句,如果是RET就在按下F8运行一步就到CALL了)为call下断点。把之前的断点移除(在Alt+B中移除,不是删除,可能我们今后还能用到这个断点呢)然后F9运行游戏。然后再重复上面的步骤 TAB-Ctrl+F9-下断-移除-运行。直到我们进入了游戏循环,无论怎么F9都会断在那个call上,也就是说从这层开始游戏运行会分支,这里只找了2个call就到了。我们移除循环中的call,激活上一个call,这里我的经验是,循环的下一层call就是一个功能的最外层call(不过这里不是这样,稍后在说)。两个call如下:

0041B395    8BC5            mov    eax, ebp
0041B397    E8 C4050000    call    0041B960
0041B39C    55              push    ebp
0041B39D    E8 8E020000    call    0041B630                        ; 循环中call
0041B3A2    395D 28        cmp    dword ptr [ebp+28], ebx

0041B80F    85C0            test    eax, eax
0041B811    74 32          je      short 0041B845
0041B813    6A 01          push    1
0041B815    8BF5            mov    esi, ebp
0041B817    E8 A4650000    call    00421DC0                        ; TAB call EAX是怪指针
0041B81C    8B0D 58697B00  mov    ecx, dword ptr [7B6958]

然后我们用上面的方法分析 这个唯一的call,eax中是怪物指针,而选中这个怪的代码在这个call中,所以这就是TAB call。但是那个eax的内容是从哪来的呢?这个eax还是程序产生的一个值,所以单单使用tab是没用的,然而在上一层call就进入了循环中了(这就不符合我的经验了),应为tab call不是每次都运行到,而上一层call一直在运行,所以一定有地方可以跳过tab call。我们向上看代码(还好循环中的call的内容不长,不用跟他)。于是我们找到了这样的代码。

0041B77C    3B05 84627B00  cmp    eax, dword ptr [7B6284]
0041B782    0F85 BD000000  jnz    0041B845                        ; 跳过TAB call
0041B788    837D 04 00      cmp    dword ptr [ebp+4], 0
0041B78C    0F84 B3000000  je      0041B845                        ; 跳过TAB call
0041B792    8B4D 08        mov    ecx, dword ptr [ebp+8]         ;EBP:base+134
0041B795    85C9            test    ecx, ecx
0041B797    0F84 A8000000  je      0041B845                        ; 跳过TAB call
0041B79D    8B15 58697B00  mov    edx, dword ptr [7B6958]
0041B7A3    8B42 4C        mov    eax, dword ptr [edx+4C]
0041B7A6    80B8 24010000 0>cmp    byte ptr [eax+124], 0F
0041B7AD    0F85 92000000  jnz    0041B845                        ; 跳过TAB call
0041B7B3    837B 20 00      cmp    dword ptr [ebx+20], 0
0041B7B7    0F85 88000000  jnz    0041B845                        ; 跳过TAB call
0041B7BD    8B01            mov    eax, dword ptr [ecx]            ; ECX:base+134+8
0041B7BF    8B50 78        mov    edx, dword ptr [eax+78]
0041B7C2    FFD2            call    edx
0041B7C4    E8 57BE2E00    call    00707620                        ; 改变EAX 之后的ESI 值
0041B7C9    8B4D 08        mov    ecx, dword ptr [ebp+8]          ; EBP:base+134
0041B7CC    8BF0            mov    esi, eax                        ; 赋给ESI
0041B7CE    8B01            mov    eax, dword ptr [ecx]
0041B7D0    8B90 80000000  mov    edx, dword ptr [eax+80]
0041B7D6    FFD2            call    edx
0041B7D8    E8 43BE2E00    call    00707620                        ; 改变EAX 之后的EDI 值
0041B7DD    8B4D 08        mov    ecx, dword ptr [ebp+8]          ; EBP:base+134
0041B7E0    8BF8            mov    edi, eax                        ; 赋给EDI
0041B7E2    8B01            mov    eax, dword ptr [ecx]
0041B7E4    8B90 88000000  mov    edx, dword ptr [eax+88]
0041B7EA    FFD2            call    edx                              ; 改变EAX
0041B7EC    8B4D 34        mov    ecx, dword ptr [ebp+34]          ; 将已选怪赋给ECX
0041B7EF    85C9            test    ecx, ecx                        ; 判断是否已选怪
0041B7F1    BA 58020000    mov    edx, 258                        ; 数组最大值?
0041B7F6    74 03          je      short 0041B7FB                  ; 已有选定怪 转
0041B7F8    8B51 04        mov    edx, dword ptr [ecx+4]          ; edx赋固定值258
0041B7FB    8B0D 94667B00  mov    ecx, dword ptr [7B6694]          ; ecx赋 A
0041B801    51              push    ecx                              ; 固定
0041B802    52              push    edx                              ; 固定
0041B803    50              push    eax
0041B804    8B45 04        mov    eax, dword ptr [ebp+4]         ;EBP:base+134
0041B807    57              push    edi                     ;y
0041B808    56              push    esi                     ;x
0041B809    50              push    eax                              ; ?
0041B80A    E8 716D0500    call    00472580                        ; 将怪指针赋给EAX
0041B80F    85C0            test    eax, eax
0041B811    74 32          je      short 0041B845
0041B813    6A 01          push    1
0041B815    8BF5            mov    esi, ebp
0041B817    E8 A4650000    call    00421DC0                        ; TAB call EAX是怪指针

之后我们给这句(下面那句)下断(这句后没有跳过tab call的内容了),游戏没有暂停,TAB选怪(这里就在用鼠标也不停了,应为已经是两个系统的问题了,之前找那边可费劲啊)游戏暂停了,F8运行可以到tab call

0041B7BD    8B01            mov    eax, dword ptr [ecx]            ; ECX:base+134+8

虽然有多个可以跳过tab call的jump 但是要执行到tab call 他们都不可以成功,所以这一段也就是完成了从怪物数组(我一直想找到但没成功)找出目标怪到完成选定目标怪的过程的代码了。下面我们来推倒她。

既然tab call需要eax是怪物指针,那么我们从下往上看,是谁最后把eax改变成怪物指针的值,断下游戏发现就是上一个call

0041B80A    E8 716D0500    call    00472580                        ; 将怪指针赋给EAX

也就是说这就是最主要的选定怪物的call了,看他前面好多push,还很多参数嘛(之前也试着从这call里找怪的数组,没有成功,后来到外面发现他也是根据一些怪的信息才定位怪的,总结心得:先看call外面在看call里面)。我们现在就留两个断点来标示我们要分析的代码,就是上面两句代码。

之后就是不断的tab选怪,F8执行一句一句分析,得出上面的注释,为了加快速度我感觉应该从下向上分析,就是断选怪call(我们要的call)的上一个call的下一句,然后先分析着一小段,得出一些结论在将断点上移,这样可以先分析表面的我们容易见到的数据,然后是深层的程序内部的数据。整个过程不难,值得注意的是EBP的内容,整段代码都没有改变它,而他正是base+134,应该注意这句,就把EBP中看似没什么关联的值结合34这个熟悉的值好好分析一下,要不会被逆推(比如我)。这个EBP也对我写call造成了一定影响,但也加深了我对汇编的理解。

0041B7EC    8B4D 34        mov    ecx, dword ptr [ebp+34]          ; 将已选怪赋给ECX

完成了分析call的过程之后就是写call了,也就是把那一大段代码改啊改啊,在到od中调试,看看哪里跟原来的不同,最终得到成品call,其中注意ebp的定位问题,既然这段代码没有改动ebp我们也不改他把,用一下其它的办法。

DWORD CallChoose()
{
    DWORD CALL_NUM = 0X707620;
    DWORD CALL_CHOOSE = 0X472580;
    DWORD something = 0X7B6694;
    DWORD mebp;
    DWORD guai;
    __asm{
        mov    ecx, DWORD PTR DS:[ADD_Base]
        mov    ecx, DWORD PTR DS:[ecx+0x134]
        mov    mebp, ECX
        mov    ecx, DWORD PTR DS:[ecx+0x8]
        mov    eax, dword ptr [ecx]            ; ECX:base+134+8
        mov    edx, dword ptr [eax+0x78]
        call    edx
        call    CALL_NUM                        ; 改变EAX 之后的ESI 值
    //    mov    ecx, dword ptr [mebp+8]          ; EBP:base+134
        mov        ecx, mebp
        mov        ecx, [ecx+8]
        mov    esi, eax                        ; 赋给ESI
        mov    eax, dword ptr [ecx]
        mov    edx, dword ptr [eax+0x80]
        call    edx
        call    CALL_NUM             ; 改变EDI
    //    mov    ecx, dword ptr [mebp+8]          ; EBP:base+134
        mov    ecx, mebp
        mov    ecx, [ecx+8]
        mov    edi, eax
        mov    eax, dword ptr [ecx]
        mov    edx, dword ptr [eax+0x88]
        call    edx                              ; 改变EAX
    //    mov    ecx, dword ptr [mebp+0x34]      ; 将已选怪赋给ECX
        mov    ecx, mebp
        mov    ecx, [ecx+0x34]
        test    ecx, ecx                        ; 判断是否已选怪
        mov    edx, 0x258                      ; 数组最大值?
        mov    ecx, something             ; ecx赋 A
        mov        ecx, [ecx]
        push    ecx                              ; ok
        push    edx                              ; ok
        push    eax
    //    mov    eax, dword ptr [mebp+4]
        mov        eax, mebp
        mov        eax, [eax+4]
        push    edi                 ; y
        push    esi                 ; x
        push    eax                              ; ok
        call    CALL_CHOOSE                      ; 将怪指针赋给EAX
        test    eax, eax
        mov    guai, eax    
    }
    return guai;
}

我对于这个的使用是这样想的,函数的返回值每调用一次会有不同,但最后会有相同的值,返回值就是怪物指针,可以将这些指针保存为一个数组,就是当前可选怪的数组,通过指针可以找到怪名字,也就是可以指定特定的怪,同过tab call就可以直接选定特定的怪了(直接写入选怪地址应该也可以吧,tab call上面有分析到一点,她很好推倒)。在加上之前我找了技能call、移动call做一个非常非常简单的可以打怪的外挂还是可以的。没有找到真正的怪物数组还是很遗憾的,还有接任务,修装备的call就等暑假在调教她们把。
  评论这张
 
阅读(1459)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017