雪豹速清_2.9.0 逆向思路

雪豹速清_2.9.0 逆向思路

image-20240622194045497

当时刚下载的时候在期末考,没时间分析。今天刚打开软件就跳出个更新弹窗,正好来分析一下

image-20240622183507025

首先用MT管理器的Activity记录功能获取到这个更新弹窗的类名为:

1
com.afollestad.materialdialogs.MaterialDialog

弹窗之所以会跳出是因为调用了show()方法,再想想为什么会跳出更新弹窗

很大可能是在app刚启动的时候,进行是否有新版本的判断,如果有新版本就调用MaterialDialog的show()方法来跳出更新弹窗

所以HOOK MaterialDialog的show()方法,当show()方法被调用时打印当前堆栈看看show()方法的调用链:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
//打印堆栈
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上)*

1
frida -U -f com.idaodan.clean.master -l D:\Code_Project\JS_project\demo1\雪豹速清_2.9.0.js --no-pause
image-20240622194437680

打印出堆栈:

1
2
3
4
5
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

回到堆栈这里,打印出的堆栈里的这些方法是由下到上调用的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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类下的所有方法:

1
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

1
2
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

梳理一下调用链:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
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编码

1
2
3
4
5
6
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看看情况):

1
2
3
4
5
6
7
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