logo头像
Snippet 博客主题

XPosed调试

TopActivity.apk

安装这个工具可以直接查看当前 App 显示的最前 Activity,后面我们接触别人写的项目,这个工具可以很方便跟踪代码的入口,项目原理是通过 AccessibilityService 服务,监听所有的界面变化,读取当前界面 Activity,需要给软件开启【辅助权限】。

项目地址:
https://github.com/109021017/android-TopActivity

安装地址

https://www.pgyer.com/983d

当然也可以通过 Adb 命令,获取 Dumpsys 当前 Activity 的信息:

adb shell dumpsys activity top

BDOpener——开启APK调试与备份选项的Xposed模块

https://github.com/riusksk/BDOpener

这是 Xposed 的插件模块,
也就是说需要刷入 Xposed 框架后,
才能使用该,通过安装这个软件,
我们可以使手机安装的软件,变为可调试状态,这样就可以通过 Android Studio 的 Monitor 工具,查看所有的进程状态,并 dumpsys 方法调用信息。

Android\Sdk\tools\monitor.bat 目录下找到

调试 方法

1
2
3
4
5
6
7
8
9
public class TargetHook implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {
//通过目标包名过滤
if (lpparam.packageName.equals("com.xxx.xxx")) {
XposedBridge.log("启动了xxx软件");
}
}
}

还是不行

https://blog.csdn.net/qq_30496695/article/details/80425676

Xposed 免重启调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

Xposed插件每次代码改动,都需要重启手机才能生效,
有时候重启一次还不生效(我的手机有一次重启 3 次,才看到生效,
还好是公司测试机,不心疼),
所以代码最好写上相关 Log 信息,来看代码生效没。

XposedBridge.log("启动了xxx软件");

不过这里分享一个免重启调试的方法,方法来自网上,感谢 DX :

/**
* @author DX
* 这种方案建议只在开发调试的时候使用,因为这将损耗一些性能(需要额外加载apk文件),调试没问题后,直接修改xposed_init文件为正确的类即可
* 可以实现免重启,由于存在缓存,需要杀死宿主程序以后才能生效
* 这种免重启的方式针对某些特殊情况的hook无效
* 例如我们需要implements IXposedHookZygoteInit,并将自己的一个服务注册为系统服务,这种就必须重启了
* Created by DX on 2017/10/4.
*/

public class HookLoader2 implements IXposedHookLoadPackage {
//按照实际使用情况修改下面几项的值
/**
* 当前Xposed模块的包名,方便寻找apk文件
*/
private final String modulePackage = "com.xxx.plugin";
/**
* 宿主程序的包名(允许多个),过滤无意义的包名,防止无意义的apk文件加载
*/
private static List<String> hostAppPackages = new ArrayList<>();

static {
// TODO: Add the package name of application your want to hook!
hostAppPackages.add("com.eg.android.AlipayGphone");
hostAppPackages.add("com.xxx.plugin");
}

/**
* 实际hook逻辑处理类
*/
private final String handleHookClass = TargetHook.class.getName();
/**
* 实际hook逻辑处理类的入口方法
*/
private final String handleHookMethod = "handleLoadPackage";

@Override
public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (hostAppPackages.contains(loadPackageParam.packageName)) {
//将loadPackageParam的classloader替换为宿主程序Application的classloader,解决宿主程序存在多个.dex文件时,有时候ClassNotFound的问题
XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Context context=(Context) param.args[0];
loadPackageParam.classLoader = context.getClassLoader();
invokeHandleHookMethod(context,modulePackage, handleHookClass, handleHookMethod, loadPackageParam);
}
});
}
}

/**
* 安装app以后,系统会在/data/app/下备份了一份.apk文件,通过动态加载这个apk文件,调用相应的方法
* 这样就可以实现,只需要第一次重启,以后修改hook代码就不用重启了
* @param context context参数
* @param modulePackageName 当前模块的packageName
* @param handleHookClass 指定由哪一个类处理相关的hook逻辑
* @param loadPackageParam 传入XC_LoadPackage.LoadPackageParam参数
* @throws Throwable 抛出各种异常,包括具体hook逻辑的异常,寻找apk文件异常,反射加载Class异常等
*/
private void invokeHandleHookMethod(Context context, String modulePackageName, String handleHookClass, String handleHookMethod, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
File apkFile=findApkFile(context,modulePackageName);
if (apkFile==null){
throw new RuntimeException("寻找模块apk失败");
}
//加载指定的hook逻辑处理类,并调用它的handleHook方法
PathClassLoader pathClassLoader = new PathClassLoader(apkFile.getAbsolutePath(), ClassLoader.getSystemClassLoader());
Class<?> cls = Class.forName(handleHookClass, true, pathClassLoader);
Object instance = cls.newInstance();
Method method = cls.getDeclaredMethod(handleHookMethod, XC_LoadPackage.LoadPackageParam.class);
method.invoke(instance, loadPackageParam);
}

/**
* 根据包名构建目标Context,并调用getPackageCodePath()来定位apk
* @param context context参数
* @param modulePackageName 当前模块包名
* @return return apk file
*/
private File findApkFile(Context context, String modulePackageName){
if (context==null){
return null;
}
try {
Context moudleContext = context.createPackageContext(modulePackageName, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
String apkPath=moudleContext.getPackageCodePath();
return new File(apkPath);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
支付宝打赏 微信打赏

打赏