注册

记一次反编译并重新打包的过程

反编译部分的介绍在文章末尾

排查原因

根据现象来看,这程序要嘛崩溃了,要嘛该App不适配此款盒子(比如ABI不支持、Target SDK Version等问题)

minSdkVersion系统版本不支持?

但是同事告诉我这款盒子是Android9,在其他的Android9和Android 4.4盒子上都跑过,没问题,排除了minSdkVersion的问题

ABI不支持?

不太可能,先不想这个

ADB才是王道

但凡遇到问题,只要设备能够adb,起码问题就解决了一半,但一问,说这盒子似乎不能Adb,,鹅鹅鹅饿~~ 后来借助adbhelper发现,此款盒子还是能adb,只是常规情况下adb的端口是60001,连上之后执行adb root的话,又会换回默认端口,这个情况我也是活久见。。

说正题,连上adb之后,通过抓日志,发现了如下问题:Permission denial: writing to settings requires:android.permission.WRITE_SECURE_SETTINGS,根据错误堆栈信息,大致是app调用了wifimanager.setWifiEnabled(true)这个方法引起的

解决

权限思路

因为自己对android.permission.WRITE_SECURE_SETTINGS这个权限并不太了解,所以从异常的字面意思理解,我以为是权限不够,所以我尝试让app拥有权限来确保其正常运行。

方法1:adb shell pm grant {包名} {权限内容}

执行命令,赋予该程序权限adb shell pm grant {packagename} android.permission.WRITE_SECURE_SETTINGS,执行命令之后,提示java.lang.SecurityException: Package xxxx has not requested permission android.permission.WRITE_SECURE_SETTINGS意思说该程序不需要这个权限,这个问题的原因是因为app并没有在清单文件中申明这个权限,这就有意思了,这个app操作需要这个权限却没有申请权限,可能主要原因是因为以前的低版本不需要,Android9需要吧,所以我们得先给他增加这个申明,然后再赋予这个权限。

通过apktool反编译,然后修改清单文件添加这个权限,再重新打包(后面再说具体得反编译重打包的步骤),一切妥当之后再次执行上面命令,果然老天是不会让我舒坦的,执行后出现异常:java.lang.SecurityException: Package android does not belong to 10034,触发问题的调用堆栈还是之前那个方法引起的。(⊙﹏⊙),思考半天,看了下它的清单文件,并没有申明targetSdkVersion,这有点怪哦,也是活久见,难道游戏apk就可以这么无视规则?那我要不给他增加上,,,嗯可以一试,还是相同的配方,给清单文件增加如下代码:

<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="22" />

然后重新打包,再来,没错,还是同样的味道,同样的问题,我以为修改来低于23,权限能够就自动允许了,现在想起来真是too young to simple。。

东搜搜西搜搜,想尝试下是不是因为这个程序不是系统app,后来将程序放在system/app下作为系统程序,还是同样问题,所以很显然,权限这条路行不通。

所以这个问题的解决办法应该参考如下内容:

这个错误是因为你的应用试图调用setWifiEnabled方法,这个方法在Android 9(API级别28)及以上版本已经被弃用。在这些版本中,只有系统应用才能调用setWifiEnabled方法。  
即使你的应用已经被安装为系统应用,并且已经获得了WRITE_SECURE_SETTINGS权限,它仍然不能调用setWifiEnabled方法。这是因为这个方法现在只能被系统UI调用,其他应用,包括系统应用,都不能调用这个方法。
你可以考虑使用WifiNetworkSuggestion API来提示用户连接到特定的Wi-Fi网络,或者使用Settings.Panel.ACTION_WIFI来引导用户到Wi-Fi设置页面。
以下是如何使用Settings.Panel.ACTION_WIFI的示例:
val intent = Intent(Settings.Panel.ACTION_WIFI)
startActivity(intent)
这段代码会打开Wi-Fi设置页面,让用户自己开启或关闭Wi-Fi。

修改程序源代码

权限的路行不通,那我们只能想办法修复app这段逻辑代码了,但是别人的apk,显然不是那么容易让人想改就改撒,提出是这里的问题,别人也不一定信啊,所以我打算自己改这个apk的编译后的源代码,让他不要触发引起异常的那个逻辑,绕过看程序能不能正常跑起来,这一步就需要懂得起smali,还好这个问题比较简单,定位到代码改了之后,重新打包,这下消停了,程序很好正常的运行。

反编译

反编译这一块涉及很多概念,以前大概接触过,都只是看,没有实际操作,有些时候操作也只是简单的反编译看下源码,但总体工具和涉及的概念主要有ApkTool、dex2jar-2.1、jarsigner、jd-gui,还有些文章提到SignApk.jar、jax-gui等;

说下自己的理解,假如我们需要重新打包一个apk,那么我们肯定要从这个apk得到我们可以编辑的文件进行修改,修改后再重新打包,这是我们需要的核心流程;

反编译APK

ApkTool,具体的作用自己查,大致意思是如果我们想看清单文件内容,资源文件之类的,我们就可以通过这个工具进行反编译,由于前面我需要给源程序在清单文件中新增权限申明,所以我们就需要先得到反编译的工程,然后直接修改清单文件即可(把AndroidManifest拖动到Android Studio或者其他文本编辑工具中直接修改然后保存即可)

  • 反编译apk :先在终端将当前位置定位到ApkTool的目录,然后执行命令apktool d {xxx.apk:你的apk名称},该命令会将apk反编译后保存在apktool所在目录下。也可以使用如下命令指定反编译后工程的存储路径apktool d -o {反编译后的存储目录} {xxx.apk},其实只需要知道反编译apk是使用的apktool d即可,查一下文档了解更详细的用法。

  • 重新编译:修改之后我们需要重新打包成apk,使用命令apk b {反编译后的存储目录},编译成功之后,会保存在指定目录下的dist文件夹中。也可以用-o 指定存储的目录。

重签名

apk反编译修改了,也重新编译成了新的apk,但此时这个apk是没有签名的,直接拿到设备上安装是不行的,所以我们需要签名。 这里就需要用到jarsign,这个应该是jdk内自带的jarsigner -verbose -keystore {签名文件路径:也就是keystore、jks文件} -signedjar {签名后的apk路径} {没有签名的apk路径} {使用的签名文件别名,也就是keyalias}如果没出错,则我们就拥有了已经签名的被修改过的apk了,可以去运行验证了。但是由于我们是用的自己签名文件签名的,是不能覆盖安装原来的apk的,两者签名不一致。

使用系统签名

这块我没尝试过,需要的自行查看搜索查看,附带个链接Android应用程序签名系统的签名(SignApk.jar)_新根的博客-CSDN博客

修改源码

跟直接修改清单文件的原理差不多,都是直接修改,但是由于是smali,就需要做一定的语法了解才能改了。也有工具可以将smali转换成java的,比如使用skylot/jadx: Dex to Java decompiler (github.com)工具,不过这个方法只是将smali转换成java来查阅,如果我们想重新打包,那还是必须修改smali文件才行的。

关于这一节建议参考:Android App 逆向入門之二:修改 smali 程式碼 (cymetrics.io)

额外说的:其实上面整个过程我们没用到dex2jar-2.1、jd-gui之类的,其实作用不同,dex2jar的作用是将apk的后缀改成zip解压出来会得到很多dex文件,我们通过dex2jar可以让这些dex转换成jar文件,jar文件就是常规生成的java class文件了,但是jar文件没法直接打开查看,就需要借助jd-gui之类的工具。。所以的目的是说我们想看看别人程序的代码的时候用的吧。

就到这吧,做个记录。。


作者:Andme
链接:https://juejin.cn/post/7257740918433529912
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册