本帖最后由 vnetuser 于 2018-5-31 23:08 编辑
一、前言
本人正在学习安卓的反编译和破解,目前学到 教我兄弟学Android逆向03 破解第一个Android游戏 https://www.52pojie.cn/thread-654654-1-1.html,最后课后作业 https://www.52pojie.cn/thread-632178-1-2.html 但在后面原版APK的下载链接失效了(没有注意看后面的有补链的{:1_932:}) 只好去寻求X度来下个APK了,结果下载下来的APK和教程里的内购版购买逻辑不同,本着学习+研究的精神就用这个来练手了,走了无数次的弯路,填了自己的一个大坑,最后才初步支付成功(还不完善),于是分享出来大家共勉.
二、准备工作
原版APK: 版本: 1.1.0.133 http://shouji.baidu.com/game/11379870.html
AndroidKiller: 版本: 1.3.1 https://down.52pojie.cn/Tools/Android_Tools/
JEB: 版本: 2.3.13.201803121754 https://www.52pojie.cn/thread-696860-1-1.html
蓝叠(模拟器): 版本: 3.1.11.455
三、动手
0B00:APK拖入模拟器安装->运行滚动的天空(会有广告,直接关闭)->进入道具商场(类似于购物车)->点击任意商品->其他支付->支付宝->返回 查看返回关键字
关键词:购买未成功,请返回游戏重新购买
0B01:APK拖入 AndroidKiller 建立工程,搜索上面的关键词中的一部分:"购买未成功"(文本转Unicode),结果如下图->双击进入smali代码编辑区:
发现在AndroidKiller无法查看java源码.
那么开启jeb 打开APK->Bytecode->字符串->搜索上面的关键词中的一部分"购买未成功"(这里中文就可以)结果如下图:
->双击搜索结果,进入smali代码展示区->鼠标右键->解析(快捷键Q),结果如下图
0B10:Jeb里可以看到解析后的源码了.已经很容易去阅读和分析逻辑了
一系列的空和状态码判断,都会显示购买未成功的提示,大概结论如下:
A) arg9是状态返回码 3010或3014是成功的状态(这个后面会用到)
B) arg10里保存的订单信息,处理后经onResponse回调
下面就是回到AndroidKiller里,修改smali代码
A)先找到onResponse方面所在的条件分支:cond_4 (这里加个Log输出 ),
向上查看代码,修改代码以便能执行到onResponse里(这里我所用的方式在所有的cond_XX后加一个Log输出,以便检测代码运行逻辑,新人,手法比较笨)
然后找到第一个判断点 让其跳转到cond_4 即可.....
也可以不用分析代码.自己手写个直接跳转的方法
[Bash shell] 纯文本查看 复制代码 const/4 v0,0x0
if-eqz v0, :cond_4
B)实现上面的跳转后就是进入onResponse的代码分析过程(我在这里遇到了第一大坑,后面会一一道来)
在jeb里搜索[方法名]关键词"onresponse"(引号内的是关键词),依然是笨重手法,列表中会过滤出带有关键词的类,点开来看很多是处理HTTP请求返回的类,也发现一些IDKSDKCallBack的匿名类,但无法区分哪一个是我们需要跟进的类,同时发现一个特点每个匿名类会有像LOG输出的东西.
跟进d类查看,
正是LOG输出,而且没有加开关,以"BaseLog"为TAG正常输出
,那么我们就以"BaseLog"抓取日志
很明显看到有
[Asm] 纯文本查看 复制代码 bdpay onResponse...{"bd_order_id":"agrl918qKkVcK1A","function_status_code":3011,"bd_order_price":"6.0","bd_order_price_original":"6.0","bd_order_status":"DK_ORDER_STATUS_FAIL","bd_order_pay_channel":"DK_ORDER_CHANNEL_ALIPAY","bd_order_product_id":"19578"}
日志的输出
继续采用0B01中的搜索[字符串]关键词"bdpay onResponse"这样很容易就找到我们的跟进对象
结合上面抓取的日志来分析.最终会走向onSendOrderInfo
[Java] 纯文本查看 复制代码 BaiDuPay.this.mCallback.onSendOrderInfo(new IProduct() {
public String getProductId() {
return this.this$1.this$0.mProductInfo.getProductId();
}
}, 5);
======================坑开始========================
于是就像A)步里改条件直接进入onSendOrderInfo 这个时候保存运行调试,但结果还是没有支付成功
跳转 onSendOrderInfo 里是不是做了什么处理呢,我就一路跟进
继续改.继续跟进
[Java] 纯文本查看 复制代码 NativeUtil.getInstance().callPayCallback(this.a, 1);
再跟
[Java] 纯文本查看 复制代码 UnityPlayer.UnitySendMessage("NativeUtils", "payCallback", v0_1);
再跟
[Java] 纯文本查看 复制代码 private static native void nativeUnitySendMessage(String arg0, String arg1, String arg2) {
}
这到这里就一脸懵逼了...进so文件了(不知道怎么处理了)最终没有支付成功
======================坑结束========================
倒回去重新分析onResponse后的代码,从抓取到的日志中看到"function_status_code":3011 这里应该是操作返回码,代码有判断是否为3010的判断.结合前面的代码猜想 3010应该是支付成功的返回码,开始修改代码跳过3010判断
方法一 修改判断条件为 if-eq v1, v2, :cond_3 结果支付成功了,反思上面的坑是我太急功近利了.跳过了中间的过程.才导致的支付失败
下面看效果:
方法二(数据伪造)在初始化JSONObject对象前修改返回的数据
[Asm] 纯文本查看 复制代码 .local v0, "result":Ljava/lang/String;
const-string/jumbo v1, "3011"
const-string/jumbo v2, "3010"
invoke-virtual {p1, v1, v2}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object v1
new-instance v0, Lorg/json/JSONObject;
invoke-direct {v0, v1}, Lorg/json/JSONObject;-><init>(Ljava/lang/String;)V
四、反思
0B00:破解要一步步来不能急功近利,要按代码逻辑走.不能跳中间任何一个环节
0B01:破解还不完善,还有个支付方式选择界面没有自动结束,大神请指点一二
0B10:如有何不足之处,还请各位指出,吾将加以学习
另附:该支付SDK的DEMO http://app.baidu.com/docs?id=15&frompos=401043#h3-tit16 |