吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 13314|回复: 49
收起左侧

[游戏安全] 【原创】CE反汇编硬追基址之pvz僵尸数组头部

  [复制链接]
lyl610abc 发表于 2021-1-29 12:58
本帖最后由 lyl610abc 于 2021-1-29 13:28 编辑

前言:

看了很多有关植物大战僵尸的教程,比较少看到用汇编来找基址的,大多是用"找出是什么访问了这个地址"来找的

但是这种方法存在弊端,一是可能存在多个指针,二是不一定搜的到

今天给大家带来CE反汇编硬追pvz的僵尸数组头部教程

适合学习人群:比萌新稍微强一丝丝足矣

事前准备

本人使用的工具:CE7.2汉化版(不用在意版本问题) PS:OD什么的不需要啦

本人使用的游戏:植物大战僵尸原版的汉化版(非年度版)        就是阳光基址是006A9EC0+768+5560的那个

教程内容

找到僵尸血量

首先瞄准一只普通僵尸,搜索得到它的血量

PS:普通僵尸的初始血量是270 豌豆射手的攻击是20 (模糊搜索可以找到这些数据)
image-mage-20210128193537060

所以我们先搜270
image-20210128193756710

然后命中之后再搜250,过滤得到

image-20210129000559707

很轻松地得到这一只僵尸的血量,先把僵尸的血量改成9999(接下来要让它被狠狠地揍,我们好断点追踪),然后右键"找出是什么改写了这个地址"
image-20210128194254141

接下来点击"显示反汇编程序"即可开启我们的反汇编之旅

开始反汇编追踪之旅

image-image-20210128194429846

反汇编窗口如上所示,贴上代码:

PlantsVsZombies.exe+131319 - 89 BD C8000000        - mov [ebp+000000C8],edi    

从这句我们可以得到ebp+c8这个地址里存的值就是这只僵尸的血量

于是问题转化为ebp从何而来?

我们在这里F5下个断点 顺便给这里加上备注
image-image-20210128195008278

然后回到游戏,等待僵尸被攻击后,断下

image-20210129000720679

这里我们可以看到EBP=14EE1914  ,暂且记下

大家都知道代码是从上往下执行的,于是我们以这行代码为起点,向上查找是什么给EBP赋值的

再贴代码:

PlantsVsZombies.exe+1312D0 - 83 EC 08              - sub esp,08 { 8 }
PlantsVsZombies.exe+1312D3 - 8B 44 24 14           - mov eax,[esp+14]
PlantsVsZombies.exe+1312D7 - 53                    - push ebx                        {这里是函数头部}
PlantsVsZombies.exe+1312D8 - 55                    - push ebp
PlantsVsZombies.exe+1312D9 - 8B 6C 24 14           - mov ebp,[esp+14]        {ebp在这里被赋值}
PlantsVsZombies.exe+1312DD - 56                    - push esi
PlantsVsZombies.exe+1312DE - 8B F0                 - mov esi,eax
PlantsVsZombies.exe+1312E0 - 83 E6 08              - and esi,08 { 8 }
PlantsVsZombies.exe+1312E3 - 57                    - push edi
PlantsVsZombies.exe+1312E4 - 89 74 24 10           - mov [esp+10],esi
PlantsVsZombies.exe+1312E8 - 75 07                 - jne PlantsVsZombies.exe+1312F1
PlantsVsZombies.exe+1312EA - C7 45 54 19000000     - mov [ebp+54],00000019 { 25 }
PlantsVsZombies.exe+1312F1 - A8 04                 - test al,04 { 4 }
PlantsVsZombies.exe+1312F3 - 74 09                 - je PlantsVsZombies.exe+1312FE
PlantsVsZombies.exe+1312F5 - 6A 00                 - push 00 { 0 }
PlantsVsZombies.exe+1312F7 - 8B C5                 - mov eax,ebp
PlantsVsZombies.exe+1312F9 - E8 52F6FFFF           - call PlantsVsZombies.exe+130950
PlantsVsZombies.exe+1312FE - 8B BD C8000000        - mov edi,[ebp+000000C8]
PlantsVsZombies.exe+131304 - 8B C5                 - mov eax,ebp
PlantsVsZombies.exe+131306 - 89 7C 24 14           - mov [esp+14],edi
PlantsVsZombies.exe+13130A - E8 01C4FFFF           - call PlantsVsZombies.exe+12D710
PlantsVsZombies.exe+13130F - 2B 7C 24 20           - sub edi,[esp+20]
PlantsVsZombies.exe+131313 - 89 44 24 1C           - mov [esp+1C],eax
PlantsVsZombies.exe+131317 - 8B C5                 - mov eax,ebp
PlantsVsZombies.exe+131319 - 89 BD C8000000        - mov [ebp+000000C8],edi { 血量被赋值}

我们找到了mov ebp,[esp+14] 并认为ebp就是在这里被赋值的,为了验证这一点,我们在这个位置下断点,并断下
image-image-20210129000936360

我们可以看到此时的ebp尚且为14,F8单步步过以后果然发现EBP变成了14EE1914   

image-20210129001041030

这时的EBP则转化为了[esp+14],这时照理来说我们应该重复之前的操作去找esp,但实则不然

因为:

(1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

萌新看到这里可能一脸懵逼:这是啥子呀,这里我也不说什么堆栈平衡的话了,通俗来说,ebp和esp都是临时的指针,只有像eax、ebx、edx、esi、edi这类寄存器我们才要向上去找是什么去赋值的,而遇到这种mov ebp,[esp+14]这类的,我们要去找之前push xxx的xxx,或者在前面直接就有mov [esp+xx],xxx的

为什么呢:一个push会让esp减少4,我们会发现,这里的ebp是[esp+14]得来的,但我们又能看到上面有一个sub esp,08

也就相当于mov ebp[esp-08+14]即mov ebp[esp+c],这里主义mov []里面的值是十六进制的,14=16*1+4=20 20-8=12

不知道进制转换的直接拿计算器算即可
image-20210128201024895

12=4*3 即3个push xxx,是不是感觉有点意义不明☆,暂且记下

接着向上找,发现已经到达了函数的头部,于是我们得到上一层去寻找了,如何判断到达头部? 看到 ret 还有一串int3就是了

也可以右键选择当前函数,然后找到选中的第一个,就可以得到函数的头部
image-20210128201630955
回到刚才我们的那个mov [ebp+000000C8],edi,下一个断点,下完断点后回到游戏,等游戏再被断下以后,可以用shift+f8执行到返回,也可以一直手动按f8直到遇到一个ret

这里我用了后面那种方式,得到了:
image-20210129001324786

此时这个pop edi上面的那个call 就是我们刚才那个函数,如果在那个call那里下断,然后F7单步步入就可以进入我们刚才的地方

然后我们在call这里做个断点,并给它一个标记call1(书签也可以设置一下,避免找不到)

image-20210129001446346

此时我们发现call之前有3个push,而这里的esi正好是第三个push,而esi的值也"正好"等于之前的14EE1914   

所以我们可以知道,之前的mov ebp,[esp+14],其实就是将esi的值赋给了它,这边主要是说明一下值的由来,其实大家都不难发现之前就是ESI=EBP=14EE1914了

于是我们的问题便又变成了[ebp+c8]->ebp->esi->[esi+c8]

我们接着向上找ESI是由谁给它赋值的,我们发现上面没有给esi赋值的语句,那会不会是上面的call给esi赋值的呢,有这个可能,但是我们可以在call之前设置断点,发现call之前esi就已经被赋值了,一路往上直到函数头部发现ESI的值都已经是被赋值了,得出结论是从上一层给我们ESI赋值的。

于是我们故技重施,直接在call这里下断点,然后执行到返回,得到:

image-20210129001830915

贴上代码

PlantsVsZombies.exe+6E004 - 55                    - push ebp
PlantsVsZombies.exe+6E005 - 56                    - push esi
PlantsVsZombies.exe+6E006 - 57                    - push edi
PlantsVsZombies.exe+6E007 - 8B F0                 - mov esi,eax                                {esi是由eax赋值的}
PlantsVsZombies.exe+6E009 - 8B F9                 - mov edi,ecx
PlantsVsZombies.exe+6E00B - 56                    - push esi
PlantsVsZombies.exe+6E00C - 8B C7                 - mov eax,edi
PlantsVsZombies.exe+6E00E - E8 1DFDFFFF           - call PlantsVsZombies.exe+6DD30
PlantsVsZombies.exe+6E013 - 8B 5F 5C              - mov ebx,[edi+5C]
PlantsVsZombies.exe+6E016 - 83 FB 06              - cmp ebx,06 { 6 }
PlantsVsZombies.exe+6E019 - 75 21                 - jne PlantsVsZombies.exe+6E03C
PlantsVsZombies.exe+6E01B - 85 F6                 - test esi,esi
PlantsVsZombies.exe+6E01D - 74 1D                 - je PlantsVsZombies.exe+6E03C
PlantsVsZombies.exe+6E01F - 8B 46 24              - mov eax,[esi+24]
PlantsVsZombies.exe+6E022 - 83 F8 16              - cmp eax,16 { 22 }
PlantsVsZombies.exe+6E025 - 74 3E                 - je PlantsVsZombies.exe+6E065
PlantsVsZombies.exe+6E027 - 83 F8 0C              - cmp eax,0C { 12 }
PlantsVsZombies.exe+6E02A - 74 39                 - je PlantsVsZombies.exe+6E065
PlantsVsZombies.exe+6E02C - 8B 86 D8000000        - mov eax,[esi+000000D8]
PlantsVsZombies.exe+6E032 - 83 F8 01              - cmp eax,01 { 1 }
PlantsVsZombies.exe+6E035 - 74 2E                 - je PlantsVsZombies.exe+6E065
PlantsVsZombies.exe+6E037 - 83 F8 03              - cmp eax,03 { 3 }
PlantsVsZombies.exe+6E03A - 74 29                 - je PlantsVsZombies.exe+6E065
PlantsVsZombies.exe+6E03C - 83 FB 03              - cmp ebx,03 { 3 }
PlantsVsZombies.exe+6E03F - 74 0A                 - je PlantsVsZombies.exe+6E04B
PlantsVsZombies.exe+6E041 - 83 FB 05              - cmp ebx,05 { 5 }
PlantsVsZombies.exe+6E044 - 74 05                 - je PlantsVsZombies.exe+6E04B
PlantsVsZombies.exe+6E046 - 83 FB 06              - cmp ebx,06 { 6 }
PlantsVsZombies.exe+6E049 - 75 1A                 - jne PlantsVsZombies.exe+6E065
PlantsVsZombies.exe+6E04B - 83 FB 06              - cmp ebx,06 { 6 }
PlantsVsZombies.exe+6E04E - 75 0B                 - jne PlantsVsZombies.exe+6E05B
PlantsVsZombies.exe+6E050 - 85 F6                 - test esi,esi
PlantsVsZombies.exe+6E052 - 74 07                 - je PlantsVsZombies.exe+6E05B
PlantsVsZombies.exe+6E054 - 8B C6                 - mov eax,esi
PlantsVsZombies.exe+6E056 - E8 E54A0C00           - call PlantsVsZombies.exe+132B40
PlantsVsZombies.exe+6E05B - 56                    - push esi
PlantsVsZombies.exe+6E05C - 8B C7                 - mov eax,edi
PlantsVsZombies.exe+6E05E - E8 2DF3FFFF           - call PlantsVsZombies.exe+6D390
PlantsVsZombies.exe+6E063 - EB 1B                 - jmp PlantsVsZombies.exe+6E080
PlantsVsZombies.exe+6E065 - 85 F6                 - test esi,esi
PlantsVsZombies.exe+6E067 - 74 17                 - je PlantsVsZombies.exe+6E080
PlantsVsZombies.exe+6E069 - 8B C6                 - mov eax,esi
PlantsVsZombies.exe+6E06B - E8 C0F1FFFF           - call PlantsVsZombies.exe+6D230
PlantsVsZombies.exe+6E070 - 8D 0C 5B              - lea ecx,[ebx+ebx*2]
PlantsVsZombies.exe+6E073 - 8B 14 8D C8F16900     - mov edx,[ecx*4+PlantsVsZombies.exe+29F1C8]
PlantsVsZombies.exe+6E07A - 52                    - push edx
PlantsVsZombies.exe+6E07B - E8 40370C00           - call PlantsVsZombies.exe+1317C0 { call2 }

我们向上找可以发现 mov esi,eax,说明esi是由eax得来的

问题再次转化为[ebp+c8]->ebp->esi->[esi+c8]->[eax+c8]

这时我们发现又到了函数头部,再次故技重施,下断并执行到返回,再来到上一层

image-20210129001954312

贴上代码:

PlantsVsZombies.exe+6D04E - 5F                    - pop edi
PlantsVsZombies.exe+6D04F - 5E                    - pop esi
PlantsVsZombies.exe+6D050 - 5D                    - pop ebp
PlantsVsZombies.exe+6D051 - 5B                    - pop ebx
PlantsVsZombies.exe+6D052 - 83 C4 20              - add esp,20 { 32 }
PlantsVsZombies.exe+6D055 - C2 0400               - ret 0004 { 4 }
PlantsVsZombies.exe+6D058 - E8 E3FCFFFF           - call PlantsVsZombies.exe+6CD40 { EAX在这里面}
PlantsVsZombies.exe+6D05D - 8B D0                 - mov edx,eax                                                {edx被eax赋值}
PlantsVsZombies.exe+6D05F - 85 D2                 - test edx,edx
PlantsVsZombies.exe+6D061 - 74 EB                 - je PlantsVsZombies.exe+6D04E
PlantsVsZombies.exe+6D063 - 80 BA BE000000 00     - cmp byte ptr [edx+000000BE],00 { 0 }
PlantsVsZombies.exe+6D06A - 74 0B                 - je PlantsVsZombies.exe+6D077
PlantsVsZombies.exe+6D06C - 8B CD                 - mov ecx,ebp
PlantsVsZombies.exe+6D06E - E8 1D000000           - call PlantsVsZombies.exe+6D090
PlantsVsZombies.exe+6D073 - 84 C0                 - test al,al
PlantsVsZombies.exe+6D075 - 75 D7                 - jne PlantsVsZombies.exe+6D04E
PlantsVsZombies.exe+6D077 - 8B C2                 - mov eax,edx                                                {eax被edx赋值}
PlantsVsZombies.exe+6D079 - 8B CD                 - mov ecx,ebp
PlantsVsZombies.exe+6D07B - E8 800F0000           - call PlantsVsZombies.exe+6E000 { call3 }

不难发现,我们这里的eax是由edx赋值的;再向上找到mov edx,eax,edx又变成了eax所以我们还是要找eax

这里其实还遇到了一个小问题,就是在mov edx,eax 这里要下断点证明是不是eax将值赋给了edx,但是设置了断点以后,一进游戏就断下来了,并且eax的值并不是14EE1914,这个时候可能就有人觉得这里不是赋值处了,但其实这里就是赋值的地方,它是一个共用段,于是我们要通过条件断点来过滤,条件断点设置如下

image-20210129002638911

通过条件断点后,果然断下了

image-20210129003109596

再往上看只有一个CALL 了,要么EAX就是在CALL里被赋值的,要么就是在上一层被赋值的

怎么确认呢?我们可以在CALL 这里下个条件断点,如果是上一层赋值的,则会断下,否则不会断下

image-20210129003330136

设置条件断点以后发现并没有断下,得出结论,EAX是在CALL里面被赋值的

于是我们先设置一个普通的断点,然后F7单步步入CALL中,然后找到CALL的尾部(跳出CALL之前肯定EAX已经被赋值完毕了),于是我们右键选择当前函数,然后找到被选中的最后一行,如图:

image-20210129003745902

代码如下:

PlantsVsZombies.exe+6CE5F - E8 8CFAFAFF           - call PlantsVsZombies.exe+1C8F0
PlantsVsZombies.exe+6CE64 - 84 C0                 - test al,al
PlantsVsZombies.exe+6CE66 - 0F85 25FFFFFF         - jne PlantsVsZombies.exe+6CD91
PlantsVsZombies.exe+6CE6C - 8B 44 24 18           - mov eax,[esp+18] { eax被赋值 }
PlantsVsZombies.exe+6CE70 - 5F                    - pop edi
PlantsVsZombies.exe+6CE71 - 5E                    - pop esi
PlantsVsZombies.exe+6CE72 - 5D                    - pop ebp
PlantsVsZombies.exe+6CE73 - 5B                    - pop ebx
PlantsVsZombies.exe+6CE74 - 83 C4 30              - add esp,30 { 48 }
PlantsVsZombies.exe+6CE77 - C2 0400               - ret 0004 { 4 }

从下往上找,不难找到mov eax,[esp+18] 这一句,验证一下,在这一句下方设置条件断点

image-20210129004014334

断下

image-20210129004050900

根据前面的经验,我们知道[esp+xxx]是之前入栈的某个地址,而这里ebx正好等于eax,所以我们就可以将问题转为找ebx

从下往上接着寻找可以找到

PlantsVsZombies.exe+6CDF9 - 8B DE                 - mov ebx,esi { ebx被赋值 }

于是ebx又变成了esi,接着往上找可以找到

PlantsVsZombies.exe+6CD70 - 8D 74 24 14           - lea esi,[esp+14]        {这里的esp+14正好和下面赋值对应}
PlantsVsZombies.exe+6CD74 - 89 44 24 18           - mov [esp+18],eax
PlantsVsZombies.exe+6CD78 - 89 44 24 1C           - mov [esp+1C],eax
PlantsVsZombies.exe+6CD7C - 89 44 24 14           - mov [esp+14],eax
PlantsVsZombies.exe+6CD80 - E8 6BFBFAFF           - call PlantsVsZombies.exe+1C8F0                         { call }
PlantsVsZombies.exe+6CD85 - 84 C0                 - test al,al
PlantsVsZombies.exe+6CD87 - 0F84 DF000000         - je PlantsVsZombies.exe+6CE6C
PlantsVsZombies.exe+6CD8D - 8B 6C 24 30           - mov ebp,[esp+30]
PlantsVsZombies.exe+6CD91 - 8B 74 24 14           - mov esi,[esp+14]                 { esi被赋值 }
PlantsVsZombies.exe+6CD95 - 8B 46 1C              - mov eax,[esi+1C]
PlantsVsZombies.exe+6CD98 - 2B 47 1C              - sub eax,[edi+1C]
PlantsVsZombies.exe+6CD9B - BB 19000000           - mov ebx,00000019                         

这里我们可以找到mov esi,[esp+14],在这里的下一句下条件断点,验证是否是esi被赋值

image-20210129004650120

果然断下了,但这里我们发现没有寄存器的值和ESI相同,说明寄存器在入栈之后,又被改变了

image-20210129004810875

于是我们只能接着向上找push xxx,或者mov [esp+xx],xx ,这里找的是mov [esi],xx 因为上面的lea esi,[esp+14]是传址指令,相当于mov [esi],xx = mov [esp+14],xx

我们很快看到上面有个mov [esp+14],eax 在那里的下一句设置条件断点EAX==0x14EE1914,很可惜并没有断下,说明CALL里面有压入的参数,于是我们直接进入CALL中查看

image-20210129005559296

直接Ctrl+G,然后输入CALL后面的地址0041C8F0 即可跳转到CALL里面进行查看

image-20210129005916187

CALL里面的代码如下:

PlantsVsZombies.exe+1C8F0 - 57                    - push edi
PlantsVsZombies.exe+1C8F1 - BF 0000FFFF           - mov edi,FFFF0000 { -65536 }
PlantsVsZombies.exe+1C8F6 - 8B 06                 - mov eax,[esi]
PlantsVsZombies.exe+1C8F8 - 85 C0                 - test eax,eax
PlantsVsZombies.exe+1C8FA - 75 08                 - jne PlantsVsZombies.exe+1C904
PlantsVsZombies.exe+1C8FC - 8B 82 90000000        - mov eax,[edx+00000090]
PlantsVsZombies.exe+1C902 - EB 05                 - jmp PlantsVsZombies.exe+1C909
PlantsVsZombies.exe+1C904 - 05 5C010000           - add eax,0000015C { 348 }
PlantsVsZombies.exe+1C909 - 8B 8A 94000000        - mov ecx,[edx+00000094]
PlantsVsZombies.exe+1C90F - 69 C9 5C010000        - imul ecx,ecx,0000015C { 348 }
PlantsVsZombies.exe+1C915 - 03 8A 90000000        - add ecx,[edx+00000090]
PlantsVsZombies.exe+1C91B - 3B C1                 - cmp eax,ecx
PlantsVsZombies.exe+1C91D - 73 12                 - jae PlantsVsZombies.exe+1C931
PlantsVsZombies.exe+1C91F - 90                    - nop 
PlantsVsZombies.exe+1C920 - 85 B8 58010000        - test [eax+00000158],edi
PlantsVsZombies.exe+1C926 - 75 13                 - jne PlantsVsZombies.exe+1C93B
PlantsVsZombies.exe+1C928 - 05 5C010000           - add eax,0000015C { 348 }
PlantsVsZombies.exe+1C92D - 3B C1                 - cmp eax,ecx
PlantsVsZombies.exe+1C92F - 72 EF                 - jb PlantsVsZombies.exe+1C920
PlantsVsZombies.exe+1C931 - C7 06 FFFFFFFF        - mov [esi],FFFFFFFF { -1 }
PlantsVsZombies.exe+1C937 - 32 C0                 - xor al,al
PlantsVsZombies.exe+1C939 - 5F                    - pop edi
PlantsVsZombies.exe+1C93A - C3                    - ret 
PlantsVsZombies.exe+1C93B - 89 06                 - mov [esi],eax { 赋值}
PlantsVsZombies.exe+1C93D - 80 B8 EC000000 00     - cmp byte ptr [eax+000000EC],00 { 0 }
PlantsVsZombies.exe+1C944 - 75 B0                 - jne PlantsVsZombies.exe+1C8F6
PlantsVsZombies.exe+1C946 - B0 01                 - mov al,01 { 1 }
PlantsVsZombies.exe+1C948 - 5F                    - pop edi
PlantsVsZombies.exe+1C949 - C3                    - ret 

这个CALL比较简短,我们直接从下面找起 ,一下就找到了mov [esi],eax 可以下个条件断点验证一下

image-20210129011029891

果然断下

image-20210129011127073

于是问题又变成了找eax(这个14EE1914我们转了多少手寄存器了???)

接着向上找EAX,这里EAX上方是RET,则肯定是从上方的语句跳转过来的,

不难找到跳转过来的语句:

PlantsVsZombies.exe+1C926 - 75 13                 - jne PlantsVsZombies.exe+1C93B

于是从跳转过来的语句接着向上找EAX的赋值

PlantsVsZombies.exe+1C8F6 - 8B 06                 - mov eax,[esi]                        {eax赋值为[esi]内部的值}
PlantsVsZombies.exe+1C8F8 - 85 C0                 - test eax,eax                        {判断eax是否为0}
PlantsVsZombies.exe+1C8FA - 75 08                 - jne PlantsVsZombies.exe+1C904        {为0则不跳转}
PlantsVsZombies.exe+1C8FC - 8B 82 90000000        - mov eax,[edx+00000090]                        {eax赋值为[edx+90]}
PlantsVsZombies.exe+1C902 - EB 05                 - jmp PlantsVsZombies.exe+1C909        
PlantsVsZombies.exe+1C904 - 05 5C010000           - add eax,0000015C { 348 }
PlantsVsZombies.exe+1C909 - 8B 8A 94000000        - mov ecx,[edx+00000094]
PlantsVsZombies.exe+1C90F - 69 C9 5C010000        - imul ecx,ecx,0000015C { 348 }
PlantsVsZombies.exe+1C915 - 03 8A 90000000        - add ecx,[edx+00000090]
PlantsVsZombies.exe+1C91B - 3B C1                 - cmp eax,ecx
PlantsVsZombies.exe+1C91D - 73 12                 - jae PlantsVsZombies.exe+1C931
PlantsVsZombies.exe+1C91F - 90                    - nop 
PlantsVsZombies.exe+1C920 - 85 B8 58010000        - test [eax+00000158],edi
PlantsVsZombies.exe+1C926 - 75 13                 - jne PlantsVsZombies.exe+1C93B

我们通过汇编语句不难得出 EAX刚开始是由[ESI]赋值的,但刚开始为0的话则为[EDX+90]赋值,也可以从外面对CALL下断,分析EAX的赋值过程得到:头部由来是[EDX+00000090],每个僵尸的大小是15C,这里其实我们已经得到了僵尸数组的动态头部地址[EDX+90],我们接着追溯EDX,这里可以看一下动态地址的头部14EE0CD8,和我们的14EE1914相减得到C3C=3132        15C=348        3132/348=9,说明我们这个僵尸是由头部地址偏移了9个僵尸~~ 然后记录一下

image-20210129013745019

接着就是找EDX,此时EDX的值为14EDB520

到这里找EDX就直接在CE里搜索了(也可以汇编里接着向上找,但一是出于篇幅问题,二是留给大家练手当作业吧)

image-20210129122247763

CE里直接搜索14EDB520,也就是EDX的值,然后去掉第一个动态的地址,第二个就是了,这个大家应该都很熟练了

image-20210129122404999

image-20210129122425097

image-20210129122509689

image-20210129122547256

基址找到了,手动添加验证一下:

image-20210129122652158

正确得到当前的僵尸血量~~~我们的反汇编追踪之旅算是告一段落了

作业

实践是检验真理的唯一标准。这不来两份热乎的作业温习温习?

第一份作业就是上面说的,继续通过反汇编的方式,从下往上跟踪EDX,然后找到基址

第二份作业则利用到了我们找到的这个僵尸数组头部的赋值语句,我们都知道所有僵尸的产生都会在这里的代码通过,那么能否在这块代码HOOK,让僵尸直接GO DIE呢?这种全屏秒杀才算是真正的全屏秒杀,直接从源头将你弄死~~~现在大多数的全屏秒杀都是通过在僵尸移动的那一块代码直接修改僵尸的状态来实现的,但是别忘了最后的僵尸BOSS,它貌似没有移动吧?因此僵尸王无法被秒杀,秒杀不够完美。第二份作业要求:HOOK僵尸头部的这块代码,实现可以秒杀包括僵尸BOSS在内的所有僵尸

总结(注意事项)

反汇编找基址其实就是从下往上,寻找目标寄存器的来源,最终找到目标

寄存器中比较特殊的EBP和ESP,要通过寻找之前入栈的寄存器来获得赋值来源

入栈操作不仅仅是push xxx 指令 还有 mov [esp+xxx],xxx 或者先lea xxx,[esp+xxx],再mov [xxx],xxx等等

有的时候向上追代码的时候,会遇到明明还没攻击到僵尸却引发了中断,并且此时寄存器里的内容都不对,有可能是共用代码段,需要用条件断点来进行判断

找到赋值语句以后可以在那里下个断点,看是否执行以后寄存器内容被修改,验证语句来源的正确性

有时候会遇到很多跳转,但要记住,如果我们的语句执行了,那么跳过我们语句的跳转肯定是没有跳的,不然我们怎么执行?

遇事不决的时候找不到来源的时候多下断点,看看寄存器的变化,实在找不到就去函数头部下断,然后一步步单步步过,看在哪里寄存器的值发生了改变

个人感言(无关技术,可跳过)

白嫖了网络教程资源这么多年,都没写过技术教程,这次算是我的首次技术教程吧,能力不足,水平有限,欢迎大家指出我的不当之处,也请大家多多包涵一下,希望能够一起变强。

最后碎碎念一下:这个教程肝了我一晚上,太肝了。出这个教程的初衷是看到现在的找基址教程十个有九个是PVZ(夸张),但一个汇编追基址的都没有(可能有?),于是出一期看看反响如何,之后可能会接着出汇编硬追代码的系列教程,视大家的热情程度而定吧

点评

大多数用PVZ都是演示CE追基地址,游戏简单没必要od追基地址。成体系的教程或者培训肯定要教OD找call找基地址,这是外挂常识。你这么肝是因为没有观察堆栈规律,同一个数值重复回溯肯定累。  发表于 2021-2-26 12:10

免费评分

参与人数 38威望 +2 吾爱币 +139 热心值 +36 收起 理由
新手12138 + 1 + 1 我很赞同!
SacXismo + 1 + 1 我很赞同!
HOOK_XYS + 1 + 1 谢谢@Thanks!
gh0st_ + 1 用心讨论,共获提升!
kiss.传说 + 1 + 1 我很赞同!
yycmd + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
解白 + 1 + 1 我很赞同!
上官云遥 + 1 + 1 我很赞同!
32154678925 + 1 + 1 热心回复!
syncking + 1 + 1 我很赞同!
secretme + 1 + 1 我很赞同!
yaomaosong7 + 1 + 1 谢谢@Thanks!
朝闻道夕死可矣 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
LoveMiku233 + 1 + 1 我很赞同!
天上一朵云 + 1 用心讨论,共获提升!
sniper9527 + 1 + 1 谢谢@Thanks!
boyulin + 3 + 1 用心讨论,共获提升!
a2556483812 + 1 + 1 我很赞同!
某中二绅士 + 3 + 1 用心讨论,共获提升!
zhizunfan + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
sargwa + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
juewang1314 + 1 + 1 用心讨论,共获提升!
补补23456 + 1 + 1 我很赞同!
Hmily + 2 + 100 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
gunxsword + 1 + 1 我很赞同!
xiahhhr + 1 + 1 热心回复!
urufu + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
石碎大胸口 + 1 + 1 用心讨论,共获提升!
领悟者的涂鸦笔 + 1 自做5分钟,教程半小时
剑圣戏金莲 + 1 + 1 谢谢@Thanks!
色调分离 + 1 + 1 我很赞同!
nightforfire + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
lin1 + 1 + 1 用心讨论,共获提升!
国际豆哥 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Jack2002 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
世俗红尘 + 2 + 1 用心讨论,共获提升!
訫誶 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
fanvalen + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

fanvalen 发表于 2021-1-29 15:11
[Asm] 纯文本查看 复制代码
define(address,"PlantsVsZombies.exe"+166D10)
define(bytes,89 B5 C8 00 00 00)

[ENABLE]
assert(address,bytes)
alloc(newmem,$1000)

label(code)
label(return)

newmem:
//将计算怪的剩余血置零它就死亡了(只写了一句汇编mov esi,0)
mov esi,0
code:
  mov [ebp+000000C8],esi
  jmp return

address:
  jmp newmem
  nop
return:

[DISABLE]
address:
  db bytes
  // mov [ebp+000000C8],esi

dealloc(newmem)


根据你提供的普通僵尸血量我找了
做了一个秒杀普通僵尸的ct脚本
耗时不到1分钟,基本下次也有效
当然研究汇编是一种读懂代码的方式
我只最求效率不求过程那种方式方便快捷就用那种
[Asm] 纯文本查看 复制代码
define(address,"PlantsVsZombies.exe"+166896)
define(bytes,89 8F D0 00 00 00)

[ENABLE]
assert(address,bytes)
alloc(newmem,$1000)

label(code)
label(return)

newmem:
mov ecx,0
code:
  mov [edi+000000D0],ecx
  jmp return

address:
  jmp newmem
  nop
return:

[DISABLE]
address:
  db bytes
  // mov [edi+000000D0],ecx

dealloc(newmem)

这还有个秒高防的

[Asm] 纯文本查看 复制代码
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)

newmem:

mov [edi+000000DC],0
originalcode:
sub [edi+000000DC],esi

exit:
jmp returnhere

"PlantsVsZombies.exe"+1663FE:
jmp newmem
nop
returnhere:


 
 
[DISABLE]
dealloc(newmem)
"PlantsVsZombies.exe"+1663FE:
sub [edi+000000DC],esi
//Alt: db 29 B7 DC 00 00 00

最后来个秒手持防御的

免费评分

参与人数 3吾爱币 +3 热心值 +3 收起 理由
gaosld + 1 + 1 谢谢@Thanks!
a2556483812 + 1 + 1 我很赞同!
lyl610abc + 1 + 1 用心讨论,共获提升!

查看全部评分

 楼主| lyl610abc 发表于 2021-1-29 12:59

后续补充

本帖最后由 lyl610abc 于 2021-2-5 19:15 编辑

补充

首先感谢大家的评论和建议。这里先总结一下大家提出的问题:

  • 反汇编追代码太过繁琐:如果只是为了实现秒杀僵尸根本无需如此大费周章,现在的代码注入HOOK之类的实现功能更加快速、高效。
  • 看不懂

先说说看不懂如何解决:本教程面向的对象需要比萌新稍微强一丝丝,如果只是萌新可能还是有点吃力的,当然不排除个别能力很强的萌新,在学习之前可以先看看其它人的教程:如何找到阳光基址的以及指针和汇编的相关知识

不汇编定位僵尸头部数组

本教程主要还是带大家学习如何通过反汇编来分析和追踪基址,如果只追求实现的话确实大可不必

接下来给大家带来如何不通过反汇编追代码来得到僵尸数组的头部地址:

僵尸数组结构分析

我们已经知道所有僵尸都是存放在同一个数组即僵尸数组中的,而每个僵尸都是用相同的结构体,暂时将其为zombie结构体:

struct zombie{
    float visiblePositionX;        //x坐标(图像位置) 
    float visiblePositionY;        //y坐标(图像位置) 
    int visible;                        //是否可见
    int row;                                //所在行数
    .......................................
    int  hp;                                //当前血量
    int hpMAX;                                //血量上限
    .......................................
};

所有僵尸的结构体的属性(成员)都是相同的,则每个僵尸结构体的长度(存储空间)应该也是相同的

所以我们可以分析出

僵尸的地址=僵尸数组头部地址+n*僵尸结构体长度        (n为第几个僵尸)

实际操作

已经知道了僵尸的结构,前面我们可以通过血量减去偏移C8得出僵尸地址 那么我们可以定位两只僵尸,并获得它们的地址,这两个地址相减得到的数值一定就是僵尸结构体长度的整数倍,并且一般来说,前后产出的两只僵尸应该就是临近的,所以得到的差值应该就是僵尸结构体的长度。

首先我们要找到两只僵尸的血量,这里因为我们前面已经得到了僵尸扣血的那个反汇编代码:

PlantsVsZombies.exe+131319 - 89 BD C8000000        - mov [ebp+000000C8],edi        {血量被赋值}

于是我们可以在这里右键找出指令访问的地址来找到僵尸的血量

image-20210129171456500

image-20210129171733700

轻松定位到了,然后我们将这两个地址加入列表

image-20210129171833349

接着再将两个地址相减(因为它们都加上了C8的血量偏移,所以直接相减不影响结构体长度的计算结果)得到:

image-20210129172005546

我们得出了和我们之前辛辛苦苦找到的每个僵尸占用空间大小一样的数值15C

得到这个关键数值后,我们就可以从当前僵尸地址开始,减去n*15C,n从1开始不断加1,直到明显出现有异于僵尸血量的数值,则最后一个符合僵尸血量的数值就是僵尸数组头部地址+C8

image-20210129172518931

image-20210129172530112

由此我们可以得出结论当前僵尸地址-8*15c-c8就可以得到僵尸数组的头部地址

image-20210129172703633

可以根据我们之前找到的指针来验证是否就是僵尸数组头部地址

image-20210129172746905

于是我们就不费吹灰之力地收割了僵尸头部数组

最后

更新新教程了:https://www.52pojie.cn/thread-1366757-1-1.html
感谢大家的评论和支持,欢迎讨论,希望我们能一起学习,一起进步~~~

fanvalen 发表于 2021-1-29 13:41
我就比较懒从不找基址,直接在作用代码段改汇编,然后找个特征码定位这个汇编地址,因为代码生成程序后基本不变,改变的只有在内存中的位置
skymilong 发表于 2021-1-29 13:23
主要是之前的教程都在教如何实现什么效果,楼主辛苦
 楼主| lyl610abc 发表于 2021-1-29 13:30
skymilong 发表于 2021-1-29 13:23
主要是之前的教程都在教如何实现什么效果,楼主辛苦

论坛的markdown格式对图床的图片有点问题,刚刚进去手动修改了一下
图片已经可以了吧
世俗红尘 发表于 2021-1-29 14:16
虽然看不懂
geleisisisi 发表于 2021-1-29 14:24
非常棒的教程,反追代码的思路非常值得学习
但是现实操作起来,如果只是为了基址性价比太低了
列明 发表于 2021-1-29 14:28
腦子:
我沒看會!

手:
這次你終於說了句實話!
zhouxinyi 发表于 2021-1-29 15:09
死追基址太费力费神费眼睛,所以有时候偷懒,能得到大致相同结果就好了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-15 08:51

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表