35.安卓逆向2-frida hook技术-过root检测
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
内容参考于:图灵Python学院
工具下载:
链接:https://pan.baidu.com/s/1bb8NhJc9eTuLzQr39lF55Q?pwd=zy89
提取码:zy89
复制这段内容后打开百度网盘手机App,操作更方便哦
上一个内容:34.安卓逆向2-frida hook技术-逆向分析加密方式(一)(api-sign so层)-利用ai大模型分析代码
之前写的是使用frida hook一些方法(java层和so层),有些app在注入frida的时候,它会强制退出,然后有些app打开的时候还会有root检测
首先是过root检测,如下图,获取root后开启app后会自动关闭,然后提示禁止Root设备启动应用,就是有些厂商为了防止使用工具调试他的app,比如使用frida调试app,做的root检测,特别是做安全的公司,root检测是最入门的技术,就为了规避别人来调试
然后又想要root,又想要app可以正常运行,不可能为了这个app把手机解root去运行,怎么办?可以找到app的root检测点,让给它干掉,app的检测肯定也是要用代码来检测,只要有代码就能干掉
root检测解决办法
修改su文件名
使用adb shell然后执行su会得到最高权限,检测root的方式就可以检测手机中是否存在su文件,就可以给su文件改个名字,来过root检测,如下图,su文件位置(不同的手机可能su所在的目录不一样)
![]()
如果su文件不在sbin目录中,直接问ai大模型让它列出su文件所有目录下图是ai给的su文件可能存在的目录
![]()
frida脚本过root检测,它的原理是隐藏 "su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk", "magisk" 这些东西,这些东西都是用来获取root的,使用 frida -Uf xxx -l xxxx 这个重启app的指令注入
/*
Original author: Daniele Linguaglossa
28/07/2021 - Edited by Simone QuatriniCode amended to correctly run on the latest frida versionAdded controls to exclude Magisk Manager
*/Java.perform(function() {var RootPackages = ["com.noshufou.android.su", "com.noshufou.android.su.elite", "eu.chainfire.supersu","com.koushikdutta.superuser", "com.thirdparty.superuser", "com.yellowes.su", "com.koushikdutta.rommanager","com.koushikdutta.rommanager.license", "com.dimonvideo.luckypatcher", "com.chelpus.lackypatch","com.ramdroid.appquarantine", "com.ramdroid.appquarantinepro", "com.devadvance.rootcloak", "com.devadvance.rootcloakplus","de.robv.android.xposed.installer", "com.saurik.substrate", "com.zachspong.temprootremovejb", "com.amphoras.hidemyroot","com.amphoras.hidemyrootadfree", "com.formyhm.hiderootPremium", "com.formyhm.hideroot", "me.phh.superuser","eu.chainfire.supersu.pro", "com.kingouser.com", "com.topjohnwu.magisk"];var RootBinaries = ["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk", "magisk"];var RootProperties = {"ro.build.selinux": "1","ro.debuggable": "0","service.adb.root": "0","ro.secure": "1"};var RootPropertiesKeys = [];for (var k in RootProperties) RootPropertiesKeys.push(k);var PackageManager = Java.use("android.app.ApplicationPackageManager");var Runtime = Java.use('java.lang.Runtime');var NativeFile = Java.use('java.io.File');var String = Java.use('java.lang.String');var SystemProperties = Java.use('android.os.SystemProperties');var BufferedReader = Java.use('java.io.BufferedReader');var ProcessBuilder = Java.use('java.lang.ProcessBuilder');var StringBuffer = Java.use('java.lang.StringBuffer');var loaded_classes = Java.enumerateLoadedClassesSync();send("Loaded " + loaded_classes.length + " classes!");var useKeyInfo = false;var useProcessManager = false;send("loaded: " + loaded_classes.indexOf('java.lang.ProcessManager'));if (loaded_classes.indexOf('java.lang.ProcessManager') != -1) {try {//useProcessManager = true;//var ProcessManager = Java.use('java.lang.ProcessManager');} catch (err) {send("ProcessManager Hook failed: " + err);}} else {send("ProcessManager hook not loaded");}var KeyInfo = null;if (loaded_classes.indexOf('android.security.keystore.KeyInfo') != -1) {try {//useKeyInfo = true;//var KeyInfo = Java.use('android.security.keystore.KeyInfo');} catch (err) {send("KeyInfo Hook failed: " + err);}} else {send("KeyInfo hook not loaded");}PackageManager.getPackageInfo.overload('java.lang.String', 'int').implementation = function(pname, flags) {var shouldFakePackage = (RootPackages.indexOf(pname) > -1);if (shouldFakePackage) {send("Bypass root check for package: " + pname);pname = "set.package.name.to.a.fake.one.so.we.can.bypass.it";}return this.getPackageInfo.overload('java.lang.String', 'int').call(this, pname, flags);};NativeFile.exists.implementation = function() {var name = NativeFile.getName.call(this);var shouldFakeReturn = (RootBinaries.indexOf(name) > -1);if (shouldFakeReturn) {send("Bypass return value for binary: " + name);return false;} else {return this.exists.call(this);}};var exec = Runtime.exec.overload('[Ljava.lang.String;');var exec1 = Runtime.exec.overload('java.lang.String');var exec2 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;');var exec3 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;');var exec4 = Runtime.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File');var exec5 = Runtime.exec.overload('java.lang.String', '[Ljava.lang.String;', 'java.io.File');exec5.implementation = function(cmd, env, dir) {if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {var fakeCmd = "grep";send("Bypass " + cmd + " command");return exec1.call(this, fakeCmd);}if (cmd == "su") {var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";send("Bypass " + cmd + " command");return exec1.call(this, fakeCmd);}return exec5.call(this, cmd, env, dir);};exec4.implementation = function(cmdarr, env, file) {for (var i = 0; i < cmdarr.length; i = i + 1) {var tmp_cmd = cmdarr[i];if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {var fakeCmd = "grep";send("Bypass " + cmdarr + " command");return exec1.call(this, fakeCmd);}if (tmp_cmd == "su") {var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";send("Bypass " + cmdarr + " command");return exec1.call(this, fakeCmd);}}return exec4.call(this, cmdarr, env, file);};exec3.implementation = function(cmdarr, envp) {for (var i = 0; i < cmdarr.length; i = i + 1) {var tmp_cmd = cmdarr[i];if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {var fakeCmd = "grep";send("Bypass " + cmdarr + " command");return exec1.call(this, fakeCmd);}if (tmp_cmd == "su") {var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";send("Bypass " + cmdarr + " command");return exec1.call(this, fakeCmd);}}return exec3.call(this, cmdarr, envp);};exec2.implementation = function(cmd, env) {if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {var fakeCmd = "grep";send("Bypass " + cmd + " command");return exec1.call(this, fakeCmd);}if (cmd == "su") {var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";send("Bypass " + cmd + " command");return exec1.call(this, fakeCmd);}return exec2.call(this, cmd, env);};exec.implementation = function(cmd) {for (var i = 0; i < cmd.length; i = i + 1) {var tmp_cmd = cmd[i];if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id" || tmp_cmd == "sh") {var fakeCmd = "grep";send("Bypass " + cmd + " command");return exec1.call(this, fakeCmd);}if (tmp_cmd == "su") {var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";send("Bypass " + cmd + " command");return exec1.call(this, fakeCmd);}}return exec.call(this, cmd);};exec1.implementation = function(cmd) {if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id" || cmd == "sh") {var fakeCmd = "grep";send("Bypass " + cmd + " command");return exec1.call(this, fakeCmd);}if (cmd == "su") {var fakeCmd = "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled";send("Bypass " + cmd + " command");return exec1.call(this, fakeCmd);}return exec1.call(this, cmd);};String.contains.implementation = function(name) {if (name == "test-keys") {send("Bypass test-keys check");return false;}return this.contains.call(this, name);};var get = SystemProperties.get.overload('java.lang.String');get.implementation = function(name) {if (RootPropertiesKeys.indexOf(name) != -1) {send("Bypass " + name);return RootProperties[name];}return this.get.call(this, name);};Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {onEnter: function(args) {var path = Memory.readCString(args[0]);path = path.split("/");var executable = path[path.length - 1];var shouldFakeReturn = (RootBinaries.indexOf(executable) > -1)if (shouldFakeReturn) {Memory.writeUtf8String(args[0], "/notexists");send("Bypass native fopen");}},onLeave: function(retval) {}});Interceptor.attach(Module.findExportByName("libc.so", "system"), {onEnter: function(args) {var cmd = Memory.readCString(args[0]);send("SYSTEM CMD: " + cmd);if (cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1 || cmd == "id") {send("Bypass native system: " + cmd);Memory.writeUtf8String(args[0], "grep");}if (cmd == "su") {send("Bypass native system: " + cmd);Memory.writeUtf8String(args[0], "justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled");}},onLeave: function(retval) {}});/*TO IMPLEMENT:Exec Familyint execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);int execv(const char *path, char *const argv[]);int execve(const char *path, char *const argv[], char *const envp[]);int execvp(const char *file, char *const argv[]);int execvpe(const char *file, char *const argv[], char *const envp[]);*/BufferedReader.readLine.overload('boolean').implementation = function() {var text = this.readLine.overload('boolean').call(this);if (text === null) {// just pass , i know it's ugly as hell but test != null won't work :(} else {var shouldFakeRead = (text.indexOf("ro.build.tags=test-keys") > -1);if (shouldFakeRead) {send("Bypass build.prop file read");text = text.replace("ro.build.tags=test-keys", "ro.build.tags=release-keys");}}return text;};var executeCommand = ProcessBuilder.command.overload('java.util.List');ProcessBuilder.start.implementation = function() {var cmd = this.command.call(this);var shouldModifyCommand = false;for (var i = 0; i < cmd.size(); i = i + 1) {var tmp_cmd = cmd.get(i).toString();if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd.indexOf("mount") != -1 || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd.indexOf("id") != -1) {shouldModifyCommand = true;}}if (shouldModifyCommand) {send("Bypass ProcessBuilder " + cmd);this.command.call(this, ["grep"]);return this.start.call(this);}if (cmd.indexOf("su") != -1) {send("Bypass ProcessBuilder " + cmd);this.command.call(this, ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"]);return this.start.call(this);}return this.start.call(this);};if (useProcessManager) {var ProcManExec = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.io.File', 'boolean');var ProcManExecVariant = ProcessManager.exec.overload('[Ljava.lang.String;', '[Ljava.lang.String;', 'java.lang.String', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'java.io.FileDescriptor', 'boolean');ProcManExec.implementation = function(cmd, env, workdir, redirectstderr) {var fake_cmd = cmd;for (var i = 0; i < cmd.length; i = i + 1) {var tmp_cmd = cmd[i];if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {var fake_cmd = ["grep"];send("Bypass " + cmdarr + " command");}if (tmp_cmd == "su") {var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];send("Bypass " + cmdarr + " command");}}return ProcManExec.call(this, fake_cmd, env, workdir, redirectstderr);};ProcManExecVariant.implementation = function(cmd, env, directory, stdin, stdout, stderr, redirect) {var fake_cmd = cmd;for (var i = 0; i < cmd.length; i = i + 1) {var tmp_cmd = cmd[i];if (tmp_cmd.indexOf("getprop") != -1 || tmp_cmd == "mount" || tmp_cmd.indexOf("build.prop") != -1 || tmp_cmd == "id") {var fake_cmd = ["grep"];send("Bypass " + cmdarr + " command");}if (tmp_cmd == "su") {var fake_cmd = ["justafakecommandthatcannotexistsusingthisshouldthowanexceptionwheneversuiscalled"];send("Bypass " + cmdarr + " command");}}return ProcManExecVariant.call(this, fake_cmd, env, directory, stdin, stdout, stderr, redirect);};}if (useKeyInfo) {KeyInfo.isInsideSecureHardware.implementation = function() {send("Bypass isInsideSecureHardware");return true;}}});
有些app使用上方的frida脚本注入后还是没办法过检测,这时可以使用面具安装Shamiko来排除app,下图红框是面具
下载Shamiko后不需要解压直接放到手机上,然后选择从本地安装,找到放 Shamiko 的目录,然后找到Shamiko的压缩包,然后点击压缩包就可以了
下图是安装 Shamiko 后的
安装完 Shamiko 后,然后来到主页点击下图红框
勾选下图红框
然后点击下图红框
然后点击下图红框位置,全部勾选上,重新打开app就可以了