Android实战:过root检测

在启动这个app时,我们会看到一个提示,表示设备处于root环境。如下图所示:
在这里插入图片描述

为了过掉到这个root检测,我们可以通过直接Hook Toast.show()方法,并打印调用堆栈信息来实现定位关键代码。以下是相关的Frida脚本代码:

Java.perform(function () {
    function showStacks() {
        console.log(
            Java.use("android.util.Log")
                .getStackTraceString(
                    Java.use("java.lang.Throwable").$new()
                )
        );
    }
    // Hook the android.widget.Toast class
    var Toast = Java.use("android.widget.Toast");
    Toast.show.implementation = function () {
        showStacks();
        console.log("Toast.show() called!");
        console.log("Toast message: " + this.getView().getAccessibilityClassName());
        this.show();
    };
});

调用堆栈信息如下:

[Pixel 4::com.hoge.android.app.fujian]-> java.lang.Throwable                                 
        at android.widget.Toast.show(Native Method)                                          
        at com.hoge.android.util.CustomToast.showToast(CustomToast.java:172)                 
        at com.hoge.android.factory.welcome.WelcomeActivity$2$1.run(WelcomeActivity.java:260)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

从堆栈信息中,我们可以看到关键函数为com.hoge.android.factory.welcome.WelcomeActivity$2$1.run()。我们可以使用JEB反编译APK,并查看代码,发现如下内容:

  Util.getHandler(WelcomeActivity.this.mContext).postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if((SystemUtils.checkSuFile()) && SystemUtils.checkRootFile() != null) {
                            CustomToast.showToast(WelcomeActivity.this.mContext, WelcomeActivity.this.getString(0x7F11071B), 100);  // string:root_toast "当前设备可能处于root环境,继续运行应用将有风险"
                        }
                    }
                }, 1000L);

因此这里的关键函数为SystemUtils.checkSuFile()和SystemUtils.checkRootFile(),继续跟进这两个函数,看看究竟是怎么进行检测root环境的。checkSuFile()函数的代码如下:

public static boolean checkSuFile() {
    Process process0 = null; 

    try {
        // 尝试执行系统命令 "which su" 来检查是否存在 su 文件
        process0 = Runtime.getRuntime().exec(new String[]{"which", "su"});
        // 读取命令的输出,检查输出的第一行
        String s = new BufferedReader(new InputStreamReader(process0.getInputStream())).readLine();
    }
    catch (Throwable unused_ex) {
        if (process0 != null) {
            process0.destroy();
        }
        return false;  
    }
    catch (Throwable throwable0) {
        if (process0 != null) {
            process0.destroy();
        }

        throw throwable0;
    }
    // 如果读取到的结果不为null,说明设备上存在su文件
    if (s != null) {
        if (process0 != null) {
            process0.destroy();
        }

        return true;
    }
    if (process0 != null) {
        process0.destroy();
    }

    return false; 
}

checkSuFile()函数核心就是通过which su命令检测su文件是否存在。接下来继续查看SystemUtils.checkRootFile()代码:

public static File checkRootFile() {
    //包含可能存在的root文件路径
    String[] arr_s = {
        "/sbin/su", 
        "/system/bin/su", 
        "/system/xbin/su", 
        "/data/local/xbin/su", 
        "/data/local/bin/su", 
        "/system/sd/xbin/su", 
        "/system/bin/failsafe/su", 
        "/data/local/su"
    };
    
    File file0 = null;
    int v = 0;
    
    // 遍历所有路径
    while (v < arr_s.length) {
        File file1 = new File(arr_s[v]);
        
        // 检查当前路径的文件是否存在
        if (file1.exists()) {
            return file1;
        }

        ++v;
        file0 = file1; 
    }
    return file0;
}

checkRootFile()函数功能也相对简单,就是检测su文件可能存在路径。因此过掉这个这个root检测的方法很简单,只需要将checkSuFile()函数返回false,checkRootFile()函数返回null即可。Frida hook代码如下:

Java.perform(function() {
    var SystemUtils = Java.use('com.hoge.android.factory.util.system.SystemUtils');

    SystemUtils.checkSuFile.implementation = function() {
        console.log('checkSuFile() is call');
        return false;  // 返回 false
    };
    SystemUtils.checkRootFile.implementation = function() {
        console.log('checkRootFile() is call');
        return null;
    };
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值