动态运行时分析:用Frida和Xposed Hook关键API
说实话,静态分析能帮你找到很多漏洞,但真正让我头皮发麻的,往往是那些只在运行时才暴露出来的问题。我记得有一次,一个App在静态扫描时干干净净,结果一上线就被爆出Activity劫持——原来攻击者利用了动态注册的Intent Filter,静态代码里根本看不出来。
所以,动态运行时分析,说白了就是给App装上“监控摄像头”。今天我就带你看看,怎么用Frida和Xposed这两个神器,实时监控组件调用和数据流。
为什么需要动态分析?
静态分析有个硬伤:它只能看到代码,看不到运行时的真实行为。你想想看,一个Activity到底被谁调用了?Intent里携带了什么敏感数据?Content Provider的URI在运行时被拼接过吗?这些问题,光看代码是回答不了的。
我个人的习惯是:先静态扫一遍,找出可疑点,然后用动态分析去验证。这样既高效,又不会漏掉运行时才触发的漏洞。
Frida:轻量级动态插桩
Frida是我最常用的工具。它不需要修改App本身,直接注入JavaScript代码就能Hook任意函数。嗯,这里要注意:Frida需要设备有root权限,或者使用Frida Gadget注入。
Hook Activity的启动流程
Activity劫持的核心,就是攻击者能拦截或伪造Intent。我们可以Hook startActivity 来监控所有Activity的启动请求:
// Frida脚本:监控startActivity调用
Java.perform(function() {
var Activity = Java.use('android.app.Activity');
var Intent = Java.use('android.content.Intent');
Activity.startActivity.overload('android.content.Intent').implementation = function(intent) {
console.log('[+] startActivity 被调用');
console.log(' Intent Action: ' + intent.getAction());
console.log(' Intent Data: ' + intent.getDataString());
console.log(' Intent Component: ' + intent.getComponent());
// 检查是否有隐式Intent
if (intent.getComponent() === null) {
console.warn('[!] 警告:隐式Intent,可能被劫持!');
}
// 继续原始调用
this.startActivity(intent);
};
});
我在项目中遇到过,有些App会动态设置Intent的Flag,比如 FLAG_ACTIVITY_NEW_TASK。这种Flag如果被恶意利用,攻击者可以把你的Activity启动到自己的任务栈里,实现劫持。所以,我一般还会Hook setFlags 方法:
Intent.setFlags.implementation = function(flags) {
console.log('[+] setFlags 被调用: ' + flags);
if (flags & 0x10000000) { // FLAG_ACTIVITY_NEW_TASK
console.warn('[!] 检测到FLAG_ACTIVITY_NEW_TASK,注意劫持风险');
}
return this.setFlags(flags);
};
监控Content Provider的数据流
Provider数据泄露,说白了就是URI被恶意拼接或者权限检查不到位。我们可以Hook ContentResolver.query 来监控所有数据库查询:
Java.perform(function() {
var ContentResolver = Java.use('android.content.ContentResolver');
ContentResolver.query.overload('android.net.Uri', '[Ljava.lang.String;', 'java.lang.String', '[Ljava.lang.String;', 'java.lang.String').implementation = function(uri, projection, selection, selectionArgs, sortOrder) {
console.log('[+] query 被调用');
console.log(' URI: ' + uri.toString());
console.log(' Selection: ' + selection);
// 检查URI是否包含敏感关键字
var uriStr = uri.toString();
if (uriStr.contains('password') || uriStr.contains('token')) {
console.warn('[!] 警告:查询可能包含敏感数据!');
}
return this.query(uri, projection, selection, selectionArgs, sortOrder);
};
});
Java.use('android.util.Log').getStackTraceString(new Exception()) 就能拿到调用栈。
Xposed:系统级Hook框架
Xposed和Frida最大的区别是:Xposed是持久化的,修改后重启App依然生效。适合做长期监控。但Xposed需要刷入框架,对设备要求更高。
Hook ActivityManagerService
Activity的启动最终会走到系统服务 ActivityManagerService。Hook这个服务,能监控到所有App的Activity启动:
// Xposed模块:监控Activity启动
public class MonitorActivity extends IXposedHookLoadPackage {
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
if (!lpparam.packageName.equals("com.android.server")) return;
findAndHookMethod(
"com.android.server.am.ActivityManagerService",
lpparam.classLoader,
"startActivity",
Intent.class,
String.class,
... // 其他参数
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
Intent intent = (Intent) param.args[0];
XposedBridge.log("[AMS] startActivity: " + intent.toString());
}
}
);
}
}
我曾经用Xposed抓过一个恶意App,它通过反射调用 ActivityManagerNative.getDefault() 来绕过权限检查。这种手法在静态代码里几乎看不出来,但运行时一Hook就原形毕露了。
数据流追踪实战
光Hook API还不够,你得把数据流串起来。我一般会做三件事:
- 标记敏感数据来源:比如从
getIntent().getData()获取的URI - 追踪数据传递路径:看它经过了哪些Activity、Service、Provider
- 检查最终使用点:比如是否被拼接到SQL查询里,或者通过
startActivity发送出去
下面这张图是我自己总结的组件调用与数据流监控框架:
避坑指南
- Frida脚本里忘记处理
overload歧义,导致Hook不生效。一定要用overload('参数类型')明确指定。 - Xposed模块里直接修改了系统服务的返回值,结果手机变砖。记住:监控为主,修改为辅,生产环境慎用。
- Hook ContentProvider时,没考虑多线程并发,导致日志乱序。加个时间戳或者线程ID就能解决。
总结
动态运行时分析,说白了就是给App做“实时体检”。Frida适合快速验证,Xposed适合长期监控。我个人建议:先用Frida做一轮快速扫描,发现可疑点后,再用Xposed做深度追踪。
记住一点:Hook不是目的,理解数据流才是。你只有知道数据从哪里来、经过哪里、最终去了哪里,才能真正堵住漏洞。
核心要点回顾:
- Hook
startActivity和setFlags监控Activity劫持 - Hook
ContentResolver.query监控Provider数据泄露 - Frida适合临时调试,Xposed适合持久监控
- 始终追踪数据流,不要只看单个API调用