# 雪豹速清_2.9.0 逆向思路 # 雪豹速清_2.9.0 逆向思路 image-20240622194045497 ## 一、去除更新提示 当时刚下载的时候在期末考,没时间分析。今天刚打开软件就跳出个更新弹窗,正好来分析一下 image-20240622183507025 首先用MT管理器的Activity记录功能获取到这个更新弹窗的类名为: ```java com.afollestad.materialdialogs.MaterialDialog ``` 弹窗之所以会跳出是因为调用了show()方法,再想想为什么会跳出更新弹窗 很大可能是在app`刚启动的时候,进行是否有新版本的判断`,如果有新版本就调用MaterialDialog的show()方法来跳出更新弹窗 所以HOOK MaterialDialog的show()方法,当show()方法被调用时打印当前堆栈看看show()方法的调用链: ```javascript //打印堆栈 function showStacks() { console.log( Java.use("android.util.Log") .getStackTraceString( Java.use("java.lang.Throwable").$new() ) ); } //HOOK MaterialDialog的show()方法 let MaterialDialog = Java.use("com.afollestad.materialdialogs.MaterialDialog"); MaterialDialog["show"].implementation = function () { showStacks();//调用时打印堆栈 console.log(`MaterialDialog.show is called`); this["show"](); }; ``` spwan方式运行HOOK脚本: > spwan方式是会重启app,在app刚开始运行的时候就执行hook代码*(这样才能在show()被调用之前hook上)* ```shell frida -U -f com.idaodan.clean.master -l D:\Code_Project\JS_project\demo1\雪豹速清_2.9.0.js --no-pause ``` image-20240622194437680 打印出堆栈: ``` com.afollestad.materialdialogs.MaterialDialog.show(Native Method) com.afollestad.materialdialogs.MaterialDialog$Builder.ۦۜۗ(Unknown Source:4) o.oOO0oooO.ۦۦ(Unknown Source:260) o.oOO0oooO.ۦۦ(Unknown Source:1) o.O0O000oO.run(Unknown Source:109) ``` > 仔细看这个堆栈信息,发现有的方法名是一个奇怪的符号:ۦۦ > > 这个app做了混淆,所以有很多类似下图这种极其抽象的符号: > > image-20240622204048675 回到堆栈这里,打印出的堆栈里的这些方法是由下到上调用的: ``` o.oOO0oooO.ۦۦ(Unknown Source:1) ↓调用↓ o.oOO0oooO.ۦۦ(Unknown Source:260) ↓调用↓ com.afollestad.materialdialogs.MaterialDialog$Builder.ۦۜۗ(Unknown Source:4) ↓调用↓ com.afollestad.materialdialogs.MaterialDialog.show(Native Method) ``` com.afollestad.materialdialogs.MaterialDialog$Builder.ۦۜۗ 就不用看了,是MaterialDialog类下的,这个方法肯定是调用了show()方法 用Jadx看看那两个o.oOO0oooO.ۦۦ 方法的内容: > 这里搜出来的方法名叫m\*\*\*\*\*是因为Jadx为了方便分析把方法名`ۦۦ` 重命名了(这种混淆符号确实让人眼睛难受) image-20240622201105473 搜到一堆重载方法,不知道是哪个,用objection hook o.oOO0oooO类下的所有方法: ```shell objection -g com.idaodan.clean.master explore --startup-command "android hooking watch class_method o.oOO0oooO.ۦۦ" ``` 这个命令的意思是用spwan方式hook o.oOO0oooO.ۦۦ 类下的所有方法: image-20240622203522350 报错了,说没找到这个方法,不知道是不是我操作的问题。没办法只能用attach方式hook试试: > attach方式是在app已经启动的情况下hook ```shell objection -g com.idaodan.clean.master explore android hooking watch class_method o.oOO0oooO.ۦۦ ``` 虽然报了一些错误,但还是hook上了: image-20240622204418954 这时候就有个问题,因为是以attach方式hook的,不是在app刚启动的时候hook而是在app正在运行的时候hook的。所以就没法通过app刚启动时弹出的更新弹窗来触发hook代码 可以通过点击“检查更新”按钮来弹出更新弹窗从而触发hook代码: image-20240622204722399 点击后在控制台上看到先触发`o.oOO0oooO.ۦۦ()`,然后触发`o.oOO0oooO.ۦۦ(android.app.Activity, o.oOO0oooo, boolean)` image-20240622205028295 梳理一下调用链: ``` o.oOO0oooO.ۦۦ() ↓调用↓ o.oOO0oooO.ۦۦ(android.app.Activity, o.oOO0oooo, boolean) ↓调用↓ com.afollestad.materialdialogs.MaterialDialog$Builder.ۦۜۗ() ↓调用↓ com.afollestad.materialdialogs.MaterialDialog.show() ``` o.oOO0oooO.ۦۦ(android.app.Activity, o.oOO0oooo, boolean)离MaterialDialog类最近,包含判断是否更新的相关代码的概率比较大,先看看: image-20240622210135613 顺便标记出调用com.afollestad.materialdialogs.MaterialDialog$Builder.ۦۜۗ()方法的地方: > m3836是Jadx将 ۦۜۗ 重命名方便分析 image-20240622213737206 来详细看看这个方法里的内容: image-20240622214517793 ***来梳理一下总的思路:*** ***一旦执行到`this.f30496 = m3881.m3836();`就会调用show()方法弹出更新弹窗,所以只要能想办法让这个方法`不执行到这句代码`,就相当于去除更新!!!*** 我这里提供一种让方法执行不到 this.f30496 = m3881.m3836();的思路: image-20240622215736481 代码是从上到下执行的,上面这里有个if判断,只要`c8453oOO0oooo.f30509 <= m27683`为true,最终一定会执行里面的其中一个return,这样就会直接结束这个方法,从而不会执行到this.f30496 = m3881.m3836(); 因为f30509和m27683都是int类型的数,要想让c8453oOO0oooo.f30509 <= m27683为true,将f30509的值改成0或者将m27683的值改成很大 我这里以后者为例 m27683的值是通过执行`C6905o0ooOO0OO.m27683(C6451o0oO0Oooo.f25301)`来获得的 所以可以hook或者直接修改smali代码,将C6905o0ooOO0OO.m27683的返回值强行改成一个非常大的数 > 注意这里的C6905o0ooOO0OO.m27683是经过Jadx重命名来方便看的 > > image-20240622221218855 > > hook或者修改smali时应该用原本的类名和方法名: > > `o.o0ooOO0OO.ۥۚ۠` 这里为了快速验证之前的思路是否正确,所以直接用HOOK来修改: > \u06E5\u06DA\u06E0是方法名`ۥۚ۠` 的Unicode编码 ```javascript let C6905o0ooOO0OO = Java.use("o.o0ooOO0OO"); C6905o0ooOO0OO["\u06E5\u06DA\u06E0"].overload('android.content.Context').implementation = function (context) { let result = this["\u06E5\u06DA\u06E0"](context); console.log(`C6905o0ooOO0OO.m27683 result=${result}`); return result; }; ``` spwan方式运行HOOK脚本: image-20240622222044016 当更新弹窗跳出来前确实调用了了C6905o0ooOO0OO.m27683方法,验证了前面的一系列分析。 接下来修改hook代码,将返回值强行改成一个很大的数(因为不知道c8453oOO0oooo.f30509的值是多少,所以直接把C6905o0ooOO0OO.m27683的返回值改成9999看看情况): ```javascript let C6905o0ooOO0OO = Java.use("o.o0ooOO0OO"); C6905o0ooOO0OO["\u06E5\u06DA\u06E0"].overload('android.content.Context').implementation = function (context) { let result = this["\u06E5\u06DA\u06E0"](context); result = 9999; console.log(`C6905o0ooOO0OO.m27683 result=${result}`); return result; }; ``` ***spwan方式运行HOOK脚本,这时候C6905o0ooOO0OO.m27683的返回值被强行改成9999,发现没有弹出更新弹窗,去除更新成功!*** 这里演示的思路是将C6905o0ooOO0OO.m27683的返回值被强行改成一个固定的很大的数字,如果是将c8453oOO0oooo.f30509的值强行改成固定的0行,只要满足c8453oOO0oooo.f30509 <= m27683