008 数据结构逆向—数组(简单版)

前言

对于游戏逆向来说,核心需求其实就只有两个

  1. 追踪游戏数据
  2. 定位游戏功能call

对于追踪游戏数据来说,单纯从一个寄存器或者内存往上追踪到这个数据的基址是较为简单的,难点在于如何通过这一个数据,找到整个数据结构。

这里先抛出三个问题

  1. 对于人物背包来说,可以通过背包物品的数量所在的地址追踪到基址,但是怎么通过物品数量找到整个背包的数据及其附带属性?
  2. 对于人物血量来说,可以通过血量所在地址追出一个基址,但是怎么通过血量的地址从而追到整个人物的属性?
  3. 同样对于人物血量来说,怎么通过人物血量找到周围所有事物包括NPC 周围怪物等等的属性及坐标?

想要解决上述的问题,就必须学会如何逆向分析程序中的数据结构,上述三个问题,对应了三种数据结构,分别是数组 链表和二叉树。这三个数据结构也是游戏里最常用的。

我们先用口袋西游,来学习一个简单版本的数组。

逆向背包数组

一维背包数组

这一次我们要逆向的目标是整个背包的物品,通过数据追踪的方式找到所有的背包物品及属性。切入点可以是背包中任意一个物品的属性,比如数量。

在这里插入图片描述

首先搜索背包中血药的数量

在这里插入图片描述

第二次搜索即可得到唯一一个结果,然后在OD中对这个地址下硬件写入断点,断点断下

在这里插入图片描述

断下的位置上一句就是写入的代码,[ecx+0x14]是当前物品的数量。那么我们就要往上追ecx,由于这个位置已经是函数头的位置了,我们需要返回上一层继续找ecx

在这里插入图片描述

ecx来源于esi,而esi来源于[eax+ebx*4]。这是一个典型的数组下标访问的代码。C++代码如下:

int arr[10];
DWORD iNum=a[i];

eax相当于是arr数组的首地址,ebx相当于是数组的下标,通过对下标取不同的值可以访问到不同的数组成员。

接着我们在这个位置下断点,观察eax和ebx的值

在这里插入图片描述

ebx的值正好和当前药品所在的第几个格子数,然后再吃另外一个药。ebx的值和当前物品的背包格子数也是一样的。

也就是说整个背包的物品是用一个数组来存放的,数组的下标代表的是物品所在的格子数。

问题在于,当前的背包有三个,分别是普通 任务和时装,理论上来说应该有三个数组,那么另外两个在哪呢?继续往上追就能得到答案。

先来回顾一下当前物品的偏移表达式

血药数量=[[eax+i*4]+0x14] 

然后我们继续往上追eax

在这里插入图片描述

eax来源于[edi+C],edi来源于ecx,所以

血药数量=[[[ecx+0xC]+i*4]+0x14] 

返回上一层,继续追ecx
在这里插入图片描述

ecx,来源于esi

血药数量=[[[esi+0xC]+i*4]+0x14] 

在这里插入图片描述

esi来源于[esp+0x1C]

在这里插入图片描述

[esp+0x1C]来源于eax,那么

血药数量=[[[eax+0xC]+i*4]+0x14] 

继续追eax,eax作为返回值来源于上一个call,进入call内部

在这里插入图片描述

这个call的内部代码的分支比较多,这里可以先单步F7走一遍,然后用减号键回退的方式整理代码执行流程

在这里插入图片描述

eax来源于[ecx+0xAD8]

血药数量=[[[[ecx+0xAD8]+0xC]+i*4]+0x14] 

在这里插入图片描述

返回上层ecx来源ebp,ebp来源ecx,表达式不变,继续返回上一层函数追ecx

在这里插入图片描述

ecx来源于上上层函数的eax,eax作为返回值,继续进上面的call,追eax

在这里插入图片描述

血药数量=[[[[[ecx+8]+0x28]+0xAD8]+0xC]+i*4]+0x14

二维背包数组

返回上层继续找ecx

在这里插入图片描述

这里我们又看到了一个数组的访问代码,在这个地方下个断点,发现eax的值为0

血药数量=[[[[[[ebp+0*4+1C]+8]+0x28]+0xAD8]+0xC]+i*4]+0x14

这个地方大概是一个二维数组,eax是数组下标,0代表第一个普通背包,1代表第二个任务背包,2代表第三个时装背包。

继续往上追ebp

在这里插入图片描述

ebp来源[eax+0x8],eax来源于[ebx+4],ebx来源ecx

血药数量=[[[[[[[[ecx+4]+0x8]+0*4+1C]+8]+0x28]+0xAD8]+0xC]+i*4]+0x14

继续找ecx

在这里插入图片描述

来源[edi+0x68]

血药数量=[[[[[[[[[edi+0x68]+4]+0x8]+0*4+1C]+8]+0x28]+0xAD8]+0xC]+i*4]+0x14

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cLGVTuAQ-1587393010884)(008 数据结构逆向—数组(简单版)].assets/1587390974080.png)

edi来源ecx

血药数量=[[[[[[[[[ecx+0x68]+4]+0x8]+0*4+1C]+8]+0x28]+0xAD8]+0xC]+i*4]+0x14

继续返回上层追ecx

在这里插入图片描述

ecx来源ebp

血药数量=[[[[[[[[[ebp+0x68]+4]+0x8]+0*4+1C]+8]+0x28]+0xAD8]+0xC]+i*4]+0x14

在这里插入图片描述

ebp来源ecx

血药数量=[[[[[[[[[ecx+0x68]+4]+0x8]+0*4+1C]+8]+0x28]+0xAD8]+0xC]+i*4]+0x14

在这里插入图片描述

ecx来源于[ebp+0x1C],而ebp是一个基地址,那么这个偏移表达式就已经追完了

血药数量=[[[[[[[[[[0xD11A50+0x1C]+0x68]+4]+0x8]+0*4+1C]+8]+0x28]+0xAD8]+0xC]+i*4]+0x14

数组结构分析

这里可以把整个偏移表达式分为三部分

背包物品数组首地址=[[[[[[[[[0xD11A50+0x1C]+0x68]+4]+0x8]+0*4+1C]+8]+0x28]+0xAD8]+0xC]
背包背包物品数组下标=i*4
背包物品属性偏移=0x14

接着我们在内存中查看一下数组首地址的内存

在这里插入图片描述

这里是一个DWORD类型的对象数组,每一个成员都是一个物品对象,找到第六个我们的血药的对象地址,数据窗口跟随
在这里插入图片描述

其中+14的位置是当前的血药数量,借用这个数据可以猜测一下+018的位置是3E7,十进制的999,应该是物品的最大数量。其他的每一个成员都是物品的属性

总结

到这里我们就完成了从物品数量到整个背包的数据结构分析的过程,识别数组结构的关键在于是否有汇编通过下标的方式访问内存

mov esi,dword ptr [eax+ebx+4];

这个数组结构仅仅是一个简单版本的,下次我们再来分析一个困难版本的数组。

最后,附上Github地址,里面有游戏下载链接和相关工具,需要请自取:
https://github.com/TonyChen56/GameReverseNote

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鬼手56

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值