接到组长下发的书城隐私协议问题,记录了一下排查过程,以后可以模仿此步骤,进行隐私协议排查工作
问题如下图所示:
很明显,我们在未被授权获取用户设备信息的情况下,频繁的请求了用户的设备信息。这是不允许的。
查找资料,如下代码,可以获取用户信息
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
imei = telephonyManager.getDeviceId();
那我们可以按照如下逻辑,进行排查工作。
1.分析我们代码里面的获取逻辑,做权限检查+imei缓存处理
2.分析三方SDK里面的获取情况
那么问题来了,检查1,自己的代码我们可以进行检索,排查。三方的SDK我们如何知晓调用情况呢,断点打到系统上?其实方案很简单,就是Hook。
一方面我们可以使用java的动态代理,Hook本应用获取的系统服务,另一方面我们可以使用Xposed,注入系统进程,Hook所有的系统服务。
市面上经常有模拟器刷量,他们Hook系统api,返回虚假的IMEI,我们可以如法炮制。条条道路通罗马,我们选择最简单的那条路(Xposed Hook)。
准备工具如下:
1.雷电模拟器
2.Xposed jar
3.Xposed开发环境部署
4.免重启Xposed模块改进
首先安装雷电模拟器,自带Root权限。启动后,安装Xposed installer(需梯子)。
然后按照工具3,部署Xposed开发环境。我已在文章末尾附上git地址,大家clone下开箱可用。
回到我们的主题,我们需要Hook系统的getSystemService,咨询了技术部的大佬@杨滨(yangbin),写出了如下的代码。
首先,我们Hook loadClass.看看是否加载了 android.content.ContextWrapper,
XposedHelpers.findAndHookMethod(ClassLoader.class, "loadClass", String.class, new XC_MethodHook() {
// 在类方法loadClass执行之后执行的代码
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// 参数的检查
if (param.hasThrowable()) {
return;
}
// 获取指定名称的类加载之后的Class<?>
Class<?> clazz = (Class<?>) param.getResult();
// 获取加载的指定类的名称
String strClazz = clazz.getName();
if (strClazz.startsWith("android.content.ContextWrapper")) {
XposedBridge.log("--------------------LoadClass-------------------------- : " + strClazz);
.......
}
}
}
);
然后我们Hook getSystemService方法
for (int i = 0; i < m.length; i++) {
XposedBridge.log("--------------HOOKED CLASS-METHOD-------------------: " + strClazz + "-" + m[i].toString());
if (m[i].toString().indexOf("getSystemService") == -1) {
continue;
}
if (!Modifier.isAbstract(m[i].getModifiers()) // 过滤掉指定名称类中声明的抽象方法
// && !Modifier.isNative(m[i].getModifiers()) // 过滤掉指定名称类中声明的Native方法
&& !Modifier.isInterface(m[i].getModifiers()) // 过滤掉指定名称类中声明的接口方法
) {
// 对指定名称类中声明的非抽象方法进行java Hook处理
XposedBridge.hookMethod(m[i], new XC_MethodHook() {
// 被java Hook的类方法执行完毕之后,打印log日志
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
.....
}
}
}
}
最后我们Hook 获取Context.TELEPHONY_SERVICE服务的调用,打印出调用栈。
// 打印被java Hook的类方法的名称和参数类型等信息
if ((param.args != null) && (param.args.length > 0)) {
for (int i = 0; i < param.args.length; i++) {
if (param.args[i] != null) {
String c = param.args[i].toString();
if (c.indexOf("phone") != -1) {
Thread.sleep(100);
new Exception("-------phone---printStackTrace").printStackTrace();
}
XposedBridge.log("---------------xxxxxx-----HOOKED METHOD: -------param-------------" + "-" + "-" + param.method + "-" + i + ":" + param.args[i]);
}
}
}
// 打印被java Hook的类方法的名称和参数类型等信息
if (param.getResult() != null) {
try {
XposedBridge.log("--------------------HOOKED METHOD: --------------result------" + param.getClass().getName() + "-" + param.method.toString() + ":" + param.getResult().toString());
} catch (Throwable e) {
}
}
这样,我们就可以在所有第三方SDK,调用系统phone服务的时候,打印出当前的调用栈。
安装好Xposed模块并勾选,因为是免重启模块,杀死宿主和模块,点开我们的书城即可查看。
在日志中我们可以查看到,广点通服务在频繁的调用,
QM统计在频繁调用
哈哈,是不是原形毕露呢,这样我们不仅可以找到是谁在调用IMEI,还可以有证据证明他们在调用,可以愉快的把图发给他们(三方SDK),让他们整改了。
一通操作,可以发现,有很多处地方在频繁获取系统服务,比如phone,网络等。可以针对这种问题,给SDK提出整改意见,进行cache处理,优化执行效率。
举一反三,我们可以Hook系统的函数,修改系统参数,Hook三方App,修改程序逻辑。仅限学习研究!
备注:
Xposed学习链接
Xposed编写
Xposed编写
免重启Xposed原理解析
java动态代理学习链接
维术大佬系列文章
开箱即用的Xposed开发环境
http://gitlab.inner.yuewen.local/zhanghao.c/XposedHook.git