一步步教你粗暴破解宫爆老奶奶-APK反编译教程

相信很多人对反编译有过兴趣,但是可能有部分人仅仅停留在通过反编译获取到apk里面的一些图片资源如style、layout等xml文件以作参考借鉴之用,可能也会有人用dex2jar+jd-gui的方式来看其java代码(如下图),但是大家都知道,这样的代码是不能回编译回去重新生成apk的,甚至代码也很容易被混淆,让你看得一头雾水


今天,我在这里就跟大家谈谈,希望通过这个博客,让大家知道,其实反编译是可以把apk反编译出来,然后修改里面的内容,然后再回编译,然后再签名,最后的结果是一个修改过的apk(当然是手机上能装的!)

大家都听过 Dalvik吧?帮大家百度了一下:
Dalvik是google专门为Android操作系统设计的一个虚拟机,经过专门针对移动平台深度优化过。Dalvik 基于寄存器,而 JVM 基于栈。基于寄存器的虚拟机对于更大的程序来说,在它们编译的时候,花费的时间更短。不同于Java虚拟机运行java字节码,Dalvik虚拟机运行的是其专有的文件格式Dex。
当一个apk被反编译后,将会得到一个装满.smali文件的文件夹,而我们这次操作正是这些smail文件。

我们以目前 比较火的《宫爆老奶奶》为例子,讲述一下如何简单粗暴反编译一款游戏:
第一步:
首先,下载 《宫爆老奶奶》 的apk(以下简称apk),我这个是从豌豆荚下的,腾讯计费的版本,这里就省略传送了。

第二步:
下载反编译用的工具——apktool(传送门:http://download.csdn.net/detail/qq359948834/5116151),下载完后,随便解压放好。

第三步:
开始反编译。先将apk放到./ApkTool/文件夹里(./代表当前文件夹,这个路径随意,下同),然后打开./ApkTool/APKTool.cmd,按照窗口提示,要先重命名apk为123.apk,重命名完毕后,按‘1:反编译’然后回车,会看到反编译成功,得到./ApkTool/APK 文件夹。

第四步:
大家可以先随便浏览下文件夹里面的内容,会看到如图所示的文件:



很明显,这是混淆过的代码,但是不要紧,混淆只不过是一种浅层次的防反编译动作,只是对一些类进行了重命名而已,对应用的逻辑函数变量的用法还是一样的。
好,初步了解后,我们先不要改动任何文件,尝试再次打开./ApkTool/ApkTool.cmd,然后选择‘3:回编译并签名’看看能不能打回原版包。
如无意外,都会出现下面这种错误:

熟悉android开发的同学可能会知道是什么原因了,我菜鸟猜了一下,应该是当前apktool.jar所使用的android平台版本比较低,所以识别不了“layout-h500dp-large”和“layout-h500dp-normal”资源文件的命名,所以我们可以修改成“layout-large”和”layout-normal“,这样,我没记错的话,android2.2系统以上的都适用了。修改后,重新选择‘3’试试看,如果步骤没错,会出现以下结果:


*以上关于警告的信息我们可以先放放不予理会。
如果大家都是出现这种情况,说明反编译成功了,接下来,大家可以随意修改图片资源以及布局文件了,只要不影响命名,以及资源数量不变,就不会影响回编译,现在,我们进入重点部分——开始修改smail文件,以实现屏蔽扣费

第五步:
先锁定计费代码。怎么锁定计费代码呢?大家可以想一下计费sdk的架构和流程:
a.用户点击UI上的物品item
b.游戏底层通过jni方式回调java层请求计费
c.弹框提示购买内容及价格
d.监听用户点击动作,发送短信(或者支付宝等支付方式)或用户取消购买,jni回调游戏底层告知购买结果(一般只有两种结果,成功与否)

所以,以上流程大家有几种方法锁定:
1、使用UltrafileSearch(一款很出名的搜索工具)批量搜索支付常用关键字(pay、purchase、success、fail、notify等等)
2、从非内部类(文件名没有$)入手,扫读所有方法名,碰到敏感方法,可以尝试添加smail代码输出log信息已判定该方法在什么时候执行
3、从与支付有关的资源入手,看看程序哪里调用了支付用到的图片和文字资源(老奶奶的资源都是写在asset,然后把所有调用支付界面的代码打成so,所以我们反编译后看不到,这个方法不适用于老奶奶这款游戏)

经过一轮苦苦摸索,终于锁定了ITencent.smali这个文件,里面有MakePay(I)V,PrePay(I)V,SendSMSCB(ILjava/lang/String;)Z 这几个很明显的方法,大家可以在这几个方法里面添加log语句(具体怎么添加,如图所示,如果还有疑问,请先阅读smail的相关语法),然后看看logcat的输出情况:

贴上代码:
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
.method public static MakePay(I)V
    .locals 3
    .parameter "id"
 
    .prologue
         #==========
    .line 8888
    const -string v0, "kelly"
    const -string v1, "========MakePay"
    invoke- static {v0,v1},Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
    #==========


*其他方法类似,这里不作赘述(注意!这里的.locals 3指的是当前方法使用了3个寄存器,因为我们的log语句一般都用到了两个寄存器,所以,当使用log时,请先留意下该方法的.locals 值是不是>=2)



修改完毕后, 直接打开反编译工具选择‘3’回编译后,再安装到手机跑跑看看logcat显示(当然,也可以直接使用‘9:一键回编译并安装’,前提是你的adb环境要搭好),如图所示:
游戏界面:

logcat如图:


*android开发者都知道,log有两个参数,一个tag一个是String型的content,大家可以发挥一下小宇宙,输出所有String型的内容看看
看到这log,我们成功一半了,说明计费代码锁定了
第六步:
修改计费逻辑。这一部分涉及不少smail语法,如果大家觉得迷茫,可以先暂停下来,看看有关smail语法的介绍。
大家看看MakePay方法里面,有一行代码:
invoke-static {p0, v0}, Lcom/tencent/webnet/WebNetInterface;->SMSBillingPoint(ILjava/lang/String;)V
略懂英语的应该也能猜到什么意思:“短信,购买,点 ”,连起来差不多意思就是生成计费短信,并提示用户付费,我们进入该方法所在的路径看个究竟(com/tencent/webnet/WebNetInterface)
如图,大家也可以在这方法加上log:

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
.method public static SMSBillingPoint(ILjava/lang/String;)V
    .locals 7
    .parameter
    .parameter
 
    .prologue
         #==========
    .line 8888
    const -string v0, "kelly"
    const -string v1, "========SMSBillingPoint"
    invoke- static {v0,v1},Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
    #==========


看到这里,大家开始头晕了吧?hold住,距离成功就差一点点了!
大家看看这个方法里面,有一句代码:

?
代码片段,双击复制
01
invoke- static {v0, v5, v1}, Lcn/emagsoftware/gamebilling/api/GameInterface;->doBillingBySms(Ljava/lang/String;ZLcn/emagsoftware/gamebilling/api/GameInterface$BillingCallback;)V


意思也很易读懂:doBillingBySms=“做,购买,通过,短信”,而且,大家再看,这个方法参数之中有一个字符串,一个int整形,以及一个回调方法BillingCallback,所以,我可以肯定,这是一个调用发短信被回调发送结果的方法!但是,大家也看到,这句代码藏在这个SMSBillingPoint方法里面的底部,也就是说,你要调用它,必须经过重重逻辑判断。
那么,现在你有两种选择:1、读懂所有逻辑,修改每个逻辑的条件,以达到doBillingBySms语句所在行; 2、直接把doBillingBySms语句提前到所有逻辑之前
很明显,我会选择第二种
但是,在选择第二种方法,也意味着,你要提供doBillingBySms的三个参数。
细心一看,你会发现,这三个参数中的第二个,也就是说v5,在方法一开始就定义了,所以参数已解决一个;
v0是什么?大家请看:

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
invoke- static {v1, v2}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
 
    move-result-object v0
 
    .line 221
    new -instance v1, Ljava/lang/StringBuilder;
 
    const -string v2, "IDO send sms code = "
 
    invoke-direct {v1, v2}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
 
    invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;


里面与v0有关的都是些字符串操作,比如StringBuilder,所以,我猜v0是一个让运营商识别所购买道具的识别码,而v1,是一个回调函数的实例,它的实例化代码为,大家去这个路径写一下log输出,对后面的步骤有用(步骤和注意点跟上面提到的如何写log一致):

?
代码片段,双击复制
01
02
03
new -instance v1, Lcom/tencent/webnet/q;
 
    invoke-direct {v1}, Lcom/tencent/webnet/q;-><init>()V


好!现在,三个参数都拿到手了,我整理一下,用以下内容,直接覆盖这个SMSBillingPoint方法:(其实我个人不太推荐删减源文件的所有代码,毕竟以后可能会有用,所以建议只把我们的代码插入到方法里的头部,然后在我们的代码的尾部加一个return-void即可)

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
.method public static SMSBillingPoint(ILjava/lang/String;)V
    .locals 7
    .parameter
    .parameter
 
    .prologue
         #==========
    .line 8888
    const -string v0, "kelly"
    const -string v1, "========SMSBillingPoint"
    invoke- static {v0,v1},Landroid/util/Log;->i(Ljava/lang/String;Ljava/lang/String;)I
    #==========
    const / 16 v6, 0x3ed
 
    const / 4 v5, 0x1
 
    const / 4 v4, 0x0
 
    const / 4 v0, 0x0
 
         sget-object v1, Lcom/tencent/webnet/b;->ah:Lcom/tencent/webnet/WebNetInterface;
 
    iput-object p1, v1, Lcom/tencent/webnet/WebNetInterface;->m_SMSCurMark:Ljava/lang/String;
 
    .line 220
    const -string v1, "%03d"
 
    new -array v2, v5, [Ljava/lang/Object;
 
    add- int /lit8 v3, p0, - 0x1
 
    invoke- static {v3}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
 
    move-result-object v3
 
    aput-object v3, v2, v0
 
    invoke- static {v1, v2}, Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
 
    move-result-object v0
          new -instance v1, Lcom/tencent/webnet/q;
 
    invoke-direct {v1}, Lcom/tencent/webnet/q;-><init>()V
 
    invoke- static {v0, v5, v1}, Lcn/emagsoftware/gamebilling/api/GameInterface;->doBillingBySms(Ljava/lang/String;ZLcn/emagsoftware/gamebilling/api/GameInterface$BillingCallback;)V
         return - void
.end method


替换好之后,我们回编译一下,看看有没有报错(报错的同学,麻烦仔细检查一下上面提到的.local有没有注意,而且也要很仔细地检查代码有没有写错),然后打开logcat,在游戏里面点击购买,看看输出情况:



很好,这下说明我们的apk即使已经动过计费逻辑,也能跑起来了
下面,是最后一步,也是最简单的一步,就是把回调失败改成回调成功,怎么改呢?大家看看com/tencent/webnet/q的内容:

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
.method public onBillingFail()V
    .locals 3
 
    .prologue
    .line 233
    sget-object v0, Lcom/tencent/webnet/b;->am:Lcom/tencent/webnet/o;
 
    const / 16 v1, 0x3e9
 
    sget-object v2, Lcom/tencent/webnet/b;->ah:Lcom/tencent/webnet/WebNetInterface;
 
    invoke- static {v2}, Lcom/tencent/webnet/WebNetInterface;->a(Lcom/tencent/webnet/WebNetInterface;)Ljava/lang/String;
 
    move-result-object v2
 
    invoke-virtual {v0, v1, v2}, Lcom/tencent/webnet/o;->a(ILjava/lang/String;)V
 
    .line 234
    return - void
.end method
 
.method public onBillingSuccess()V
    .locals 3
 
    .prologue
    .line 227
    sget-object v0, Lcom/tencent/webnet/b;->am:Lcom/tencent/webnet/o;
 
    const / 16 v1, 0x3e8
 
    sget-object v2, Lcom/tencent/webnet/b;->ah:Lcom/tencent/webnet/WebNetInterface;
 
    invoke- static {v2}, Lcom/tencent/webnet/WebNetInterface;->a(Lcom/tencent/webnet/WebNetInterface;)Ljava/lang/String;
 
    move-result-object v2
 
    invoke-virtual {v0, v1, v2}, Lcom/tencent/webnet/o;->a(ILjava/lang/String;)V
 
    .line 228
    return - void
.end method


怎么改?不用教吧?直接把onBillingSuccess的内容复制粘贴,替换onBillingFail方法原有的内容(其实细心的同学可以发现,两个方法的区别就在于那个字符串“ const/16 v1, 0x3e9”和“ const/16 v1, 0x3e8”而已)
大功告成,现在打开反编译工具,回编译后安装到手机,试试看吧(注意!为保险起见,建议各位断网+飞行模式,你懂的)


写在最后:
作为一个开发者,我们要尊重每一个应用,无论游戏好玩不好玩好不好用,它都代表着一个开发者全部的心血,赞之合理,踩之有度。
至于软件扣费这个情况,无可否认,对于已经习惯免费的国人来说,一开始可能不习惯,但是,试想下,一款优秀软件,只需要20块钱左右,就已经可以买到很不错的道具了,而且有更加好的游戏体验及乐趣,再加上,这些钱能帮助到开发者开发出更多更好玩的游戏更精彩的应用,这是一个良性循环,希望玩家、开发者、用户能一起构建这种氛围。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cordova-hot-code-push-plugin 是 Cordova 平台下的一个插件,可以帮助开发者实现 APK 包热更新。下面是详细的使用教程: 1. 安装插件 在 Cordova 项目中执行以下命令安装插件: ```bash cordova plugin add cordova-hot-code-push-plugin ``` 2. 配置插件 在 Cordova 项目的 `config.xml` 文件中添加以下配置: ```xml <hcp> <auto-download enabled="true" /> <auto-install enabled="true" /> <widget id="com.example.app" version="0.0.1"> <content src="index.html" /> <platform name="android"> <preference name="android-minSdkVersion" value="16" /> <preference name="android-targetSdkVersion" value="30" /> <icon src="res/android/ldpi.png" density="ldpi" /> <icon src="res/android/mdpi.png" density="mdpi" /> <icon src="res/android/hdpi.png" density="hdpi" /> <icon src="res/android/xhdpi.png" density="xhdpi" /> <icon src="res/android/xxhdpi.png" density="xxhdpi" /> <icon src="res/android/xxxhdpi.png" density="xxxhdpi" /> <allow-navigation href="*" /> <allow-intent href="*" /> <access origin="*" /> </platform> </widget> </hcp> ``` 其中,`auto-download` 和 `auto-install` 分别表示是否开启自动下载和自动安装更新。`widget` 标签下的其他配置项与 Cordova 项目一致。 3. 打包 APK 在 Cordova 项目中执行以下命令打包 APK: ```bash cordova build android --release ``` 4. 生成更新包 在 Cordova 项目中执行以下命令生成更新包: ```bash cordova-hcp build ``` 该命令会在项目根目录下生成一个 `www.zip` 文件,该文件包含了需要更新的代码和资源。 5. 上传更新包 将 `www.zip` 文件上传到服务器上。可以使用任何支持 HTTP 文件下载的服务器,例如 Apache、Nginx 等。 6. 应用更新 在 Cordova 项目中引入 `chcp.js` 文件,并在应用程序启动时执行以下代码: ```javascript chcp.fetchUpdate(function(error, data) { if (error) { console.error('Failed to fetch update:', error); } else if (data) { console.log('Update is available:', data); chcp.installUpdate(function(error) { if (error) { console.error('Failed to install update:', error); } else { console.log('Update installed successfully'); } }); } else { console.log('No update available'); } }); ``` 该代码会检查是否有更新可用,并在有更新时下载并安装更新。 以上就是使用 cordova-hot-code-push-plugin 实现 APK 包热更新的详细教程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值