[踩坑][Android]代码混淆引发的连环惨案

背景

老规矩,先交代背景。
现状是这样:

  1. wifi-ext-service.jar是我们开发的wifi的扩展接口的实现;
  2. wifi-service.jar与wifi-ext-service.jar均在编译时将代码混淆;
  3. wifi-ext-service.jar依赖wifi-service.jar;
  4. AOSP原生编译规则中,wifi-service.jar会静态依赖android.hardware.wifi-V1.0-java;
    在这里插入图片描述
    一切都相安无事,直到现在有个开发需求,需要wifi-ext-service.jar依赖android.hardware.wifi-V1.0-java并调用其中的IWifiChip/IWifi的某些函数;

问题 - 如何依赖

首先遇到的第一个两难问题:wifi-ext-service.jar在编译时到底要不要静态依赖android.hardware.wifi-V1.0-java?

选择1 非静态依赖android.hardware.wifi-V1.0-java

结果: 启动system_server时crash:

08-20 14:01:54.801  2911  2911 I system_server: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.hardware.wifi.V1_0.IWifiChip$requestChipDebugInfoCallback" on path: DexPathList[[zip file "/system/framework/services.jar", zip file "/system/framework/ethernet-service.jar", zip file "/system/framework/wifi-service.jar", zip file "/system/framework/com.android.location.provider.jar", zip file "/system/framework/car-frameworks-service.jar", zip file "/system/framework/wifi-ext-service.jar"],nativeLibraryDirectories=[/system/lib64, /system/product/lib64, /system/lib64, /system/product/lib64]]
08-20 14:01:54.801  2911  2911 I system_server:   at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:134)
08-20 14:01:54.801  2911  2911 I system_server:   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)
08-20 14:01:54.801  2911  2911 I system_server:   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
08-20 14:01:54.801  2911  2911 I system_server:   at void com.ext.server.wifi.q.<init>(android.content.Context) ((null):-1)
08-20 14:01:54.801  2911  2911 I system_server:   at void com.ext.server.wifi.WifiExtService.<init>(android.content.Context) ((null):-1)
08-20 14:01:54.801  2911  2911 I system_server:   at java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[]) (Constructor.java:-2)
08-20 14:01:54.801  2911  2911 I system_server:   at java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[]) (Constructor.java:343)
08-20 14:01:54.801  2911  2911 I system_server:   at com.android.server.SystemService com.android.server.SystemServiceManager.startService(java.lang.Class) (SystemServiceManager.java:98)
08-20 14:01:54.801  2911  2911 I system_server:   at com.android.server.SystemService com.android.server.SystemServiceManager.startService(java.lang.String) (SystemServiceManager.java:72)
08-20 14:01:54.801  2911  2911 I system_server:   at void com.android.server.SystemServer.startOtherServices() (SystemServer.java:1169)
08-20 14:01:54.801  2911  2911 I system_server:   at void com.android.server.SystemServer.run() (SystemServer.java:450)
08-20 14:01:54.801  2911  2911 I system_server:   at void com.android.server.SystemServer.main(java.lang.String[]) (SystemServer.java:303)
08-20 14:01:54.801  2911  2911 I system_server:   at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2)
08-20 14:01:54.801  2911  2911 I system_server:   at void com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run() (RuntimeInit.java:493)
08-20 14:01:54.801  2911  2911 I system_server:   at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:838)

原因分析:
由于非静态依赖并不会在编译时将需要的类打包进wifi-ext-service.jar中,而是需要在运行时,通过SYSTEMSERVERCLASSPATH环境变量,找到可能提供这些类的jar包,并依次查找。
而在此当中,唯一静态引入这些类的wifi-service.jar又将其混淆了,因此按照包名、类名查找的话,完全没法找到;

这里估计会有人想到,是不是可以修改proguard,使其在混淆时将指定包名下的类排除除去就可以了?确实如此,但是仍然会有概率遇到选择2时的这个问题:

选择2 静态依赖android.hardware.wifi-V1.0-java

结果: 开启热点后system_server进程crash:

08-20 14:22:26.449   984   984 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: main
08-20 14:22:26.449   984   984 E AndroidRuntime: java.lang.NoSuchMethodError: No static method p()Lb/a/a/a/b/a/a; in class Lb/a/a/a/b/a/a; or its super classes (declaration of 'b.a.a.a.b.a.a' appears in /system/framework/wifi-service.jar)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at com.ext.server.wifi.h.onReceive(Unknown Source:85)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0(LoadedApk.java:1391)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at android.os.Handler.handleCallback(Handler.java:873)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:99)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:193)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at com.android.server.SystemServer.run(SystemServer.java:473)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at com.android.server.SystemServer.main(SystemServer.java:303)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:838)

原因分析:
看到这两行我就觉得大概率和混淆有关了:

08-20 14:22:26.449   984   984 E AndroidRuntime: java.lang.NoSuchMethodError: No static method p()Lb/a/a/a/b/a/a; in class Lb/a/a/a/b/a/a; or its super classes (declaration of 'b.a.a.a.b.a.a' appears in /system/framework/wifi-service.jar)
08-20 14:22:26.449   984   984 E AndroidRuntime: 	at com.ext.server.wifi.h.onReceive(Unknown Source:85)
  • 首先,调用栈停留在wifi-ext-service.jar中的类,因此没有理由报wifi-service.jar中的类找不到方法;(wifi-ext-service主要是扩展wifi-service的接口,正常情况下不会反向持有wifi-service中的对象,何况wifi-service是混淆过的,要反向调用几乎不可能);
  • 其次,通过反编译发现,wifi-service.jar与wifi-ext-service.jar中都存在b.a.a.a.b.a.a这个类,而前者的这个类没有p()方法,后者是有的,与报错信息显示一致;
  • 为了确认这一推测,我通过对比反编译后的代码与源代码,确认反编译代码中提到的b.a.a.a.b.a.a类的p()方法实际为一个我自己创建的HAL接口的JAVA侧getService()方法调用;通过另一个静态JAVA库导入;

那么综合来看,结果比较明显了:由于wifi-service与wifi-ext-service各自在编译时并不知晓对方的存在(没有静态依赖),因此混淆时出现了类命名冲突的情况,导致在调用时跳转到了错误的类中,出现异常;

要解决这个问题,同样我们需要修改proguard文件,将具备区分度的包名保留;

解决 - 方案选择

在修改Proguard后,貌似上面两个选择都可以了:

  • 首先,需要为wifi-service的混淆添加例外,将android.hardware.wifi-V1.0-java包含的类从混淆的目标中移除出来:
-keep class android.hardware.wifi.**{*;}
  • 其次,为了防止a.a.a.a这种高概率会重复的类名冲突,需要将wifi-ext-service中大部分的包名区分出来:
-keeppackagenames vendor.ext.**

修改完后,问题得以解决;

后记 - 选择

最后,虽然使用同样的改法可以解决两个选择的问题,但是由于CTS测试项(详见https://blog.csdn.net/u014175785/article/details/115333461)的原因,以及我在调试过程中出现的交叉依赖导致ClassLoader加载报错等问题(这个问题在我写这篇文章时没有复现出来,因此没法展开介绍,后续如果再次遇到这类问题,届时再更新),我不建议采用静态依赖的方式导入;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值