本帖最后由 zpp0196 于 2019-7-4 12:04 编辑
2019.7.4 补充:
本来这个帖子是申请账号写的,申请到之后一段时间后没登给我收回去了,然后一年半过去了,我又看到了这篇帖子,发现前天还有人回复(好感动),于是我抱着死马当活马医的心态又尝试登了一下账号,结果登上了,在这里说明一下,回复我不一定看,评论区留给你们自己讨论吧
以下是原文:
不知道从哪个版本开始抖音加入了 Xposed 检测,但是这个检测并不影响 APP 的使用,只是简单的用 Toast 提示(但是每次进去看着也很不舒服),如果没有安装 Xposed 自然不会有任何的提示,那既然他是检测 Xposed 的,那我就用 Xposed 解决他,下面是分析思路:
用到的工具:
apk:抖音短视频_v1.6.8.apk
IDE:Android Studio 3.0
反编译工具:Android killer 1.3.1.0、MT 管理器 2.4.4(需要 VIP)
1. 首先先看一下 hook 前的原图:
2. 找关键字:
以 Xposed 为关键字(突破点)在工程(抖音短视频_v1.6.8.apk)中搜索,最后确定最有嫌疑的位置为:classes2/com.ss.android.ugc.aweme.app.i.smali
3. 分析代码:
smali 源码不好分析所以我转换成 Java 代码分析:
转换完可以看到 com.ss.android.ugc.aweme.app.i 这个类中有 4 个 boolean 返回值的方法:
private static boolean a() *
public static boolean a(Context paramContext)
private static boolean b() *
private static boolean b(Context paramContext) *
其中带 * 号的方法里面可以搜到 Xposed 关键字:
private static boolean a():
private static boolean b():
private static boolean b(Context paramContext):
但是并没有像上面图中那样完整的一句话(基本都在 Log 中)。
4. 首次试水:
[Java] 纯文本查看 复制代码 package me.zpp0196.ss.xpatch;
import android.content.Context;
import android.util.Log;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
/**
* Created by zpp0196 on 2018/1/8.
*/
public class Hook implements IXposedHookLoadPackage{
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable{
if(!lpparam.packageName.equals("com.ss.android.ugc.aweme")){
return;
}
findAndHookMethod("com.ss.android.ugc.aweme.app.i", lpparam.classLoader, "a", new XC_MethodReplacement(){
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable{
logI("com.ss.android.ugc.aweme.app.i.a()");
return false;
}
});
findAndHookMethod("com.ss.android.ugc.aweme.app.i", lpparam.classLoader, "a", Context.class, new XC_MethodReplacement(){
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable{
logI("com.ss.android.ugc.aweme.app.i.a(Context param)");
return false;
}
});
findAndHookMethod("com.ss.android.ugc.aweme.app.i", lpparam.classLoader, "b", new XC_MethodReplacement(){
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable{
logI("com.ss.android.ugc.aweme.app.i.b()");
return false;
}
});
findAndHookMethod("com.ss.android.ugc.aweme.app.i", lpparam.classLoader, "b", Context.class, new XC_MethodReplacement(){
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable{
logI("com.ss.android.ugc.aweme.app.i.b(Context param)");
return false;
}
});
}
private void findAndHookMethod(String p1, ClassLoader lpparam, String p2, Object... parameterTypesAndCallback){
try{
XposedHelpers.findAndHookMethod(p1, lpparam, p2, parameterTypesAndCallback);
}catch(Throwable throwable){
logE(throwable.getMessage());
}
}
private void logI(String msg){
if(BuildConfig.DEBUG)
Log.i(getTAG(), msg);
}
private void logE(String msg){
if(BuildConfig.DEBUG)
Log.e(getTAG(), msg);
}
private String getTAG(){
return getClass().getSimpleName();
}
}
编译后重启手机运行抖音 APP,依然会有提示,而且日志里面也没有打印任何有用的信息,证明这些方法都没有被调用过(起码目前是这样)。
5. 入手 strings.xml:
既然在 java 代码里面没找到,Xposed 这个关键字也没有在 strings.xml 里面出现,那还有一种可能就是 Toast 中的字符串是拼接得到的,这次换一种搜索方式:
这次只搜前面的几个字「检测到」:
果然搜到了,将 "%s" 换成 "Xposed" 不就是上面 Toast 的内容了么,接着在 public.xml 中搜索他的 id(a_v):
很明显用到的是第二个 type="string" 的,接着将他的 id(0x7f09020d) 转换为 10 进制(2131296781) 再次搜索结果没有搜到任何东西,以前就遇到过这种坑,然后我选择换工具继续找。
6. 换工具继续找:
PS:电脑端有其他工具应该也可以查出来,不过我不常用,用的多的还是手机上的 MT 管理器,照猫画虎,按照个人习好来。
这个 apk 有 3 个 dex 文件,除过 classes2 中的 R$string 以外,能搜到的唯一一个结果在 classes1/com.ss.android.ugc.aweme.app.b.a.i 里面:
反编译(需要会员)直接查看 java 源码得到:
[Java] 纯文本查看 复制代码 public class i implements a {
public static ChangeQuickRedirect a;
public void a() {
if (PatchProxy.isSupport(new Object[0], this, a, false, 4264, new Class[0], Void.TYPE)) {
PatchProxy.accessDispatch(new Object[0], this, a, false, 4264, new Class[0], Void.TYPE);
} else if (com.ss.android.ugc.aweme.app.i.a(AwemeApplication.t())) {
n.a(AwemeApplication.t(), String.format(AwemeApplication.t().getString(0x7f09020d), new Object[]{com.ss.android.ugc.aweme.app.i.b}));
c.a("find_hook", com.ss.android.ugc.aweme.app.i.b, null);
}
}
}
看到 format() 和 getString(0x7f09020d) 就可以猜到这一行应该就是显示 Toast 的方法,他没有返回值,应该不是判断的方法而是显示 Toast 的方法。
7. 再次试水:
这个相对于上面的可能性很大,所以直接 hook 打印日志测试:
[Java] 纯文本查看 复制代码 package me.zpp0196.ss.xpatch;
import android.util.Log;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
/**
* Created by zpp0196 on 2018/1/8.
*/
public class Hook implements IXposedHookLoadPackage{
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable{
if(!lpparam.packageName.equals("com.ss.android.ugc.aweme")){
return;
}
logI("start hook ShakeSound");
findAndHookMethod("com.ss.android.ugc.aweme.app.b.a.i", lpparam.classLoader, "a", new XC_MethodReplacement(){
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable{
logI( "com.ss.android.ugc.aweme.app.b.a.i.a()");
return null;
}
});
}
private void findAndHookMethod(String p1, ClassLoader lpparam, String p2, Object... parameterTypesAndCallback){
try{
XposedHelpers.findAndHookMethod(p1, lpparam, p2, parameterTypesAndCallback);
}catch(Throwable throwable){
logE(throwable.getMessage());
}
}
private void logI(String msg){
if(BuildConfig.DEBUG)
Log.i(getTAG(), msg);
}
private void logE(String msg){
if(BuildConfig.DEBUG)
Log.e(getTAG(), msg);
}
private String getTAG(){
return getClass().getSimpleName();
}
}
编译运行,结果就是那个烦人的 Toast 没有了:
控制台的 log:
01-08 18:13:59.469 7209-7209/? I/Hook: start hook ShakeSound
01-08 18:13:59.607 7209-7209/? I/Hook: com.ss.android.ugc.aweme.app.b.a.i.a()
01-08 18:14:00.047 7242-7242/? I/Hook: start hook ShakeSound
01-08 18:14:00.096 7242-7242/? I/Hook: com.ss.android.ugc.aweme.app.b.a.i.a()
01-08 18:14:00.737 7305-7305/? I/Hook: start hook ShakeSound
01-08 18:14:00.770 7305-7305/? I/Hook: com.ss.android.ugc.aweme.app.b.a.i.a()
一共连续打印了 3 次(至于为什么是三次这个要问抖音开发者),并且已经达到了预期的结果并且也不影响 APP 的使用,大功告成。
解析到此结束,感谢观看。
需要此模块的机友可以下载附件中的 zip 解压得到模块打钩重启手机即可(测试1.6.6、1.6.8、1.6.9、1.7.0、1.7.1、1.7.2 可用)。
抖音反 Xposed 检测.zip
(76.37 KB, 下载次数: 1159)
第一个版本发布的时候忽略了系统版本,导致 5.0 以下的系统不能用,已经更新了。
如果有什么 Bug 影响到了软件的正常使用,请见谅,我平常只是看看视频,目前还没发现有什么影响。
补充:更多内容参考Xposed那些事儿 -- xposed框架的检测和反制,应用下载更新详见https://www.coolapk.com/apk/173571。 |