由于某个机缘,我拿到一个赛车app,玩了一会想买个装备,竟然要我掏钱包,做为一名cracker,我以为个人尊严受到了严重的蔑视(无奈钱包空空),我以为要捍卫我那脆弱的玻璃心(钱包),因此,开干吧。我搜索了网上相关的帖子,发现这个apk的破解都是讲了关键点都在哪里,没有具体的关键点查找思路,因此我从新本身破解了一次,中间屡次误入歧途,我把本身的详细思路发在这里,与全部的菜鸟共勉。html
Android killer v1.3.1.0 -- 用于搜索字符串和重打包,下文使用缩写AKjava
Apktool Box v1.6.4 – 用于获取调试启动命令,下文使用缩写ABandroid
小米5 MIUI9.5.1.0 android7.0 – 用于运行apk程序员
Android Studio 2.3.3(安装 smalidea-0.0.5插件) – 用于调试smali源码,下文使用缩写AS编程
Jadx-gui 0.7.1 – 用于查看smali反编译源码,其实AK也有反编译功能,可是AK的反编译有的地方没有jadx好看,我发现switchcase结构AK老是翻译成ifelse结构。网络
使用AS调试smali须要apk设置调试标识(否则AS会显示错误:Unable to open debugger port (localhost:7800): java.net.SocketException "connection reset"),用AK打开apk,从工程管理器栏打开文件androidmanifest.xml,在application项添加以下代码:app
1
|
android:debuggable="true"
|
以下图:tcp
而后选择菜单android->编译,重打包APK。并安装到米5里面。ide
使用AB打开apk,点击启动命令按钮生成调试启动命令,函数
将上图中下面的命令拷贝到cmd中,启动apk,手机中apk会停在调试启动界面。而后查看apk的进程PID,
而后使用adb命令转发调试到tcp端口8700,以下:
接下来,使用AS创建smali源码的工程,并配置调试端口,这部份内容网上有现成的教程,这里就很少说了,创建完了以后,点击调试按钮,AS下面显示日志以下表示启动调试成功:
到此,调试环境搭建成功,下面开始破解。
老思路,先是试用一下。点击游戏的购买,会弹出一个购买的框,须要输入手机号和验证码,这里随便输入一个手机号和验证码,点击确认支付,不出意外会失败,并弹出一个提示框:
好了,这是个人第一个第一个失败点。个人思路是,既然它给了这个错误提示,那么显示这个错误的地方确定有支付成功和失败的逻辑,那么我修改了这个逻辑,就能够了。OK,下面就是如何找到这个判断的逻辑。没错,字符串查找,最传统的方法,在android里面搜字符串,不能直接搜汉字,须要将它转为unicode码,而后将“短信验证码验证失败”转换为unicode码,则为“\u77ed\u4fe1\u9a8c\u8bc1\u7801\u9a8c\u8bc1\u5931\u8d25 ”,结果没有找到,好吧,是否是字符串拼接出来的呢,短一点,搜“短信验证码”,而后有了搜索结果
很差意思,我是小菜看不懂smali,将其转换为java源代码,
原函数太大了,这里只贴了一部分,看着逻辑真不像,那么究竟是不是这个逻辑呢?验证的办法很简单,在这里下个断点,而后,没有断下来。那么在函数入口下个断点,仍是没有来。好吧,这个思路以失败了结。后来跟踪代码我才知道这个支付框是从so里面弹出来的。呜呜。。
以前搜过相似的帖子,帖子说是搜字符串“支付成功”,因此我将字符串转化为unicode码,到AK里面去搜索,而后搜索到三个结果:
一样,验证这里是否是判断是否支付成功的逻辑代码,在每一个字符串所在的函数头部设置断点,这里没有在字符串所在的位置设置断点是由于我是不会掏钱包的,全部的操做都是支付失败的操做,支付成功的代码逻辑确定是不会来的,因此在函数头部设置断点,而后,点击确认支付没有断下来,可是当我点击关闭按钮时,却成功的断在了第一个函数中。这是意外的惊喜。而后使用jadx查看这个函数的逻辑:
代码的逻辑很清晰,检查参数resultCode的值,而后判断是否支付成功,因此这里颇有可能就是我要的关键代码逻辑。验证一下,把全部的switch结构都改为到case1分支。Smali代码的语法是把全部的case放到一块,以下
上面代码的意思是将switch里面的值与1比较,结果为0则跳转到pswitch_0标号,结果为1则跳转到pswitch_1执行,因此这里把全部的标号都改成pwtich_0,并在下面添加一行,这样默认状况也会跳转到pswtich_0,即三种无论resultCode为什么值,都会跳转到成功的分支,以下:
最后,编译重打包,安装测试,成功,OK。至此,成功破解了这个app的内功功能。
其实,当初我并无按下支付框的关闭按钮,因此我走的是另外一条思路,若是看到这里你还有耐心,能够看下个人弯路,哈哈。
思路三:个人弯路
当在三个“支付成功”字符串所在的函数设置断点,点击手机上确认支付按钮时,三个断点都没有来。而后我换了搜所的字符串为“支付失败”,而后搜到6个结果
我在6个结果的字符串所在的函数头部设置断点,点击确认支付按钮,结果全部的断点都没有来。后来我就去网上搜帖子,见到有帖子说“支付失败”所在的一个函数checkPayResultTest的调用者在用户点击购买时被调用。因此我转变了思路,放弃了直接查找判断是否支付成功的代码,而是查找能在支付过程当中会被执行到的函数,而后我能够从这个函数跟踪到判断支付的代码。使用jadx打开apk,定位到函数checkPayResultTest,右键find usage,
而后查看其调用函数,
在此函数的头部设置断点,当我点击购买时,程序断在了这里。这是个喜讯。此时,我发现手机上的支付框尚未弹出来,因此我想,我能够从这里跟踪下去知道支付框弹出,而后找到确认支付按钮的回调。因而我一路F7单步步入跟进去,当调试跟踪到下图中的红线标识部分时我跟不进去了:
经过查资料我才知道,这是jni调用,我这才知道了,为何我以前设置的失败断点都没有来,缘由最后掉用到so库里了。那怎么办,难道我要算调试so文件么?而后我仔细观察了这个函数调用,发现这里有个回调,因而我找到回调定义的地方,
哈哈,是否是很眼熟,在回调里面设置断点,而后此次我鬼使神差的点击了支付框的关闭按钮,而后断下来了。哈哈。再而后的操做就如同上个思路同样了。这就是个人弯路了。
这里怎么说呢,其实也不算是程序的漏洞,而是程序员的一种编程习惯。我称之为“漏洞”,经过这个“漏洞”能够定位到支付功能必须执行的某些代码。思路是这样的,我发如今程序的代码中有不少调试日志输出,我若是能修改程序输出日志,那么当我使用支付功能的时候,相关代码会输出相关调试信息,而后我搜索输出的字符串,不就能够定位到支付功能必定会调用的代码吗!
首先,随便找一段代码,看看它是如何输出的,
从上图能够看出,调试信息的输出是经过一个叫LogUil.iT函数实现的,找到这个函数:
这里会看到,代码中有个DEBUG标志,若是此标志为真则输出调试信息,而后找到这个标志赋值的位置:
原本觉得这个标志是会在构造里面赋值的,没想到竟然是判断sdcard路径下有没有alg,哈哈,那就更简单了,我在手机的sdcard下面放了一个alg文件,
而后打开DDMS,启动程序,点击购买,DDMS日志视图里面发现以下信息:
到AK里面去搜索字符串“支付接口被游戏调用”,哈哈,有一条结果:
转到java源代码:
在AS中对应位置下断点,程序成功断下来啦。哈哈。
虽然走了不少的弯路,可是也发现了不少有趣的东西。例如经过日志来定位代码,so中弹出对话框是没法在java中找到关键点的,要多试几种别的操做。
附件太大,这里给个连接吧:https://pan.baidu.com/s/1P40TZLvJXV727-mlJLNIdA
本帖子若是引发任何其它负面的影响,请版主直接删帖便可。
若是转载,请声明来自看雪。