记一次失败的微信跳一跳逆向

微信6.6.1版本后推出了小游戏,作为逆向选手当然要看看如何改掉自己的分数,虽然失败了,但还是要记录一下,感觉自己的思路是没有问题的。

本来是1月1日白天应该完成的,结果拖到了现在1月6日,又拖到了1月11日,失去热度了,而且有些思路也被人发出来了,本文也只能勉勉强强发出来吧。

最开始的想法就是改包,但跳一跳使用的是https还是微信自带的长连接,这个需要仔细考虑一下,毕竟是微信自己的游戏,走内置的长连接也是可以理解的。

当时网上流行的思路有两个:

  1. 通过截屏,图像处理后进行模拟点击,刷分数;
  2. 改包,截获了上传分数的API,逆完JS后发现是使用session_id来加密分数,用https给服务器上传数据。

已经有人实现了,所以搞大新闻的念头也就断掉了,而且改包这种操作显然不符合我这种逆向选手的身份嘛,太low了。

之后就随便玩了一会儿,想着如果用户网络环境很差的情况下,不小心破了所有人的记录,但是由于上传失败了,对用户来说一定是很大的打击。本着这个思路,开小号故意在离线情况下进行游戏,破纪录之后关机来防止内存中有东西,之后开机联网,确实记录被上传成功了。

那么这时候就有了新的思路,有两个。

  1. 分数肯定是存放在文件里的,所以修改数据库、篡改分数,从而让服务器信任我们的离线分数,是可行的。
  2. 逆向js,找到分数增加的地方,使用xposed强行绕过对于wxpkg完整性的校验,或者对小游戏的game.js进行修改,从而也让服务器信任我们。

开始搞哇!一年前对小程序的逆向已经让我对这套东西挺熟的了,本质上就是魔改过的webview,用js实现与android的通信,通过官方提供的文档结合逆向,可以理解为一个沙箱。一年过去了,应该有人把轮子写出来了,(然后真的有人写了各种各样的轮子),找到一个php版的,还不错https://github.com/Clarence-pan/unpack-wxapkg

首先要找到存放分数的位置,这个不难,有root之后到处删文件,看删到哪个文件的时候,就会无法将离线成绩同步到服务器即可。主要注意的位置就是/sdcard/tencent,/data/data/package/xxxxxx/*.db,删一会儿就会发现存放在AppBrandComm.db里。同时,也可以一边玩,一遍ls -la查看文件的读写情况,离线游戏一定会涉及到写文件的操作,也检查到是在AppBrandComm.db的缓存里,是shm、wal、ini文件。查了一下是sqlite3.7以后引进的新技术,不直接写db文件,而是写缓存、等所有的连接断开之后(或者其他种种情况)再进行同步操作。

微信的私有db是加密的,使用SqlCipher,密钥的算法也在各种地方都有被人公开过,md5(IMEI+uin)[0:7](操作时候找了一个很不靠谱的md5计算网站,居然给我算错了,怀疑数据库加密方式变掉了,于是开始踩坑之旅)

嗯,假设数据库加密方式变了,我们来探索一下新的加密方式吧!这里主要读了一下尼古拉斯-赵四的文章,http://www.wjdiankong.cn/android逆向之旅-静态方式破解微信获取聊天记录和通讯/,但是版本变得太多了,有些const-string已经搜不到了,也删除了大量的符号信息。因为这台手机IMEI和uin我不确定是否正确,(因为双卡双待、新注册马甲),于是找了一个很蠢的方法,使用xposed对String.substring(0,7),看一眼值和堆栈,值看起来像md5,栈看起来像database。

 

手动把这个像md5的给他改几个字节,触发了微信的自我检测,更加确定了我的猜想,因为自动修复的位置在com.tencent.mm.plugin.dbbackup.DBRecoveryUI.e。这不显然是数据库操作么。。。名字都这么直接了。

逆一下,hook一下,发现加密方式没有变,是之前算md5的网站故意坑我。

而且这DBRecoveryUI部分代码的逻辑很清晰,一下就看出来IMEI和uin的拼接,偷偷diss一下开发者的混淆策略,虽然经常用的部分混淆的挺不错,但这部分跟没混淆也差不多。

另外,

IMEI存放的位置是 ./shared_prefs/DENGTA_META.xml: <string name="IMEI_DENGTA">868029020104725</string> ,

uin存放位置是  ./shared_prefs/auth_info_key_prefs.xml: <int name="_auth_uin" value="-1701378319" /> ,居然是负数。。。

这样就可以防止以后再忘掉。

这里有两个难点,一是寻找记录存放的位置,二是触发与服务器的同步。

噗……然后我们继续干正事,密钥得到了,下载一个Sqlcipher.exe,解密一下就可以修改AppBrandComm.db,里面有几条很明显的记录,但是由于缓存机制的原因,这个db文件并不是实时的,而且我们也没有办法触发这个文件的更新(试过了重启、kill各种操作。。。)感觉更多的是靠运气去触发它的更新。

里面有一个叫xx的表,通过读game.js也可以看到一些它的信息。

经过一番研究,AppBrandComm.db里确实存放了上次游戏的数据,包括分数和最后一步的跳跃力度,多次尝试后发现无效。存放了历史最高水平,修改后也无法同步到服务器上。所以数据库里没有存放离线最高记录的数据,但又会在哪呢,用户私有目录没有其他地方被更新过,sd卡里肯定也没有,另外一个可能的就是与好友头像、好友数据存放的目录,或者是cache里,因为这些在数据库里是没有的,离线也可以获取到,只是位置不太清楚。

宣告gg。。。不知道在哪存着,思路应该是对的,有条件的话可以xposed注入一个FileObserver来观测一下到底是在哪里。

第二个思路,绕过check修改js代码。由于太忙了没来得及看,而且对js的语法很陌生,方法肯定是有的。。。

总之,从客户端安全的思路出发,和网上流行的方法不大一样23333,虽然没成功,但也算是一种创新吧~

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code