当前位置:网站首页 > 网络安全培训 > 正文

Android逆向-Android基础逆向7(内购干货集合)

freebuffreebuf 2018-02-28 306 0

本文来源:i_春秋

本文作者:MSTLab-EvilChen

0x00 前言

首先,本来想写NDK的,但是还是先把这个流程过一遍吧,这个流程是必不可少的。
其次,RMB真的是一个好东西。

导航

由于本人为了节省时间,不想贴太多的代码,所以总结了一个导航栏目。并且在栏目中有内容的说明。帮助了解。希望一起进步。
博客系列导航
为了练习方便,顺便把apk进行了一个整理。
练习传送门

内容

1.内购基础

0x01 内购知识

基本知识

什么是内购?

内购就是游戏内部购买。

SDK厂商

1.移动
2.电信
3.联通
4.支付宝
5.微信
6.其他

其他破解

拇指玩
网侠手机站
7723
爱吾
7yw趣游
软天空
西西软件园
葫芦侠三楼

游戏平台

1.某咕游戏

0x02 经验总结

关键点通用总结

通用1

最古老的方法就是搜索关键字:
“成功“
“失败”

绕过通用

switch

(1)覆盖switch失败转为成功。
(2)更改switch跳转
(3)最后一种我最喜欢作用,思路最明确,使用goto进行跳转。跳转到成功即可。

某咕游戏总结

方法 :onResult

移动总结

onbillingfinish()
dobilling()
onresult()

联通总结

payCallback()
PayResult()

电信总结

paySuccess()

支付宝总结

支付失败
9000
ResultStaus

0x03 某咕游戏破解实例

也不能说是因为篇幅问题吧,就是有点犯懒,不想截取一些简单的步骤。所以能简写就简写,这样能多分析几个实例。

实例是我刚找的。

原版apk:练习传送门在这里找,编号:2001

实例分析(1)

暂停:2018年2月12日00:34:05
原因:吵到我爸睡觉了。

开始时间: 2018年2月12日14:58:17

第一步:试玩。

自己玩

1.png

第二步:反编译,搜索关键字。

1.搜索“成功”

这里搜索到了三条数据

2.png

点进去之后是这样一个方法:

.method public static d()V     .locals 4      const/4 v3, 0x1      const/4 v2, 0x0      sget v0, Lcom/xy/kom/d/bk;->i:I      invoke-static {v0}, Lcom/xy/kom/g/p;->b(I)Z      sget v0, Lcom/xy/kom/d/bk;->h:I      invoke-static {v0}, Lcom/xy/kom/g/p;->c(I)Z      sget-boolean v0, Lcom/xy/kom/d/bk;->G:Z      if-eqz v0, :cond_4      sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v0, v0, Lcom/xy/kom/GameActivity;->m:Lcom/xy/kom/g/p;      invoke-virtual {v0}, Lcom/xy/kom/g/p;->x()Ljava/util/ArrayList;      move-result-object v0      invoke-static {}, Lcom/xy/kom/g/f;->l()Lcom/xy/kom/g/f;      move-result-object v1      invoke-virtual {v0, v1}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z      :goto_0     sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v0, v0, Lcom/xy/kom/GameActivity;->m:Lcom/xy/kom/g/p;      invoke-virtual {v0}, Lcom/xy/kom/g/p;->t()V      sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v0, v0, Lcom/xy/kom/GameActivity;->r:Lcom/xy/kom/d/ei;      if-eqz v0, :cond_0      sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v0, v0, Lcom/xy/kom/GameActivity;->r:Lcom/xy/kom/d/ei;      invoke-virtual {v0, v2}, Lcom/xy/kom/d/ei;->a(I)V      :cond_0     sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      const/4 v1, 0x6      invoke-virtual {v0, v1}, Lcom/xy/kom/GameActivity;->a(I)V      invoke-static {}, Lcom/xy/kom/d/bk;->h()V      sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      const-string v1, "\u8d2d\u4e70\u6210\u529f\uff01\u9053\u5177\u5df2\u53d1\u653e"      invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;      move-result-object v0      invoke-virtual {v0}, Landroid/widget/Toast;->show()V      sget-object v0, Lcom/xy/kom/GameActivity;->N:Lcom/xy/kom/e/a;      invoke-virtual {v0, v3}, Lcom/xy/kom/e/a;->a(I)V      sput-boolean v3, Lcom/xy/kom/GameActivity;->M:Z      invoke-static {}, Lcom/xy/kom/a/h;->f()I      move-result v0      const/16 v1, 0xd      if-ne v0, v1, :cond_2      sget v0, Lcom/xy/kom/GameActivity;->h:I      const/4 v1, 0x2      if-ne v0, v1, :cond_2      sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v0, v0, Lcom/xy/kom/GameActivity;->m:Lcom/xy/kom/g/p;      invoke-virtual {v0}, Lcom/xy/kom/g/p;->w()Ljava/util/ArrayList;      move-result-object v0      invoke-interface {v0}, Ljava/util/List;->size()I      move-result v1      sget-object v2, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v2, v2, Lcom/xy/kom/GameActivity;->m:Lcom/xy/kom/g/p;      invoke-virtual {v2}, Lcom/xy/kom/g/p;->l()I      move-result v2      if-ne v1, v2, :cond_1      sget-object v1, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v1, v1, Lcom/xy/kom/GameActivity;->r:Lcom/xy/kom/d/ei;      invoke-interface {v0}, Ljava/util/List;->size()I      move-result v2      add-int/lit8 v2, v2, -0x1      invoke-interface {v0, v2}, Ljava/util/List;->get(I)Ljava/lang/Object;      move-result-object v0      check-cast v0, Lcom/xy/kom/g/f;      invoke-virtual {v1, v0}, Lcom/xy/kom/d/ei;->b(Lcom/xy/kom/g/f;)V      :cond_1     sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v0, v0, Lcom/xy/kom/GameActivity;->r:Lcom/xy/kom/d/ei;      sget-object v1, Lcom/xy/kom/d/bk;->d:Lcom/xy/kom/g/f;      invoke-virtual {v0, v1}, Lcom/xy/kom/d/ei;->a(Lcom/xy/kom/g/f;)V      invoke-static {}, Lcom/xy/kom/d/bk;->m()V      :cond_2     sget-boolean v0, Lcom/xy/kom/d/bk;->G:Z      if-nez v0, :cond_3      const/4 v0, 0x0      sput-object v0, Lcom/xy/kom/d/bk;->d:Lcom/xy/kom/g/f;      :cond_3     return-void      :cond_4     sget-object v0, Lcom/xy/kom/GameActivity;->A:Lcom/xy/kom/GameActivity;      iget-object v0, v0, Lcom/xy/kom/GameActivity;->m:Lcom/xy/kom/g/p;      invoke-virtual {v0}, Lcom/xy/kom/g/p;->x()Ljava/util/ArrayList;      move-result-object v0      sget-object v1, Lcom/xy/kom/d/bk;->d:Lcom/xy/kom/g/f;      invoke-virtual {v0, v1}, Ljava/util/ArrayList;->add(Ljava/lang/Object;)Z      goto/16 :goto_0 .end method


3.png

这里找到一个调用成功的方法。我们继续溯源查看。

发现是一个onResult方法。


4.png

解决方法:
(1)覆盖switch失败转为成功。
(2)更改switch跳转
(3)最后一种我最喜欢作用,思路最明确,使用goto进行跳转。跳转到成功即可。

恩,改完之后汇编,整个游戏就破解好了。
没什么好说的。

测试成果。

是成功的,懒的玩。不想发图,自己测试吧,有疑问可以找我。

实例分析(2)

之前没有找好,现在去找找。
找练习的APK的时候主要注意三点。
(1)最好是单机
(2)选择大小的时候选小一点的,恩,反编译快。我们的目的是为了练习。
(3)无壳,现阶段可定脱不了壳。

找到了一个什么酷跑什么的游戏。
三步走

第一步 试玩

原版apk:练习传送门在这里找,编号:2002

拿到游戏,首先就要玩一下是不,人家怎么购买的你总要知道吧。说不定会有新的发现。


5.png

反编译破解

搜索关键字“成功失败”

6.png

点开之后进去,发现,原来还是一个onResult。

.method public onResult(ILjava/lang/String;Ljava/lang/Object;)V     .locals 3     .param p1, "paramAnonymousInt"    # I     .param p2, "paramAnonymousString"    # Ljava/lang/String;     .param p3, "paramAnonymousObject"    # Ljava/lang/Object;      .prologue     goto :pswitch_0     .line 26     packed-switch p1, :pswitch_data_0      .line 37     const-string v0, "Unity"      new-instance v1, Ljava/lang/StringBuilder;      const-string v2, "\u8d2d\u4e70\u9053\u5177\uff1a["      invoke-direct {v1, v2}, Ljava/lang/StringBuilder;->init>(Ljava/lang/String;)V      invoke-virtual {v1, p2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;      move-result-object v1      const-string v2, "]\u53d6\u6d88\uff01"      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;      move-result-object v1      invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;      move-result-object v1      invoke-static {v0, v1}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I      .line 38     invoke-static {}, Lcom/huibang/paopao/MainActivity;->access$0()Ljava/lang/String;      move-result-object v0      invoke-static {}, Lcom/huibang/paopao/MainActivity;->access$1()Ljava/lang/String;      move-result-object v1      const-string v2, "cancel"      invoke-static {v0, v1, v2}, Lcom/unity3d/player/UnityPlayer;->UnitySendMessage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V      .line 41     :goto_0     return-void      .line 29     :pswitch_0     const-string v0, "Unity"      new-instance v1, Ljava/lang/StringBuilder;      const-string v2, "\u8d2d\u4e70\u9053\u5177\uff1a["      invoke-direct {v1, v2}, Ljava/lang/StringBuilder;->init>(Ljava/lang/String;)V      invoke-virtual {v1, p2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;      move-result-object v1      const-string v2, "]  \u6210\u529f\uff01"      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;      move-result-object v1      invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;      move-result-object v1      invoke-static {v0, v1}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I      .line 30     invoke-static {}, Lcom/huibang/paopao/MainActivity;->access$0()Ljava/lang/String;      move-result-object v0      invoke-static {}, Lcom/huibang/paopao/MainActivity;->access$1()Ljava/lang/String;      move-result-object v1      const-string v2, "success"      invoke-static {v0, v1, v2}, Lcom/unity3d/player/UnityPlayer;->UnitySendMessage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V      goto :goto_0      .line 33     :pswitch_1     const-string v0, "Unity"      new-instance v1, Ljava/lang/StringBuilder;      const-string v2, "\u8d2d\u4e70\u9053\u5177\uff1a["      invoke-direct {v1, v2}, Ljava/lang/StringBuilder;->init>(Ljava/lang/String;)V      invoke-virtual {v1, p2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;      move-result-object v1      const-string v2, "] \u5931\u8d25\uff01"      invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;      move-result-object v1      invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;      move-result-object v1      invoke-static {v0, v1}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I      .line 34     invoke-static {}, Lcom/huibang/paopao/MainActivity;->access$0()Ljava/lang/String;      move-result-object v0      invoke-static {}, Lcom/huibang/paopao/MainActivity;->access$1()Ljava/lang/String;      move-result-object v1      const-string v2, "fail"      invoke-static {v0, v1, v2}, Lcom/unity3d/player/UnityPlayer;->UnitySendMessage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V      goto :goto_0      .line 26     nop      :pswitch_data_0     .packed-switch 0x1         :pswitch_0         :pswitch_1     .end packed-switch .end method


7.png

咪咕整个支付流程大概就是这个样子。(我猜的)

原本游戏(隐藏不可见)—咪咕支付接口(可见)——咪咕支付处理(不可见)——返回结果(可见)——回馈给原本游戏(不可见)

我们搞的其实就是在返回结果上动手脚。

测试

测试我做了,但是截图不了,有兴趣的可以自己去做下尝试。

总结

咪咕游戏最明显的一个特征就是 onResult()这个方法,只要改了这个方法,那么就可以轻松搞定了。当然你也可以通过其他手段找到它的特征。不过经验是可以提高效率哒嘛。

0x04 结束语

说明

这些只是对方法的一个总结,在总结的时候,可能没有时间整理实例了,但是在之后有时间或者遇到的话,那么我们就可以从这里找到方法去破解内购等。当然也包括了二次破解等说明。
之后如果需要则进行补充。

转载请注明来自网盾网络安全培训,本文标题:《Android逆向-Android基础逆向7(内购干货集合)》

标签:移动逆向

关于我

欢迎关注微信公众号

关于我们

网络安全培训,黑客培训,渗透培训,ctf,攻防

标签列表