剑网三怪物二叉树分析

一、用ce找出怪物血量

1.png

已知怪物血量是可见的。攻击前先搜一次血量,每次攻击都搜一次。剑网三这个游戏是64位的,但是一开始是从32位转变过来的,大部分数据类型基本上都是32位的。所以用4字节搜血量

2.png


对这个地址进行访问,并且攻击怪物

3.png

任意找一条跟就可以了,我找的是我鼠标选中的这一条。根据经验,大致应该八成可以肯定这个r8是怪物对象,那么我们只要往上跟踪找出怪物对象的来源就可以了。这类情况我会选择偷懒上IDA。

二、dump游戏用IDA分析

可以用x64dbg附加上后,使用scylla插件来dump游戏内存。

然后拖进ida。注意用64位的ida。

跳转到刚才ce找到的相应位置

4.png

红箭头是刚才找到的位置。我们应该从这往上找到R8寄存器里值得来源。可以看到黄色箭头,R8来源于rax。根据经验rax来源八成来自于绿框的call。

所以我们进入call。F5

5.png

看到这个伪代码可以先观察一手。

已知这个call返回的是当前被攻击的怪物的对象。所以直接可以看result = v4[5]

这个可以看成v4 + 0x28

看到上面有个while循环。判断*(BYTE*)(v5+0x19)的值。等于1就退出循环。

再看下面的代码 判断 v5+8的值是否大于a2。a2来源于上一层的参数。

这个判断是和否都不会立刻跳出循环。会把v5的值存放在v4。而v4又是最后怪物对象的关键数据。

所以这个a2可以猜测是个标志。能够确认当前怪物的标识。那么这个while就可以看成是在遍历怪物了,通过标识取出当前攻击的怪物对象。这个结构结合起来已经很明显了,这是个二叉树。

v5[0]是左树 ,v5[2]是右树 ,v5 + 0x19 里的值等于1的话应该是树到尾部了。

那么只需观察最上面的参数a1。a1很明显是个二叉
 

6.png


树相关的值。

黄色箭头是刚才进入的call。

根据ida分析。我们需要寻找这个call的第一个参数。根据基础知识,可以知道第一个参数是ecx。那么就找到了红色箭头处。显而易见。接来下敲代码遍历它。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

void PlayClass::GetPlayTree(DWORD64 StartAddress,int LocalFlag)

{

    if (StartAddress)

    {

        if (ReadMemory<BYTE>(StartAddress + 0x19== 0)

        {

            shared_ptr<PlayInfo>Player(new PlayInfo);

            DWORD64 PlayerObject = ReadMemory<DWORD64>(StartAddress + 0x28);

            strcpy(Player->m_Name, (char*)(PlayerObject + PlayNameOffset));

            if (ReadMemory<DWORD32>(StartAddress + 0x20== LocalFlag)

            {

                Player->m_FlyStatus = ReadMemory<DWORD32>(PlayerObject + PlayFlyStatusOffset);

                Player->m_FlyValue = ReadMemory<DWORD32>(PlayerObject + PlayFlyValueOffset) / 100;

                Player->m_BestFlyValue = ReadMemory<DWORD32>(PlayerObject + PlayFlyBestValueOffset) / 100;

                Player->bIsLocal = true;

            }

            Player->m_Flag = ReadMemory<DWORD32>(PlayerObject + PlayFlagOffset);

            Player->m_Object = PlayerObject;

            Player->m_Hp = ReadMemory<DWORD32>(PlayerObject + PlayHpOffset);

            Player->m_BestHp = ReadMemory<DWORD32>(PlayerObject + PlayBestHpOffset);

            Player->m_Mp = ReadMemory<DWORD32>(PlayerObject + PlayMpOffset);

            Player->m_BestMp = ReadMemory<DWORD32>(PlayerObject + PlayBestMpOffset);

            Player->m_pos.m_x = ReadMemory<DWORD32>(PlayerObject + PlayXOffset);

            Player->m_pos.m_y = ReadMemory<DWORD32>(PlayerObject + PlayYOffset);

            Player->m_pos.m_z = ReadMemory<DWORD32>(PlayerObject + PlayZOffset);

            Player->m_Level = ReadMemory<DWORD32>(PlayerObject + PlayLevelOffset);

            m_PlayInfo.push_back(Player);

            DWORD64 TreeLeft = ReadMemory<DWORD64>(StartAddress);

            GetPlayTree(TreeLeft, LocalFlag);

            DWORD64 TreeRight = ReadMemory<DWORD64>(StartAddress + 0x10);

            GetPlayTree(TreeRight, LocalFlag);

        }

    }

}

7.png

结束

第一次发帖,好紧张,不要喷我。呜呜呜

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值