Android逆向实战——以某APP跳过广告为例
字数 1042 2025-08-22 18:37:14
Android逆向实战:跳过某APP广告的完整教学
1. 准备工作
1.1 所需工具
- MT管理器:用于查看APK信息和Activity记录
- Objection:动态分析工具,用于方法hook
- Jadx:反编译工具,用于查看Java源码
- Frida:动态插桩工具,用于运行时修改应用行为
- Apktool:用于反编译和回编译APK
- 签名工具:如apksigner,用于回编译后的APK签名
1.2 目标APP分析
目标APP的广告流程:
- 启动时首先加载
com.qiyi.video.WelcomeActivity - 然后跳转到
org.qiyi.android.video.MainActivity - 在MainActivity中处理广告逻辑
2. 动态分析
2.1 使用Objection进行初步hook
# hook MainActivity的所有方法
objection -g com.qiyi.video explore -s "android hooking watch class_method org.qiyi.android.video.MainActivity.*"
发现WelcomeActivity hook失败,转而分析MainActivity。
2.2 关键方法hook
# 监控触摸事件和广告日志
objection -g com.qiyi.video explore \
-s "android hooking watch class_method org.qiyi.android.video.MainActivity.dispatchTouchEvent --dump-args" \
-s "android hooking watch class_method com.qiyi.video.startup.Startup.log --dump-args"
通过对比跳过广告和未跳过广告的日志,发现广告时间减少和触摸事件变化。
3. 跳过广告的两种方法
3.1 方法一:模拟点击跳过广告
分析dispatchTouchEvent方法:
@Override
public final boolean dispatchTouchEvent(MotionEvent motionEvent) {
tv1.a aVar = this.S;
if (aVar != null) {
aVar.a(motionEvent);
}
return super.dispatchTouchEvent(motionEvent);
}
使用Frida生成并发送模拟点击事件:
Java.perform(function() {
console.log('Begin...');
const MainActivityClass = Java.use('org.qiyi.android.video.MainActivity');
// 获取MotionEvent相关类
var MotionEvent = Java.use('android.view.MotionEvent');
var PointerProperties = Java.use('android.view.MotionEvent$PointerProperties');
var PointerCoords = Java.use('android.view.MotionEvent$PointerCoords');
var SystemClock = Java.use('android.os.SystemClock');
// 设置指针属性
var properties = [PointerProperties.$new()];
properties[0].id.value = 0;
properties[0].toolType.value = MotionEvent.TOOL_TYPE_FINGER.value;
// 设置坐标(跳过按钮位置)
var coords = [PointerCoords.$new()];
coords[0].x.value = 469.13126;
coords[0].y.value = 48.949013;
// 定时查找MainActivity实例并发送点击事件
setTimeout(function() {
Java.choose('org.qiyi.android.video.MainActivity', {
onMatch: function(instance) {
console.log('Found instance:', instance);
setTimeout(function() {
var downTime = SystemClock.uptimeMillis();
var eventTime = SystemClock.uptimeMillis();
// 发送ACTION_DOWN事件
var me_move = MotionEvent.obtain.call(
MotionEvent, downTime, eventTime,
MotionEvent.ACTION_DOWN.value, 1,
properties, coords, 0, 0, 0, 0, 2, 0, 0x1002, 0x2
);
instance.dispatchTouchEvent(me_move);
// 发送ACTION_UP事件
eventTime = SystemClock.uptimeMillis();
var me_up = MotionEvent.obtain.call(
MotionEvent, downTime, eventTime,
MotionEvent.ACTION_UP.value, 1,
properties, coords, 0, 0, 0, 0, 2, 0, 0x1002, 0x2
);
instance.dispatchTouchEvent(me_up);
}, 1000);
},
onComplete: function() {
console.log('Completed');
}
});
}, 1000);
});
3.2 方法二:修改广告请求逻辑
通过分析日志发现>>> Splash Ad相关逻辑,追踪到关键方法:
public final void r() {
boolean z14;
if ((MixUIUtils.isTabletDevice() && GPadSpecialLogic.hideSplashAd()) || q()) {
return;
}
// 关键判断条件
if (StringUtils.equals("0", SpToMmkv.get(QyContext.getAppContext(),
"isIgnoreAdReqWhenAppLaunchForPlayer", "0",
SharedPreferencesConstants.LAUNCH_SHAREPREFERENCE_NAME))
&& f42.a.b() && !f42.a.d()) {
z14 = true;
} else {
z14 = false;
}
if (z14) {
return; // 跳过广告请求
}
sy1.n.d(null, "requestSplashAd"); // 请求广告
// 其他广告相关逻辑...
}
使用Frida hook关键方法:
Java.perform(function() {
// Hook SpToMmkv.get方法
var SpToMmkvClass = Java.use('org.qiyi.basecore.utils.SpToMmkv');
SpToMmkvClass.get.overload('android.content.Context', 'java.lang.String',
'java.lang.String', 'java.lang.String').implementation = function(context, str, str2, str3) {
if (str === "isIgnoreAdReqWhenAppLaunchForPlayer") {
console.log('SpToMmkv.get() called for isIgnoreAdReqWhenAppLaunchForPlayer');
return "1"; // 修改返回值
}
return this.get(context, str, str2, str3);
};
// Hook f42.a.b方法
var f42_a_Class = Java.use('f42.a');
f42_a_Class.b.implementation = function() {
console.log('f42.a.b() called');
return true; // 强制返回true
};
// Hook f42.a.d方法
f42_a_Class.d.implementation = function() {
console.log('f42.a.d() called');
return false; // 强制返回false
};
});
4. 静态修改方法
4.1 反编译APK
apktool.bat d .\iqiyi.apk
4.2 修改smali代码
找到f42.a.b方法的smali代码,修改使其直接返回true:
.method public b()Z
.registers 2
const/4 v0, 0x1 # 修改为直接返回true
return v0
.end method
或者直接删除条件判断部分,只保留其他两个条件的判断。
4.3 回编译和签名
apktool.bat b .\iqiyi\
# 然后使用签名工具对回编译后的APK进行签名
5. 关键点总结
- Activity流程分析:通过MT管理器或logcat确定广告相关的Activity
- 日志监控:使用Objection监控关键日志输出,定位广告相关方法
- 两种绕过方法:
- 动态模拟点击跳过按钮
- 静态修改广告请求逻辑
- Frida使用技巧:
- 监控方法调用及参数
- 修改方法返回值
- 生成并发送模拟事件
- 静态修改要点:
- 定位关键判断条件
- 修改smali代码逻辑
- 回编译和签名注意事项
6. 注意事项
- 本教程仅用于学习Android逆向技术,请勿用于非法用途
- 修改他人APP可能违反用户协议和相关法律
- 不同版本APP的实现可能不同,需要根据实际情况调整分析方法
- 回编译后的APK需要正确签名才能安装运行
- 动态分析方法(Frida)需要设备root或模拟器环境