PJ一个小游戏
最近发现一个PC移植安卓的单机小游戏挺有意思(游戏名称ZTcgYmIgYWYgZTggODkgYjIgZTQgYmYgYWUgZTQgYmIgOTkgZTUgYmQgOTU=),于是试着玩了下,发现还不错,就是人物太穷了买不起漂亮的衣服😜,我这现实中是个穷X就算了,游戏里我还能惯着它,直接开搞
准备阶段
第一步
当然是下载啦,这游戏还算挺大的
拖到jadx里看看
哎哟,木有加固。再仔细看看看,我们好像发现了点什么,这是不是Web组件😏
直接去asset目录下看看
哦豁,发现了一些东东
解压出来跑跑
一般遇到这种类型的App,都可以直接解压出来尝试一下在本地直接运行一下试试
哦豁,报错了,这种情况下我们进入下一步
启动一个http服务
一般遇到这种类型的App,都可以直接解压出来尝试一下在本地跑一下,或者直接就起一个http服务试试。
此时Python同学飘过并留下一行命令:
python3 -m http.server 8088 # 启动一个简单http服务
再次访问
浏览器中输入http://127.0.0.1:8088
,然后就可以发现运行起来了
只要浏览器中运行起来,那就可以开搞了😯
分析
经过准备阶段后我们发现这其实算是个网页游戏,而且我们连源码都拿到了,那就先去看一下源码吧
我们要什么
首先需要确定我们需要什么,呐做人呢最重要的就是开心咯,怎么开心呢,有钱人的快乐我想象不到,在游戏里做个富翁体验体验嘛好了。所以在这个游戏里也就是这两个
搜索一下关键字
知道了我们要什么,那么这时候就可以去源码中搜索一下看看有木有相关内容
emmm,还行,结果不多,我们先找找有没有我们需要的信息
找到了配置文件,然后我们拿到了我们需要的某些信息,这个现在暂时先留着
找一个切入点
任何分析都要有个切入点才可以,这个app的切入点我定在了个人信息界面,因为这个界面会展示用户的灵石数量😜,图片在上面,这里就不贴了
确定切入点后我们这时候需要找到界面上对应的获取灵石的方法去追溯信息是从哪里取出来的,此时还是搜索“灵石”好了,如果“灵石”中找不到就再找找其他的信息。
哎哟,看看我们又发现了什么
调试
经过上面几步操作后,我们已经掌握了不少信息了,此时就需要调试一下看看,验证一下我们的思路是不是正确的
-
F12->源代码->找到对应方法->下断点
-
运行至断点处
由于我们判断此处是人物信息界面,所以我们打开人物信息界面应该就是在断点处停下
此时我们可以看到已经在断点处停下了。注意:此时如果我们只是改变人物信息的展示可以直接修改goldItemNumber但是这可能仅仅是展示出现了变化,实际消费是消费不了的,所以我们要追踪一下更深层次的调用。
-
单步调试
我们点击F11(单步执行下一个函数调用)或者上图的左起第三个按钮,具体是单步进入还是F10(单步跳过)视情况而定,需要跟踪下一个函数就F11,如果不关注下一个函数的执行情况就F10。
此处我们需要了解一下goldItemNumber的值从何而来,所以我们就跟到每一个方法中去看下
这一步我们进入了numItems方法中并且看到了此方法返回了几个值,增加断点查看一下,此处我打的三个断点是最开始调试的时候断的,实际上不打断点直接调试也可以正常进行。
-
继续调试
开始调试itemContainer,进入方法后我们发现,传入的参数“item”即为需要获取信息的对象,而方法中的return this._items;
就是返回的具体值。
此时我们可以在控制台打印一下“_items”
-
发现关键信息
此时我们发现“_items”是个字典,但是此时的key值我们并不清楚具体含义,此时可以通过三种方式来确定
- 基于我们已经知道这个返回的信息中肯定包含灵石数量,所以我们查看自己当前的灵石数量,来猜测哪个key对应灵石
- 查看我们准备阶段发现配置文件中找到的灵石的信息,可以发现灵石的id正好就是“5”
- 继续跟踪代码,找到具体的解析逻辑
我比较推荐前两种,毕竟比较省事,少看点代码少费点脑子😜
-
尝试修改信息
跟踪到这里之后我们可以大胆猜测一下,现在已经是比较底层的调用了,所以我们如果在这里把灵石数量改掉是否就可以实现我们一夜暴富的梦想呢,我们可以在控制台尝试修改一下
修改之前我们可以看到,我们灵石数量为100不可以购买这个150的丹药。
修改之后可以看到“_items”的值已经变化
也可以进行购买了
-
修改源码
// return this._items;
let mitem = this._items;
for(let key in mitem){
console.log(itmitemem[key]);
if(mitem[key]>10 && mitem[key] < 500){
console.log('替换返回值');
mitem[key] = 9999;
}
}
console.log("获取个人物品" + mitem);
return mitem;
可以实现自动补充损耗
增加物品
经过以上操作,我们可以增加我们的灵石数量和其他的物品数量,但是却并不能凭空增加物品,即只能修改现有物品的数量,那么怎样才能增加物品呢,我们需要继续分析
此时需要思考一件事情,什么情况下可以增加人物的物品
此时我们可以考虑分析一下存档时可不可以查找到有保存物品信息的情况,从而去修改
寻找存档方法
可以考虑查看存档时是否有网络请求,所以我们可以在调试界面查看一下
分析和跟踪方法
-
寻找存档方法
存档时,可以发现存在一个名为“Save2.ogg_”的请求,此时我们可以在发起程序标签中看到他的调用栈
-
分析调用栈
此时需要挨个查看一下调用堆栈中的方法,分析一下其保存步骤中是否涉及调用和存储人物信息,选的太靠前跟起来容易跟丢,选的太靠后容易找不到关键信息,我分析的时候看了好几个方法,此处就不一一赘述了,直接进入executeSave方法下几个断点并进行存档操作
-
找到目标方法
可以看到方法已经阻塞了,然后再次进行单步调试,我们可以看到有个“ DataManager.saveGame(savefileId)”方法,跟进去看看
-
调试目标方法
这个看着就很像了,进去看看
这里基本就是我们需要的内容了
-
继续找到我们需要的数据
我们可以把方法走到最后一步,然后打印出cntents来看看内容
-
尝试修改数据
我们发现“_items”中的内容应该就是我们的物品信息,此时尝试增加物品,继续去控制台修改信息
-
恢复运行查看效果
恢复运行后会保存成功,此时我们直接查看一下效果
-
修改源码
DataManager.makeSaveContents = function() {
// A save data does not contain $gameTemp, $gameMessage, and $gameTroop.
const contents = {};
...
contents.actors = $gameActors;
// contents.party._items = {4: 1, 5: 9999,8: 8000,9:8000, 20: 500, 22: 300, 55: 1, 83: 1, 84: 500, 86: 999, 87:999, 88:999, 162: 1, 312: 1, 317: 1};
contents.party = $gameParty;
return contents;
};
-
进阶一点的话可以增加修改器,本次分析就到这了