文章总结: 本文介绍一套配置驱动的浏览器控制台工具,用于Android逆向与黑盒测试。通过JSON配置适配任意App,利用fridaagent在App进程内调用startActivity绕过非导出Activity限制,配合截图判定机制自动识别有效页面。核心结论是这套思路将繁琐的枚举页面、逐个打开、判断有效变成点一下的事。可操作建议是配置化后换App只需改JSON配置,agent只改launch签名。 综合评分: 85 文章分类: 实战经验,移动安全,逆向分析,安全工具
Control Server:在浏览器里点一下就跳转 Android Activity
原创
Lior1969 Lior1969
Moonlight安全
2026年9月6日 00:00 北京
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
配置驱动 + 五个端点,把「枚举页面、逐个点开、截图判定」做成一个本地网页控制台
做 App 逆向和黑盒测试时,最大的重复劳动是「把几百个页面逐个打开看一眼」。am start 打不开非导出 Activity,frida 命令行又太碎。这篇把一个浏览器面板讲清楚:列全 Activity、点上就跳、实时抓主机、截图自动判定是不是有效页面。读完你能直接把这个控制台套到任意 App 上。
01 为什么非要一个「点一下」的控制台
先看三个真实痛点:
ADB 只能开导出页 —— 非 exported 组件 am start -n 直接抛 SecurityException,root 也一样。深层页面要靠壳或跳转路由才能进。
frida 命令行太碎 —— attach、createScript、load、再在 rpc 里一行行调用 launch,每个页面都要停一次、看一次,没法批量。
截图判不了真内容 —— 开了几十个页面,哪些是有效页、哪些是黑屏加载转圈,靠人眼一张张看太累。
所以理想形态是:浏览器里一个面板,左边列全部 Activity,点「打开」按钮就跳到那个页面;右边实时显示抓到的请求主机、当前画面,并自动给出这张截图是 VALID、BLACK 还是 LOADING。
02 配置驱动:一套代码适配任意 App
整个控制台不带任何 App 专属字段,全部走一个 JSON 配置文件。命令只需:
python -u control_server_any.py --app app.json
# 然后浏览器打开 http://127.0.0.1:8000/
配置文件就这点字段:
{
"pkg": "com.example.app", // 包名(launch / 回首页用)
"process": "com.example.app", // 检查/附着进程名(可等于 pkg)
"port": 14725, // gadget 监听端口
"activities_path": "./activities.txt", // Activity 静态列表
"hook_js_path": "./control_hook.js", // frida hook / agent 脚本
"title": "目标app 页面控制台", // 网页标题
"launch_mode": "cls" // 覆盖 launch 调用签名
}
Activity 列表既支持 JSON 的 {"activities":[...]},也支持纯文本每行一个类名(空行和 # 注释跳过)。JSON 项还能标 exported 和 launcher,面板上对应显示「导出 / 非导出」,launcher 项高亮。
03 launch_mode:自动探测「怎么调 launch」
不同 App 的 agent 导出不同:有的 launch(cls),有的 launch(pkg, cls),有的还带 extras。控制台用 launch_mode 统一处理,默认 auto 自动探测:看 hook 有没有 rpc.exports.jump,有就按带 pkg 的签名,否则按 cls。
| launch_mode | 调用签名 | 对应 agent | | — | — | — | | auto | 有 jump 则 pkg_cls_extras,否则 cls | 无需指定 | | cls | launch(cls) | bypass_agent.js | | pkg_cls | launch(pkg, cls) | 通用简单 agent | | pkg_cls_extras | launch(pkg, cls, extrasJson) | control_hook.js |
04 五个端点就能干活
后端就一个 HTTP Server,监听 8000 端口,端点少而直白。前端渲染一个面板,三个区域各跑一条轮询。
| 端点 | 作用 |
| — | — |
| GET / | 控制面板(主机列表 + Activity 列表 + 点击跳转 + 截图) |
| GET /acts | 返回全部 Activity 的 JSON 列表 |
| GET /hosts | 实时捕获的主机(走 rpc.exports.hosts) |
| GET /screen | 当前屏幕实时判定一帧 |
| GET /shot | 截图并判定,保存到 out 目录(?name=X&wait=1) |
| GET /img/
前端点「打开」其实是两步:先 POST /open 跳转,再 GET /shot?wait=1 截图判定,把结果塞回预览图。跳转是否成功,看返回里 res 的前缀——不是 ERR、不是 no-java 就算成功,异步返回 queued 也算打开过了。
05 关键机制:进程内 startActivity 绕过非导出
前端「打开」能开非导出页,靠的是 agent 里这段 rpc.exports.launch。它不是用 adb 起组件,而是在 App 自己的 uid 内,用 ActivityThread.currentApplication().getApplicationContext() 拿上下文,ctx.startActivity(intent) 起组件——同 uid 内跨组件调用不查 exported,SecurityException 就这么没了。加 FLAG_ACTIVITY_NEW_TASK 保证它落到新任务栈。
launch: function (pkg, cls, extrasJson) {
return new Promise(function (resolve) {
Java.perform(function () {
var at = Java.use("android.app.ActivityThread");
var app = at.currentApplication();
var ctx = app.getApplicationContext();
var it = Java.use("android.content.Intent").$new();
it.setClassName(pkg, cls);
it.addFlags(0x10000000); // NEW_TASK
// extrasJson 可给页面戴参,数据依赖页才有真内容
ctx.startActivity(it);
resolve("OK " + cls);
});
});
}
除了 launch,agent 还能导出 jump(path, paramsJson) 走 ARouter 带参跳转——数据依赖页(详情、订单这种要参数的)光点 Activity 是空的,带参数才渲染得出。这一步命中 auto 探测,决定走哪种 launch 签名。
06 截图判定:VALID / BLACK / WHITE / LOADING
控制台复用了截图判定脚本,把 png 下采样到 160×160,算五个指标再分类:
gray 灰度
mean_lum 平均亮度
black_frac <30 占比 white_frac >235 占比
distinct 量化色数(每通道 8 级) colorful_frac 饱和>40 占比
edge_density 相邻像素亮度差>20 占比(内容是否丰富)
判定顺序和阈值,直接决定你一眼看到的标签:
BLACK mean_lum < 25 或 black_frac > 0.85 // 近全黑
WHITE mean_lum > 235 或 white_frac > 0.85 // 近全白
LOADING edge_density < 0.05 且 distinct < 70 // 内容贫瘠(启动/转圈)
VALID 其余(内容丰富)
这里有个容易踩的坑:判断不能只看「彩色占比」。品牌纯色启动页(深绿 logo 那种)也是饱和色,但如果用 colorful_frac 判定会被误判成 VALID。改用 edge_density(内容边界密度)+ distinct(色数)两个维度,纯色启动页边界和色数都极低,自然落到 LOADING。
截图走 adb exec-out screencap -p 以二进制写文件,Windows 下也安全;非 VALID 帧会按 1.6 倍间隔重截(最多若干次),直到拿到有效内容或超时。
07 复用的前置条件(做到才不白干)
adb 可见 + root —— attach 要经 adb forward tcp:port,截图要 exec-out screencap。
App 已到可导航的 Main —— 得有 Java 桥接,agent 才能在 uid 内 startActivity。
标准可 attach 的 frida gadget —— 这是最关键的一条。
7.1 反检测 gadget 会卡住标准 attach(attach 墙)
为了躲开 App 的反 frida 检测,有些人用 knox-frida 这类去标记反检测构建的 gadget。它能绕过 App 的 10 秒 SIGKILL,但代价是连握手都改成反检测那套——标准 frida 客户端去 attach 会直接报 internal server error。这个「attach 墙」一旦出现,控制台是接不上的,得换回标准可 attach 的 gadget,或者在 gadget 旁配套精确匹配版本的 frida / 专属管理端。
7.2 FLAG_SECURE 剥不掉,截图就一直是黑帧
很多 App 的关键页(支付、钥匙、二维码、深色启动页)会设 FLAG_SECURE(0x2000) 防截屏。光剥 Window 层面不够,必须连 SurfaceControl 的 setSecure 一起强制 false——否则一个防截屏页会把整个进程表面的 secure 位点亮并「毒化」,导致此后再截任何页都是 0 字节。这也是之前「有些页面截不了图」的真因:不是页面问题,是进程被毒了。control_hook.js 里把 Window.addFlags / setFlags、SurfaceControl.setSecure、SurfaceControl$Builder.setSecure、View.setSecure 全钩了个遍。
7.3 没有 SSL 放行和 root 绕过,导航时进程会被杀
导航离不开网络,而高危 App 多半带 pinning + root/watchdog 检测。agent 里要把 SSL_get_verify_result → 0(关键在 native BoringSSL,光 hook 上层 Java HostnameVerifier 够不到)、trust manager 空实现、killProcess 置空、root 检测的 b/c/d/e → false、风险弹窗 no-op。没有这些,跳两个页面 app 就被 watchdog 干掉了。
本节要点
控制台能通用,靠的是配置驱动 + launch_mode 自动探测;能开非导出页,靠的是进程内 startActivity;能一眼看出真页面,靠的是截图判定。最难的一关在「标准可 attach 的 gadget」这个前置条件,反检测 gadget 会直接堵死 attach。
08 踩坑记录:为什么导航不稳定
跑起来后最容易遇到两个「看起来像死了」的坑:
别用 screencap 判定 App 死没死 —— 视频类、支付类页面 surface 设了 FLAG_SECURE,screencap 就是黑帧。得看用户能看到的画面,或剥掉 setSecure 后的控制台截图。
别信 dumpsys 的 ResumedActivity —— 单 Activity + 路由模型的 App(比如抖音类)会长期停留在 SplashActivity,dumpsys 报的前台和真实页面对不上。以截图或用户视角为准。
勿 force-stop 健康进程 —— 冷启动时 AMS 的 start-timeout 约 10 秒会非确定性杀进程,重试进程内启动就行,别反复重启母进程。
09 小结
这套「配置驱动 + 浏览器面板 + 进程内跳转 + 截图判定」的思路,把黑盒测试里最琐碎的「枚举页面、逐个打开、判断有效」变成了点一下的事。核心一句话:用 App 自己的 uid 把它想藏的页面自己打开,再靠截图判定知道哪个是真页面。配置化之后,换个 App 只改一份 JSON,agent 只改 launch 签名,主体一行不动。
扫码关注 · MoonLight安全
每周一篇,专注一线安全实战与方法论
本文工具 · 开源地址
本文用到的 control_server_any.py 与 control_hook.js 已清洗为通用可复用代码,随项目 8eeth0ven / bfs-clicker 一起开源在:
https://github.com/8eeth0ven/bfs-clicker
如果对排查隐藏页面、逆向动态接口有帮助,欢迎 Star、在看或分享给同好。关注 MoonLight安全,持续输出脱壳、抓包、签名逆向与黑盒测试实战。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:Moonlight安全 Lior1969 Lior1969《Control Server:在浏览器里点一下就跳转 Android Activity》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。








评论