zoukankan      html  css  js  c++  java
  • 植物大战僵尸无冷却分析

    植物大战僵尸无冷却分析

    起因

    网上已经有很多帖子分析植物大战僵尸冷却的。有的看不出是个什么逻辑,一会搜索1,一会搜索0的,看不出来是什么门道。

    没办法只能自己操刀按自己的想法分析看看了,就当学习。

    准备工具

    • x32dbg
    • 植物大战僵尸
    • Cheat Engine 7.1

    过程

    先把阳光数量变成可控的,阳光基址就不说怎么找了。其实不找也行只要把阳光变的多点就行,目的就是能随时用阳光。

    按照网上的思路反复搜索1,搜索0的确是能做到无CD,但是看不出门道。换一个思路,冷却时间是最为直观的。就是种上植物之后,卡片会变成冷却状态,有一个冷却进度,如下图的豌豆射手。

    image-20201225211205630

    所以目标就是先搜索出来记录这个冷却时间的地址。

    这个冷却时间有两种可能,

    1. 种上植物后,程序设置一个冷却时间,之后慢慢的往下减,减到0冷却就没了。
    2. 种上植物后,程序将变量置0,开始计时,慢慢的增加,增加到某个阈值,就是无冷却了。(其实是这个)

    搜索方法为了统一,不管它是增加计时,还是减数计时,搜索方法就一个。

    搜索记录冷却时间的地址

    搜索方法

    1. 搜索未知的初始值
    2. 冷却阴影变动,就再搜索变动了的数值
    3. 未发现第一格冷却计时地址,接着重复第2步

    先用CE附加植物大战僵尸进程。

    接着种上植物,CE搜索未知的初始值。

    首次扫描

    image-20201225213248582

    冷却阴影变动后按下图操作

    再次扫描

    image-20201225213604224

    一直重复再次扫描的步骤,慢慢的筛选,当一个冷却结束后,可以再种一个植物(必须是同一格)。

    其实中间可以穿插一些未变动的数值搜索,这样可以更快的检索出结果来。

    搜索结果

    image-20201225214626128

    看动图可以种植的时候是0,有冷却时间的时候随时间增长。

    zwzdjssq12

    很明显就是第一格的冷却时间,把他拉下来,右击后选择「找出是什么改写了这个地址」

    image-20201225220434452

    记录下改写指令的汇编地址004B2FEA

    image-20201225220818798

    实现无冷却

    CE 先使用一阶段,关掉CE,打开X32dbg附加植物大战僵尸

    image-20201225221130189

    按下Alt+A附加上植物大战僵尸进程

    image-20201225221242752

    Ctrl + g到跳转窗口,跳转到刚刚记录下来的004B2FEA地址。

    image-20201225221640322

    跳转到地址004B2FEA指令处的分析。

    image-20201225222524355

    // 伪代码大概就是这个意思
    // ...
    coolDownTime++;
    if ( coolDownTime > 当前植物的冷却需要的总时长) {
        // 取消冷却 
        cancelCooling(当前植物);
    }
    // ...
    

    实现无冷却有一下两种方法。

    方法一

    nop掉004B2FF3跳转指令

    image-20201225223333171

    方法二

    把比较换成与0比较

    // 改成这个样子
    // ...
    coolDownTime++;
    if ( coolDownTime > 0) {
        // 取消冷却 
        cancelCooling(当前植物);
    }
    // ...
    

    image-20201225223547239

    这样改过之后打上补丁玩个游戏就没意思了,可以用CE代码注入,实现动态修改。

    这里只演示第二种方法,第二种会了第一种方法就是大同小异。

    x32dbg剥离植物大战僵尸进程

    image-20201226220554244

    CE附加上植物大战僵尸进程,点击查看内存。

    image-20201226220656272

    ctrl + g跳转到刚记录的004B2FEA指令地址(就是+1指令的地址)

    image-20201226220953310

    实现的是第二种方法,所以我们选中下面这条指令

    PlantsVsZombies.exe+B2FF0 - 3B 47 28              - cmp eax,[edi+28]
    

    image-20201226221247759

    安下面图片一步一步来

    image-20201226221407775

    image-20201226221539274

    image-20201226221630868

    下面是生成出来的代码,没有任何改动

    image-20201226221831655

    修改后的代码

    image-20201226222017507

    [ENABLE]
    //code from here to '[DISABLE]' will be used to enable the cheat
    alloc(newmem,2048)
    label(returnhere)
    label(originalcode)
    label(exit)
    
    newmem: //this is allocated memory, you have read,write,execute access
    //place your code here
    
    originalcode:
    // cmp eax,[edi+28]
    cmp eax, 0
    jle PlantsVsZombies.exe+B3007
    
    exit:
    jmp returnhere
    
    "PlantsVsZombies.exe"+B2FF0:
    jmp newmem
    returnhere:
    
     
    [DISABLE]
    //code from here till the end of the code will be used to disable the cheat
    dealloc(newmem)
    "PlantsVsZombies.exe"+B2FF0:
    cmp eax,[edi+28]
    jle PlantsVsZombies.exe+B3007
    //Alt: db 3B 47 28 7E 12
    

    接着就是分配到当前的CT表,保存完这个页面就可以关了。

    image-20201226222123239

    在主界面就能看到刚刚保存的脚本

    image-20201226222301695

    这样可以动态修改指令。勾上就是无冷却,取消就是正常代码。

    第一种方法和第二种方法都可以实现,第一种方法留下自己实现吧。

    看看效果

    lq

    游戏,索然无味。

    到这里还没有结束,不是为了实现冷却,而是尽量的多分析一下看看。

    继续深入一点分析-挖掘基址

    把刚刚汇编的地方还原,跳出当前函数看看上一层的逻辑。

    断在004B2FEA之处后,先点击运行到返回 => 在单步步过一下 ( 或者双击右下角堆栈窗口的0019F9EC地址数据,也可以跳转到上一层逻辑)

    image-20201225225145077

    上一层函数的逻辑

    image-20201225225921563

    形成伪代码就是

    // ...
    cardList = [豌豆射手, 向日葵, 樱桃炸弹 ....]
    cardCount = [eax + 24] // 当前可使用的植物卡片数量
    count = 0              // xor ebx, ebx
    if (cardCount > 0) {
        do {
        	card = cardList[count];
        	handlerCard(card);  // 最开始分析的call, 里面执行+1 重置冷却时间
        	count++;    	
        } while(count < cardCount);
    }
    // ...
    
    

    逻辑大致是清晰了,现在找基址一下基址。现在关注一些上下文信息

    image-20201225231801986

    # 汇编语句
    00428E40            | 8B87 5C010000        | mov eax,dword ptr ds:[edi+15C]        |
    00428E46(断点处EIP)  | 33F6                 | xor esi,esi                           | esi = 0
    00428E48            | 3958 24              | cmp dword ptr ds:[eax+24],ebx         | [eax + 24] 是格子数量   最上面(xor ebx, ebx)
    00428E4B            | 7E 1B                | jle plantsvszombies.428E68            | if
    00428E4D            | 8D49 00              | lea ecx,dword ptr ds:[ecx]            |
    00428E50            | 8D4403 28            | lea eax,dword ptr ds:[ebx+eax+28]     | 这是数组
    00428E54            | E8 57A10800          | call plantsvszombies.4B2FB0           | 刚刚分析的就是这个call
    00428E59            | 8B87 5C010000        | mov eax,dword ptr ds:[edi+15C]        |
    00428E5F            | 46                   | inc esi                               | i++
    00428E60            | 83C3 50              | add ebx,50                            |
    00428E63            | 3B70 24              | cmp esi,dword ptr ds:[eax+24]         | esi < [eax + 24]
    00428E66            | 7C E8                | jl plantsvszombies.428E50             |
    # 寄存器信息
    EAX : 19B9EC90
    EBX : 00000000
    ECX : 0000019E
    EDX : 00000163
    EBP : 0019FA5C
    ESP : 0019F9F0
    ESI : 1FF12C18
    EDI : 200DB408
    EIP : 00428E46
    

    call plantsvszombies.4B2FB0需要传入植物卡片的地址([ebx+eax+28] ),eax 是上下文提供的,ebx是偏移相当于高级语言中i++的作用。

    现在eax 的值不确定,有两种方法,

    1. 一个是向上看eax是谁给的,慢慢向上一层一层的找
    2. 使用CE搜索eax寄存器的值19B9EC90。(eax = [edi+15C], 搜索edi(200DB408)就行)

    我选择第二种,因为第一种我试过了,不好使不方便。

    第二种方式:x32dbg剥离植物大战僵尸进程。

    image-20201225232827074

    换成CE加载,搜索edi寄存器的值200DB408(注意先勾上十六进制

    image-20201225234628935

    拉下来右键=>『找出是什么访问了这个地址』。

    搜索ESI值0295B120

    基址都记录下来吧,以后可能都会用到。(其实随便选一个就行)

    <Address>PlantsVsZombies.exe+3794F8</Address>
    <Address>PlantsVsZombies.exe+37959C</Address>
    <Address>PlantsVsZombies.exe+379670</Address>
    <Address>PlantsVsZombies.exe+379618</Address>
    

    组合分析使用基址

    // 猜测
    CARDS {
        // ....
        int count;     // +24
        Card list[X];  // +28  每个Card大小为50  
        // 后面分析这个数组好像是固定长度  控制 [CARDS + 0x24] 可以扩容和减少格数
        // 设置超过数组的 size 就会程序异常
        // .....
    }
    
    //植物卡片对象 地址
    CARDS = [[[PlantsVsZombies.exe+379618] + 0x868] + 0x15C]
    //植物卡片个数  可以实现扩容和减少格数
    [CARDS + 0x24]
    // 第N格植物卡片地址 N > 0
    [0x50 * N + CARDS + 0x28]
    // 第N格植物卡片地址 N > 0 冷却记录
    [0x50 * N + CARDS + 0x28 + 0x24]
    // 第N格植物卡片地址 N > 0 冷却时间
    [0x50 * N + CARDS + 0x28 + 0x28]
    // 模块起始地址
    00400000 - PlantsVsZombies.exe
    

    有了这些分析就可以写代码了。

    Python 实现辅助

    下面放一部分,具体的全部代码可以看附录里面的代码,大多读写内存的操作都是封装的Win32Api(还不如用C++写)

    # 省略 .......
    pid = get_pid("PlantsVsZombies.exe")
    print("PlantsVsZombies.exe 进程id: " + str(pid))
    processHandle = open_process(pid)
    
    def showCard(processHandle):
        count = plant_cards_count(processHandle)
        os.system("cls")
        x = PrettyTable(["格子", "当前冷却时间", "总时间"])
        for n in range(count):
            plant_info = get_plant_n(processHandle, n)
            x.add_row([n+1, plant_info["cooling"], plant_info["cool_time"]])
        title = "阳光:{}".format(getSunCount(processHandle))
        print(x.get_string(title=title))
    
    def drawTable():
        while True:
            showCard(processHandle)
            time.sleep(1)
    # 滚动滚轮
    def on_scroll(x, y, dx, dy):
        # dy == -1 下滑
        # dy ==  1 上滑
        sunCount = getSunCount(processHandle)
        setSunCount(processHandle, sunCount + (5 * dy))
    # 省略 .......
    

    效果:向上滚动滚轮增加阳关,向下滚动滚轮减少阳关(注意动态中阳关的变化)。可以看到有几个格子,冷却时间,总时间。

    231

    修改的功能就只有一个阳光,其他的就不写了。有兴趣的可以下载附件中的CT(里面包含无冷却,格子数量的控制功能)。

    总结

    整个过程的分析是完成了,就像开篇说的搜索1/0的方法还是没有探索出来是怎么影响的,知道『原理』的可以撩一撩,是从什么角度分析的,学习一下。

    文中提到的方式都可以实现无冷却,分析过程中也随便扒拉出了其他信息,比如当前格子的冷却,当前植物冷却时间的总时间,还有格子数量[CARDS + 0x24]。分析该到一段落了,大多分析结果都是通过少量已知的上下文条件,和我的经验推断出来的(不一定准确),如有异议可以回帖交流啦。

    前往下载附件

  • 相关阅读:
    高效、稳定开发功能的一些心得
    记录一些遗忘的程序基础知识
    Linux NFS
    Nginx Upstream模块
    Redis命令总结
    手动搭建redis集群(3台)
    laravel使用总结(二)
    InnoDB体系架构总结(二)
    laravel 设计思想简单了解
    Redis原理及集群相关知识
  • 原文地址:https://www.cnblogs.com/pi-laoban/p/14559025.html
Copyright © 2011-2022 走看看