
1. 为什么需要逆向MIUI的framework.jar第一次逆向MIUI系统的时候我踩了个大坑。当时在做一个资源替换的功能在其他品牌的手机上运行得好好的一到小米手机上就直接崩溃。调试的时候发现小米竟然自己实现了一个MiuiResources类来管理资源这跟原生Android完全不同。这种情况在Android开发中很常见。不同厂商都会对系统进行深度定制而小米的MIUI系统又是出了名的魔改王。framework.jar作为Android系统的核心框架包含了ActivityManager、PackageManager这些关键类。如果你要做系统级开发或者插件化不搞清楚这些定制代码很容易掉坑里。我遇到的具体问题是资源替换失效。后来发现是因为MIUI重写了Resources类的加载逻辑导致常规的hook方法完全失效。这时候就必须把framework.jar反编译出来看看小米到底改了哪些东西。这就是逆向工程的价值——当官方文档不完善时直接看代码是最靠谱的解决方案。2. 获取framework.jar的两种实战方法2.1 从手机直接提取适用于Android 5.0-6.0第一次尝试时我像处理其他手机一样直接去/system/framework目录找framework.jar。结果发现小米的这个jar包居然是空的文件大小只有几十KB明显不正常。后来查资料才知道在Android 5.0到6.0的MIUI系统上真正的框架代码被编译成了boot.oat文件。这个文件位于/system/framework/arm/目录下x86架构的设备则在x86目录。提取步骤是这样的先获取root权限需要解锁BL使用adb pull命令把boot.oat拉取到电脑adb pull /system/framework/arm/boot.oat ~/Desktop/用oat2dex工具转换java -jar oat2dex.jar boot boot.oat这个命令会生成对应的dex文件然后就可以用dex2jar工具转换成可读的jar包了。2.2 从ROM包提取通用方法更通用的方法是从MIUI官方ROM中提取。小米的ROM包结构比较特殊主要步骤如下到小米社区下载对应机型的完整ROM包解压后会看到system.new.dat.br文件使用Brotli工具解压brotli -d system.new.dat.br -o system.new.dat再用sdat2img转换成img镜像sdat2img.py system.transfer.list system.new.dat system.img最后用7-Zip或者ROM助手解压system.img这个方法虽然步骤多但适用于所有MIUI版本。我建议把解压出来的整个framework目录都保存好因为除了framework.jar像services.jar、core-oj.jar这些也都可能包含定制代码。3. 逆向分析的关键工具链3.1 dex2jar的使用技巧拿到dex文件后我习惯用dex2jar的最新版本来转换d2j-dex2jar.sh framework.jar -o framework-dex2jar.jar这里有几个常见问题需要注意如果遇到com.googlecode.d2j.DexException: not support version错误说明dex版本太新需要更新工具转换后的jar包用JD-GUI打开时部分代码可能显示不全这时可以尝试用Bytecode Viewer对于混淆过的代码建议配合CFR反编译器使用3.2 代码对比分析逆向出来的代码往往很庞大我常用的分析方法是先反编译原生AOSP的对应版本framework用Beyond Compare与MIUI的代码做对比重点关注重写的方法和新增的类比如在分析MiuiResources时我发现小米重写了loadXmlResourceParser方法这就是导致我资源替换失败的根本原因。4. 典型逆向案例分析MiuiResources让我们具体看看MIUI是怎么魔改Resources的。逆向出来的MiuiResources类主要做了这些改动新增了主题资源加载逻辑public XmlResourceParser loadXmlResourceParser(NonNull String file, int id, boolean overlay) throws NotFoundException { // 先尝试从主题包加载 if (mThemeResources ! null) { XmlResourceParser tpp mThemeResources.loadXml(file, id); if (tpp ! null) return tpp; } // 再走默认逻辑 return super.loadXmlResourceParser(file, id, overlay); }修改了资源缓存策略增加了动态图标支持这些改动导致常规的资源替换方案在MIUI上失效。我的解决方案是hook掉整个MiuiResources实例而不是像原生Android那样只替换其中的AssetManager。5. 逆向过程中的常见问题解决5.1 版本兼容性问题不同MIUI版本的framework差异很大。我遇到过的情况包括Android 6.0的MIUI 8使用oat格式Android 9.0的MIUI 11又改回了jar格式Android 12的MIUI 13引入了新的权限控制建议建立版本对照表记录各个版本的特性变化。5.2 反编译失败处理当遇到反编译工具报错时可以尝试使用多个工具交叉验证如jadxbytecode-viewer手动修复dex文件头对于部分损坏的dex可以直接分析smali代码5.3 代码混淆问题MIUI从版本12开始对部分框架代码进行了混淆。对于这种情况先识别出关键的系统类如ActivityThread通过方法签名和调用关系推断功能结合运行时日志分析实际调用流程6. 进阶技巧动态调试framework代码静态分析有时不够直观我更喜欢用动态调试的方法在Android Studio中导入反编译的framework源码使用smalidea插件调试smali代码关键断点位置ActivityThread的main方法Instrumentation的newApplicationResourcesManager的getResources动态调试可以帮助理解代码的实际执行流程特别是对于MIUI这种深度定制的系统。记得调试时要使用eng或者userdebug版本的系统镜像。逆向MIUI框架最考验的是耐心。有时候为了找一个方法的实现需要在几十个dex文件中反复搜索。但一旦理清了它的设计思路很多兼容性问题就迎刃而解了。我的经验是遇到问题先别急着hack把framework的代码读透才是根本解决方案。