008 数据结构逆向—数组(简单版)
文章目录
- 前言
- 逆向背包数组
- 一维背包数组
- 二维背包数组
- 数组结构分析
- 总结
前言
对于游戏逆向来说,核心需求其实就只有两个
- 追踪游戏数据
- 定位游戏功能call
对于追踪游戏数据来说,单纯从一个寄存器或者内存往上追踪到这个数据的基址是较为简单的,难点在于如何通过这一个数据,找到整个数据结构。
这里先抛出三个问题
- 对于人物背包来说,可以通过背包物品的数量所在的地址追踪到基址,但是怎么通过物品数量找到整个背包的数据及其附带属性?
- 对于人物血量来说,可以通过血量所在地址追出一个基址,但是怎么通过血量的地址从而追到整个人物的属性?
- 同样对于人物血量来说,怎么通过人物血量找到周围所有事物包括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
008 数据结构逆向—数组(简单版)相关推荐
- 009 数据结构逆向—数组(困难版)
文章目录 前言 数组逆向 通过人物血量查找人物属性 调call取对象 call内追局部变量 逆向加密数组下标 分析人物属性 总结 前言 通过之前的分析,我们已经对数组结构有了一个简单的了解,这次就用幻 ...
- 数据结构练习题――Hero In Maze 简单版
数据结构练习题――Hero In Maze 简单版 时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte 总提交:306 ...
- 基于java的数据结构学习——数组实现的栈以及简单应用C++实现
基于java的数据结构学习--数组实现的栈以及简单应用的 C++ 实现 源码: // // Created by PC-Saw on 2019/1/3. //#ifndef DATA_STRUCTUR ...
- Java版数据结构之数组模拟环形队列demo
Java版数据结构之数组模拟环形队列demo 我的代码仓库:https://github.com/zhuangbinan/datastructure 类 CircleArray package clu ...
- 资料分享:送你一本《数据结构(C语言版)》电子书!
要想写出可复用.可扩展.易维护.灵活性好的代码,「数据结构」这一关必须要过啊! 在数据结构与算法的众多教材中,奉为经典的当属清华大学严蔚敏老师的著作.很多学校也选择这本书作为考研指定教材. 正在学习数 ...
- 资料分享:送你一本《数据结构(C#语言版)》电子书!
对于信息类专业的学生而言,数据结构与算法是一门必修的课程.只有学好这门课程,熟练掌握线性表.栈.队列.树.图等基本结构,以及在这些结构上的各种算法,才能利用计算机去解决实际问题. 如何学好这门课程呢, ...
- 数据结构(C语言版) 第 八 章 排序 知识梳理 + 习题详解
目录 一.归并排序 二.交换排序 1.快速排序 2.冒泡排序 三.插入排序 1.直接插入排序(基于顺序查找) 2.折半插入排序(基于折半查找) 3.希尔排序(基于逐趟缩小增量) 四.选择排序 0.直接 ...
- 数据结构(C语言版) 第 六 章 图 知识梳理 + 习题详解
目录 一. 图的基本定义和术语 一.图的基本概念 1.度 2.连通 (1)连通图 (2)强连通/强连通图 3.回路 4.完全图 二.图的三种存储结构 1.邻接矩阵表示法 2.邻接表(链式)表示法 3. ...
- 数据结构(C语言版) 第二章 线性表 知识梳理+作业习题详解
目录 一.线性表顺序存储结构(顺序表) 0.线性表的基本概念 1.样例引入:多项式相加 二.线性表链式存储结构(链表) 0.链表的基本概念 1.前插法代码实例 2.链表尾插法完整代码附带各种操作 三. ...
最新文章
- 高处看Surface,WIndow,View,SurfaceView
- 获取init程序的调试信息和uevent的调试信息需要打开的两个宏
- 我对北京印象之10年前后
- jQuery的JSONP
- 【机器学习】特征提取代码汇总
- Google play billing(Google play 内支付)
- docker centos 环境 安装 python
- GNU make manual 翻译(八十二)
- 黑鲨游戏手机2 Pro跑分曝光:搭载骁龙855 Plus实锤
- hive 查询是否包含字符串_oracle判断一个字符串中是否包含另外一个字符串
- HTML5期末大作业:体育主题网站设计——足球(9页) HTML+CSS+JavaScrip校园篮球网页作业成品 学校篮足球网页制作模板 学生简单体育运动网站设计成品
- 鸟哥linux命令小结
- 【一起学数据结构与算法分析】第二篇:字谜游戏
- 秒杀活动,怎么设计全套技术方案
- h5页面如何预览excel文件_kintone excel预览插件
- ISV的想法,用友全都懂
- 从JMM到CAID再到分布式事务-1
- Google Play In-app Billing 踩过的那些坑
- 电子商务安全欺诈预防市场现状研究分析-
- W3C标准包括什么?
热门文章
- DL之MaskR-CNN:基于类MaskR-CNN算法(RetinaNet+mask head)利用数据集(resnet50_coco_v0.2.0.h5)实现目标检测和目标图像分割(语义分割)
- RL之DQN:基于TF训练DQN模型玩“打砖块”游戏
- deap实战_2017中国数学建模大赛_B题_第二题
- 8.2 TensorFlow实现KNN与TensorFlow中的损失函数,优化函数
- 逻辑回归模型详解(Logistic Regression)
- vs2017 不能加载.vdproj
- Python爬虫之Scrapy框架使用selenium
- 迭代器和生成器的区别
- ASP.NET Core 1.1 Preview 1 简介(包含.NETCore 1.1升级公告)
- 三十九、Android原理 不需要关闭后台运行程序