星尘找怪物数组新手教程
2009-06-19 07:03:39| 分类:
外挂学习
| 标签:
|举报
|字号大中小 订阅
本来是想找到怪物的基本的数组和偏移(另外这个偏移是不是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就等暑假在调教她们把。
评论这张
转发至微博
转发至微博
评论