文章目录
- 分析环境
- 逆向分析
- 日志分析法
- 字符串分析法
- 去除弹窗
- 添加个人信息的破解
- 总结
分析环境
系统:Android 4.4
工具:Windows 10 64bit 夜神模拟器 Android Killer
游戏:全民捕鱼V1.7
文件: fkby.apk
大小: 14450756 bytes
修改时间: 2016年3月 11日, 14:53:34
MD5: C67C9D8DB091BE205457B1C6B9BC1352
SHA1: 0FD4027602C2628568E52806603BA1FC95EBE90D
CRC32: 406D694D
文件信息如上,有VT权限的话可以直接下载
这个游戏虽然已经下架,但是分析思路非常值得初学者学习。
逆向分析
进入游戏商城,点击购买金币,会弹出购买失败的提示,可以根据这个字符串作为切入点去分析app,也可以根据日志去分析。这里我们先通过日志去分析整个app
日志分析法
将apk加载到Android Killer
选择已经开启的模拟器,点击日志
点击查找进程按钮
根据apk的包名确定需要查找的进程ID。点击开始按钮
点击金币,此时窗口出现多条日志,由于这里还没有进行支付,将所有日志清空
然后点击确定,出现支付失败的提示。
那么这一段日志,必然调用了支付的方法,我们可以从下往上分析整个日志。
关键日志如下:
Failed DX_payCode2 == 5125375
FaildCode == 1211
orderFinish code = 3 result= 0
DX_payCode2必然是和支付相关的错误码
这里直接在工程中搜索这个关键词
来到了关键地方
当前类内有三个方法,支付取消,支付失败和支付成功
但是观察这个类名,可以知道当前这个是匿名内部类,所以我们没法直接找到调用pay函数的地方,这里可以用一个取巧的办法。
将支付失败的代码全部删掉
然后将支付成功的代码复制到支付失败方法内
修改完成之后可以看到已经购买成功了。但是这种方法属于是取巧,并不适用于所有的游戏破解。我们再来观察支付成功和失败函数的区别
两个函数的区别在于传入的 GameJni.OderFinish传入的第二个参数和SendMessage传入的第三个参数。
发消息的代码和界面相关,这个暂时先不管,我们可以找到支付失败函数将0改成1看看会产生什么效果
将v1修改为1,然后保存编译
首先弹出购买失败页面,然后弹出购买成功提示,表示我们已经修改成功了。
字符串分析法
接着我们可以用字符串分析的方法来破解这个apk
切入点为购买失败的提示信息
在搜索框中输入购买失败,然后转成Unicode
直接搜索,就定位到了购买失败的调用地方
查看源码发现这里有购买成功和失败的调用语句,但是这个位置只是弹出购买成功和失败的提示,所以我们需要再搜索别的地方
initShow((String)paramMessage.obj);continue;GamePay.sendOrder((String)paramMessage.obj);continue;buyFail((String)paramMessage.obj);continue;buyOk((String)paramMessage.obj);continue;payFail((String)paramMessage.obj);
这里就需要挨个搜索代码中出现的函数名,找到可以修改的地方
最终通过payFail定位到最后一个地址
同样可以找到关键代码,然后将参数2修改为1即可破解成功
去除弹窗
接下来我们希望将当前的这个弹出去掉,直接显示购买成功
想要去除这个弹窗,就需要在这个窗口弹出之前调用游戏中的OderFinish方法。继续用日志分析法来分析
点击购买出现弹窗,然后查看当前出现的日志。
event_id=buyMoney, label=1000
GameJni order payCode = 3 num= 1
order = 5125375
GamePay sendOrder payCode = 5125375
context.payType = 1
payCode = 5125375
DX payCode in DXSend == 5125375
这一次我们想要去除弹窗的话应该从上往下对日志进行分析。
搜索GameJni order payCode
这个字符串
查看JAVA代码,order方法接着又调用了下面这个方法
GamePay.mListener.order(paramInt1, paramInt2);
继续进入order方法查看代码
这一段代码我们并不知道是什么作用,但是看代码最后调用了OderFinish方法,第二个参数为0,说明这里是购买失败的分支。
如果我们直接让代码跳转到OderFinish方法,并且将第二个参数修改为1,是否就可以跳过弹窗的过程?
接着来实际验证~
找到IAPListener.smali的order方法
来到函数末尾,首先将v0修改为1,然后复制::cond_2
这个标签
然后在函数头直接goto到OderFinish的位置,保存并编译安装。
点击购买之后,直接弹出提示,显示成功信息,由于我们跳过了所有方法,直接调用购买成功的方法,所以没有弹出Toast提示信息
添加个人信息的破解
为了更有趣一点,我们在购买成功的提示上添加自己的个人信息。
但是当前的这个类,并不是主界面,没有办法拿到Toast函数需要的this指针,所以只能想其他办法。
通过代码我们可以看到当前的order函数是可以给主界面发送消息的,这里发送的消息是10004
点击IAPHandler来查看一下消息响应函数
通过定义的静态变量跟函数名我们已经能拿到消息ID和函数的对应关系。所以如果想让程序弹出一个提示信息显示购买成功,只需要发送一个ID为10010的消息即可
这里我们修改的方式为将if语句注释,然后修改ID为10010,最后goto到OrderFinish函数
首先将V3消息ID修改为0x271A
然后注释掉第一条if语句
在发送完消息后直接goto到OrderFinish函数
然后搜索购买成功字符串
然后修改这个字符串。实际效果如图:
成功加上了我们自己的个人信息。接着我们在游戏启动界面,再添加一个个人信息提示
找到入口类的onCreate方法,拉倒函数末尾,右键->插入代码->Toast
保存并编译
修改完成之后在游戏启动界面弹出了我们自定义的提示信息。比起破解这个环节应该是最有成就感的了。
总结
安卓游戏内购的破解简单的思路都是大同小异,也可以更改调用的函数参数等.smail代码与伪Java代码很接近自然语言逻辑思路,在没有安卓加固(壳)的游戏上做一些内购破解还是很简单的.去网上Download几个游戏练习一下破解就很有成就感.