朋友们现在只对常读和星标的公众号才展示大图推送,建议大家把“亿人安全“设为星标”,否则可能就看不到了啦
绕过APP强制更新 我们在拿到一些APP老版本的时候,可能会要求我们进行更新,有时候我们不更新,它的接口也是可以使用的,但是它会弹出更新框,盖住了APP,使我们无法进行操作,所以我们这时候需要绕过APP的强制更新
如何绕过强制更新 一般绕过强制更新有两种方法: 1、某些app启动向后端发送请求,获取APP的最新版本号,跟本地版本号做笔记,如果两个版本差距过大就会强制弹出窗,要求用户进行更新,但是他的弹窗代码在首页,只要切换到别的页面,这个弹窗就没了。对于这种形式的弹窗只需断开WiFi,进入app,然后连接WiFi,就可以绕过了。 2、第二种就是断网也绕不过的,只要联网,在任意一个界面都会弹出,这是我们可以通过反编译,找到弹窗位置进行hook
搜索:最新版本,只搜索到一个结果,双击进入,可以看出如果后端查到的版本高,就会弹出窗强制要求更新,只要执行updateDialog.show();就会弹窗,所以我们需要去hook这个方法,让他不运行
后面就要启动frida,然后进行端口转发
adb shell
su
cd /data/local/tmp/
ls
./frida-server-16.1.7-an
import subprocess
subprocess.getoutput("adb forward tcp:27042 tcp:27042")
subprocess.getoutput("adb forward tcp:27043 tcp:27043")
使用spawn方案
但是这时会发现只要运行hook脚本,APP就闪退了,这是因为做了frida反调试,那我们此时就要绕过frida反调试了,这就是下面要介绍的如何绕过frida反调试。
绕过frida反调试
import frida
import sys
rdev = frida.get_remote_device()
pid = rdev.spawn(["com.xxxx.xxxx"])
session = rdev.attach(pid)
scr = """
Java.perform(function () {
var dlopen = Module.findExportByName(null, "dlopen");
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
Interceptor.attach(dlopen, {
onEnter: function (args) {
var path_ptr = args[0];
var path = ptr(path_ptr).readCString();
console.log("[dlopen:]", path);
},
onLeave: function (retval) {
}
});
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var path_ptr = args[0];
var path = ptr(path_ptr).readCString();
console.log("[dlopen_ext:]", path);
},
onLeave: function (retval) {
}
});
});
"""
script = session.create_script(scr)
def on_message(message, data):
print(message, data)
script.on("message", on_message)
script.load()
rdev.resume(pid)
sys.stdin.read()
运行hook脚本后,会发现加载到/lib/arm64/libmsaoaidsec.so时程序崩了,删除该文件即可
这时我们需要绕过代理的检测,抓更底层的包,不抓https的包,抓socket的包,需要使用APP进行,这里我们使用SocksDroid.apk,使用之前关闭手机系统代理
与burpsuite进行联动 通过上一步我们已经绕过了APP的代理检测,但是我们想要将包转发到burp中应该怎么做呢?
在Charles点击External Proxy Settings设置,配置burp代理
配置好之后,burp就可以收到转发过来的数据包了
root检测和绕过方案
打开APP,由于我们的手机是root过的,所以一打开软件,会产生提示
手机端启动frida-server,然后进行端口转发 运行这个js脚本:
查看手机APP,此时以成功绕过
打开面具,进入模块,选择从本地安装,将zip刷入,点击重启
绕过方案三: 我们还可以通过反编译定位代码,通过hook进行绕过 反编译APP后,搜索"威胁您"
上述代码通过MiscUtil.isSimulator检测是否在模拟器中运行和 MiscUtil.isRooted()检测是否root。
我们先看 MiscUtil.isRooted()代码,可以看到这段代码主要是通过检查系统路径中的文件来判断是否是否被root,在"/system/xbin/", "/system/bin/", "/system/sbin/", "/sbin/", "/vendor/bin/", "/su/bin/"文件目录后进行拼接bh.y然后进行检测,我们bh.y可以发现该处的变量就是su,所以就是在上述路径后拼接su,查看这些目录下是否有su文件,如果有就返回true,没有就返回false
public static boolean isRooted() { String[] strArr = {"/system/xbin/", "/system/bin/", "/system/sbin/", "/sbin/", "/vendor/bin/", "/su/bin/"}; for (int i2 = 0; i2 < 6; i2++) { try { String str = strArr[i2] + bh.y; if (new File(str).exists()) { String exec = exec(new String[]{"ls", "-l", str}); String str2 = "isRooted=" + exec; if (TextUtils.isEmpty(exec) || exec.indexOf("root") == exec.lastIndexOf("root")) { return false; } return true; } } catch (Exception e2) { e2.printStackTrace(); } } return false; }
接下来我们查看MiscUtil.isSimulator代码,该段代码主要是查看Build文件中,有没有一些虚拟设备的关键词,该处可以直接写hook脚本进行绕过
public static boolean isSimulator(Context context) {
return Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.toLowerCase().contains("vbox") || Build.FINGERPRINT.toLowerCase().contains("test-keys") || Build.MODEL.contains("google_sdk") || Build.MODEL.contains("Emulator") || Build.MODEL.contains("MuMu") || Build.MODEL.contains("virtual") || Build.SERIAL.equalsIgnoreCase("android") || Build.MANUFACTURER.contains("Genymotion") || (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")) || "google_sdk".equals(Build.PRODUCT) || ((TelephonyManager) context.getSystemService(AliyunLogCommon.TERMINAL_TYPE)).getNetworkOperatorName().toLowerCase().equals("android");
}