在Hook与反Hook的道路上参考大厂的技术是最为有效的,在我hook过的app也就微信和抖音居多了,正好昨天想分析一下抖音,所以Jadx打开抖音apk了,所以今天就来记录一下抖音的防Xposed实现。
严重声明 本文的意图只有一个就是通过分析app学习更多的逆向技术,如果有人利用本文知识和技术进行非法操作进行牟利,带来的任何法律责任都将由操作者本人承担,和本文作者无任何关系,最终还是希望大家能够秉着学习的心态阅读此文。
1.打开apk
电脑浏览器进入360应用市场,直接搜索抖音,下载apk文件,使用bin/jadx-gui打开apk,搜索文本一下,让子弹飞一会儿
2.搜索文本xposed
可以看到搜索中主要有两个文件中有所涉及
方法isInstallXposed
可以看到这是很常见的自造异常检测方法。
通过自造异常,读取异常堆栈中是否包含xposed字符串来识别,但isInstallXposed方法并没有被用到。
类C29647a
/* renamed from: com.ss.sys.ces.c.a */
public class C29647a {
/* renamed from: a */
private static String f86072a = "a";
/* renamed from: b */
private static String f86073b = "XposedBridge.jar";
/* renamed from: c */
private static String f86074c = "de.robv.android.xposed.XposedBridge";
/* renamed from: d */
private static String f86075d = "com.saurik.substrate";
/* renamed from: e */
private static String f86076e = "com.saurik.substrate.MS$2";
/* renamed from: a */
public static boolean m56344a() {
return C29647a.m56345a(f86073b) && C29647a.m56347c();
}
/* renamed from: a */
private static boolean m56345a(String str) {
try {
String readLine;
Set<String> hashSet = new HashSet();
StringBuilder stringBuilder = new StringBuilder("/proc/");
stringBuilder.append(Process.myPid());
stringBuilder.append("/maps");
BufferedReader bufferedReader = new BufferedReader(new FileReader(stringBuilder.toString()));
while (true) {
readLine = bufferedReader.readLine();
if (readLine == null) {
break;
} else if (readLine.endsWith(".so") || readLine.endsWith(".jar")) {
hashSet.add(readLine.substring(readLine.lastIndexOf(ZegoConstants.ZegoVideoDataAuxPublishingStream) + 1));
}
}
bufferedReader.close();
for (String readLine2 : hashSet) {
if (readLine2.contains(str)) {
return true;
}
}
} catch (Throwable unused) {
return false;
}
}
/* renamed from: b */
public static boolean m56346b() {
return C29647a.m56345a(f86075d) && C29647a.m56348d();
}
/* renamed from: c */
private static boolean m56347c() {
try {
throw new Exception("");
} catch (Exception e) {
for (StackTraceElement className : e.getStackTrace()) {
if (className.getClassName().equals(f86074c)) {
return true;
}
}
return false;
}
}
/* renamed from: d */
private static boolean m56348d() {
try {
throw new Exception("");
} catch (Exception e) {
int i = 0;
for (StackTraceElement stackTraceElement : e.getStackTrace()) {
if (stackTraceElement.getClassName().equals("com.android.internal.os.ZygoteInit")) {
i++;
if (i == 2) {
return true;
}
}
if (stackTraceElement.getClassName().equals(f86076e)) {
return true;
}
}
return false;
}
}
}
可以看到 private static变量中两个是Xposed框架的,两个是Substrate框架的。
里面只有两个public static方法供外部调用,方法结果也都是boolean值。经分析,一个是检测Xposed,一个是检测Substrate,检测方法大致相同,现只说明Xposed的。
检测加载库
/* renamed from: a */
private static boolean m56345a(String str) {
try {
String readLine;
Set<String> hashSet = new HashSet();
StringBuilder stringBuilder = new StringBuilder("/proc/");
stringBuilder.append(Process.myPid());
stringBuilder.append("/maps");
BufferedReader bufferedReader = new BufferedReader(new FileReader(stringBuilder.toString()));
while (true) {
readLine = bufferedReader.readLine();
if (readLine == null) {
break;
} else if (readLine.endsWith(".so") || readLine.endsWith(".jar")) {
hashSet.add(readLine.substring(readLine.lastIndexOf(ZegoConstants.ZegoVideoDataAuxPublishingStream) + 1));
}
}
bufferedReader.close();
for (String readLine2 : hashSet) {
if (readLine2.contains(str)) {
return true;
}
}
} catch (Throwable unused) {
return false;
}
}
m56345a方法是通过拼接”/proc/” Process.myPid() “/maps”,读取App自身加载的库中的jar和so文件查看是否含有XposedBridge.jar文件。
自造异常
/* renamed from: c */
private static boolean m56347c() {
try {
throw new Exception("");
} catch (Exception e) {
for (StackTraceElement className : e.getStackTrace()) {
if (className.getClassName().equals(f86074c)) {
return true;
}
}
return false;
}
}
m56347c方法是通过自造异常,读取异常堆栈中是否包含de.robv.android.xposed.XposedBridge字符串来识别是否被Xposed hook