Recall 2.0 - 打造一款能掌握你所知的一切的人工智能。


这篇文章收集了《从 Trace 到洞察:SmartPerfetto AI Agent 的 Harness Engineering 实战》发布后收到的技术问题,以问答形式展开讨论。
提问背景: Claude Code 的 Skill 系统支持 scripts/ 目录放确定性脚本,避免 LLM 泛化。既然可以用 scripts/ 执行固定的 SQL,为什么还要自建一套 YAML Skill 系统?YAML Skill 是不是本质上是一个让性能工程师按预定义规则执行 SQL 的工具?
Claude Code Skills 和 SmartPerfetto YAML Skills 解决的是不同阶段的问题:
1 | 开发阶段(我写代码时): |
Claude Code 的 Skill 运行在开发者的终端里,是 CLI 工具的扩展。SmartPerfetto 的 YAML Skill 运行在 Express 后端的 Skill Engine 中,是 Agent 在运行时通过 MCP 工具 invoke_skill 调用的分析单元。两者的执行环境、调用方式、数据流完全不同。
1. 参数化 SQL,不是固定脚本
性能分析的 SQL 不是写死的——同一个 Skill 需要接受不同的参数(进程名、时间范围、帧 ID 列表):
1 | steps: |
${main_thread_utid} 和 ${start_ts} 是 Claude 调用 invoke_skill 时传入的参数。YAML Skill Engine 做参数替换后执行 SQL。如果用 scripts/,要么写 shell 脚本接收参数拼 SQL(容易出注入问题),要么写完整的 Python/Node 脚本——复杂度比 YAML 高很多。
2. 自描述的输出格式(DataEnvelope)
1 | display: |
每个 step 声明了输出列的名称和类型。前端根据这个 schema 自动渲染表格——duration 类型自动格式化为 ms,timestamp 类型支持点击跳转到 Perfetto 时间线。scripts/ 方式的输出是自由文本,前端没法自动渲染。
3. 可组合(composite + iterator)
一个 composite Skill 可以引用多个 atomic Skill,iterator 可以遍历数据行逐帧分析。这种组合在 YAML 中是声明式的,Skill Engine 负责编排执行。scripts/ 方式要实现同样的组合需要自己写编排逻辑。
4. 面向性能工程师,不是面向开发者
提问者说对了:YAML Skill 本质上是一个让性能工程师按预定义规则贡献分析逻辑的工具。性能工程师知道该查什么 SQL、该看什么指标,但不一定会写 TypeScript。YAML 格式让他们直接定义 SQL 查询和输出格式,不需要碰后端代码。修改后 DEV 模式刷新浏览器即可生效。
| 维度 | Claude Code scripts/ | SmartPerfetto YAML Skill |
|---|---|---|
| 运行环境 | 开发者终端 (CLI) | Express 后端 (runtime) |
| 调用者 | 开发者通过 /skill 命令 | Agent 通过 invoke_skill MCP 工具 |
| 参数化 | 需要自己处理 | `${param |
| 输出格式 | 自由文本 | DataEnvelope (schema-driven) |
| 前端渲染 | 不涉及 | 自动表格/图表 |
| 组合能力 | 手动编排 | composite / iterator / conditional |
| 贡献门槛 | 需要写脚本 | 只写 YAML + SQL |
两者不是替代关系,而是在不同层面解决不同问题。
提问背景: 文章说「已知场景用 Strategy 文件约束必检项,但每个阶段内的具体查询和深钻方向由 Claude 自主决定」。这个约束和自主之间的边界在哪里?具体是怎么做到的?
这个混合设计靠三层机制配合实现:Strategy 文件定义「必须做什么」,Planning Gate 强制「先计划再执行」,Verifier 事后检查「是否真的做了」。
以滑动分析的 scrolling.strategy.md 为例,它定义了多个分析阶段,但每个阶段的约束强度不同:
硬约束(必须执行,跳过会触发验证错误):
Phase 1.9 根因深钻是最严格的阶段,策略文件里直接用了 🔴 标记和「禁止」字样:
1 | **Phase 1.9 — 根因深钻(🔴 强制执行,不可跳过):** |
软指引(建议但可跳过):
Phase 1.5(架构感知分支)和 Phase 1.7(根因分支)用的是「建议」「改用」等措辞,Claude 可以根据实际数据决定是否执行:
1 | **Phase 1.5 — 架构感知分支:** |
Strategy 文件的全部内容被原文注入 System Prompt,注入时加了一行硬性说明:
1 | 场景策略(必须严格遵循) |
Claude 直接在 System Prompt 中看到这些阶段定义、🔴 标记和「禁止」字样。
Claude 在执行任何 SQL 查询或 Skill 调用之前,必须先调用 submit_plan 提交分析计划。没有提交计划就调用 execute_sql 或 invoke_skill 会被直接拒绝:
1 | function requirePlan(toolName: string): string | null { |
关键点在于:Gate 只要求计划存在,不要求计划和 Strategy 的阶段完全对应。 Claude 可以提交任何结构的计划——它可以把 Phase 1 和 1.5 合并,可以加入 Strategy 没提到的额外步骤,也可以根据初步数据调整深钻方向。
提交计划时,系统会做场景感知的关键词检查(比如滑动场景检查计划中是否提到了「帧」「jank」等词),但这只是 warning 级别——计划即使不包含这些词也会被接受。
这个设计的目的是:强制 Claude 在动手之前先想清楚要做什么(规划纪律),但不限制它怎么想(规划自由)。
计划和执行之间可能有偏差——Claude 可能提交了计划但实际跳过了某个关键步骤。Verifier 在分析结束后做多维度事后检查,以启发式行为检查为主,同时补充计划/假设/场景完整性校验:
a) 场景完整性检查——分析输出是否覆盖了场景的核心内容:
1 | // 滑动场景:检查是否有显著掉帧但没做 Phase 1.9 深钻 |
b) 假设闭环检查——所有 submit_hypothesis 是否都有对应的 resolve_hypothesis。
c) 因果链深度检查——CRITICAL/HIGH 级别的 findings 是否包含足够的因果连接词和机制性术语(启发式文本匹配)。
d) 可选的 LLM 复核——用独立的 Haiku 模型做证据支撑度验证(可关闭)。
如果检查发现 ERROR 级别问题,会触发 Correction Prompt 让 Claude 补做。
注意 Verifier 不检查 Claude 的计划阶段是否匹配 Strategy 的阶段编号——它检查的是「关键分析动作是否体现在输出中」,不是「计划格式是否正确」。
把三层机制叠在一起,不同阶段的约束强度形成了一个光谱:
| 阶段 | Strategy 语气 | Planning Gate | Verifier 检查 | 约束强度 |
|---|---|---|---|---|
| Phase 1(概览) | 建议 | 需要计划 | 不单独检查 | 中 |
| Phase 1.5(架构分支) | 建议 | — | 不检查 | 低 |
| Phase 1.7(根因分支) | 建议+条件 | — | 不检查 | 低 |
| Phase 1.9(根因深钻) | 🔴 必须/禁止 | — | 检查是否调用了深钻工具 | 高 |
| Phase 2(补充深钻) | 可选 | — | 不检查 | 无 |
| Phase 3(综合结论) | 必须覆盖分布 | — | 检查结论完整性 | 中 |
而 general.strategy.md(未匹配到场景时的 fallback)则完全是软指引:只给了一个按用户关注方向的路由决策树(CPU → cpu_analysis,内存 → memory_analysis),没有任何必须执行的阶段。Claude 在 general 场景下有完全的自主权。
Strategy 文件告诉 Claude「分析滑动问题至少要做这几件事」,Planning Gate 确保它先想后做,Verifier 事后检查关键步骤有没有真的做。 但在这个框架内,具体查什么数据、用哪个工具、按什么顺序,都是 Claude 根据实际数据自主决定的。
提问背景: 我们在建设 Agent 的过程中,从最初默认 Agent 有能力理解并决策一切给它的 Skill,到现在几乎在 Skill 中写死了一棵决策树,这中间踩坑的出发点都是:「我们认为 Agent 有 xx 能力,但它没有」,导致其输出偏离我们的预期,于是我们不断地给 Skill 加边界,最后变成了一个写死的 Workflow。
Agent 和 Workflow 不是两个工具、两个框架——它们是同一个光谱的两端:
1 | 写死的 Workflow ◄──────────────────────────────────► 完全自主的 Agent |
| 维度 | Workflow | Agent |
|---|---|---|
| 控制流 | 开发者在代码中写死 if/else | LLM 自主选择下一步 |
| 工具选择 | 预定义执行顺序 | LLM 根据数据按需选择 |
| 分支条件 | 代码中的条件判断 | LLM 推理判断 |
| 失败处理 | try/catch + 重试逻辑 | LLM 自我反思 + 换方向 |
| 可预测性 | 确定性高 | 不确定性高 |
| 适应新场景 | 需要开发者加分支 | 可以自主探索 |
但工程实践中,几乎没有人处在光谱的任何一端。 纯 Workflow 无法处理未知场景;纯 Agent 在关键步骤上不可靠。实际落地的系统都在光谱的某个中间位置。
「默认 Agent 有能力理解一切 → 发现它做不到 → 不断加约束 → 变成写死的 Workflow」——这个路径的根本问题在于:对 Agent 的能力做了全局一刀切的判断。
但 Agent 的能力在不同环节差异巨大:
| 能力维度 | LLM 可靠度 | 该交给谁 |
|---|---|---|
| 意图理解(用户想干什么) | 高 ✅ | Agent(但简单场景可以用关键词匹配替代) |
| 计划制定(分几步做、先做什么) | 中等 ⚠️ | 需要约束框架:Strategy 文件给框架,LLM 填细节 |
| 数据收集(该查什么) | 中等 ⚠️ | 半自主:Skill 定义了查什么,Agent 决定顺序和参数 |
| 数据推理(看到数据后归因) | 高 ✅ | Agent——这是 LLM 最大的价值 |
| 精确计算(数值统计) | 极低 ❌ | 工具系统(SQL / Skill Engine) |
| 自我评估(知道自己对不对) | 低 ⚠️ | 外部 Verifier,不信任 Agent 自评 |
正确的做法不是「全局选 Agent 或全局选 Workflow」,而是按环节分配:
1 | 场景识别 → Workflow(确定性逻辑,不需要 LLM 参与) |
SmartPerfetto 没有在 Agent 和 Workflow 之间二选一,而是对不同分析阶段设定了不同的约束强度(详见 Q2)。这里从「能力边界」的角度重新审视这个设计:
高约束(Phase 1.9 根因深钻)——因为 Agent 在「决定是否深钻」这件事上不可靠:
1 | # scrolling.strategy.md 中的 Phase 1.9 |
为什么要硬约束?因为我们发现 Agent 有一个系统性偏差:它倾向于在拿到概览数据后就直接出结论,跳过深钻。这不是模型不够聪明——Claude 完全有能力做根因深钻——而是模型存在「路径依赖」:概览数据已经包含了统计分类(reason_code),对模型来说「直接用分类标签出结论」比「花 3 轮工具调用做逐帧深钻」的认知成本低得多。
低约束(Phase 1.5 架构分支)——因为 Agent 在「根据数据选择工具」上足够可靠:
1 | # scrolling.strategy.md 中的 Phase 1.5 |
这里用「改用」「注意」等建议性措辞,不强制。因为架构检测的结果(Flutter/WebView/Standard)已经被确定性代码放进了 system prompt,Agent 看到这个信息后选择正确 Skill 的概率很高。
零约束(general 场景)——因为 Agent 在「未知场景自主探索」上是唯一选择:
1 | # general.strategy.md — 只给路由决策树,不给任何必须执行的步骤 |
general 场景没有任何硬约束,因为进入 general 意味着用户的问题超出了预定义场景,Workflow 无法处理。此时只能信任 Agent 的自主探索能力。
Agent 的能力边界不取决于模型参数量或 benchmark 分数,而取决于三个工程因素:
1. 观测能力——Agent 能”看到”什么数据
同一个模型,给它 scrolling_analysis Skill 的 L2 结构化帧数据 vs 让它自己写 SQL 查原始表,分析质量差距非常显著。Agent 的上限由你给它的数据工具决定。SmartPerfetto 用 164 个 YAML Skill 封装了领域专家的查询逻辑,Agent 通过 invoke_skill 拿到的是处理过的、结构化的分析数据,而不是原始的百万行 trace 事件。
2. 约束框架——Agent 在什么范围内决策
不约束的 Agent 像一个没有任务清单的实习生——知识够但不知道该先做什么。Strategy 文件、Planning Gate、Verifier 多层机制共同定义了 Agent 的决策边界:Strategy 告诉它「至少要做什么」,Planning Gate 强制它「先想后做」,Verifier 事后检查「分析是否充分」(启发式检查 + 假设闭环 + 场景完整性 + 可选的 LLM 复核)。
3. 反馈质量——Agent 做错后能否被纠正
Agent 的 findings 中存在相当比例的问题(浅层归因、假阳性、遗漏关键步骤)。单纯依赖模型自我纠错效果有限。SmartPerfetto 用多层验证 + 外部纠错 prompt 来闭环:
1 | Verifier 发现 ERROR → 生成 Correction Prompt → 触发 SDK 重试 |
有人会指出:scrolling.strategy.md 读起来就像一份 SOP(标准作业程序)——有编号的 Phase、条件表、必做项、甚至直接写了 invoke_skill("scrolling_analysis", {...})。这和「在 Skill 里写死决策树」有什么区别?
直说:在数据收集阶段,SmartPerfetto 的滑动分析就是一个 Workflow。 Strategy 文件就是 SOP,它把领域专家的分析经验编码成了确定性步骤。这是故意的。
关键在于理解 SOP 覆盖了什么、没覆盖什么:
SOP 能覆盖的(数据收集)——Strategy 文件干的事:
1 | scrolling.strategy.md: |
SOP 写不出来的(推理归因)——Agent 的价值所在:
1 | - 47 帧掉帧中,哪些帧是同一根因?(数据聚类) |
不同场景的 SOP 程度不同:
| Strategy 文件 | SOP 程度 | 原因 |
|---|---|---|
scrolling.strategy.md | 高 — Phase 编号 + 条件表 + 必做项 | 滑动分析方法论最成熟,最优数据收集路径已知 |
startup.strategy.md | 中高 — 有 Phase 结构,深钻方向更开放 | 启动场景更多样(冷/温/热、不同瓶颈) |
anr.strategy.md | 中 — 2-skill pipeline,但根因分析全靠推理 | ANR 根因高度多样 |
general.strategy.md | 低 — 只有路由决策树,无必做项 | 未知场景,无法 SOP 化 |
scrolling.strategy.md 是 SOP 程度最高的,因为滑动分析方法论最成熟。general.strategy.md 几乎没有 SOP,因为用户问题完全不可预测。
所以正确的理解是:SmartPerfetto = 「SOP 驱动的数据收集 + Agent 驱动的推理归因」。
SOP 解决「分析滑动问题至少要看哪些数据」——这个问题有确定性答案,用 SOP 是对的。Agent 解决「拿到数据后怎么推理因果、怎么组织结论」——这个问题每个 trace 不同,写不成 SOP。
回到你们的踩坑:问题不是「Skill 变成了 SOP」——数据收集阶段就应该用 SOP。问题是「SOP 吃掉了推理」——如果 SOP 连结论都写死了(”看到 X 就输出 Y”),Agent 就真的退化成 Workflow 了。关键是让 SOP 止步于数据收集,把推理留给 Agent。
Agent 和 Workflow 的区别不是「智能 vs 写死」,而是「决策权的分配方式」。Agent 的能力边界由「观测能力 × 约束框架 × 反馈质量」共同决定。正确的做法是按环节分配决策权——在 Agent 可靠的环节给自主权,在 Agent 不可靠的环节加约束——而不是全局一刀切。
提问背景: Agent 的架构有过不同的设计和演进——从最初的 ReAct 架构,到 LangGraph 的节点式架构,不同的 Agent 架构设计会给它带来怎样的影响?在搭建自己的业务 Agent 时,是否需要考虑架构对 Agent 性能的影响?例如 SmartPerfetto 是在 Claude Agent SDK 的基础上基于业务理解加入了不同的 Skill 加载模式。
| 架构 | 控制流模型 | 开发者角色 | 适合场景 |
|---|---|---|---|
| ReAct | 线性循环:Think → Act → Observe → Think… | 定义工具 | 工具少、路径短的简单任务 |
| LangGraph 节点式 | DAG 图:节点=步骤,边=条件跳转 | 设计图结构 + 定义节点 + 写跳转条件 | 步骤明确、分支有限的确定性流程 |
| SDK 原生 | SDK 管理 turn loop,开发者只定义 tools | 定义工具 + 注入上下文 | 工具多、路径不可预测、需要 LLM 自主编排 |
它们的核心区别在于「谁来决定下一步做什么」:
SmartPerfetto 的架构是 Claude Agent SDK(SDK 原生)+ 三层约束(Strategy/Planning Gate/Verifier):
1 | Claude Agent SDK 提供: SmartPerfetto 自建: |
为什么不用 LangGraph?
性能分析的根因推理路径是不可预测的。同样一个「滑动卡顿」,根因可能是:
如果用 LangGraph,你需要为每一种根因路径预定义一个 DAG 节点和跳转条件。性能分析有 21 个 reason_code,每个可以组合深钻——排列组合后的路径数量使得 DAG 图变得不可维护。
更根本的问题是:在看到数据之前,你不知道该走哪条路径。LangGraph 的 DAG 图假设开发者能提前预知所有分支条件,但性能分析的分支条件取决于运行时数据。
SDK 原生架构的优势:
LLM 自主选择工具路径,但通过三层约束确保关键步骤不被跳过:
1 | # LangGraph 需要预定义的 DAG: |
以下是 SmartPerfetto 基于业务理解做的架构改进,每一个都直接对应一个业务问题:
1. 条件化工具加载——减少 Agent 的决策空间
SmartPerfetto 的 MCP 工具总数最多 20 个(9 个 always-on + 11 个条件注入),但一次分析只注入其中的子集:
1 | // claudeMcpServer.ts — 按模式切换工具集 |
业务原因: 工具越多,Agent 选错工具的概率越大。一个只需要快速回答「帧率是多少」的查询,如果看到十几个规划/假设/比较工具,Agent 可能会过度分析。
2. Sub-Agent 场景门控——避免不必要的并行开销
1 | // claudeAgentDefinitions.ts — 只在复杂场景启用 sub-agent |
| 场景 | Sub-Agent 配置 | 原因 |
|---|---|---|
| scrolling | frame-expert + system-expert | 帧分析和系统分析适合拆分,由 orchestrator 协调 |
| startup | startup-expert + system-expert | 启动阶段分析和资源竞争分析适合拆分 |
| anr | 无 sub-agent | ANR 是 2-skill 管线,额外 sub-agent 反而增加开销 |
注:sub-agent 的实际并行性取决于 SDK 内部调度策略,我们按并行采证来设计 prompt,但实际执行可能是串行的。
3. Lightweight vs Full 双模式——快问快答不走完整管线
当用户问「这个 trace 的帧率是多少」时,不需要走完整的 Planning → Skill → Verification 管线。SmartPerfetto 的 ClaudeRuntime 在入口处做复杂度分类:
1 | analyze(query) |
业务原因: 用户的提问中有相当比例是事实性查询(「帧率多少」「有没有 ANR」),走完整管线会不必要地增加延迟。
需要,但改进方向不是换底层框架(ReAct → LangGraph),而是在现有框架上加业务约束层。 具体建议:
从你的 Skill 决策树中提取 Strategy 文件:把写死在代码里的 if/else 决策逻辑,改写为自然语言的分析策略(Markdown 文件),按场景注入 system prompt。这样领域专家可以直接修改分析逻辑,不需要碰代码。
加 Planning Gate:requirePlan() 的实现极其简单(不到 10 行代码),但效果显著——强制 Agent 先想后做,经验上能大幅减少跑偏。
加事后 Verifier:不检查 Agent 的中间步骤是否「正确」(这个很难判断),只检查关键步骤是否「发生了」(这个很容易判断)。
按场景/复杂度动态调整工具集和约束强度:不是所有查询都需要同样的分析深度,给简单查询开一条快速通道。
架构选择是业务问题,不是技术问题。ReAct/LangGraph/SDK 只是控制流的不同实现方式——真正影响 Agent 性能的是你在控制流之上搭建的约束层。SmartPerfetto 选择 SDK 原生不是因为它最先进,而是因为性能分析的根因路径不可预测,预定义 DAG 不如让 Agent 在约束框架内自主探索。
提问背景: 想做场景识别、路由到正确的 Skill,在建设这部分的时候应该更多基于「用户原声」还是「日志」,或者有什么更好的方法?场景识别的几条路径各有问题:代码匹配(关键词匹配会导致筛选结果过大或过小)、LLM 理解(LLM 的理解不一定准确)、日志还原(能筛选有无滑动,但不一定是用户关注的问题)。
SmartPerfetto 的场景识别不是靠单一信号源,而是三层信号配合,每层解决不同的问题:
1 | Layer 1: 用户原声 — 关键词匹配 → 场景类型(scrolling / startup / anr / ...) |
Layer 1:用户原声(关键词匹配,<1ms)
1 | // sceneClassifier.ts — 46 行代码,完成了全部场景分类 |
关键词定义在每个 Strategy 文件的 YAML frontmatter 中,不是硬编码在 TypeScript 里:
1 | # scrolling.strategy.md frontmatter |
为什么用关键词匹配而不是 LLM?
关键词匹配不够的地方怎么办?
关键词匹配的确有边界——当用户说「这个 app 为什么慢」时,关键词无法确定是启动慢还是滑动慢。SmartPerfetto 的处理方式是:匹配不到就 fallback 到 general 场景,让 Agent 在 general 策略的路由决策树中自主选择方向。
1 | # general.strategy.md — 没有任何硬约束,只给路由建议 |
这个设计的核心思路是:不要试图在入口处 100% 准确分类,而是让准确的情况走快速路径(关键词 → Strategy),不确定的情况走探索路径(general → Agent 自主路由)。
Layer 2:Trace 数据——架构检测(确定性代码)
场景分类只解决了「用户想分析什么」,但同一个场景(如滑动)在不同渲染架构下的分析路径完全不同:
| 架构 | 渲染管线 | 分析差异 |
|---|---|---|
| Standard Android | UI Thread → RenderThread → SurfaceFlinger | 主线程 + RenderThread 双线分析 |
| Flutter TextureView | 1.ui → 1.raster → JNISurfaceTexture → RenderThread updateTexImage | 双出图管线,需要分析 Flutter engine 线程 + 纹理桥接 |
| Flutter SurfaceView | 1.ui → 1.raster → BufferQueue → SurfaceFlinger | 单出图管线,不经过 RenderThread |
| WebView | CrRendererMain → Viz Compositor | Chromium 渲染管线,线程名不同 |
| Compose | UI Thread (Composition) → RenderThread | 和 Standard 类似但有 Composition 阶段 |
架构检测委托给 YAML skill rendering_pipeline_detection——它在 SQL 层做线程/Slice 信号采集、管线打分、子变体判定,支持 24 种细粒度渲染架构。TypeScript 侧(architectureDetector.ts)只负责调用 skill 和映射结果,不做直接的 if/else 判断:
1 | rendering_pipeline_detection skill (SQL) |
检测结果被注入到 system prompt 中(通过 arch-flutter.template.md 等模板),Agent 看到架构信息后选择对应的分析工具。
Layer 3:数据完整性——能力寄存器
Trace 采集配置不同,可用的数据维度也不同。有的 trace 没有 GPU frequency 数据,有的没有 thermal zone。SmartPerfetto 在分析开始前探测 18 个数据维度的可用性:
1 | frame_rendering: ✅ (456 rows) |
这个信息同样注入 system prompt,告诉 Agent 哪些维度可以分析、哪些维度数据缺失。避免 Agent 调用没有数据支撑的 Skill 后得到空结果再换方向——这种试错浪费 1-2 个工具调用的 token。
1. 代码匹配(关键词):可以用,但要设计好兜底
提问者说「关键词匹配会导致筛选结果过大或过小」。SmartPerfetto 的经验是:
/启动.*慢/ 比单独匹配「启动」更精确general 兜底解决「过小」问题:匹配不到就不猜,交给 Agent 自主探索2. LLM 理解:不建议用在分类入口,可以用在兜底路径
LLM 的分类在 SmartPerfetto 中不是 Layer 1,而是 general 场景中 Agent 的自主路由——这时 Agent 已经拿到了 trace 数据,可以结合数据做更准确的判断。
3. 日志还原:适合做 Layer 2 的补充信号
日志能告诉你「trace 中有什么」(有无滑动事件、有无 ANR),但不能告诉你「用户关心什么」。SmartPerfetto 的数据完整性探测就是这个角色——它不参与场景分类,但为 Agent 提供数据可用性信息。
场景识别不要试图用一个信号源解决所有问题。用关键词匹配做快速路由(准确的情况),用 general 兜底做 Agent 自主探索(不确定的情况),用 trace 数据做架构和完整性补充。关键词匹配 + 优先级排序 + compound patterns + 兜底策略,46 行代码就够了。
提问背景: 目前线上 Skill 运行的时候发现,AI 自主探索、下钻根因容易跑偏,给出不正确的结果。比如 SmartPerfetto 博客中提到的例子——在前期定位到 RenderThread 被 Binder 阻塞后(基于确定性步骤),后面的多个假设形成和验证是纯 AI 发挥吗,还是说针对 Binder 阻塞我们可能给 AI 一些常见的原因作为引导让它自己排查?
SmartPerfetto 的做法是结构化推理框架 + 按需知识注入:
1 | 确定性步骤产出数据 |
三个关键机制让 AI 自主探索变得更可靠:
SmartPerfetto 提供了 submit_hypothesis 和 resolve_hypothesis 两个 MCP 工具,不是让 Agent 在内心独白中隐式推理,而是强制外显化:
1 | Agent 调用: |
为什么有效? 假设管理工具迫使 Agent 在行动之前明确声明「我在验证什么」和「我预期看到什么」。这有两个好处:
“针对 Binder 阻塞我们可能给 AI 一些常见的原因作为引导吗?”
是的,但不是写死在 Skill 中,而是通过 lookup_knowledge MCP 工具按需加载。Agent 发现 Binder 阻塞后,可以调用:
1 | invoke lookup_knowledge("binder-ipc") |
返回一份 Binder IPC 的知识模板(knowledge-binder-ipc.template.md),包含:
关键设计:知识是 Agent 主动拉取的,不是系统强制注入的。 目前共有 8 个知识模板(rendering-pipeline、binder-ipc、gc-dynamics、cpu-scheduler、thermal-throttling、lock-contention、startup-root-causes、data-sources),如果在 system prompt 中预先注入全部模板,会消耗大量 token 且大部分不相关。通过 MCP 工具按需加载,Agent 只在需要时才获取对应领域的背景知识。
SmartPerfetto 还在 Strategy 文件中提供了条件化的深钻建议表,这也是一种引导:
1 | # scrolling.strategy.md Phase 1.9 |
这个表不是写死的决策树——它是给 Agent 的查找表。Agent 看到数据后,根据数据中的指标值决定走哪一行。如果数据不匹配任何一行,Agent 可以自主探索。
在数据工具(execute_sql / invoke_skill)成功返回的前几次调用中,SmartPerfetto 在结果末尾附加一段推理提示:
1 | // claudeMcpServer.ts |
成本极低(~20 tokens/次,前 4 次共 ~80 tokens),但效果显著。 之所以不是全程附加,是为了在分析后半段控制 token 开销——前几次 nudge 已经建立了「收到数据 → 先反思 → 再行动」的模式。没有这个 nudge,Agent 倾向于连续调用工具而不停下来思考——收集了 5 次数据但没有形成任何中间结论,最后的总结质量很差。
1 | 1. 先看总览 → 发现 47 帧卡顿,P90 = 23.5ms |
注意 Step 4-9 全部是 AI 自主探索,但受到三个约束:
1. 给数据,不给结论
Skill 应该返回结构化数据(帧耗时、线程状态分布、阻塞函数列表),而不是已经得出的结论(「RenderThread 阻塞是因为 Binder」)。让 AI 自己从数据中推理结论,比让它基于别人给的结论做进一步分析更可靠。
2. 给框架,不给路径
Strategy 文件应该定义「必须做什么」(Phase 1.9 必须深钻),而不是「怎么做」(先查 A 再查 B 再查 C)。Agent 在有框架约束的情况下自主选择路径,比在没有任何约束下自由探索要可靠得多,又比写死路径灵活得多。
3. 给知识,不给答案
知识模板应该包含「可能的原因分类和排查方法」,而不是「如果看到 X 就是 Y」。前者帮助 Agent 建立推理框架,后者把 Agent 变回 Workflow。
4. 验证行为,不验证结论
Verifier 应该用启发式规则检查「分析输出是否体现了关键动作」(结论中是否有深钻分析痕迹、假设是否都已 resolved、因果链是否有足够深度),而不是试图判断「结论是否正确」(这个你在离线评估中用 LLM Judge 做,不应该在运行时做)。注意这是文本模式匹配级别的启发式检查,不是精确的工具调用日志审计。
AI 自主探索的可靠性不是靠「写死引导」来保证的,而是靠三个机制:假设管理工具让推理外显化、按需知识注入提供领域排查框架、ReAct nudge 防止盲目工具调用。关键原则是「给数据不给结论、给框架不给路径、给知识不给答案」。
提问背景: 大模型 Agent 的输出质量很大程度取决于 system prompt 的设计。SmartPerfetto 在每次分析时是如何构造 prompt 的?不同场景、不同轮次之间 prompt 有什么变化?token 预算怎么控制?
SmartPerfetto 的 system prompt 不是一个静态字符串,而是由 buildSystemPrompt() 函数(claudeSystemPrompt.ts:260)在每次 SDK 查询前动态拼接的。拼接遵循一个核心原则:
按「稳定性」排序——越不容易变化的内容越靠前,越动态的内容越靠后。
这个设计的原因是 Anthropic API 的自动缓存机制:system prompt 超过 1024 tokens 时,API 会自动对 prompt 前缀做缓存。如果把不变的部分放在最前面,多轮对话中大部分 prompt 可以命中缓存,显著降低延迟和成本:
1 | Same trace + same scene: ~4000 tokens cached (~80% savings) |
1 | ┌───────────────────────────────────────────────────────┐ |
所有 prompt 内容都在 Markdown 文件中定义(详见 Q1),TypeScript 只做加载和变量替换:
1 | // strategyLoader.ts — 模板系统 |
模板文件清单:
| 类别 | 文件 | 用途 |
|---|---|---|
| 静态模板 | prompt-role.template.md | 角色定义 |
prompt-output-format.template.md | 输出格式规则(91 行) | |
prompt-quick.template.md | 快速模式精简 prompt | |
| 方法论 | prompt-methodology.template.md | 分析方法论(含 {{sceneStrategy}} 占位符) |
| 架构指南 | arch-standard.template.md | Standard Android 渲染指导 |
arch-flutter.template.md | Flutter 引擎指导 | |
arch-compose.template.md | Jetpack Compose 指导 | |
arch-webview.template.md | WebView 指导 | |
| 选区模板 | selection-area.template.md | 时间范围选区({{startNs}}, {{endNs}}…) |
selection-slice.template.md | Slice 选区({{eventId}}, {{ts}}…) | |
| 比较模式 | comparison-methodology.template.md | 双 trace 对比方法论 |
| 场景策略 | 12 个 *.strategy.md | scrolling/startup/anr/memory/… |
| 知识模板 | 8 个 knowledge-*.template.md | 按需加载的领域知识(非 prompt 注入) |
| 辅助模板 | prompt-complexity-classifier.template.md | Quick/Full 分流判定(不注入 prompt,但决定走哪条路径) |
预算上限: 4500 tokens(MAX_PROMPT_TOKENS)。纠错重试时,如果检测到 SDK auto-compact(对话历史被自动压缩),会将预算降到 3000 tokens 以留出空间;否则复用原始 prompt。
Token 估算方法: 混合中英文估算——中文字符按 1.5 tokens/字,ASCII 按 0.3 tokens/字。这是粗略近似,但用于预算管理足够准确。
超预算时的渐进丢弃策略:
当拼接完成后 token 数超出预算,按优先级从低到高依次丢弃整个 section:
1 | 丢弃顺序(最先丢弃 → 最后丢弃): |
永不丢弃的内容:
在 ClaudeRuntime.analyze() 中,prompt 拼接前需要经过二十多个准备阶段(Phase)来收集所有上下文:
1 | Phase 0: 选区上下文日志 |
所有 Phase 的结果汇入 ClaudeAnalysisContext 对象,传给 buildSystemPrompt() 做最终拼接。
不是所有查询都需要完整的 4500-token prompt。当用户问事实性问题(如「帧率是多少」)时,SmartPerfetto 使用精简的 quick prompt:
1 | // buildQuickSystemPrompt() — ~1500 tokens |
| 维度 | Quick Mode | Full Mode |
|---|---|---|
| 目标 tokens | ~1500 | ~4500 |
| 场景策略 | 无 | 12 套之一 |
| 方法论 | 无 | prompt-methodology.template.md |
| 对话上下文 | 无 | findings + notes + entity + summary |
| Planning Gate | 无 | 有 |
| Verifier | 无 | 有 |
| 适用场景 | 「帧率多少」「有没有 ANR」 | 「分析滑动卡顿」「分析启动性能」 |
在多轮分析中(用户追问或 drill-down),prompt 的变化取决于 SDK session 是否命中 resume:
第 1 轮: 无对话上下文、无历史计划、无分析笔记
第 2 轮起 — SDK session resume 命中(4 小时内):
previousFindings 和 conversationSummary第 2 轮起 — SDK session 过期或不可用:
sessionContext.generatePromptContext(2000),≤2000 tokens)纠错重试轮: 如果检测到 SDK auto-compact(对话历史被自动压缩),token 预算从 4500 降到 3000,渐进丢弃会更激进地移除非关键 section。如果没有发生 auto-compact,复用原始 system prompt。
用户输入 "分析滑动卡顿",Flutter TextureView 架构,第 1 轮:
1 | [Tier 1] prompt-role.template.md → "你是 Android 性能分析专家..." |
用户追问 "深入分析第 3 帧",第 2 轮(SDK session resume 命中):
1 | [Tier 1-3] 与第 1 轮相同(命中 ~80% 缓存) |
Prompt 按「稳定性」四层排序(Static → Per-Trace → Per-Query → Dynamic),利用 API 前缀缓存实现多轮对话 ~80% token 节省。模板系统让领域专家可以直接编辑分析策略而不碰 TypeScript。超预算时按优先级渐进丢弃,但永远保留角色定义、场景策略和用户选区——这三者决定了分析的方向和范围。
提问背景: SmartPerfetto 的分析能力由 YAML Skill 承载。完整的 Skill 清单可以帮助理解系统的分析覆盖范围。
| 分类 | 数量 | 说明 |
|---|---|---|
| Atomic | 87 | 单步检测/统计,一条或几条 SQL 完成 |
| Composite | 29 | 组合多个 atomic skill,支持 iterator/conditional |
| Deep | 2 | 深度剖析(callstack、CPU profiling) |
| Pipeline | 28 | 渲染管线检测 + 教学(24+ 种架构) |
| Module | 18 | 模块化配置:app/framework/hardware/kernel |
| 合计 | 164 |
单步数据提取和检测,是所有高层 Skill 的构建基础。
帧渲染与掉帧:
| Skill ID | 一句话描述 |
|---|---|
| consumer_jank_detection | 从 SF 消费端角度检测真正的掉帧(per-layer buffer 枯竭) |
| frame_blocking_calls | 识别每个掉帧帧期间的阻塞调用(GC、Binder、锁、IO) |
| frame_production_gap | 检测帧生产间隙:连续帧之间的 gap 超过 1.5× VSync |
| frame_pipeline_variance | 检测帧时长抖动与高方差区间 |
| render_pipeline_latency | 分解帧渲染全链路各阶段耗时 |
| render_thread_slices | 分析 RenderThread 的时间片分布 |
| app_frame_production | 分析应用主线程的帧生产情况 |
| sf_frame_consumption | 分析 SurfaceFlinger 消费帧的情况 |
| sf_composition_in_range | 分析 SurfaceFlinger 合成延迟 |
| sf_layer_count_in_range | 统计时间范围内 SF 活跃图层数量 |
| present_fence_timing | 分析 Present Fence 时序,检测实际显示延迟 |
| game_fps_analysis | 针对游戏场景的帧率分析,支持固定帧率模式 |
VSync 与刷新率:
| Skill ID | 一句话描述 |
|---|---|
| vsync_period_detection | 检测 VSync 周期,返回刷新率和置信度 |
| vsync_config | 从 trace 中解析实际的 VSync 周期和刷新率设置 |
| vsync_alignment_in_range | 分析帧与 VSync 信号的对齐情况 |
| vsync_phase_alignment | 分析输入事件与 VSync 的相位关系,定位跟手延迟瓶颈 |
| vrr_detection | 检测设备是否使用可变刷新率(VRR/LTPO/Adaptive Sync) |
CPU 与调度:
| Skill ID | 一句话描述 |
|---|---|
| cpu_topology_detection | 从 cpufreq 动态检测 CPU 大小核拓扑 |
| cpu_topology_view | 创建可复用 SQL VIEW _cpu_topology |
| cpu_slice_analysis | 分析 CPU 时间片分布(动态拓扑检测) |
| cpu_load_in_range | 分析指定时间范围内各 CPU 核心的负载情况 |
| cpu_cluster_load_in_range | 计算大核簇和小核簇的整体 CPU 负载百分比 |
| cpu_freq_timeline | 分析各 CPU 核心的频率变化时间线 |
| cpu_throttling_in_range | 检测 CPU 热控限频情况 |
| sched_latency_in_range | 分析线程调度等待时间分布,检测 CPU 争抢 |
| scheduling_analysis | 分析线程调度延迟(Runnability) |
| task_migration_in_range | 分析线程在大小核之间的迁移频率 |
| thread_affinity_violation | 检测主线程/RenderThread 的高频迁核行为 |
| thermal_predictor | 基于 CPU 频率趋势预测热限频风险 |
| cache_miss_impact | 统计 cache-miss 计数器并评估波动 |
GPU:
| Skill ID | 一句话描述 |
|---|---|
| gpu_render_in_range | 分析 GPU 渲染耗时和 Fence 等待 |
| gpu_freq_in_range | 分析 GPU 频率变化情况 |
| gpu_metrics | 分析 GPU 频率、利用率和渲染性能 |
| gpu_power_state_analysis | 分析 GPU 频率状态切换,识别降频压力与抖动 |
主线程分析:
| Skill ID | 一句话描述 |
|---|---|
| main_thread_states_in_range | 统计区间内主线程状态、阻塞函数与占比 |
| main_thread_slices_in_range | 统计区间内主线程切片耗时分布 |
| main_thread_sched_latency_in_range | 统计主线程 Runnable 等待时间分布 |
| main_thread_file_io_in_range | 统计区间内主线程文件 IO 相关切片耗时 |
Binder IPC:
| Skill ID | 一句话描述 |
|---|---|
| binder_in_range | 分析指定时间范围内的 Binder 事务 |
| binder_blocking_in_range | 分析同步 Binder 调用中对端进程的响应延迟 |
| binder_root_cause | 对慢 Binder 事务进行服务端/客户端阻塞原因归因 |
| binder_storm_detection | 检测 Binder 事务风暴:短时间内过多 IPC 调用 |
锁与同步:
| Skill ID | 一句话描述 |
|---|---|
| lock_contention_in_range | 分析指定时间范围内的锁竞争情况 |
| futex_wait_distribution | 统计 futex/mutex 锁等待分布与耗时 |
启动专用(19 个):
| Skill ID | 一句话描述 |
|---|---|
| startup_events_in_range | 查询启动事件及 TTID/TTFD 指标 |
| startup_slow_reasons | 启动慢原因(Google 官方分类 + 自检)v3.0 |
| startup_critical_tasks | 自动识别启动区间内所有活跃线程,按 CPU 时间排序 |
| startup_thread_blocking_graph | 利用 waker_utid 构建线程间的 block/wakeup 关系图 |
| startup_jit_analysis | 分析 JIT 编译线程对启动速度的影响 |
| startup_cpu_placement_timeline | 按时间桶分析主线程核类型变化,检测启动初期被困小核 |
| startup_freq_rampup | 分析冷启动初期 CPU 频率爬升速度,检测升频延迟 |
| startup_binder_pool_analysis | 分析启动期间 Binder 线程池利用率和饱和度 |
| startup_hot_slice_states | 分析启动区间内 Top N 热点 Slice 的线程状态分布 |
| startup_main_thread_states_in_range | 统计启动阶段主线程 Running/Runnable/Blocked 占比 |
| startup_main_thread_slices_in_range | 统计启动阶段主线程切片热点 |
| startup_binder_in_range | 统计启动阶段 Binder 调用分布 |
| startup_main_thread_file_io_in_range | 统计启动阶段主线程文件 IO |
| startup_sched_latency_in_range | 统计启动阶段主线程 Runnable 等待时延 |
| startup_main_thread_sync_binder_in_range | 统计启动阶段主线程同步 Binder 耗时 |
| startup_main_thread_binder_blocking_in_range | 分析启动阶段主线程同步 Binder 阻塞明细 |
| startup_breakdown_in_range | 统计启动阶段各归因原因耗时占比 |
| startup_gc_in_range | 统计启动阶段 GC 切片及主线程占比 |
| startup_class_loading_in_range | 统计启动阶段类加载切片耗时 |
内存与 GC:
| Skill ID | 一句话描述 |
|---|---|
| gc_events_in_range | 查询给定进程的 GC 事件和可选时间范围 |
| memory_pressure_in_range | 分析指定时间范围内的内存压力指标 |
| page_fault_in_range | 分析 Page Fault 和内存回收对性能的影响 |
输入与触摸:
| Skill ID | 一句话描述 |
|---|---|
| input_events_in_range | 提取区间内的原始输入事件,分析分发延迟 |
| input_to_frame_latency | 测量每个 MotionEvent 到对应帧 present 的延迟 |
| touch_to_display_latency | 测量从触摸到帧渲染的端到端延迟 |
| scroll_response_latency | 测量滚动手势从输入到首帧渲染的响应延迟 |
系统与设备:
| Skill ID | 一句话描述 |
|---|---|
| system_load_in_range | 分析系统整体 CPU 利用率和进程活跃度 |
| device_state_snapshot | 采集 trace 期间的设备环境信息(屏幕、电量、温度等) |
| device_state_timeline | 追踪设备状态随时间的变化 |
| wakelock_tracking | 追踪 Wake Lock 持有情况,检测电池功耗异常 |
其他:
| Skill ID | 一句话描述 |
|---|---|
| blocking_chain_analysis | 分析主线程阻塞链:谁阻塞了主线程?唤醒者在做什么? |
| anr_main_thread_blocking | 深度分析 ANR 中主线程阻塞原因 |
| anr_context_in_range | 提取第一个 ANR 事件数据用作时间窗口锚点 |
| app_lifecycle_in_range | 追踪 Activity/Fragment 生命周期事件 |
| compose_recomposition_hotspot | 检测 Jetpack Compose 重组热点 |
| webview_v8_analysis | 分析 WebView V8 引擎:GC、脚本编译、执行时间 |
| rendering_pipeline_detection | 识别应用渲染管线类型(24 种细粒度检测) |
| pipeline_key_slices_overlay | 查询管线关键 Slice 的 ts/dur 用于时间线 overlay |
组合多个 atomic skill,支持 iterator(逐帧/逐事件深钻)和 conditional(条件分支)。
| Skill ID | 一句话描述 |
|---|---|
| scrolling_analysis | 滑动分析主入口:概览 → 帧列表 → 根因分类 → 逐帧诊断 |
| flutter_scrolling_analysis | Flutter 特定帧分析,使用 Flutter 线程模型 |
| jank_frame_detail | 分析特定掉帧的详细原因:深钻 jank 原因和根因分类 |
| startup_analysis | 启动分析主入口:Iterator 模式、大小核分析、四象限 |
| startup_detail | 分析单个启动事件:主线程耗时、Binder、CPU 大小核占比 |
| anr_analysis | ANR v3.0 分析:系统问题 vs 应用问题、分类处理 |
| anr_detail | 单个 ANR 事件详情:四象限、Binder 依赖、死锁检测 |
| cpu_analysis | CPU 分析:时间分布、大小核分析、调度链路 |
| gpu_analysis | GPU 分析:频率分布、内存使用、帧渲染关联 |
| memory_analysis | 内存分析:GC 事件、GC 与帧关联、线程状态 |
| gc_analysis | GC 分析:基于 stdlib android_garbage_collection_events |
| binder_analysis | Binder 深度分析:事务基础、线程状态 |
| binder_detail | 单个 Binder 事务详情:CPU 大小核、四象限、阻塞原因 |
| thermal_throttling | 温度监控、热节流检测、CPU 频率相关性 |
| lock_contention_analysis | 锁竞争多维度分析:基于 android.monitor_contention |
| surfaceflinger_analysis | SF 帧合成性能:GPU/HWC 合成比例、慢合成检测 |
| click_response_analysis | 点击响应分析:基于 stdlib android_input_events |
| click_response_detail | 单个慢输入事件详情:延迟分解、四象限、主线程阻塞 |
| scroll_session_analysis | 单个完整滑动区间:Touch 阶段 vs Fling 阶段 FPS |
| navigation_analysis | Activity/Fragment 跳转性能:生命周期、转场动画 |
| lmk_analysis | LMK 分析:原因分布、时间线、频率 |
| dmabuf_analysis | DMA Buffer 分析:分配、释放、泄漏检测 |
| block_io_analysis | Block IO 分析:设备级统计、队列深度、长耗时 IO |
| io_pressure | IO 阻塞数据检测、IO Wait 时间、严重度评估 |
| suspend_wakeup_analysis | 休眠/唤醒分析:时间分布、唤醒源排行 |
| network_analysis | 网络分析:流量概览、应用流量、协议分布 |
| irq_analysis | 硬中断和软中断的频率、耗时、嵌套情况 |
| scene_reconstruction | 通过用户输入和屏幕状态还原用户操作场景 |
| state_timeline | 四泳道连续状态时间线:设备/用户/应用/系统 |
深度剖析,通常需要更长的执行时间。
| Skill ID | 一句话描述 |
|---|---|
| cpu_profiling | CPU 性能剖析:使用热点和调度效率深度分析 |
| callstack_analysis | Running 状态下的调用栈热点分析 |
渲染管线检测 + 教学。每个 pipeline skill 对应一种渲染架构,包含管线描述、关键线程、性能指标和优化建议。
| Skill ID | 渲染架构 |
|---|---|
| pipeline_android_view_standard_blast | Android 12+ 标准 HWUI + BLASTBufferQueue |
| pipeline_android_view_standard_legacy | Android 12 前标准 HWUI + Legacy BufferQueue |
| pipeline_android_view_software | CPU Skia 软件渲染,无 RenderThread |
| pipeline_android_view_mixed | View + SurfaceView 混合渲染 |
| pipeline_android_view_multi_window | 同进程多窗口(Dialog/PopupWindow) |
| pipeline_android_pip_freeform | 画中画和自由窗口模式 |
| pipeline_compose_standard | Jetpack Compose + HWUI RenderThread |
| pipeline_flutter_textureview | Flutter PlatformView 降级模式 |
| pipeline_flutter_surfaceview_skia | Flutter + Skia 引擎(JIT Shader) |
| pipeline_flutter_surfaceview_impeller | Flutter + Impeller 引擎(预编译 Shader) |
| pipeline_webview_gl_functor | 传统 WebView,App RenderThread 同步等待 |
| pipeline_webview_surface_control | 现代 WebView + Viz/OOP-R 独立合成 |
| pipeline_webview_textureview_custom | X5/UC 等定制 WebView 内核 |
| pipeline_webview_surfaceview_wrapper | WebView 全屏视频包装模式 |
| pipeline_chrome_browser_viz | Chrome Viz 合成器,多进程架构 |
| pipeline_opengl_es | 直接 OpenGL ES / EGL 渲染 |
| pipeline_vulkan_native | 原生 Vulkan 渲染 |
| pipeline_angle_gles_vulkan | ANGLE: OpenGL ES → Vulkan 翻译层 |
| pipeline_game_engine | Unity/Unreal/Godot 等游戏引擎 |
| pipeline_surfaceview_blast | 独立 SurfaceView + BLAST 同步 |
| pipeline_textureview_standard | SurfaceTexture 纹理采样/合成模式 |
| pipeline_camera_pipeline | Camera2/HAL3 多流相机渲染 |
| pipeline_video_overlay_hwc | HWC 视频层硬件加速叠加 |
| pipeline_hardware_buffer_renderer | Android 14+ HBR API 直接 Buffer 渲染 |
| pipeline_surface_control_api | NDK SurfaceControl 直接事务提交 |
| pipeline_variable_refresh_rate | VRR/ARR + FrameTimeline 动态刷新率 |
| pipeline_imagereader_pipeline | ImageReader API:ML 推理、录屏、自定义相机 |
| pipeline_software_compositing | SF CPU 软件合成回退(GPU 不可用时) |
注:
_base.skill.yaml是 Pipeline Skill 的基础模板文件,不注册为可用 Skill,不计入总数。
模块化分析配置,按层级组织。Agent 通过 list_skills 发现并按需调用。
硬件层(5 个):
| Skill ID | 一句话描述 |
|---|---|
| cpu_module | CPU 频率、热节流和电源状态 |
| gpu_module | GPU 渲染、频率和显存使用 |
| memory_module | 内存带宽、LMK、dmabuf、PSI、缺页 |
| thermal_module | 温度传感器、热节流检测、冷却策略 |
| power_module | Wake Lock、CPU idle、电源模式、休眠/唤醒 |
框架层(6 个):
| Skill ID | 一句话描述 |
|---|---|
| surfaceflinger_module | 帧渲染时序、卡顿原因、GPU 合成 |
| choreographer_module | VSync 信号、doFrame 回调、帧生产管线 |
| ams_module | 应用生命周期、进程管理、启动时序 |
| wms_module | 窗口动画、Activity 转场、多窗口 |
| art_module | GC、JIT 编译和内存分配 |
| input_module | 触摸延迟、输入派发和点击响应 |
内核层(4 个):
| Skill ID | 一句话描述 |
|---|---|
| scheduler_module | 线程调度延迟、CPU 利用率、大小核分配 |
| binder_module | 跨进程调用、阻塞事务、调用延迟 |
| lock_contention_module | Mutex/Futex、Java monitor、死锁检测 |
| filesystem_module | Block IO、文件操作、数据库、SharedPreferences |
应用层(3 个):
| Skill ID | 一句话描述 |
|---|---|
| launcher_module | 主屏性能、应用启动、小部件更新 |
| systemui_module | 状态栏、通知栏、快速设置、导航栏 |
| third_party_module | 第三方应用性能、卡顿和资源使用 |
1 | Module Skills (配置层) |
Agent 的典型调用路径(以滑动分析为例):
1 | invoke_skill("scrolling_analysis") ← Composite,内部调用多个 Atomic |
下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!
一个人可以走的更快 , 一群人可以走的更远

这篇文章记录了 SmartPerfetto 从零到可用过程中的关键技术决策——为什么选这个方案而不是那个,哪些地方踩了坑,踩完之后怎么调整的。
我做了多年 Android 性能优化。日常工作中大量时间花在 Perfetto trace 分析上——Perfetto 是 Google 开源的系统级 trace 工具,采集帧渲染、线程调度、CPU 频率、Binder 通信等数据,几乎是 Android 性能分析的标准工具。它的 trace_processor 引擎把 trace 加载到一个嵌入式 SQLite 数据库中,支持用 SQL 查询。
分析 trace 的过程是高度重复的:找到问题区间、查帧数据、看线程状态、追阻塞链、关联系统指标。每次做的事情类似,但每个 trace 的细节不同。这种「流程固定、细节变化」的工作特点很适合 AI Agent 来处理——把固定流程中的数据收集和初步归因自动化,人来做最后的判断和确认。
SmartPerfetto 就是这个尝试的产物。它在 Perfetto UI 上加了一个 AI 分析面板,用户用自然语言提问(如「分析滑动性能」),背后由 Claude Agent 通过 MCP(Model Context Protocol,Anthropic 提出的工具调用协议)调用 trace_processor 执行 SQL,自主完成多轮数据收集和分析。
写这篇文章的目的,是把构建过程中的工程决策和教训记录下来。从最初的「直接调 API」到现在的最多 20 个 MCP 工具(9 常驻 + 11 条件注入)+ 164 个 YAML Skill + 三层验证体系,中间的每个设计选择都有具体的反例在推动——试过不行才换的方案。这些踩坑记录对做 AI Agent 应用或者做 Android 性能工具的工程师可以直接借鉴。
一个滑动 trace,120Hz 设备,用户反馈列表滑动偶尔卡顿。打开 Perfetto 看到惯性滑动阶段有 18 帧掉帧,其中 3 帧 Full 级(~60ms,120Hz 设备的单帧预算是 8.33ms)。
掉帧(Jank): Perfetto 的 frame_timeline track 记录每帧渲染耗时。超过 VSync 周期(120Hz 下为 8.33ms)用户会感知卡顿。
jank_type字段区分掉帧类型:App 侧超时、SurfaceFlinger 合成延迟、Buffer Stuffing(BufferQueue 队列背压)等。
路径 A:手动分析
1 | 1. 打开 Perfetto UI,拖动时间轴找到滑动区间 |
thread_state 记录线程的调度状态(Running / Runnable / Sleeping / Uninterruptible Sleep 等)。不同状态指向不同的排查方向——Runnable 通常提示 CPU 调度层面的问题,Sleeping 通常提示等待/阻塞层面的问题。
waker_utid字段记录了唤醒线程的源线程 ID,可以辅助追踪跨进程的阻塞链。
第 3-4 步是主要工作量——18 帧掉帧,每帧都需要展开 thread_state、追踪阻塞原因、关联 CPU 调度。分析过程是逐帧串行的:每帧的下钻路径可能不同(Binder? 锁? GC? IO?),全部看完再汇总。
路径 B:SmartPerfetto Agent
用户输入 "分析滑动性能",以下是 Agent 实际执行的操作(来自 session log session_agent-1774679540422):
1 | classifyScene("分析滑动性能") → scrolling (<1ms, 关键词匹配) |
Metrics 快照 (来自 logs/metrics/):16 次工具调用,0 次失败,SQL 平均 652ms。
下图展示了一次完整分析的请求生命周期——从用户输入到最终结论的每一步:

两条路径的分析步骤相同——查帧数据 → 定位 jank → 追踪阻塞链 → 关联系统状态 → 归纳结论。
差异在于:手动分析逐帧串行,每帧需要手动展开和追踪;Agent 通过 scrolling_analysis Skill 用一条 SQL 批量获取全部 18 帧的结构化数据,再选代表帧深钻阻塞链。
Agent 的分析结果同时落地到 Perfetto UI 上:
运行截图:以 SmartPerfetto 前端以 Perfetto 插件的形式存在

运行截图:滑动分析的时候详细分析每一个掉帧的地方, 点击最左边那个剪头可以展开

运行截图:滑动分析结论
运行截图:滑动分析结论,代表帧分析

运行截图:滑动分析结论,代表帧分析

运行截图:每一轮分析都有单独的分析 report,内容与前端显示的一致(更详细一些)

分析结论、数据表格和 Perfetto 时间线在同一个界面上。Agent 完成批量数据收集和初步归因后,工程师在 Perfetto UI 上确认关键发现。
需要说明的是,当前 Agent 在复杂边界情况下仍然需要人的判断(后文会具体讨论误诊问题)。这篇文章记录的是构建这个 Agent 背后的工程决策过程。
在开始讨论架构之前,需要先回答一个根本问题:为什么不能直接把 trace 数据发给 LLM 让它分析?这个问题的答案决定了 SmartPerfetto 整个架构的出发点。
一个实际的 Perfetto trace 的数据规模是这样的:
| 维度 | 典型值 |
|---|---|
| Trace 文件大小 | 50MB - 500MB |
| 事件数量 | 百万 ~ 千万级 |
| 序列化为文本后 | 数 GB |
| Claude 最大 context | ~200K tokens(约 150KB 文本) |
两者差了好几个数量级。即使是一个较小的 50MB trace,里面的 slice(函数调用记录)、counter(CPU 频率采样点)、thread_state(线程调度状态)等数据序列化后也远超 LLM 的上下文容量。
这就意味着 LLM 不可能直接「看到」trace 数据。它必须通过工具按需查询——先用 SQL 找到需要的数据子集(比如某个时间范围内某个线程的状态分布),拿到查询结果后再做分析。这个约束从根本上决定了 SmartPerfetto 必须是一个 工具驱动 的 Agent 架构,而不是把数据喂进 prompt 的简单方案。
性能分析的日常工作围绕精确数值展开:帧耗时的 P50 / P90 / P99 分位数、VSync 周期检测(需要对 VSYNC-sf 间隔取中位数并吸附到标准刷新率)、CPU 利用率的百分比计算、各线程状态的时间占比。
LLM 处理这类数值计算时经常出错。一个实际例子:早期测试中,Claude 把 16.7ms 的帧耗时判断为「正常,未超过 VSync 周期」——它按 60Hz(16.67ms)的帧预算来算了。但这个 trace 采集自一台 120Hz 设备,单帧预算应该是 8.33ms,16.7ms 实际上超预算了一倍。这类错误看起来很小,但在性能分析中会导致完全相反的结论。
数值计算必须由工具完成——SQL 的 AVG()、PERCENTILE() 和 YAML Skill 中预定义的统计逻辑,保证每次计算结果一致且精确。
Android 的渲染管线复杂度是很多开发者没有预期到的。最常见的三种渲染路径是:标准 HWUI 管线(HWUI 是 Android 默认的硬件加速渲染引擎,应用的 View 绘制指令在主线程生成,由 RenderThread 提交给 GPU,最终经 SurfaceFlinger 合成到屏幕)、Flutter 的双线程模型(1.ui → 1.raster,不走 RenderThread)、以及 WebView 的 Chromium 管线(CrRendererMain 线程负责渲染)。除此之外还有 Jetpack Compose、游戏引擎、相机管线等。SmartPerfetto 的架构检测系统目前识别 24+ 种渲染管线,不同管线的 jank 分析需要查看不同的线程和指标——这也是为什么架构检测是分析的第一步。
卡顿的根因可能跨线程(主线程阻塞 → 原因在 RenderThread)、跨进程(App 等待 → system_server 的 WindowManagerService 响应慢)、甚至跨硬件层(CPU 调度到小核 → 算力不足 → 帧超时)。
LLM 的训练数据中包含这些概念——它「知道」什么是 RenderThread,什么是 Binder,什么是 SurfaceFlinger。但面对一个具体的 trace,它缺乏将这些知识按场景分阶段运用的能力。比如分析滑动卡顿时,需要先检查帧级数据(哪些帧掉了、掉帧类型是什么),再针对占比最高的根因类型选择不同的深钻路径(App 侧阻塞走 blocking_chain_analysis,合成端延迟走 SurfaceFlinger 分析)。这种分步骤、有条件分支的分析流程,需要通过策略注入来引导。
即使解决了数据访问问题,直接让 LLM 产出性能分析结论仍然面临可靠性问题。在 SmartPerfetto 的实际运行中,我观察到几类典型的输出问题:
后文第二部分会详细讨论这个问题——agentv3 上线 18 天后的质量审查显示,约 30% 的 Agent 结论包含不同程度的误判。
基于这四个问题,SmartPerfetto 的架构按以下方式分工:
1 | LLM (Claude) 负责: 工具系统负责: |
LLM 做推理和表达,工具做查询和计算。连接两者的是 MCP(Model Context Protocol,Anthropic 提出的工具调用协议)——Claude 通过标准 MCP 接口调用 trace_processor 执行 SQL、调用 YAML Skill 做结构化分析、查询 Perfetto stdlib 模块。分析结果通过 SSE(Server-Sent Events)实时推送到 Perfetto UI 前端。
支撑这个分工的工程基础设施包括:场景路由(根据用户问题注入不同的分析策略)、数据压缩(控制返回给 LLM 的数据量)、质量验证(拦截 LLM 的领域误判)。后面几个部分展开讨论每个部分的设计过程。
下图是完整的系统架构,展示了从用户请求到分析结论的 4 个阶段:

Anthropic 在 2024 年 12 月发表的《Building Effective Agents》(作者 Erik Schluntz、Barry Zhang)中,将 AI 系统分为两类:
这个区分的实际意义在于灵活性和可控性的权衡。Workflow 提供可预测性,适合步骤固定的任务;Agent 提供灵活性,适合需要根据中间数据调整方向的开放式问题。Andrew Ng 的描述很准确:不需要二元地判断一个系统是不是 Agent,而是把它看作不同程度的 Agent 化。SmartPerfetto 的 agentv2 和 agentv3 分别对应这个光谱的两端。
性能分析不是一个「给输入得输出」的固定流程,它是一个探索性的推理过程。以一个实际的滑动分析为例:
1 | 1. 先看总览 → 发现 47 帧卡顿,P90 = 23.5ms |
每一步决策都依赖前一步的结果——无法在分析开始前就确定所有步骤。Pipeline 无法处理「这个 trace 的问题可能在 GPU,也可能在 GC,需要根据中间数据动态选择下钻方向」这种需求。
SmartPerfetto 的设计是确定性和灵活性的混合:已知场景(滑动、启动、ANR 等)用 Strategy 文件约束必检项,保证不遗漏;但每个阶段内的具体查询和深钻方向由 Claude 自主决定。未匹配的场景则完全交给 Claude 自主探索。
agentv2 使用 DeepSeek 作为后端,采用 Governance Pipeline 架构——通过 planner / executor / synthesizer 三阶段编排,本质上是预定义的多步骤工作流(历史 commit 6d80aefb: “Replace the 13-step agentv2 governance pipeline with Claude-as-orchestrator”)。
这个架构在标准 Android 应用的滑动分析上工作得不错,但遇到非标准情况就出问题了。比如 Flutter 应用的 trace 里没有标准的 frame_timeline 数据,管线拿到空结果后继续执行后续步骤,最终输出基于空数据的结论。
2026 年 3 月 2 日(commit 6d80aefb),我切换到 Claude Agent SDK。Claude 接收工具定义和策略后,自主决定调用什么工具、按什么顺序、查什么数据。
一个 AI Agent 通常具备以下特征,agentv3 的实现对照如下:
| 特征 | SmartPerfetto 中的实现 | 代码位置 |
|---|---|---|
| 自主性 | Agent 自主决定调用哪个工具、按什么顺序 | claudeRuntime.ts |
| 推理能力 | 每次工具调用后追加 REASONING_NUDGE 触发显式反思 | claudeMcpServer.ts:84 |
| 工具使用 | 最多 20 个 MCP 工具调用 trace_processor | 9 常驻 + 11 条件 |
| 规划能力 | submit_plan + requirePlan() 门控 | 轻量模式关闭 |
| 反思能力 | 3 层 Verifier + Correction Prompt (max 2 轮) | claudeVerifier.ts |
| 错误恢复 | SQL 纠错学习 + 跨会话误判模式学习 | 跨文件 |
| 记忆 | 短期: Analysis Notes / Artifact Store;长期: Pattern Memory / SQL Fix Pairs | 7 层记忆 |
1 | agentv2 (Workflow): 固定管线 → 每步预定义 → 意外数据 = 错误结论 |
从 3 月 2 日到 3 月 20 日,经历了 9 轮架构审查。其中影响最大的几轮:
| 轮次 | 日期 | 主要发现 |
|---|---|---|
| Round 1 | 3/2 | 初始 SDK 集成后 12 个修复——SQL 知识库没接入 System Prompt,jank_frame_detail 中 CPU 核数硬编码为 4 |
| Round 3 | 3/12 | 架构接线审计——12 处「实现了但没接上」的断连,比如验证管线在 0 findings 时被跳过 |
| Round 7 | 3/15 | Perfetto Stdlib 集成——预加载模块 4→22,Schema Index 708→761 |
| Round 9 | 3/20 | 18 天真实 trace 后的生产质量审查——3 P0 + 4 P1 + 5 P2,催生了三层验证系统 |
2026 年 3 月 19 日(commit d5a1d7b3),发现冷启动被错误分类为热启动。追踪后发现这是一个跨 4 层的联动问题:
1 | Layer A (Perfetto Stdlib): bindApplication 的 ts 比 launchingActivity 早 ~98ms → 被过滤器排除 |
修复规模:重写 10 个下游 Skill,新增 4 个启动分析 Skill。这个问题说明在 Skill 依赖链中,上游的一个字段语义错误会逐层放大。
2026 年 4 月 7 日(commit a0ad63ba)抓到的另一类跨层 Bug:分析超时之后,session 已经清理、SSE 流已经收尾,但 trace_processor 的 stderr 仍然在 90 秒后陆续吐出 no such table: cpu_frequency_counters / no such column: ts 这类错误——孤儿日志,没有 owner 可以归因到任何 session,前面错误 4 的两条纠错对就是从这堆 stderr 里反查出来的。
根因在 SDK Query 的异步生命周期:
1 | Layer A (Claude Agent SDK): SDK 内部的 AsyncIterator 还在生产 message |
AsyncGenerator.return() 和 break 只对消费侧生效,不会反向通知生产侧的外部资源(SDK 子进程 + MCP 工具执行队列)。修法是把 sdkQueryWithRetry 的返回类型从单个 AsyncIterable 改成 { stream, close } 二元组,timeout / 异常 / finally 三个路径都显式调一次 close(),让 SDK 主动 abort 子进程:
1 | // claudeRuntime.ts |
这个 Bug 之所以隐蔽,是因为表面症状(孤儿 SQL 错误日志)和真实根因(异步资源生命周期错配)相隔很远——错误信息长得像「Agent 写错 SQL」,但其实是「Agent 早就停了,是 SDK 子进程没停」。在 Agent 应用中,”break 一个循环” 经常没有想象中那么干净;任何长生命周期的异步资源都需要显式的 close 通道,而不是依赖 for-await 的自动析构。
一开始我把 12 个场景(scrolling / startup / ANR / interaction / pipeline / game / memory 等)的分析策略全部塞进 System Prompt,总计 15000+ tokens。逻辑是:Claude 应该知道所有场景的分析方法,这样不管用户问什么都能应对。
实际运行后发现 Claude 会混淆不同场景的术语——在分析滑动时引用了启动阶段的指标,把 VSync 间隔(帧间时序)和 bindApplication(进程初始化)搞混。根本原因是不同场景的术语存在大量重叠,「帧」在滑动场景里是渲染帧,在启动场景里是首帧显示,12 套策略同时出现时 LLM 无法区分上下文。
解决方式是做场景分类,每次只注入一套策略:
1 | // sceneClassifier.ts — 12 场景, <1ms 执行 |
关键词和优先级声明在每个 .strategy.md 的 YAML frontmatter 中,不硬编码在代码里:
1 | # scrolling.strategy.md |
添加新场景只需新建一个 .strategy.md 文件。DEV 模式下支持热加载,修改后刷新浏览器即可生效。
调整之后 System Prompt 从 ~15000 tokens 降到 ~4500 tokens,策略混淆的问题没有再出现。新增场景也从改代码变成了新建一个 .md 文件。
当多轮对话积累了较多上下文(分析笔记、历史计划、模式记忆等),System Prompt 可能重新超过 4500 token 预算。这时按优先级逐个丢弃低价值段落:SQL 知识库参考(Claude 可以用 lookup_sql_schema 工具按需查询)→ 历史分析经验 → 历史踩坑记录 → SQL 纠错对 → 子代理协作指引 → 历史分析计划。核心段落(角色、方法论、场景策略、输出格式)不会被丢弃。
决策 1 解决了 System Prompt 的膨胀问题。但即使场景策略只注入了一套,Agent 在执行过程中每次调用 Skill 仍然会产生大量数据(200+ 行帧数据),这些数据全部放进上下文带来新的问题。
早期版本把 Skill 执行结果(比如 200 行帧数据、487 行阻塞分析)完整返回给 Claude。每个 Skill 结果约 3000 tokens,一次分析调用 5-8 个 Skill,仅 Skill 数据就占 15000-24000 tokens。
token 成本是一方面,更意外的发现是:数据越多,Claude 的输出质量反而越差。面对 200 行帧数据时,它倾向于逐行描述(「帧 1 耗时 12.3ms,帧 2 耗时 15.7ms…」)而不是做模式归纳。我猜测原因是上下文中充斥大量数字后,LLM 的注意力被分散了。
解决方式是把 Skill 结果存入 ArtifactStore,返回给 Claude 的只有紧凑引用(~440 tokens)——行数、列名和摘要信息。需要详情时,Claude 通过 fetch_artifact 按需分页获取。完整数据通过独立的 SSE(Server-Sent Events)通道发送给前端渲染,不经过 LLM。
1 | invoke_skill("scrolling_analysis") 执行结果: |
fetch_artifact 的三个粒度:
| 级别 | 返回内容 | 约 tokens |
|---|---|---|
summary | 行数 + 列名 + 首行样本 | ~50 |
rows | 分页数据 (offset/limit) | ~200-500 |
full | 完整原始数据 | ~3000 |
调整后每个 Skill 的 token 成本从 ~3000 降到 ~440,8 个 Skill 从 ~24000 降到 ~3520 tokens。Claude 的输出从逐行描述变成了模式归纳,前端仍然能拿到完整数据做表格渲染。
agentv3 上线 18 天后,我做了一次系统性的质量审查(2026 年 3 月 20 日,commit da63eaf9)。统计结果让我意外:约 30% 的 Agent 结论包含不同程度的误判。
以下是实际遇到的误判案例:
1 | [案例 1] Agent 将 VSync 对齐偏移标记为 CRITICAL |
这些误判有一个共同特点:它们不是逻辑错误,而是 领域经验的缺失。高刷设备上 VSync 微小偏移是正常的、Buffer Stuffing 的延迟发生在管线队列层面而非 App 逻辑、单帧异常不构成模式——这些判断依赖对 Android 图形栈的深入理解,Claude 的训练数据对这些细节覆盖不足。
认识到这一点后,我建立了三层递进验证:
1 | Layer 1: 启发式检查 (无 LLM 调用) |
验证发现严重问题时,生成 Correction Prompt 让 Claude 修正结论(最多 2 轮)。
跨会话学习: 确认的误判模式被持久化到 logs/learned_misdiagnosis_patterns.json,下次分析时自动注入 System Prompt。例如系统学到了:
1 | { |
注:学习到的误判模式不会立即生效。代码中要求
occurrences >= 2才会进入有效模式集——首次记录只是标记,同一模式第二次出现时才会注入到后续分析的 System Prompt 中,避免孤立事件造成过度矫正。
做性能分析的团队一般都有自己的 SOP(标准操作流程):滑动卡顿怎么查、启动慢怎么分析、ANR 怎么定位。SOP 通常是一份文档或检查清单,有经验的工程师照着做,新人跟着学。
Anthropic 的 Claude Code 有一套 Skills 系统,本质上是参数化的 Prompt 模板——注入上下文后提交给 Agent 执行。一个自然的想法是把性能分析 SOP 写成这种 Prompt 模板,让 Claude 按 SOP 执行。
我一开始也走了这条路。给 Claude 的 Prompt 是:「查询 frame_timeline 表,找出 jank 帧,分析主线程在 jank 帧期间的状态分布。」
Claude 理解意图没问题,但每次生成的 SQL 不一样。有时候 JOIN 路径写对了(slice → thread_track → thread),有时候直接写 slice.utid——这个列不存在。查出来的结果格式也不固定,有时候 3 列有时候 5 列,前端渲染没法做。
原因很简单:SOP 是给人看的,工程师看到「查 frame_timeline」知道具体该写什么 SQL。LLM 对 Perfetto 的 SQL schema 理解不完整(这些 schema 在训练数据中覆盖有限),每次从 SOP 文本到 SQL 的翻译过程都会引入方差。
SmartPerfetto 的 YAML Skill 采用了不同的思路——不是 Prompt 模板,而是声明式的 SQL 执行单元:
1 | # YAML Skill: SQL 预定义,结果格式固定 |
两种方式的核心区别在于「谁来写 SQL」。Prompt 模板让 LLM 每次动态生成 SQL,结果格式不可预测,无法做回归测试;YAML Skill 预定义了 SQL 和输出 schema,参数替换后执行,结果格式固定,可以稳定地回归测试和前端渲染。
| 维度 | Prompt 模板 (SOP 式) | YAML Skill (声明式执行) |
|---|---|---|
| SQL 来源 | LLM 每次动态生成 | YAML 预定义,参数替换 |
| 结果格式 | 每次可能不同 | 固定的列名和类型 |
| 可回归测试 | 不支持 | 6 条 trace 回归测试全通过 |
| 前端渲染 | 需要解析自由文本 | Schema-driven 表格/图表 |
| 可组合 | 不支持 | composite skill 调用 atomic skill |
| 厂商适配 | 需要写不同 Prompt | .override.yaml 覆写 SQL |
最终的分工是:Claude 负责理解意图、选择 Skill、推理归因;YAML Skill 负责精确的 SQL 查询和结构化输出。Claude 通过 invoke_skill 调用 Skill,Skill 返回结构化数据,Claude 基于数据做判断。
一个自然的问题是:为什么不直接把 87 个 atomic 分析能力注册为 87 个 MCP Tool,让 Claude 直接调用?
实际试过会发现一个问题:MCP 的 tool list 会随着工具数量线性增长。87 个工具意味着每次 API 调用都要在请求中附带 87 个工具的描述(名称、参数 schema、使用说明),这个固定开销会占据大量 token。更重要的是,当 Claude 面对 87 个工具时,它的选择准确率会下降——工具太多,它不知道该用哪个。
SmartPerfetto 的设计是 Claude 只看到 2 个和 Skill 相关的 MCP Tool:
invoke_skill(skillId, params) — 执行指定的 Skilllist_skills(category?) — 按场景类别查询可用的 Skill 列表通过 list_skills(category="scrolling") 按需发现能力,再用 invoke_skill 调用。2 个 MCP Tool 封装了 160+ 个分析能力,工具列表的 token 开销是固定的。
另一个好处是 YAML 格式降低了贡献门槛。性能分析专家如果对某个分析场景有经验,可以直接写 YAML Skill 定义 SQL 查询和输出格式,不需要懂 TypeScript 或修改后端代码。修改后在开发模式下刷新浏览器即可生效(热加载),迭代周期在秒级。
Skill 数量从项目初期的十几个增长到现在的 164 个,增长的驱动力不是「尽可能多」,而是分析实践中不断遇到新的场景需要覆盖——比如最初只有标准 HWUI 的帧分析,后来遇到 Flutter 应用需要专门的 Skill,再遇到厂商差异需要 override,再遇到启动分析中 JIT、class loading、Binder pool 各自需要独立的检测逻辑。
当前的 Skill 按类型分布如下:
| 类型 | 数量 | 位置 | 说明 |
|---|---|---|---|
| Atomic | 87 | skills/atomic/ | 单一检测能力(VSync 周期、CPU 拓扑、GPU 频率、GC 事件等) |
| Composite | 29 | skills/composite/ | 多步组合分析(如 scrolling_analysis 编排多个 atomic Skill) |
| Pipeline | 28 | skills/pipelines/ | 渲染管线检测 + 教学(24+ 种 Android 渲染架构识别) |
| Module | 18 | skills/modules/ | 按模块分类的分析(app / framework / hardware / kernel) |
| Deep | 2 | skills/deep/ | 深度分析(CPU profiling、callstack 分析) |
另有 skills/vendors/ 下 8 个厂商的 .override.yaml(Pixel / Samsung / Xiaomi / Honor / OPPO / Vivo / Qualcomm / MTK),覆盖通用 Skill 中的厂商特定 SQL。
早期 Skill 的输出是平铺的——一个 Skill 返回一张大表,200 行帧数据混在一起,用户打开就看到全量数据,没有层次感。实际使用中发现工程师的阅读习惯是:先看概要(掉帧率多少、P90 多少),再决定要不要展开看详情,再针对具体帧深钻。
现在 Skill 的输出按层级组织,前端渐进式渲染:
1 | summary — "47 帧卡顿, P90=23.5ms, SEVERE 占 12%" |
Skill 的每个 step 通过 display.level 声明自己的展示层级(实际使用最多的是 detail — 240 处、key — 170 处、summary — 81 处)。前端根据 DataEnvelope 中的列类型(timestamp、duration、percentage、bytes 等)和交互动作(navigate_timeline 跳转到 trace 位置、navigate_range 选中时间范围、copy 复制数据)自动渲染表格和图表——新增一个 Skill,前端不需要写额外的代码。这是 164 个 Skill 而前端代码量仍然可控的关键。
最初所有 Skill 都只有一种 step:执行一条 SQL。后来遇到需要组合多个 Skill 的场景(比如 scrolling_analysis 需要先查帧数据,再对每个 jank 帧做阻塞分析),以及需要遍历数据行的场景(逐帧诊断),逐步扩展了 step 类型:
| Step 类型 | 说明 | 使用频次 |
|---|---|---|
atomic | 单条 SQL 查询,最基础的 step 类型 | 最常用 |
skill | 引用另一个 Skill 的结果,用于组合分析中复用已有能力 | 56 处 |
iterator | 遍历数据行,对每行执行子查询 | 5 个 composite Skill 中使用 |
diagnostic | 诊断步骤,生成结构化的诊断结论 | 38 处 |
parallel | 并行执行多个 step(代码已支持,尚未在 Skill 中使用) | 0 |
conditional | 根据条件选择分支(代码已支持,尚未在 Skill 中使用) | 0 |
iterator 是逐帧分析的核心——比如对 18 个 jank 帧中最严重的 8 个,逐一执行 blocking_chain_analysis,每帧独立分析阻塞原因。parallel 和 conditional 在类型系统中已定义,目前还没有 Skill 使用——这是因为当前的分析场景用 skill 引用 + iterator 遍历已经能覆盖,后续引入更复杂的场景(如多路并行数据采集)时会用到。
以下几个例子说明为什么需要这么多专用 Skill——每个 Skill 背后都有一个「通用方案处理不了」的具体问题。
框架的 jank_type 标记不等于用户感知的掉帧。存在 Hidden Jank——框架标记 jank_type='None' 但用户感知到卡。原因是框架的判定口径和用户的实际感知之间存在差异。
SmartPerfetto 用独立的 consumer_jank_detection Skill 做掉帧判定:通过 VSYNC-sf 间隔的中位数估算实际 VSync 周期,再用 1.5 倍 VSync 周期作为阈值,基于相邻帧的 present_ts 差值(帧实际显示到屏幕的时间戳)判断是否掉帧。不依赖框架标记。
一帧掉帧的根因可能涉及多层因果链:
1 | 帧 42 耗时 62ms (预算 8.33ms) |
blocking_chain_analysis Skill 用 3 步 SQL 提供这条链的关键线索:主线程状态分布(Running / Sleeping / IO 各占多少)→ 唤醒者追踪(通过 waker_utid 找到是谁唤醒了主线程)→ 阻塞函数汇总(futex / binder_wait / io_schedule 各累计多少时间)。这种跨层分析用通用 Prompt 让 Claude 自己写 SQL 很难稳定实现。
Flutter 的两种渲染模式涉及不同的线程,分析时需要看不同的目标:
| 模式 | Jank 分析目标线程 | 是否经过宿主 RenderThread |
|---|---|---|
| TextureView (双管线) | 1.ui + 1.raster + RenderThread | 是 |
| SurfaceView (单管线) | 1.ui + 1.raster | 否 |
如果用标准 HWUI 的分析逻辑去分析 Flutter SurfaceView 应用,会把 1.raster 线程的耗时错误归因到 RenderThread。SmartPerfetto 通过架构检测(24+ 种渲染管线)自动识别 Flutter 应用并切换到专用的 flutter_scrolling_analysis Skill。
但「自动识别 Flutter」本身也踩了坑(commit 355df8ee,4/6)。早期的 pipeline 检测器是给每种架构单独打分,分数最高的胜出——结果 Flutter TextureView 的 trace 经常被误判为 STANDARD。原因是 Flutter TextureView 的宿主侧仍然走 HWUI 管线(Choreographer#doFrame / DrawFrame / RenderThread),这些信号同时被 STANDARD 和 TEXTUREVIEW 两个分类吸收。STANDARD 的信号覆盖面更广(trace 里几乎一定有 Choreographer 帧),总分常常压过专属的 TEXTUREVIEW,把 Flutter 应用误分到 STANDARD。同样的问题也出在 WeChat Skyline(被 WEBVIEW 吸收)和游戏引擎(被 STANDARD/MIXED 吸收)上。
修法不是调权重,而是给特化 pipeline 加 exclude_if:TEXTUREVIEW 一旦看到 Flutter 1.ui / 1.raster 信号就直接屏蔽 STANDARD 分类;STANDARD_LEGACY/MIXED/SURFACEVIEW_BLAST 看到 Game Engine 信号就互斥;OPENGL_ES 看到 WebView/Game 信号就互斥。24+ 种 pipeline 不能各打各的分,需要一个「特化 → 通用」的优先级链。 这是「pipeline 多了之后必须做相互排斥」的典型例子——也是为什么 Skill 数量增长到 160+ 之后,光「正确路由到哪个 Skill」本身就成了独立的工程问题。
高通、联发科、Google Tensor 的 trace 中,相同指标的字段名不同(比如 GPU 频率在高通叫 gpufreq,联发科可能叫 gpu_freq_khz)。.override.yaml 让同一个 Skill 在不同平台上自动适配 SQL,不需要为每个厂商写独立 Skill。
前面讨论的 Skill 系统最终都落到 SQL 查询上——每个 Skill 的 step 执行的是预定义的 SQL。SQL 是 SmartPerfetto 的核心——所有性能数据的获取最终都通过 SQL 查询 trace_processor 完成。这部分展开讨论 SQL 层面的几个工程问题:查询模式设计、官方 stdlib 复用、Schema 索引、结果压缩和纠错学习。
Perfetto trace 的数据本质上是带时间戳和持续时长的事件流。性能分析中最常见的操作是判断两个事件在时间上是否重叠——比如某帧渲染期间,主线程有没有被 Binder 调用阻塞。
YAML Skill 中大量使用的核心 SQL 模式是时间区间 JOIN——判断两个事件是否在时间上重叠。下面这条 SQL 的业务含义是:对于每个掉帧,找出在这帧渲染期间同时发生的阻塞调用(如 GC、Binder、锁),并计算它们重叠了多少毫秒:
1 | -- 业务含义:掉帧帧和阻塞调用的时间重叠分析 |
这里的
MIN(end1, end2) - MAX(start1, start2)是计算两个区间重叠长度的标准公式。在 Perfetto trace 中,时间戳精度到纳秒,这种区间 JOIN 能精确到 0.001ms 的粒度。
另一个常用模式是递归 CTE 做时间分桶。比如分析启动过程中 CPU 大核/小核的使用分布变化:
1 | -- 递归生成时间桶(最多 30 个,防止递归失控) |
_cpu_topology是 Perfetto stdlib 提供的视图,把 CPU 核心分类为 prime / big / medium / little。递归 CTE 限制最多 30 个桶,防止在极长 trace 上递归失控。
这些 SQL 模式被封装在 YAML Skill 中,通过 ${param|default} 语法接受参数。Claude 不需要自己写这些复杂的时间区间 JOIN——它调用 invoke_skill 传入时间范围和进程名,Skill 负责执行预定义的 SQL 并返回结构化结果。
Perfetto 官方维护了一套 SQL 标准库(stdlib),提供了大量预定义的视图和函数。比如 android_frames 视图封装了帧渲染数据的多表关联逻辑,_android_critical_blocking_calls 内部表汇总了关键阻塞调用。直接使用这些官方抽象,比手写 SQL 从底层表关联要稳定得多。
SmartPerfetto 对 stdlib 的集成经历了几轮迭代——其中一次回退还把「优化的方向」整个翻了过来:
初始阶段: 只预加载了 4 个 stdlib 模块(android.frames.timeline、android.binder、android.startup.startups、android.input),大部分 Skill 的 SQL 直接查底层表。优点是启动快,缺点是 Skill 里到处自己手写多表 JOIN
Round 7 (3/15): 把预加载集扩展到 22 个模块,包括 linux.cpu.utilization、android.garbage_collection、android.oom_adjuster、slices.with_context,覆盖 CPU/GC/OOM/slice 等常用维度。当时的逻辑是:trace 加载时一次性把所有常用 stdlib 模块批量 INCLUDE,后续 Skill 查询零开销
回退到 lazy 加载 (4/1, commit 0afeb60f): 22 模块的 eager preload 在生产中翻车了——200MB+ 的大 trace 上,启动时并发 INCLUDE 22 个模块会同时占用 trace_processor_shell 的 RPC 连接,触发 socket hang up。根因是 trace_processor_shell 是单线程的 SQLite 引擎,最不擅长并发 INCLUDE 这种「批量 schema mutation」负载。 最终的修法是把 eager preload 收回,只保留 3 个 Tier-0 模块,且改成首次 query 时 lazy + 串行加载 + 最多 3 次重试:
1 | // workingTraceProcessor.ts |
这 3 个是按「skill 引用次数」筛出来的最高频依赖。其余 stdlib 模块改由 Skill YAML 的 prerequisites 段或 SQL 里显式的 INCLUDE PERFETTO MODULE 在第一次用到时按需声明
按需发现: perfettoStdlibScanner.ts 扫描 Perfetto 源码目录自动发现所有可用模块,通过 list_stdlib_modules MCP 工具让 Claude 按需 INCLUDE 非预加载的模块
1 | // perfettoStdlibScanner.ts — 扫描 perfetto/src/trace_processor/perfetto_sql/stdlib/ |
这次回退的教训和文章前面的「数据越多 Claude 输出反而越差」是同一类的——「在系统启动时把所有可能用到的资源都准备好」是直觉上最优、实际上最差的策略。无论是给 LLM 的上下文还是给 trace_processor 的 stdlib,先 lazy + 按需加载,等真正出现性能瓶颈再考虑预热,几乎总是更稳的选择。
另一个独立的教训是:使用 stdlib 的 android_garbage_collection_events 视图比自己 JOIN slice + thread + process 表查 GC 事件要稳定得多——因为 GC 事件的 slice name 在不同 Android 版本中有变化(concurrent mark sweep vs young concurrent copying vs HeapTaskDaemon),stdlib 已经处理了这些兼容性问题。但 stdlib 视图自己也有坑(列名前缀、模块未自动加载),后面 SQL 纠错那一节会展开讲。
Perfetto trace_processor 包含数百个表和视图,加上 stdlib 的模块,Claude 不可能全部记住。lookup_sql_schema MCP 工具提供了一个搜索接口,让 Claude 按关键词查找相关的表、视图和函数定义。
底层是一个从 Perfetto 源码自动生成的索引文件(perfettoSqlIndex.light.json),包含 761 个模板,每个模板记录了名称、类别、类型(table/view/function)、列定义和参数。
查询时使用分词匹配 + 评分排序:
配合 sqlKnowledgeBase.ts 的意图映射,还支持双语查询:用户输入「卡顿」会映射到 ['jank', 'frame', 'dropped'] 等搜索词,输入「启动」会映射到 ['android_startups', 'launch', 'time_to_display']。多个意图同时命中时,分数叠加——比如查询「启动帧卡顿」同时触发 startup 和 jank 两个意图,匹配到两者交集的模板分数最高。
当 Claude 使用 execute_sql 直接查询时,可以传入 summary=true 参数触发结果压缩。压缩逻辑在 sqlSummarizer.ts 中实现:
数值列: 计算 min、max、avg 和分位数(P50 / P90 / P95 / P99),让 Claude 了解数据分布,不需要看原始行。
字符串列: 统计 top 5 值及其出现次数,了解数据的类别分布。
样本行选择: 从完整结果中选 10 行有代表性的样本。选择策略是:如果数据中有 dur、latency、jank、count 等和性能相关的列,按该列降序排列取 top 10(最严重的数据通常最有分析价值);如果没有明确的性能指标列,等间距采样。
1 | -- 200 行原始结果 (~3000 tokens) 压缩为: |
这和前面提到的 Artifact Store 配合使用——Artifact Store 压缩的是 Skill 结果(invoke_skill 返回的数据),SQL Summarizer 压缩的是 Claude 直接执行 SQL 时的结果。两层压缩覆盖了 Agent 获取数据的两条路径。
Claude 对 Perfetto 的 SQL schema 不完全熟悉,会写出有错误的查询。以下是实际记录的典型错误(来自 logs/sql_learning/error_fix_pairs.json):
错误 1:JOIN 了不存在的列
Perfetto 的 slice 表没有直接的 utid 列。要关联 slice 和 thread,需要经过 thread_track 中间表:slice.track_id → thread_track.id → thread_track.utid → thread.utid。
1 | -- 错误: no such column: s.utid |
错误 2:列名歧义
1 | -- 错误: ambiguous column name: name (slice 和 process 都有 name 列) |
错误 3:对 counter 表的数据模型理解有误
Perfetto 的 counter 表存储的是采样点(时间戳 + 值),不是区间数据,没有 dur 列。
1 | -- 错误: no such column: c.dur |
错误 4:stdlib 表名 / 列名陷阱
这两条都是 commit 05922e67 加进去的——发现源是「无主孤儿 stderr」:分析早就结束了,trace_processor 还在喷错误日志,反查回去才定位到 Agent 在 dynamic SQL 里反复踩同样的坑。
1 | -- 错误 4a: no such table: cpu_frequency_counters |
stdlib 视图作者经常会用领域前缀的列名来避开多表 JOIN 时的 ambiguous column 问题,但 Claude 默认假设的是 ts/dur 这种通用约定。这种「stdlib 自己的命名习惯 vs 通用 SQL 习惯」的冲突没法靠 schema introspection 完全自动解决——lookup_sql_schema 工具能告诉 Claude 表存在和有哪些列,但不能预测「这次 Claude 一定会想当然地写 ts」。只能靠纠错对累积来兜底。
这些错误的检测和学习机制是这样的:当 SQL 执行失败时,错误信息和 SQL 被暂存;当后续有 SQL 执行成功时,系统通过 Jaccard 相似度匹配(排除 SQL 结构关键词如 SELECT/FROM/WHERE,以及 Perfetto 通用 token 如 utid/dur/slice)判断是否是同一查询的修正版本。匹配阈值 >30%,时间窗口 60 秒。匹配成功则生成 error→fix 对并持久化到磁盘。
新分析开始时,最近 10 条纠错对加载到 System Prompt,Claude 在写 SQL 之前就能看到这些已知的坑。纠错对设置 30 天 TTL,过期自动清理——Perfetto 的 SQL schema 会随版本更新变化。
最后一个部分稍微跳出产品本身,聊一下开发过程。SmartPerfetto 是用 AI 辅助开发的——从第一行代码到现在,Claude Code 是主要的编程工具。回顾这三个月,我使用 AI 辅助开发的方式本身也经历了几次迭代,和 SmartPerfetto 从 agentv2 到 agentv3 的演进有相似的逻辑。
先简要说明涉及的工具和概念:
--dangerously-skip-permissions(危险模式)和 bypass permissions,让 Claude 无需逐次确认即可自主执行文件编辑、命令运行、Git 操作等。这大幅提升了迭代速度——Claude 可以连续执行「改代码 → 跑测试 → 看结果 → 修复 → 再跑」的完整循环而不被权限弹窗打断,代价是需要开发者对 Claude 的操作有足够信任和事后审查/commit、/simplify),Hooks 是在特定事件(如工具调用前后)自动执行的脚本阶段 1:直接对话
最早期的开发方式是在 Claude Code 中直接描述需求,让 AI 修改代码。类似于结对编程中一个人说、一个人写。这个阶段人需要逐行审查每次修改,因为 AI 对项目上下文的理解有限,经常做出不符合整体架构的局部修改。
阶段 2:Plan Mode(SuperPower)
开始使用 Plan Mode 后,工作流变成:我描述需求 → AI 输出结构化的实施方案(要改哪些文件、每个文件改什么、改动顺序和依赖关系)→ 我审查方案 → 确认后 AI 执行。这把 review 的重心从「逐行看代码」转移到了「审查架构方案」,效率明显提升。
阶段 3:Plan Mode(SuperPower) + 引入同行 Review(Codex)
单靠一个 AI 生成方案,容易出现盲区。我开始在 Plan Mode 的方案确定后,把方案发给 Codex 做独立审查。Codex 以只读方式访问代码库,从架构合理性、边界情况、遗漏风险三个角度给反馈。这相当于在 AI 开发流程中引入了 code review 环节。
文章前面提到的 9 轮架构审查,大部分都经过了这个流程。以 Perfetto Stdlib 集成为例(Round 7,3 月 15 日),Codex 审查了 3 轮,累计提出 36 条反馈,其中涉及 stdlib 模块预加载策略、Schema Index 的缓存失效机制等我在方案中遗漏的问题。
阶段 4:Harness 化的工程流水线
到后期,开发流程变成了:
1 | 1. 我确定需求和架构方向 |
这个流程中,人的介入集中在第 1 步(需求和架构决策)和第 4 步(评估 review 反馈)。代码细节、测试执行、格式整理由工程流水线完成。
回过头看,我的 AI 辅助开发流程和 SmartPerfetto 的 Agent 分析流程在结构上是相似的:
| 维度 | SmartPerfetto Agent 分析 | 我的 AI 辅助开发 |
|---|---|---|
| 意图理解 | Scene Classifier 识别场景 | 我确定需求方向 |
| 策略注入 | .strategy.md 注入分析方法论 | Plan Mode 输出实施方案 |
| 执行 | MCP 工具调用 SQL/Skill | Claude Code 执行代码修改 |
| 质量验证 | 三层 Verifier (启发式+Plan+Haiku) | 回归测试 + Codex review |
| 纠正循环 | Correction Prompt 让 Claude 修正 | 测试失败 → 分析 → 修复 → 重跑 |
| 跨会话学习 | Pattern Memory + SQL 纠错 | CLAUDE.md 规则积累 + memory 系统 |
两个系统的演进方向也一致:人的介入从执行层逐步上移到决策层。 SmartPerfetto 从固定管线(人定义每一步)到自主推理(人定义目标和约束);我的开发方式从逐行 review 到审查架构方案。
这不是偶然——Harness Engineering 的核心就是构建足够的工程基础设施(测试、验证、review),使得人可以信任 AI 的执行结果,把注意力放在更高层的决策上。
下图汇总了 SmartPerfetto 的 Harness Engineering 全景——从输入路由到跨会话学习:

回顾这三个月的迭代,从 agentv2 的 13 步固定管线到 agentv3 的自主推理,从约 30% 误判率到三层验证,从 15000 tokens 的 System Prompt 到 4500 tokens 的按需加载——每一步变化都有具体的失败经历在推动。
做完这个项目之后,我对 AI Agent 应用开发有两个体会。
第一个是:主要工作量不在 LLM API 调用本身,而在围绕 LLM 的工程基础设施:
第二个体会是:Agent 的「环境」比 prompt 的措辞重要得多。 agentv3 初期我花了不少时间调整 System Prompt 的用词和格式,后来发现真正影响 Agent 输出质量的不是 prompt 怎么写,而是给它什么工具、返回什么数据、施加什么约束。三个具体的例子:
submit_plan 门控后,Claude 不再没有方向地查 SQL(之前会出现连续 SELECT * FROM slice → SELECT * FROM thread 的无目的查询),分析路径变得有组织lookup_knowledge 工具后,根因分析的深度从「主线程阻塞」推进到「Binder 对端 system_server 因 CPU 被调度到小核导致响应延迟」这些改进都不是通过调整 prompt 文字实现的,而是通过改变 Agent 的工具集和数据环境实现的。如果我要给做 AI Agent 应用的工程师一个建议,就是把精力放在工具设计和数据控制上,而不是 prompt engineering 上。
当前的 SmartPerfetto 是一个交互式分析工具,还远远没有达到可以发布的程度,所以目前还是闭源的,由我个人在负责开发。后续的工程方向包括:
.override.yaml 只覆盖了核心 Skill。更多厂商专属指标(高通 Snapdragon Profiler 数据、联发科 MAGT 信号、三星 GameOptimizing 服务)需要逐一对接在合适的时候本工具会开源处理(因为各个大厂内部都在做了,所以开源出来大家集思广益,共同开发),对进度感兴的同学可以加我微信进群聊或者私聊。
下面是个人的介绍和相关的链接,期望与同行的各位多多交流,三人行,则必有我师!
一个人可以走的更快 , 一群人可以走的更远

16 KB 内存页面大小的支持,是Google Play 新提出的要求。要在2026年5月31日之前,满足这一条件:
Android 15 的 16KB page 检测主要看三件事:
对于aab 来说,上面的三个要求,一般只用关注PT_LOAD。因为aab 有压缩率,所以关于压缩的两项检验直接计算是不准确的。Google Play 在分发时会自动处理。
官方文档:
https://developer.android.com/guide/practices/page-sizes?utm_source=chatgpt.com&hl=zh-cn
关于so 文件是否合规的检测,主要有以下几种方法:
可以解压出so文件,然后使用ndk 工具检测(一定使用PowerShell,cmd无法运行):
1 | llvm-objdump.exe -p E:\Test\so\arm64-v8a\libanogs.so | Select-String -Pattern "LOAD" |
运行结果可以看LOAD off 类型行尾是不是带有212、213。
低于2**14的so文件都不符合。
工具的路径在:
1 | {YourNDKPath}\toolchains\llvm\prebuilt\windows-x86_64\bin |
但是这里只检查了PT_LOAD。
Google 官方提供了检测工具:
可以直接使用这个脚本进行检测。
1 | check_elf_alignment.sh APK_NAME.apk |
最后,如果将Android Studio 更到最新版本,即可使用Apk Analyze 功能进行检测。
前者报错为:1
4 KB LOAD section alignment, but 16 KB is required
后者报错为:1
RELRO is not a suffix and its end is not 16 KB aligned
Unity相关的so,需要通过提升Unity 编辑器版本号的方式进行解决。
第三方SDK 相关的so,需要联系相关提供商进行SDK 升级。
如果无法完成合规,应该考虑取消对该插件的接入。
如果是自己使用NDK 编译的so,需要升级NDK工具并在编译中指定相关参数。
1 | ({NDK Path}/ndk-build ^ |
对于Android.mk 文件和Application.mk 文件也有内容需要修改:
如果旧内容涉及cmd-strip,在打包时会报错。这是因为NDK r23+中,strip 工具路径变成 LLVM 版本。最简单的解决方式是删掉这一行,新版本不需要手动调用strip,会自动调用。
如果文件中存在:APP_STL := gnustl_static,也需要进行修改。
修改为:APP_STL := c++_static
为了兼容RELRO 必须在 segment 末尾(suffix)和 RELRO end 必须 16KB 对齐,需要在Android.mk 中增加:
1 | LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 |
最后,在旧的代码中,如果使用了PAGE_SIZE / PAGE_MASK 宏,这会报错,在新版本中,NDK 不再提供。
需要增加以下内容:
1 | #ifndef PAGE_SIZE |
升级到新版Unity之后,如果不修改代码,可能不会让C++代码重新导出。
也可以删除Library目录下的Bee目录和所有的il2cpp_*目录的缓存,强制生成。

对于经历过 2007-2017 年移动操作系统大洗牌时代的用户,Android 曾是一面旗帜。
在 BBOS、塞班、Windows Mobile「百家争鸣」之后,由谷歌牵头的 Android 成为仅存的硕果。这个开源操作系统,曾经是包容、多样与打破陈规的象征,与隔壁精致、有板有眼,却封闭的 iOS 形成了鲜明对比。

▲ 图|WIRED
然而多年以后,谷歌变了,Android 也变了。
2026 年 4 月 1 日,本来是个大家都开心的日子,谷歌突然宣布:
Android 开发者验证功能自近日起全面推出,所有开发者必须向谷歌注册自己的应用。未来如果系统检测到安装包没有注册信息,将会强制启动 7 天的「安装冷静期」,或者要求用户必须接上电脑用 ADB 授权安装。
这套名为「高级侧载」(advanced sideload)的功能预计在今年 8 月向所有安卓用户推出,「冷静期」功能则计划 2027 年在全球范围施行。
本质上,谷歌封锁了「侧载」应用,即直接通过 .apk 文件直装应用的路子。

▲ 图|Aurich Lawson
从不断收紧的第三方应用侧载限制,到针对全球开发者的强制认证要求,再到令人难绷的「七天安装冷静期」,叠加前面转向闭源的新闻——无不在释放一个令人心寒的信号:
谷歌正在亲手杀掉曾经由它开启的开放 OS 时代。
毕竟如果我们回看 Android 诞生初期,它之所以能够击溃塞班、抗衡 iOS,靠的绝不是单纯「免费」,同时还有那份近乎野蛮的开放性。

▲ 图|TechRadar
正是对于「开放性」的包容,让 Android 成功突围,得以在全球移动 OS 市场上和苹果抗衡,以后来居上的姿势告诉全世界:
手机操作系统,何必是被严密限制的黑盒?它完全可以是一张白纸,由厂商、开发者、用户共同书写——
如果你不喜欢厂商预装的桌面,就直接换一个启动器;Play Store 也不是唯一的下载渠道,各种第三方应用市场百花齐放。
当然,如果你想要的应用没有上架应用商城,完全可以通过侧载的方式安装。

▲ 知名第三方应用市场 F-Droid|Android Authority
这种高自由度和可定制化,就是 Android 森林能够如此茂盛的根基,也是它相比坚持「封闭花园」策略的 iOS 的最大竞争优势。
但今天的谷歌,似乎早已忘记了当年「不作恶」(Don’t be evil)的口号,同时患上了某种「权力焦虑症」——它要控制系统里每一条 ADB 指令的流向,质询每个安装包的来源。

这完全就是「屠龙勇士终成恶龙」的现实版本。
谷歌正在用一种温水煮青蛙的方式,将 Android 变成一个披着「开源」的皮、实则高度集权的私家领地。

▲ 图|How-to-geek
在谈到这些限制时,谷歌永远都只会抛出「安全」和「用户体验」的理由。
诚然,移动安全至关重要,在如今这个手机承载了我们 95% 日常生活的时代来说更是如此,但我们已经经历了太多太多血淋淋的教训——
所有拿「安全」做挡箭牌的商业决策,最后都变成了攫取用户信息获利的手段。

更何况,谷歌在不管不顾地推进这种封闭化进程时,反而让自己露出了一个极其尴尬的姿势。
「没有苹果命,得了苹果病。」这句话以前是形容盲目抄袭苹果产品形态、却忽视了苹果设计逻辑的手机厂商用的,现在用来形容谷歌倒是再贴切不过——
没有人能够否认,iPhone + iOS 软硬件结合的「围墙花园」(walled garden)模式在商业上的成功,iPhone 用户也乐于留在其中。

▲ 图|Apple
但我们必须清楚:苹果能够跑通这一套逻辑的前提,是它真的做到了「为用户提供一个完整的闭环生态」。
iPhone 只能从 App Store 获取应用不假,但 App Store 里的应用不仅会经过苹果严苛的技术审核,更重要的是:苹果的服务足够便捷、稳定,且能够在全球范围提供相对统一的高质量内容。

▲ 图|Apple
反观谷歌 Play Store,光是 Play Store 本身的 Bug 频出和应用质量的良莠不齐,就足以让谷歌梦里的「围墙花园」地基垮掉。
虽然 App Store 里面也有不少粗制滥造的东西,但相比 Play Store 的生态还是小巫见大巫了。

▲ Play Store 付费榜
哪怕谷歌已经扯着嗓子喊了几年的 Play Protect 机制和强制 API 规定,我们依然能在 Play Store 的推荐页乃至首页,看到大量粗制滥造的马甲包。
甚至在 2026 年的今天,Play Store 免费区里面依然潜伏着太多字面意义上的「毒瘤」应用。

▲ 麦卡菲安全通报的数个 Play Store 毒瘤应用|McAfee
而在这种官方渠道无法做到尽善尽美的情况下,谷歌却还要斩断用户寻找第三方替代方案的后路,好一个又当又立的典范。
别忘了,Play Store 同样是锁区的,并且锁区机制相比 App Store 简直有过之而无不及。
对于很多地区的用户来说,侧载 APK 其实跟所谓的极客精神八杆子打不着——而是为了在官方商店堵死的情况下,维持手机的基本功能。

▲ 图|Reddit
而谷歌紧赶慢赶想要关上侧载这扇门,本质上就是在强迫用户接受一个德不配位的商店服务。
谷歌对 Android 核心资产的态度转变,更是让人加深对这个操作系统的不信任。
从去年开始,谷歌就开始宣布 Android 的部分核心功能不再向 AOSP 开放,而是整合进其私有的 GMS 服务中。
换言之,以前「原生」和「类原生」的区别,已经被谷歌自己切割成「Pixel OS」和「其它」。
同时,AOSP 源代码的公开频率和深度也在大幅削减,直至谷歌最后宣布:仅会向部分生产 Android 手机的企业伙伴提供 AOSP 源码。小型硬件品牌、第三方 ROM 和个人开发者,哪凉快哪歇着去吧。

▲ 图|Android Authority
这就是 Android 从开源转向闭源的标志。
那个曾经属于全球开发者的 Android、那个曾经用「农村包围城市」战术赶超 iOS 的 Android,其开放与自由的属性,正在被谷歌从内部一点点掏空。
自从 Pixel 手机的业务站稳脚跟,谷歌就开始试图通过控制底层代码和基础 API,把 Android 从一个公共资源池,转型为纯粹的、为谷歌搜索、广告、应用生态业务服务的赚钱工具。

▲ 图|Google Ads
这种商业上的贪婪,正是最近几代 Android 大版本在审美和质量上表现得极其分裂的原因——
它既想要苹果那样对软硬件生态的话语权,又舍不得放下它那套依靠大规模数据采集和广谱分发的商业逻辑。
这其中最典型的例子,就是谷歌对 UI 设计规范的反复无常。
你或许还记得 Material Design,那个谷歌曾经提出的介于拟物化和扁平化之间的、以「折纸」为哲学的设计语言:

▲ 图|Tech & ALL
从 Material Design 1.0 到现在的 Material You、Material 3 Expressive,且不说安卓本身的设计语言有多割裂,谷歌做了这么多年设计先锋,到头来却连自家全家桶的设计都没办法统一跟上最新标准。
自家房间都扫不干净,谷歌又有什么颜面指挥全世界 Android 开发者呢?

▲ Material 3 Expressive 效果图|Google Design
理念的混乱、审美的平庸,正是谷歌无法建立起类似苹果那样的品牌信仰和生态凝聚力的原因。
然而在这种软实力缺失的前提下,谷歌却试图通过强硬的硬性限制——比如可能在 2027 年全球上线的「七天安装冷静期」——来建立防御壁垒。
这种做法不仅是逃避责任,更是一种技术上无能的表现。

▲ 图|Interesting Engineering
如果一个系统需要通过人为制造障碍、折磨用户耐心的方式,来规劝用户应该做什么,维持所谓的安全,那只能说明这个系统的底层架构已经混乱到了无法通过正常技术手段解决问题的地步。
苹果之所以是苹果,因为它从卖 iPhone 的第一天就设计好了如何运转这样一个封闭的生态系统。
谷歌想要变成苹果,用的方法却是「头疼砍头、脚痛砍脚」。
从 18 年前的 Android 1.0 走到今天,谷歌似乎忘记了 Android 之所以能有如今的地位,正因为它是一个「和 iOS 不一样的选择」。

▲ 图|Android Police
然而当谷歌把 Android 变得越来越像一个廉价、粗糙且充满限制的 iOS 仿制品时,它就失去了自己最核心的竞争优势——
既然非得从两个封闭系统里选一个,那我凭什么选尾大不掉的 Android,而不去买更完善、更安全、封闭得井井有条的 iPhone 呢?
「开放」与「封闭」的矛盾中心,就是谷歌没有办法拿出一个真正能够在封闭系统内运行的足够好的 Android 产品,来为自己的策略撑腰。
它既没有苹果那样端到端的生产研发实力,又没有苹果的品位和审美,更是至今保留着 Android 里面抠都抠不掉的牛皮癣——年代断层的 UI、无法统一的 API、以及封闭又稀碎的软件生态。
苹果给用户喂饭,虽然不一定合每个人的胃口,但好歹是饭。
而谷歌喂的,就很难说是什么东西了。
![]()
▲ 图|9to5Google
直白地说,谷歌对于 Android 开放性动手动脚,本质就是缺乏远见且充满傲慢的体现,在自己的地位稳固后,开始逐渐剥离曾经赋予它权力的「草根」生态,转而渴望独裁的横征暴敛。
如果谷歌继续在封闭之路上狂奔,那它最终收获的不会是一个稳定的赚钱机器,而只会是一个死气沉沉的荒芜花园。
因为谷歌在 18 年之后,已经彻底忘记了:
人们选择 Android,难道是因为它像 iOS?
#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。
去年在接入安卓SDK时,会有部分渠道有要求手写闪屏的情况,下面是当时的笔记,这只是最简单的一种方法。
很好的例子:
https://www.jianshu.com/p/a609f510b19a
https://blog.csdn.net/l799069596/article/details/47094731
安卓动画:https://blog.csdn.net/IO_Field/article/details/53101499
除去游戏本身的闪屏之外,有的渠道会要求,有额外的渠道闪屏。为了使用一套资源出不同渠道包,我们可以对接渠道的AS工程进行处理,单独设置闪屏。
首先,创建一个闪屏Activity,为你的主Activity,这样在游戏的一开始你就可以看到闪屏了。
这里需要注意的是,你原先的Activit也需要在Manifest中注册打开日志,否则在打包的时候会找不到,报错:
https://blog.csdn.net/qq_28301007/article/details/52265775
1 | <activity android:name="...Activity"/> |
下面是主Activity,也就是闪屏Activity的代码,需要根据AS的提示import缺少的部分。
1 | import android.animation.ObjectAnimator; |
1 | <?xml version="1.0" encoding="utf-8"?> |
在上面控制闪屏格式的style.xml中,可以看到闪屏的背景色设置为了白色。这里有一些常用的颜色xml:https://blog.csdn.net/sundaysunshine/article/details/53509854
除了这两处之外,还需要根据style.xml中的配置,放好闪屏图片,设置闪屏背景。
整个闪屏的原理就是创建一个动画,在动画播放完成之后,去执行一个新的activity。在补全报错的部分之后,还是有一些细节部分需要注意的。
首先是结束时间的判定。判定时机总共有两种,一种是获取动画的进度,就像这里的例子,使用(int)animation.getAnimatedFraction()进行获取一个从0~1的数,来表示目前的动画的播放进度。除此之外还可以获取播放的时间,这个函数是:getAnimatedValue(),它可以获取属性的当前值。使用这两个函数可以很方便地控制动画的时间和动作。
除此之外,在调起另一个Activity之后,我结束了这个Activity。这是因为如果使用默认的LaunchMode,在重新唤醒应用时,闪屏会再次启动,然后走完动画,应用重启。这就造成了应用无法关闭的状况,只能后台强制杀掉。解决办法就是让闪屏只执行一次。
去年的这个时候,我在忙于接入各种SDK。接渠道SDK,是一件十分薛定谔的事情。你觉得很容易,的确很容易,但是,也很容易遇到问题。然后我就陷入了长期的自闭状态,再加上偷懒,然后博客就断更了一年。现在回头来回忆一下,去年的这个时候,接入SDK时的那些体验。
1.酷派
充值之后,服务器收不到消息,对接也没有人。
现在看来很明显,已然黄了。
2.应用宝
传说中的5000人大群只有2个技术的大渠道。每天上午问问题会施舍你两句,下午是肯定不会回答问题的,团建能团建半个月。这个渠道我是使用聚合sdk接入的。需要注意的是,接入时有测试阶段,和正式阶段之分,游戏货币名不能修改,同时还必须接入腾讯的信鸽推送SDK,否则无法过审,手动接入成本极高。
3.金立
高版本会造成初次进入闪退,主动获取权限也不行,必须低版本编译。
华为手机会出现渲染错误,游戏变成紫红色。
需要安装支付插件。
现在也应该没有接入的必要了。
4.华为
相当棒的渠道,文档详细,对接起来体验也很不错。充值错误的时候,每一步骤,原因都会有显示。
但是不支持第三方工具接入。
需要安装支付插件。
5.魅族
商品id配置不明,会出现莫名的变动,很不靠谱。
支付回调生效需要1天的时间,需要对商品进行映射,对接很麻烦的渠道。
需要安装支付插件。
6.360
包体最大,足足有50多k的方法数,不分包就是死。
7.百度
方法数排名第二,仅次于360。
高版本编译会无法使用闪屏。
提审体验极差。说好的SDK不强用更,但是等到提审后告诉你不合格。
8.联想
商品id为自动生成,需要做好映射。
AnySDK接入需要注意参数顺序。
9.UC
无法使用第三方工具进行接入。
闪屏比较蛋疼,在sdk初始化时自动播放。首次运行时无法正常显示,时机不一定,容易和应用闪屏覆盖。
10.OPPO、VIVO
无法使用第三方工具进行接入。
需要安装支付插件。
11.小七
文档描述不明确,注意对登陆回调的处理方式,注重切换账号的测试。
SDK的Manifest中,最高宽高比设置为2.2。如果游戏中有对这个参数进行修改,需要进行统一。
12.拇指玩
sdk默认背景为透明,会造成有些版本的手机唤起sdk时会显示桌面为背景。或者是切换到主屏后,再回来,只有单独的sdk页面。
解决方式是把style.xml中的windowIsTranslucent值置为为false。
回调处理方式与其他sdk略有不同,Log与执行功能部分的代码进行了分离。
目前版本,无法使用qq登陆等方式,在登陆界面仍没有去掉该入口。
其他:
在运营过程中,小米、UC、应用宝和魅族会不同频率出现无法登录的问题,属正常现象,是他们的SDK服务器抽风了,会报一些很可怕的错误,比如应用不存在,应用id无效之类的。这时候只需要稳定好用户的心态即可,没有任何解决办法。
Haven 是一款免费、开源的安卓一站式 SSH、VNC、RDP 和 SFTP 客户端。@Appinn
![Haven - 一站式开源 SSH、VNC、RDP 和 SFTP 客户端[Android] 45 Haven - 一站式开源 SSH、VNC、RDP 和 SFTP 客户端[Android] 45](https://www.appinn.com/wp-content/uploads/2026/03/cover-1774426285496-1.jpg)
Haven 功能还挺多的:
| SSH 终端功能 | 说明 |
|---|---|
| 多标签终端 | 同时管理多个连接 |
| Mosh 支持 | 弱网/切换网络不断线 |
| Eternal Terminal | 类似 Mosh 的稳定连接方案 |
| 自动重连 | 掉线恢复 |
| tmux / zellij / screen 集成 | 自动附着会话 |
| 键盘工具栏 | 移动端补全 Ctrl / Alt 等键 |
| 文本选择复制 | 适配触屏操作 |
| URL 自动识别 | 点击直接打开 |
| 功能 | 说明 |
|---|---|
| 本地端口转发(-L) | 本地 → 远程 |
| 远程端口转发(-R) | 远程 → 本地 |
| ProxyJump(-J) | 多跳 SSH(跳板机) |
| SOCKS5 / SOCKS4 / HTTP 代理 | 走代理连接 |
| RDP over SSH | 桌面通过隧道走 |
| 功能 | 说明 |
|---|---|
| VNC 客户端 | Linux / 自建桌面 |
| RDP 客户端 | Windows 远程 |
| 手势操作 | 拖拽 / 缩放 / 滚动 |
| 键盘映射 | 适配移动端输入 |
| 功能 | 说明 |
|---|---|
| 文件浏览 | 类似文件管理器 |
| 上传 / 下载 | 双向传输 |
| 多标签页 | 多服务器切换 |
| 排序 / 管理 | 基础文件操作 |
| 功能 | 说明 |
|---|---|
| SSH Key 支持 | Ed25519 / RSA / ECDSA |
| 密钥生成与导入 | 本地管理 |
| Host Key 校验(TOFU) | 首次信任机制 |
| 指纹变化检测 | 防中间人攻击 |
| 生物识别锁 | 指纹 / 面部 |
| 无遥测(No telemetry) | 不收集数据 |
| 本地存储 | 不依赖云 |
| 功能 | 说明 |
|---|---|
| Local Desktop | 手机本地跑 Linux 桌面 |
| 基于 PRoot + Xvnc | 无需 root |
| Xfce4 环境 | 轻量桌面 |
| 类似“手机变 Linux” | 偏极客玩法 |
![Haven - 一站式开源 SSH、VNC、RDP 和 SFTP 客户端[Android] 46 Haven - 一站式开源 SSH、VNC、RDP 和 SFTP 客户端[Android] 46](https://www.appinn.com/wp-content/uploads/2026/03/1_terminal.avif)
![Haven - 一站式开源 SSH、VNC、RDP 和 SFTP 客户端[Android] 47 Haven - 一站式开源 SSH、VNC、RDP 和 SFTP 客户端[Android] 47](https://www.appinn.com/wp-content/uploads/2026/03/5_desktop.avif)
![Haven - 一站式开源 SSH、VNC、RDP 和 SFTP 客户端[Android] 48 Haven - 一站式开源 SSH、VNC、RDP 和 SFTP 客户端[Android] 48](https://www.appinn.com/wp-content/uploads/2026/03/8_toolbar_config.avif)
原文:https://www.appinn.com/haven-android/
随着 OpenClaw 的流行,在手机上用终端,也要流行了吧 
如果你经常去户外,需要一款可以记录 GPS 轨迹的应用,可以试试这款开源工具 GPSLogger,它轻量、小巧、功能专一,同时又省电。在记录 GPX/KML 轨迹的同时,还能添加注释。@Appinn

感谢小众软件论坛 @X948720857 同学在《想找一个功能非常单一的轨迹机录软件(安卓版) 》问题中的推荐,以及群组中 @Yves 同学的推荐。
GPSLogger 是一款开源安卓应用,它可以按照指定的时间间隔记录 GPS 坐标,并保存为 GPX、KML、CSV、NMEA 和 CSV 格式,如果数据支持,还可以同时记录速度、方向和高度。
其他功能包括:


记录 GPS 轨迹这件事,青小蛙遇到的场景是出门爬山。
在山中你需要默认无手机信号,所以需要提前下载别人的轨迹,以防迷路。而这些轨迹文件,都是通过诸如 GPSLogger 这样的应用记录下来的。
所以青小蛙在爬山使用别人轨迹的同时,也在自己记录,不过一般情况下使用了两步路。但耗电的确是个大问题。
通常情况下,我会带两部手机,一部开飞行模式,只用来查看轨迹和记录轨迹,以防没电。
其他用户,欢迎各位来分享。
原文:https://www.appinn.com/gpslogger-android/
使用 redroid 等安卓虚拟环境,可能会发现 google play 用不了的问题。
虽然系统集成了 gapps,但系统提示 “设备未获得play保护机制认证”,无法登录 play 商店。
可能的原因比较多,这里大概是因为虚拟机的型号没在google的数据库里。
解决方案就是,获取 GSF ID 注册到 Google。

ffffffffprintf "%d\n" 0xffffffff,转换换成10进制数字。
有些应用在安卓上是独占的,iOS 上又没有比较好的替代品,而且 iOS 上没有能用安卓模拟器。
如果使用多个设备,维护的心智成本又高,被这个问题困扰了许久。
最近碰巧了解了 scrcpy, 用于远程控制安卓,终于解决了这个问题。
需要的工具
由于已有PVE环境,这里选用PCT,主要步骤
1 | androidboot.redroid_width=1668 androidboot.redroid_height=2388 androidboot.redroid_fps=60 |
ps: 安卓容器对宿主机性能似乎有一定要求,J4125 只是勉强够用,流畅度一般。
安装 scrcpy ,连接命令
1 | scrcpy --audio-codec=aac \ |
参数解释
--audio-codec=aac同步声音,使用 AAC 编码,默认参数可能导致没有声音--video-codec=h264使用 H.264 视频压缩编码--video-bit-rate=16M16Mbps 码率,高画质--max-fps=60最大帧率 60FPS,画面流畅--tcpip=192.168.10.181:5555Wi-Fi adb 连接设备--start-app=io.legado.app.release (可选)连接后直接启动 Legado App,应用列表可使用adb shell pm list packages -3查看appstore中安装 scrcpy-mobile
由于该应用的用户界面易用性比较差,表单也不支持有些 scrcpy 参数,这里直接使用快捷指令打开应用。
设置打开 scrcpy-mobile 后,开启引导式访问,防止误触。同时可以在 iOS 设置中开启引导式访问的面容id,防止频繁输入密码。

scrcpy-mobile 的 url schema
1 | scrcpy2://192.168.10.181:5555?enable-audio=true&audio-codec=aac&video-bit-rate=16M&video-codec=h264&max-fps=60 |
最后,这也未尝不算一种 NTR
如果你平时有从 GitHub、论坛下载 .apk 手动安装安卓应用的习惯,这个变化可能会直接影响你。
Google 在 Android 开发者博客上发布了名为《Android开发者验证:平衡开放性、选择与安全性》的文章,明确了未来高级用户安装未验证 .apk 应用的具体规则,最长需要 24 小时才能完成安装。@Appinn

Google 无法确认开发者身份的应用,就属于陌生 APK 安装包。比如:
说简单点,就是 Google 需要知道:这个 App 是谁开发的。

当用户自己为安卓手机安装 .apk 应用时:

如用户安装的应用开发者是 Google 验证开发者,则不会进入此流程,会立即完成安装。
Google 允许开发者在未经过认证的情况下,可以与一小群人(最多 20 台设备)共享应用程序。
国内手机(华为 / 小米 / OPPO / vivo)基本不受影响:
没有 Google Play 服务
没有 Google Play Protect 完整体系但中国区应用商店已经自带了开发者实名、应用备案。
全部都受此限制。包括:
只要开发者未通过验证,都可能触发高级安装流程。
目前主流评论中,有三派观点:
代表:
观点:Android 终于开始认真对付诈骗和恶意应用了
代表:
观点:Android 正在失去“无需许可发布软件”的灵魂
还记得这篇文章么:谁拥有你的手机?F-Droid 与 Google 的“侧加载”之战
代表:
观点:开放系统在今天的监管和安全环境下,很难继续完全开放
| 日期 | 里程碑 | 开发者聚焦 |
|---|---|---|
| 2025 年 8 月 | 宣布了新的 Android 开发者验证要求 | 了解新要求并报名参与抢先体验。 |
| 2025 年 11 月 | 抢先体验开始 | 如果收到邀请,请开始进行身份验证和应用注册。 |
| 2026 年 3 月 | 面向所有开发者开放注册 | 开始进行身份验证和应用注册,以便您希望继续在已获认证的 Android 设备上安装的所有应用都能顺利安装。 注册以抢先体验受限分发账号。 |
| 2026 年 6 月 | 限量分发账号开始抢先体验 | 如果您收到邀请,请创建账号并分享您的反馈。 |
| 2026 年 8 月 | 受限分发账号在全球范围内推出 面向用户的更高级别流程在全球范围内推出 | 如果您适合使用受限分发账号,请创建账号并注册应用。 |
| 2026 年 9 月 | 开始实施地区性强制措施 | 验证合规性,以免您的应用在巴西、印度尼西亚、新加坡和泰国境内被禁止安装。 |
| 2027 年及以后 | 全球违规处置 | 继续在全球范围内分阶段发布。 |

前几天 1Password 官宣涨价,最高 33% 幅度,青小蛙也开始寻找新的替代者了。在社区里还有一个正在进行的提名《我最喜爱的密码管理器》。
碰巧 @waaabc 同学提到了 StickyPassword 这款拥有终身授权的软件,1P 用一年,SP 用一辈子。

现在常见的密码管理器,大概率是:1Password、Bitwarden、LastPass……
但你可能不知道,有一款诞生于 2001 年 的密码工具,至今还在更新。
StickyPassword 是一款有 25 年历史的密码管理器工具,来自 AVG 前高管团队。从 2001 年至今,他们只做一件事:让密码管理更简单、更安全。
25 年下来,全球超过 200 万用户在用。没有铺天盖地的广告,全靠口碑。

StickyPassword 拥有一个特色功能:Contactless Connect 非接触式连接,无需在电脑上安装任何软件,通过手机扫码即可完成自动登录,非常适合远程访问、公共场合设备。
具体为:

在手机应用中搜索找到你想要登录的网站,点它:

这时电脑上刚刚弹出的窗口会发生变化,只需要点击链接,把用户名和密码拖到对应的输入框中,就能完成远程密码登录啦:

注意这个过程,电脑不需要安装任何软件,只需要手机 APP 即可。
StickyPassword 还能创建一个为 Windows 用的 U 盘密码管理器,只需要插入 U 盘,完成登录,拔出 U 盘,就搞定了。
StickyPassword 拥有30天免费试用,包括上面提到的非接触式连接也能免费试用,之后就需要付费使用了,否则会限制云同步、多设备共享、紧急访问、非接触式连接等功能。U盘功能是免费的。
终身版本价格:198 元。相比较 1Password 个人版 300 多人民币/年的价格,还是非常非常划算的。

StickyPassword 拥有免费版本,不过只能限制单设备使用,其他主要区别:
通过青小蛙的链接购买,我们将获得返利,感谢支持。
原文:https://www.appinn.com/stickypassword/
由于频道被封,整理一下还算有用的内容发到这里来。偏技术向闲聊,发布一些随谈、碎碎念或短篇/价值密度不高等我觉得不适合专门写一篇博客但仍然有留下来的价值的内容,包括但不限于编程想法、系统内部解构、人生感悟等。
有挺多人好奇我的人生经历(见 #303),比如我在我的领域是怎么起步的,还有我作为一个厌学、走职业教育路的差生的故事(#88 #303),这里一并留下来。
部分我觉得现在没什么用的内容比如纯情感发泄和线下贴贴就不再留着了。另外考虑到这里偏正式,部分条目有修改。
本频道任何消息均不构成医学建议。
看这里的很多人应该都是科班程序员出身,走的是普高考大学读计算机然后可能还有读研读博然后进入大厂这条理所应当的路。可能你们很难了解到我这样的职校生的人生,主流媒体的报道也多是围绕着天才,而我们职校生很难得到关注。所以这里会有很多我作为职校生的思考,希望能提供一个不一样的视角。
中考五五分流让一半的学生去读了职校,但现在主流叙事却只把职校学生当成审丑对象来满足自己的优越感,把上普高上本科考研读博考公成为人生赢家当成唯一的定死的路,职校生的评论区充斥着“保送富士康”“和我的准时宝说去吧”等高高在上的刻板印象凝视,他们失去话语权失去主体性成为别人应对学历焦虑、确认自己的努力是值得并感叹“还好我还没有跟他一样”的工具,我只感觉到溢出的社达气息。我承认我也在反思职校和职校生自己的缺点,比如学校里强调所谓的早上七点必须离开宿舍、早读必须大声等形式主义来掩盖教学质量的落后,还有一方面后悔没考上高中另一方面又不尝试通过高职高考等方式提升学历的同学,但我的反思是为了修正错误,而不是建构所谓的等级体系。很多年轻人受到的教育都是“好好学习改变命运”,“不学习以后就要干又苦又低薪的活”,这种焦虑逼着所有人往上爬。但是,难道所谓底层工作就真的天生低人一等吗?做到尊重与平等,承认工程师和外卖员流水线普工一样光荣,优化职教学生的课程质量让职教不再名不副实,同时保障所有劳动者的权益,才是学历通胀时代的正确解法。
TODO
频道已创建。
意外发现magisk中某个关键组件存在问题,影响magisk hide的隐蔽性,可以导致riru被轻易检测,各类xposed实现的某个特征无法被用户通过命令隐藏
再次总结:magisk能运行到现在是一个奇迹
给 magisk 提交了一个 pr ,出现 magiskhide 完全或随机失效的可以尝试
https://github.com/topjohnwu/Magisk/pull/4507
https://github.com/topjohnwu/Magisk/blob/v23.0/native/jni/magiskhide/proc_monitor.cpp#L387-L403
妙呀,之前我遇到的那个 raise(SIGSTOP) 停不下来的问题是另一个bug(应该算bug吧)
1 | /* We use a trick to have more optimized code (fewer pointer reloads): |
1 | #define INIT_S() do { \ |
https://github.com/topjohnwu/Magisk/pull/4731
busybox 内置一个神奇优化,把一些变量声明成 const 然后用魔法去改,但是改变 const 在 c 里是 ub,编译器不知道数据依赖关系,会把代码优化成会崩溃的形式…
https://cs.android.com/androidx/platform/frameworks/support/+/c50410874c4f5c64e0089a161a24347e0f39d711
androidx 的兼容方法 ProcessCompat.isApplicationUid(int) 在 API 17-23 上看起来漏了一个 return ,会丢掉已经获取到的结果,固定返回 true;API 16 工作正常。
https://segmentfault.com/a/1190000041412586
Android 4.x 时代的设计规范
http://adchs.github.io/index.html
附带一篇当时对 Holo 和 Android Design 的评价
http://www.geekpark.net/news/179488
https://www.visualsource.net/
生成 git 仓库可视化的开发(施法)过程视频
https://juejin.cn/post/7100079518756552734
血压高了,就这也敢叫 《android 进阶宝典》
简单看了一下,一些明显错误:
其实方法的本质就是arm指令,然后JVM的执行引擎会执行arm指令
arm 的 cpu 直接就能执行 arm 指令,jvm 也不是用来执行 arm 指令的,jvm 只接受字节码。android 上的 dalvik/art 稍有不同,接受 dalvik 字节码指令集(通常称为 smali)。至于所谓的 arm 指令,那是 runtime 在用户手机上生成的,即使没有,程序也可以被解释执行。
arm指令是存在于dex文件中的,也就是说,我们可以从dex文件中取出arm指令,查看一个方式是如何被执行的
dex 里没有 arm 指令。如果要查看被编译后的机器指令,请使用 dex2oat 将其编译为 oat 后再 oatdump 。
JVM的执行引擎会将arm指令从方法区中拿出来,放到虚拟机栈中执行(栈帧的概念,每一个方法对应的dx指令集就是一个栈帧,每一次方法调用都有栈帧入栈和出栈)
这里假设你的”arm 指令“是字节码,它在执行的时候也不会被放到虚拟机栈中再执行。栈是程序执行时的临时数据区,程序通过各种指令操作,放/取数据,而非指令。另外,”dx 指令集“又是什么玩意儿?
同是执行 10 + 20 ,JVM是先创建一个10变量,然后再创建20 ,最后将两个相加然后返回;但是dx指令是直接计算好了,然后创建v0 = 30,直接返回,所以:Android编译器在编译的过程中会做优化,提高执行的效率
首先,你给的 java 字节码里面没有加法指令,是个除法指令,也就是说这不是你给的加法函数编译出来的结果。这种优化叫常量折叠,从理论上来说 javac 也会进行这种优化。
之前我们介绍过阿里的AndFix或者Sophix是通过hook native层修改字节码指令完成,之前我们介绍的arm指令集,就是实现热修复的基础。所以AndFix热修复,就是将正确的arm指令替换调异常的arm指令,等到再次加载这个类执行方法时,执行引擎拿到的是正确的arm指令交由虚拟机栈。
函数入口与指令本身有着本质区别。替换函数入口也不需要了解 arm 指令集。
记录当前方法被调用的次数,如果超过某个限制,那么该方法就被标记为是热方法,热方法是被缓存到一块内存,下次执行到这个方法,不需要压栈,直接返回结果
hotness_count_ 与 JIT 编译相关,当方法未被编译而调用次数达到阈值后,会有专门的 JIT 线程把它编译为机器指令加速执行。“热方法是被缓存到一块内存,下次执行到这个方法,不需要压栈,直接返回结果”,首先非热方法也在内存中,其次压栈与方法调用有本质区别。我觉得你应该是想说 inline 优化,但那与 hotness_count_ 无关。
找到ArtMethod,在JNI层是能够实现的,通过JNIEnv的FromReflectedMethod函数
从 android 11 开始,FromReflectedMethod 返回的可能不是 ArtMethod*。
尤其是通过hook native底层修改arm指令集
你是在说 inline hook?
转发自 南宫雪珊 https://t.me/vvb2060Channel/441
以大小写英文或点(.)开头,后续可以用大小写英文、数字、点(.)和下划线(_)
package(包名)和sharedUserId有额外规则:不是非法文件名。即不能为 . 或 .. ,以utf8方式转成比特数组后,长度不能大于255。(虽然aapt2连250都不允许……)
需要至少一个点:package,sharedUserId,不以:开头的process。
不要求至少一个点:splitName,以:开头的process。
不以:开头的process如果是system,例外允许。
以:开头的process需要至少两个字符,即不能只有一个:。
完了吗?没有,这只是 ActivityManagerService 内部认为的名字。如果用 ps 命令或者去读 /proc/<pid>/cmdline 这个文件,在同时支持 64 位和 32 位的系统上,读出来的进程名会有 98 个字符(64 位)或 108 个字符(32 位)的限制,超出的部分会被截断。
这个奇怪的数字是怎么来的?实际上是 zygote 进程启动时命令行的长度。
98 来自于:
https://cs.android.com/android/platform/superproject/+/android-15.0.0_r1:system/core/rootdir/init.zygote64.rc;l=1
1 | /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote |
1 | /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload |
很明显,这不可靠,比如 Android 4.0.1 上查看 init.rc 可知这个数字应该是 75:
https://cs.android.com/android/platform/superproject/+/android-4.0.1_r1:system/core/rootdir/init.rc;l=409
1 | /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server |
这还只是考虑 AOSP 的情况,如果再考虑 OEM,比如三星有三个 zygote,参数肯定不一样……
https://harrychen.xyz/2022/03/23/hijack-memory-access-using-linux-signal-handler/
https://developer.android.com/ndk/reference/group/libdl
这是 android_dlopen_ext 还有那一堆 flags 的文档。里面只说了 android_dlopen_ext is available since API level 21,没说那些 flags 是什么时候添加的。
以 Android 5.1 为例,有效的 flag 只有这么几个:https://cs.android.com/android/platform/superproject/+/android-5.0.0_r1.0.1:bionic/libc/include/android/dlext.h;l=57-62
1 | /* Mask of valid bits */ |
使用不支持的其他 flag 如 ANDROID_DLEXT_FORCE_LOAD 会直接被 linker 报错拒绝加载。坑人呢
https://github.com/android/ndk/issues/1772
Release 模式的 APP 在非主线程上对 /proc/self/exe 进行 readlink 在旧版本的 Android/(Kernel?)上会触发 Permission denied 错误。把 debuggable 设置为 true 后正常,在主线程进行也正常,在没有 SELinux 的 Android 5.0 AVD 上也正常。
猜测可能是旧版本 Android 的 SELinux 有问题?
这个问题导致了大量旧 Android (5.x/6.x)用户更新 Magisk 25.0 后“卡在开屏页”
应该是 kernel 问题,在非 Android 平台上也有出现
https://github.com/moby/moby/issues/18883
Pixel 6 系列(只看了 6a 但是应该是整个系列都有这个问题)的 Android 13 QPR2 B1/2
boot.img 里的 ramdisk 用的 gzip 压缩,vendor_boot.img 里的 ramdisk 用的 lz4_legacy。
bootloader 解包的时候是把两个 ramdisk 拼起来扔给 kernel 然后 kernel 直接整包解压。这需要两个 ramdisk 起码使用相同的压缩格式。所以 boot.img 里的 ramdisk 从来没有被成功解压过,自然 Magisk 怎么修补都无效。这就是 修补原厂 boot.img 没有反应但是修补 Pixel 7 的 boot 刷入就好了的原因 (https://github.com/topjohnwu/Magisk/issues/6441)
Pixel 6 系列机型 QPR2 用户临时的解决方案:
更新:QPR2 Beta 3 已修复。Pixel 6 系列手机的用户可以正常修补 boot.img 获取 root。
Google:自己写的 文档 ,当然要由自己亲手破坏
Android 7.0.0_r1 SDK24 没有 fd 检查,没有 frameworks/base/core/jni/fd_utils-inl.h
Android 7.1.0_r1 SDK25 没有 fd 检查,没有 frameworks/base/core/jni/fd_utils-inl.h
Android 7.0.0_r29 SDK24 有 fd 检查:https://cs.android.com/android/platform/superproject/+/android-7.0.0_r29:frameworks/base/core/jni/fd_utils-inl.h
Android 7.1.0_r2 SDK25 有 fd 检查:https://cs.android.com/android/platform/superproject/+/android-7.1.0_r2:frameworks/base/core/jni/fd_utils-inl.h
如果你的应用(无论 root 还是 非 root)需要假定 Android 的内部行为,最好不要直接检查 SDK_INT 不然莫名其妙的崩溃就是下场。
Magisk 假定 fds_to_ignore 这个参数不存在就没有 fd 检查,然后在 华为/魅族的 7.0 上崩了。
Pine 根据系统版本假定 kAccCompilerDontBother 的值,然后在官方的 Pixel 2 8.0 ROM 上崩了。
今天意外发现乌云网 www.wooyun.org 已经没有 DNS 解析记录了(以前是访问显示正在升级),分享一个备份 https://wooyun.js.org/
致敬
https://github.com/android/ndk/issues/1751
Android 文档:TypedArray implements AutoCloseable added in API level 1
实际上:直到 Android 11.0.0_r1 这个类都没有实现 AutoCloseable 这个 interface。
所以,如果你很自然的写出了
1 | try (var typedArray = obtainAttributes()) {} |
或者
1 | obtainAttributes().use {} |
之类的代码,在旧版本上会崩溃。没有警告。
同样情况的还有 LocalServerSocket 这个类。直到 8.0 都没有实现 Closeable。
这个类 比 TypedArray 更离谱,TypedArray 大家都知道是用 recycle,而 LocalServerSocket 一直都有 close,但是偏偏一直没去 implements Closeable。
https://juejin.cn/post/7208345469658415159
时隔多年又看见了这种『一个 app 有多少个 XXX』这种问题。备份一下我的评论,以免又被掘金删掉。
首先,hashCode 跟对象地址没有半毛钱关系。确实有部分虚拟机选择将 hashCode 直接实现为内存地址,但是 ART 不是。
ART 的实现在这里:http://aospxref.com/android-13.0.0_r3/xref/art/runtime/mirror/object.cc?fi=GenerateIdentityHashCode#170
很明显可以看出 1103515245 是一个线性同余法生成伪随机数选择的常用魔数(不过整个算法看起来不是典型线性同余)。
至于为什么生成的 Application 对象 hashCode 值相同,可能是因为这些进程都从 Zygote 继承了相同的随机数种子,而 framework 内代码对象创建次数往往相同,经过相同的随机次数后产生一致结果就很正常了。
你可以在 Application 的静态代码块内创建随机数量的对象扰乱结果,应该就能得到不一致的 hashCode。
然后是『获取物理内存地址』,Unsafe 这种方法获取到的依然是虚拟的逻辑地址,且用户空间没有办法获取真实的物理地址(除非利用内核漏洞)。
全部给逻辑地址的好处很多:
1.可以在内存紧张时将未使用的内存空间临时换到硬盘上存储,应用实际访问时再触发缺页中断从硬盘读数据,整个过程对处在用户空间的应用完全没有影响
2.逻辑地址无法直接跨进程使用,增强安全性
3.完全阻止恶意应用读写其他进程的私有内存空间
等等等等。
然后我觉得『一个app到底有多少个 Application』『一个 app 有多少个 Context』这种问题一点意义都没有。如果是想知道『一个 app 的进程有多少个 Context』,可以调用 VMDebug.getInstancesOfClasses 这个方法。
文中忽略了一种情况,就是多个应用跑在同一个进程。当多个应用具有相同的签名,配置的 sharedUserId 相同且 android:process 为相同的共享进程时,会发生这种情况。此时一个进程会创建多个 Application 对象(每个应用一次)。
之前发现在自己的 Android 5.1 kernel 3.10 arm32 设备上调用 mremap 移动内存空间时会奇怪地报出 EINVAL (invalid argument) 错误,怀疑是低版本 kernel 的问题。后面西大师发现 6.0 x86 的 AVD 上也可以复现出这个错误,x86_64 却不会,而且主动使用 linux-syscall-support 这个库调用 mremap 是没问题的,所以猜测是旧版本 bionic 的实现问题。
果然,旧版本 mremap 参数列表里第四个 int 写成了 unsigned long,缺少变长参数 ( http://aospxref.com/android-6.0.1_r9/xref/bionic/libc/include/sys/mman.h#62 ),同时 x86 发起 syscall 的时候也只处理了四个参数( http://aospxref.com/android-6.0.1_r9/xref/bionic/libc/arch-x86/syscalls/mremap.S#18 )
然后找到了这个修复提交 https://android-review.googlesource.com/c/platform/bionic/+/180130
所以如果你的程序用了 mremap 又想兼容 7.0 以前的设备,请不要使用系统自带的 libc 里面的 mremap,自己 syscall 或者使用 linux-syscall-support 代替。
(离谱,好特么坑啊
提醒:想要兼容旧设备,还有其他坑……
android 6.0 以前,系统 libc 的 getmntent 和 getmntent_r 是空实现。
https://cs.android.com/android/_/android/platform/bionic/+/e3c4acf1e3ef36c2ab1f48b1261dec9a1d8330a4
还有,init.rc 的 exec 也是空实现……
http://aospxref.com/android-5.0.2_r3/xref/system/core/init/builtins.c#257
clock_nanosleep 这个函数的行为也不对,在 https://android-review.googlesource.com/c/platform/bionic/+/110652 这个提交之前它在出错时会返回 -1 然后把错误码设置到 errno 里,正确行为应该是直接返回正数的 errno
魅蓝 M3 Note,系统版本 Android 5.1,内核版本 Linux localhost 3.10.72+ #1 SMP PREEMPT Tue Sep 22 18:07:30 CST 2020 aarch64 Android
在这台设备上,syscall getrandom 会返回 0 同时 errno 变为 2 (No such file or directory)
似乎只在 64 位运行时出现,32 位正常。
而 getrandom 这个 syscall 从 Linux 3.17 才开始有,正常情况下它应该失败且返回 -1,errno 设置为 ENOSYS。
手上的其他 3.10 设备都没有这种怪行为。
而很不幸,较新一点的系统 libc 里面有个函数,叫 getentropy,它会尝试循环 syscall getrandom,只有当它返回 -1 的时候才会认为内核不支持这个 syscall 而进行回退。这个函数会在 libc 初始化时被调用。
所以如果你的程序静态链接了新的 libc,在这台设备上运行的时候会在 libc 初始化时调用 getentropy 而陷入死循环,连 main 都没有机会运行。
修复手段也不是没有,在编译时添加选项使用 wrap functions 功能覆盖掉这几个函数,然后处理一下 getrandom 返回 0 的情况。不过我觉得把当时弄出这种东西的魅族工程师拖出来打一顿比较好。
顺带一提,在这台设备上你想运行 lldb-server 也会因为同样原因卡死,strace 也会不明原因卡死,我是去找了一份 gdb 发现能用才发现这个问题的,不然连 backtrace 都拿不到
摘要:在长沙街头碰上人借车费,说晚上就还,然后就被删好友了
图片懒得补了,碎碎念可以补一下:
啊睡不着,瞎扯几句
我 2020 年刚进中职的时候,有个同班同学总是找我借饭卡刷,还有微信借钱,后面还带了另一个人找我借钱。我当时想都没想就借给他们了,到后面滚雪球越滚越多,他们借了我 642 块。后面我找他们要钱的时候他们老是说没钱,再后面这两个人, 一个退了学,一个街头持刀抢劫别人被抓了。就只还了150,他们到现在还欠我差不多500块,而我甚至连他们其中一个人的名字都不知道。
性格缺陷是这样的,害怕又渴望社交,害怕好不容易建立起来的社交关系维持不下去。
这回也是,我不认识这个人,这个人路上见到我说微信限额了帮忙付个 79 块的车费。
我这是善良还是纯圣母呢,我觉得是圣母。
我甚至觉得哪天我挂了去见上帝的时候上帝会说哟豁,好久没见过这么纯净的灵魂了。
大家别学我当这种冤种哦
睡了,明天还有 第 81 届中国教育装备展示会
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/permission/Permissions.md
给系统开发者的权限文档,竟然塞在这种地方,想不到
不过我这里用 Chrome 打开这个页面,Using role for permission protection 这个链接是 blocked,不懂 Google 在搞什么。应该是指向这个链接 https://cs.android.com/android/platform/superproject/+/master:packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/RolePermissionProtection.md
顺便带上一份 Android 13 的权限列表,http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/core/res/AndroidManifest.xml
需要其他版本的,选好版本直接搜索 /core/res/AndroidManifest.xml 就好了
转发自 不存在的世界 https://t.me/illusory_world/4359
https://nano.ac/posts/86257129/
拿到了一台华为 Nova 1 (Android 7.0,EMUI 5.0.4),getprop 显示是全盘加密,然而输密码解锁时这台设备的表现完全不像全盘加密。
在没有输密码解锁时连上 adb,mounts 显示 /data 已经挂载上 f2fs,vold.decrypt = trigger_restart_framework,vold.post_fs_data_done = 1,表明它已经解密完成。
而正常的已经设置密码的 Android 全盘加密设备的解密流程应该是:设备开机 -> 给 /data 挂载上 tmpfs -> 启动 framework -> framework 显示输锁屏密码页面 -> 用户输密码后,解密密钥 -> 关闭 framework,解密 data,挂载真正的东西到 /data -> 再次触发 post-fs-data 正常开机。
查看 dmesg 后发现这台设备在解锁之前用默认密码解密就成功了,锁屏密码似乎就只是锁屏密码。华为对 FDE 设备开机时间过长所做的“优化”?
编写了一个 PoC https://github.com/canyie/BypassKeyguard ,经测试能在设备开机后第一次输入密码前绕过锁屏进入桌面并访问用户数据,侧面印证了上面的猜想。
(为自己读了三年的感想总结,仅作备份)
0.快跑!如果你是 2023 届中考生,不是特殊情况,快去复习!想啥中专!
1.就算你真打算进中专,也一定要去中考考一下,别签那啥自愿放弃中考同意书!有很多好的中专也是要看中考成绩的
2.好好选学校,好的中专跟坏的中专差别很大。中考成绩出来发现没希望上普高的话,没打算复读的话,建议早点选好学校。有很多好的中专是有高考班的,但是学位不多,想报趁早。
亲身经历,咱中考没考,报学校又是等快开学了才去问,结果都没啥学校还有学位,最后进了间民办中职。
3.如果你成功进入中专,在课室里上着课,那么无论如何,恭喜你进入人生新阶段!不过不要觉得进了中专就舒服不用学习了,越垃圾的学校规矩越多还特喜欢整活。以笔者亲身经历来说,这学校能停任何课让你去搞卫生,甚至在离考试还有两三天的时候对我们上一届高考班发出“你们还是高考班,你们连卫生都搞不好你们高个屁的考”这种离谱言论并让他们停课搞卫生。
4.在学校的时候,尽量完善自己的课后生活。有升学的打算的话可以复习文化课和专业课,特别是英语单词,如果你们地区要考英语而你比较差的话建议一开始就狠抓英语。
5.强烈建议报技能竞赛,无论是专业竞赛还是计算机竞赛英语竞赛或者什么禁毒知识竞赛法治知识竞赛,学校没有的话就和学校申请自己代表学校去,无论如何让校领导对你形成两个印象,一是“这是个优秀的好学生”,二是“这个学生能给我学校争到荣誉”
6.强烈建议高一就去考技能证书,尤其是广东学生。个人建议计算机证书和英语证书最好拿到一张。
7.别觉得你的同学有多么善良,尤其是在中职学校。你的很多同学会在一年内选择退学或者被开除。高一的时候,我有个同学借了我六百多到现在都没还,后面这个学生大街上持刀抢劫路人被抓了。我们班还发生过晚自习一群人起哄上台用课室多媒体放黄色视频的事情,这种情况保证自己别被影响到就好了。在一间不怎么样的学校,很难看见希望,但是无论如何相信自己。
8.无论第一年多么苦多么不适应,都请珍惜,第二年随着你们班上大部分学生满了16岁,有些学校会开始以“实习”的名义送学生进厂打螺丝。这个时候竞赛的好处就体现出来了,大部分学校都不会送竞赛生进厂。笔者曾经有幸体验过三个月,那三个月里每天基本上都是因为手指套破损来不及换搞到一手的血,三个月下来拿笔都拿不稳,还高个毛线考。
9.如果你不太好运,已经进厂了,牢记一件事:实习进厂再苦至少拿到毕业证就能离开,没专业技能到社会上不走运的话这就是你以后一辈子的生活。
10.如果打算升学,建议最晚考试前一年开始准备文化课,除非您是技能竞赛保送生。当然任何时候开始学都不晚,各省考纲不同,以笔者广东考生的经验来说学一个学期都能考得很不错了(当然那样绝对累死)。
11.语文的话我其实觉得背那些古诗文没什么必要了,有这时间不如多记几个数学公式。时间充裕的话可以专门去记,不充裕的话那早读的时候读一下就好了,时间紧迫的话直接忽略都没问题。数学最后一道题做不出来就别纠结了,还不如去检查前面的小题,本人就是这样在考场上丢了十分😭
祝所有 2023 届中考生旗开得胜
提醒:近日盗号骗子盛行,请大家注意账号安全,注意以下行为:
强烈建议添加任何人为联系人时取消勾选 “Share my phone number” 选项,同时不要随意截图,需要发送截图时裁剪掉敏感信息。
https://twitter.com/oasisfeng/status/1661046351151665153?s=19
网上随便找了几个包看了下,play 版 6.48.0 target 31 即 Android 12,国内版 6.49.0 target 27 即 Android 8.1,国内版 6.60.0 target 29 即 Android 10。
拿到了实体卡 开心
发个新闻
https://j.eastday.com/m/1685165054031431
存档链接
https://web.archive.org/web/20230530003013/https://j.eastday.com/p/1685165054031431
疑似相关的央视网视频报道
http://m.app.cctv.com/video/detail/5a400b4969334dea87d7b05b0d1fd6a8/index.shtml#0
央视网报道被转发至哔哩哔哩
https://b23.tv/YNmoZR7
https://t.me/TooruchanNews/26896
https://t.me/LetITFlyW/9983
留一个文章链接避免上面频道也被封:https://juejin.cn/post/7338239261194010674
冷知识:从 Android 12 开始,应用可以声明 UPDATE_PACKAGES_WITHOUT_USER_ACTION 权限(是普通权限,用户无法禁止),然后调用新的 PackageInstaller.SessionParams#setRequireUserAction(int) API,来静默更新自己。无需用户确认。
看起来这么流氓的功能为什么没被国内一众流氓软件跟进呢🤔
猜测是要么是不知道,要么是因为 target sdk 限制:此 API 要求被安装的应用至少 target 30 (在 Android 13 及之前)或 31 (Android 14 及之后),并且未来的 Android 版本里还会继续提升这个限制。
PS: MIUI 用户应该是不受影响,在开启 MIUI 优化的情况下,整个 PackageInstaller API 都被完全破坏,无法使用。应该已经修好了
https://source.android.com/docs/core/runtime/signed-config
竟然还有这种东西,我可以理解为官方后门吗?
(注:RCE=远程代码执行 EoP=权限提升 ID=信息泄露 DoS=拒绝服务)
CVE-2021-0693 ID 高危
漏洞成因:Shell 应用错误把一个 provider 设置成其他 app 能访问,导致应用可以访问不应该能访问的数据。
CVE-2021-0314 EoP 高危
漏洞成因:卸载应用的确认弹窗没有设置不能被覆盖,导致恶意应用可以自行弹出悬浮窗遮挡住关键的确认信息,让用户在不知情的情况下卸载应用。
CVE-2017-13242 ID 中危
漏洞成因:蓝牙配对的时候,会弹出一个对话框,里面有一个选项是要不要允许配对设备访问通讯录。这个选项框包含了对端设备的名字,而这是攻击者可控的,然后攻击者可以通过在设备名字里插入换行符把关键的提示信息顶出屏幕。
CVE-2018-9432 EoP 高危
漏洞成因:基本和上面那个一样,攻击者改设备名把关键的确认信息顶出屏幕。
CVE-2021-0691 EoP 中危
漏洞成因:sepolicy 里多加了几行,授予了 system app 写入已安装 apk 的权限。尽管只是个中危漏洞,但它是『魔形女』漏洞链的重要一环,攻击者利用此漏洞可成功将原本数个越权任意写入文件的漏洞转化为任意代码执行。
CVE-2021-39631 ID 高危
漏洞成因:这个漏洞就更离谱了,一个提示消息写得不够清晰,被认定为高危漏洞…… 对应补丁在这里 https://android.googlesource.com/platform/packages/apps/Settings/+/a36d55e8f83e8bf6e50254cda04632e233598f42
CVE-2021-0434 EoP 高危
漏洞成因:警告信息写的不够详细。
CVE-2023-21090 DoS 高危
漏洞成因:没有限制 app 的 uses-permission 里值的最大长度,导致可以写得非常非常长把系统给搞崩溃。
千里之堤,溃于蚁穴。
“我想躺在一张很大很软的床上 想做个好孩子”
好孩子是什么呢
我小学时候奖状能挂满一面墙 我是好孩子吗
我五年级开始发病逃学 我是好孩子吗
我大概五六年级开始自学编程 每天抱着手机就为了学编程 我是好孩子吗
我小学拿缝衣针捅进插座里电自己 拿刀划自己手腕 我是好孩子吗
我小学有两年+初中四年(休过一年学)都几乎没去上学 连我们班任课老师都不认识我 我是好孩子吗
我的同学在发奋图强学习文化课的时候我在惠爱看病 浪费了家里不知道多少钱 我是好孩子吗
我连中考都不敢去参加 最后随便上了所中职 我是好孩子吗
我害怕社交害怕到想吃烤肠拿着钱在店门口徘徊不敢进去 我是好孩子吗
我头发前过眉侧过耳后过颈 我是好孩子吗
好孩子是什么呢
“乖”的、“听话”的,就是好孩子吗
AssetManager.addAssetPath 这个 hidden api 应该很多人都在用,提醒一下这玩意的两个坑:
这个故事告诉我们没事最好别用 hidden api,用这种玩意就是给自己找麻烦。
(以下均为大概时间):
04:30 突然醒了 不知道过了多久才睡着
06:40 醒了 在床上发呆 玩手机
08:30 到了公司开始写代码
09:30 开始发躯体化症状
10:30 持续不能缓解 请假回来休息 然后躺在床上不知道什么时候睡着了
13:40 醒了 然后在床上躺着玩手机
14:30 努力从床上下来去吃饭
15:00 吃完饭回来在床上躺着发呆和玩手机 知道自己要干正经事就是没力气去干
18:00 傍晚了 感觉心理状态明显好转 甚至有点想涩涩 努力逼自己干了急需的正经事情(其实也就只需要十分多钟就能干完 orz)
19:00 从床上下来吃饭 玩手机 洗澡 玩手机
22:30 想着应该尽量拉住自己 然后给自己下单了个智能手环 orz
23:10 睡觉
(然后三点半又醒了在这里打字 emmm)
冷知识测验:在 Java 中,调用 java.lang.Math 类的 abs(int) 方法一定会返回非负数吗?
答:Math.abs(Integer.MIN_VALUE) 会因为 int 不够放它的绝对值而溢出,返回 Integer.MIN_VALUE,负数。
有人问“你会后悔初中没去读吗?你会后悔上一间中职学校吗?”
其实实际上,我妈到现在都也还在不断重复“要是你初中的时候忍忍就好了”之类的观点。
我其实不后悔。我甚至觉得当时做的决定非常正确。可能说唯一有点后悔的是没选到一间比较好的中职学校,进厂打了几个月螺丝。
一方面,我厌学,另一方面,初中阶段很多孩子开始进入青春期,一堆小孩完全不知道自己在干什么,把霸凌当玩笑。再后面大家都为了升学努力,待在这种环境里只会让我心理状况更加恶化。
我自知我的人格是缺损的。所以我甚至很感激 gap 的那几年,我能尝试去把残破的人格补全。那几年里我脱离让我恐惧的学校环境,不用再为“又在学校发病又要麻烦老师把我送回家”这种事情内疚,我可以一点一点学习如何正确和别人相处,还能静心研究自己喜欢的事情。后面到了中职,虽然还是非常非常害怕,但是它至少是个比较轻松的低压环境,我可以尝试去融入它,我可以犯错。
到现在三年中职读完,从第一次住宿舍到一个人跑几百公里去陌生城市实习,感觉真的是个奇迹。虽然现在情况还是不太好,但至少有独立活着的机会了。
所以,如果你刚刚参加完中考,打算读中职的话,不用失望,好好读下去就好了。至于学历,中职学校也是可以升学的,况且如果活不下去,在意学历有啥用?
顺便放首歌:https://www.bilibili.com/video/BV1N64y1B7NZ
打开 https://bughunters.google.com 注册账号,可以阅读里面的 Rules 了解哪些问题会被认定为安全漏洞。还有就是,提交安全问题的报告或者补丁,满足漏洞奖励计划(VRP)的话,是有可能会奖钱的!!一般来说,漏洞本身的影响越大、提交的报告质量越高,获得的赏金也就会越多。所以初次提交建议仔细阅读 Rules 里的内容。
确定发现的问题是安全漏洞之后,就可以进入 Report 页面选择要报告漏洞的影响范围(原文是 “report types”,翻译为 “报告类型” 感觉并不对,不知道怎么翻译才好)。我发现的漏洞位于 AOSP 内,影响 Android 操作系统,所以我选择了 Report a security vulnerability in a Google-owned product 然后点击 Report。
然后它会让你填写你的名字和联系方式,然后会让你写要报告的问题的简要描述(会被当作 Issue 的标题),该漏洞位于哪个地方(我这里是 Android 直接在下拉框里选择 Android 就好了),然后是详细描述你的问题,越详细越好,最好把详细漏洞点和成因都写出来,可以上传一个不超过 50MB 的文件(大家一般都是上传 PoC 之类的吧,我是传了个演示视频)来辅助说明。然后点击确认,它就会在 Google 的内部 Issue Tracker 里为你创建一个对应的 Issue。这个 issue 默认是被保护的,只有你和被指定的 Google 员工可以查看。对了,一个很好的点是,你不一定要用英文!Google 有来自全球不同地区的员工,用你的母语沟通基本上是没问题的!
我是 6.28 提交的漏洞报告,6.29 这个报告就被 triaged 了,给我定的 Priority P2 + Severity S2,然后会有人让你确认有没有签 Google 的 CLA ,还会问你你打算怎么被感谢(我的理解就是怎么在 Android Security Acknowledgements 那个页面的 Researchers 一栏上写你的信息吧,至少我是这样理解然后按这样回复的),然后也会提醒你上传 PoC 之类的。
6.30 我回复了之后,7.13 获得了这样的回复:
Thank you for your submission. This vulnerability has been rated as Moderate severity with Medium Quality and unfortunately does not meet our bar for reward. We will pass this report to a feature team for remediation and will be closing this report and not providing further updates. Thank you for working with the Android Vulnerability Reward Program!
中等质量和没有赏金是意料之中的,毕竟没花时间去详细研究导致报告里的信息不够详细;至于漏洞严重性我一开始评估的是 High 高危,可能是满足了分级调节方式给我降到了 Moderate 中危,其实有点失望,不过也在意料之中。
我当时想着中危应该也会给 CVE 编号吧,看往年的页面说不定也有致谢信息,然后发现了这条:
Additionally, starting May 15th, 2023, Android will no longer assign Common Vulnerabilities and Exposures (CVEs) to most moderate severity issues. CVEs will continue to be assigned to critical and high severity vulnerabilities.
得,连 CVE ID 都没了,再也不相信信息安全了
不建议 更新 Magisk v26.2 (准确来说是 26106 及之后所有的版本一直到最新的 26202),建议等待已知问题都被修复后再尝鲜
花式爆炸
Edit: v26.3 应该把所有 bug 修好了,吧?
想知道详情的可以点击下面几个链接
https://github.com/topjohnwu/Magisk/commit/de00f1d5a94b83ad7bf49b0bdffab310e58db471
https://github.com/topjohnwu/Magisk/issues/7214
https://github.com/topjohnwu/Magisk/issues/7264
https://github.com/topjohnwu/Magisk/issues/7274
所以为什么这种问题只到发版的时候才能发现啊,根本没人用 canary 是吧
翻到了这本神书 是我读中职的时候学校发的
中职教育到底搞的咋样 看看应该就懂了(
我妹是 2017 年出生的,我比她大 13 岁,那个时候已经是初中生,我们这边的儿童游乐园大人陪小孩进去大人是不收钱的,然后你就能看见我打着照顾我妹的旗号在海洋球池里不停扔球而我妹安安静静坐在旁边的景象。
很多人看见大孩子玩这种东西应该都会奇怪,因为他们觉得大孩子应该坐在学校里上课或者就算玩游戏也不该玩这种婴幼儿玩的东西。这其实是人对他人的一种“期望”。
人从小到大都活在“期望”里。我妹出生之后我们期望着她三个月会翻身六个月会坐八个月会爬一岁会站,我们每天和她说话希望她早点学会说话,她不会做幼儿园的算术题的时候我家里人会叹气说这么简单的题都不会以后怎么办。就算到爷爷奶奶这个退休的年纪我们一家也期望着他们身体健康,晚上烧一桌合胃口的饭菜。
但是我觉得人不该只活在期望里。人生的意义不该是为了满足别人对自己的期望。
人生的意义是啥?我觉得该是享受。
享受啥?享受快乐。享受炎炎夏日电视机播着高糖饮料伤身而你拧开一瓶冰镇快乐水灌进嘴里,享受去吃了心心念念好久的龙虾自助发现也不是那么贵,享受你心爱的人说宝宝我爱你然后亲你一口,享受蒸鸡蛋你非要往里试试加可乐会是啥味道的瞬间,享受看见一个笑话你朋友说有他妈这么好笑吗而你笑到肚子疼,享受自己花时间写的东西有人读有人点赞,享受在网上看见有精神病在试图教你人生的意义是什么你觉得很奇特顺手转发给你的朋友。
我们现在的教育搞的快乐像原罪一样,但是我觉得享受快乐是人与生俱来的权力。
碎碎念:突然发现一直都在提出奇奇怪怪的想法 但是大部分最后都是被别人做出来
例子:
native bridge 注入:最后被 Riru ZygiskOnKernelSU 采用,Magisk Zygisk 也计划改成这样实现
MomoHider :从 Shamiko 开始我就没怎么动过了
resetprop 检测:一直知道有这个方法 懒得写 最后被 nullptr 先写出来加进牛头检测器了
重写 zygisk 注入,改成监控 preload-class 并 ptrace zygote:写到一半突然就不想写然后 git reset 了 然后被 ZygiskNext 写出来用上了
该说不愧是 ISFP 吗,绝对不做没有 deadline 的事情(
写了一下 Android 启动过程中 init 这个进程的一些细节,以及 magiskinit 是怎么处理这些不同设备的
可能是你在网上能找到的关于 2SI、 magiskinit 等鬼东西的最详细的文章
https://blog.canyie.top/2023/11/12/android-booting-shenanigans-and-magiskinit-analysing/
Android 14 有一项行为变更,ActivityManager.killBackgroudProcesses() 这个 API 不能结束其他应用的进程了,只能终止自己的后台进程
但是查看 2023-10 安全公告会发现这个补丁实际上被下发到了 Android 11-13,还被授予了 CVE-2023-21266 这个编号,类型是 EoP 权限绕过,定级为高危
之前一直想不明白为什么 Google 会把行为变更当成安全漏洞处理,直到今天突然想到,可以结束其他应用后台进程,会对 RAM 使用量造成影响,那可以判断 kill 前后的 RAM 使用量,如果出现大幅度下降说明 kill 成功,说明 kill 之前这个应用有进程在运行,相当于绕过了权限检查指定软件包是否在运行,是侧信道
信息安全,真他娘的奇妙
其实这样解释也和 Google 其他行为自相矛盾
之前有个漏洞(具体编号忘了 CVE-2023-21377),是任意第三方 app 可以 inotify 其他应用的 apk 路径,对应应用启动的时候一定会 open apk 然后就会收到通知,相当于绕过了“使用记录访问权限”监听对应应用启动
Google 给出的补丁是用 sepolicy 封堵对应权限,然而“为了破坏现有 app,只对 target >= 34 的应用启用此限制”
只能理解为 Google 内部管理混乱
更新:查看了 CVE 描述,发现是能用这个玩意“绕过 play 保护”,也就是能一直杀掉 play protect 的进程。嗯,也挺离谱的……
试了一下小米社区的解锁答题(2023.12.07 更新的)
嗯,非常好,题目非常有质量
成功把我给挡在外面了
公开两个检测 resetprop 的方法:
通过 setprop/getprop 等手段操作property 实际上是操作了位于 /dev/__property__ 下的文件。按 property 各自的 SELinux Context 存储,相同的 context 分为一组,存储在一个文件内。每个文件大小为固定的 128KB。需要使用的 prop_bt prop_info 等对象由一个线性内存分配器实现,每次分配内存时只是简单地 bump 地址,不支持释放内存。
更多细节可以查看 https://blog.canyie.top/2022/04/09/property-implementation-and-isolation/
Magisk 的 resetprop 在删除 property 时,会将 prop_bt 中指向 prop_info 的引用置空,然后清空整个 prop_info 的内存。问题就发生在这里,prop_info 的内存被清空但并没有被释放,这就导致对应内存位置出现一片很大的空区域。通过检测这里,应用可以检测到对应属性区域有属性被删除了,进而推断出设备已经 root(因为正常情况 property 是不支持删除的)。
什么时候会发生删除操作?通过 resetprop 重置 ro 也就是只读属性时。而保存着 bootloader 锁定状态的多个 property 和保存着 native bridge 的 ro.dalvik.vm.native.bridge 还有经常被修改的设备指纹都是只读属性。也就是说,除非避免修改这些属性,否则就会被检测到,而不修改 bootloader 状态的属性又会导致里面直接存着“已解锁”,应用一样可以读到。
在 https://github.com/topjohnwu/Magisk/commit/f41994cb52ca08856216a8da0a28ed148c833f4e 过后,作为副作用,上面的问题刚好被缓解,但还有另一个问题:
prop_info 上有一个字段叫 serial,当这个 prop_info 被更新时,serial 会自增 2。也就是说,prop 被更新的次数 = serial / 2。而对于 ro 属性,它们是只读的,正常情况根本无法被更新,因此 serial 应该始终保持为 0。也就是说,如果发现 serial 不为 0 的只读属性,就代表它被 resetprop 过。
我们调查发现已经有应用在使用这些方法检测 root,Shamiko 1.0+ 已经尽全力隐藏了相关痕迹。我知道有很多人并不愿意使用 Shamiko,而其他隐藏方案的开发者并不知道这两个检测点,也就没有办法处理它,所以我公开了。
阅读以下三篇博客,可以感受三星的代码质量
https://blog.oversecured.com/Two-weeks-of-securing-Samsung-devices-Part-1/
https://blog.oversecured.com/Two-weeks-of-securing-Samsung-devices-Part-2/
https://blog.oversecured.com/Discovering-vendor-specific-vulnerabilities-in-Android/
Android 不为人知的新功能:Financed Device 的原生支持
这个功能做了很久,但是非常低调,我完全找不到文档,甚至没法确定这个功能到底做完没有,唯一能找到的只有这句话:
A financed device is a device purchased through a creditor and typically paid back under an installment plan. The creditor has the ability to lock a financed device in case of payment default.
(Ref: https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:packages/modules/Permission/framework-s/java/android/app/role/RoleManager.java;l=175 )
简单来说,financed device 指通过分期付款购买的设备,这个功能借用了现有 Android for Work 中设备管理(device owner)的功能,允许债权人自定义的 app 对设备施加使用限制或在逾期不付钱的情况下远程锁定设备。现有 DevicePolicyManagerService 中添加了特定的 FINANCED_DEVICE_OWNER 类型,与传统的完全受管设备(fully-managed devices)区别,限制了 financed device owner 所能执行的操作,更加安全(?)。
从设计上来看,设备第一次开机,设置向导时 DeviceLockController 向自定义的 app 授予 android.app.role.FINANCED_DEVICE_KIOSK 这个 role(Android 14+),app 通过调用新增的 DeviceLockManager API 调用 DeviceLockController 提供的服务,DeviceLockController 验证权限后利用现有设备管理的 lock task 机制锁定设备。而 financed device owner 可以直接调用 DevicePolicyManager API 管理设备。不知道为什么要分两个,可能是允许 OEM 自定义。
以后就可以享受和 iphone 一样的,分期付款逾期不付直接被锁定手机的体验了。
注:搜索可以发现 Google 早在 2020 年就已经在 DeviceLockController 中加入了相关功能,但是并没有在系统底层添加原生支持。添加支持应该是为了方便 OEM 自定义?
https://www.xda-developers.com/google-device-lock-controller-banks-payments
Android 11 中引入的软件包可见性(package visibility, https://developer.android.com/training/package-visibility )可以过滤应用能够访问的应用列表,但实际上是鸡肋功能
一方面,该功能虽然对 PM API 及其他一些 API (如 getDefaultSmsPackage)返回的结果进行了过滤,但系统中仍然存在大量 API 允许应用违反可见性获得未知包,如 AccessibilityManager.getEnabledAccessibilityServiceList() 允许应用获得正在运行的无障碍服务列表,还有 Settings API 允许应用通过读取系统设置的方式获得无障碍服务列表及通知监听器列表等
另一方面,系统中存在大量漏洞允许应用绕过软件包可见性查询指定软件包是否存在,以 CVE-2021-0975 为例,该漏洞允许攻击者通过系统抛出的异常信息中的微小差异判断软件是否已被安装。对应补丁在 https://cs.android.com/android/_/android/platform/frameworks/base/+/bf0d59726a0d9973f6867faedac0fe476c81fe8b
类似的漏洞 Google 给予的评级一直都是 Moderate severity 因此只在 Android 大版本迭代时对其进行修复。这种漏洞还有多少,我简单检索了一下,仅仅只是 Android 14 中修复的有 CVE 编号的漏洞就至少有图上这些。同时,2023 年 5 月起大部分 moderate 漏洞不会再被授予 CVE 编号,被默默修复而不为人所知的漏洞又会有多少呢?
注:即使使用 HideMyApplist 这样的 Xposed 模块,也无法阻止软件通过上述方式违规获得信息。不排除未来会有软件利用这种方式绕过用户安装的 HideMyApplist 等模块获取敏感应用(如 Magisk/KernelSU manager)信息。如果想治住这些软件,稍微靠谱一点的方法是利用多用户,把它们扔一个单独的用户里。注意必须是完全用户,使用 work profile 是不行的。
1、2:把 service 打成了 ervice,少了一个 s,而且是两个 API 的示例代码一起打错。我 debug 了三个多小时才发现!!
https://developer.android.com/reference/android/nfc/cardemulation/HostApduService
https://developer.android.com/reference/android/nfc/cardemulation/OffHostApduService
3:文档里给出的示例代码引用的 API 根本不存在,尝试编译直接报错
https://developer.android.com/reference/android/content/om/OverlayManagerTransaction
4:一个 API,注释里写了可能返回 null,却被标记成 NonNull
https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/content/pm/PackageManager.java;l=7390?q=PackageManager.java
5:已经被修复的一个错误,用 void 表示状态
所谓“系统框架”其实指的就是 system server 进程,其中运行着大量的关键系统服务。虽然应用的进程是由 zygote fork 出来的,但实际上每个应用进程都会先向 system server 注册自己,system server 发回应用的信息,如 apk 路径,然后应用进程继续执行。只要作用于 system server 的模块都有机会篡改这个 apk 路径,打破作用域的限制,向任意应用进程注入代码。
这就完了吗?没有。
如果被注入的应用被授予了 root 权限,那恶意模块就能以该应用作为跳板,进一步拿到 root 权限。
那如果我一个应用都不给 root 呢?很遗憾,你的 root 管理器应用(比如 magisk 的 app)本身就有 root 权限,直接把恶意代码注入进去,就又能拿到 root 了。
强烈建议各位激活任意模块时都小心一点,尤其是当它推荐你选择“系统框架”的时候。
(PS:前几天就想发了,但是刚好碰上愚人节,容易被觉得是愚人节玩笑,所以延后几天)
https://t.me/Rosmontis_Daily/4631
(虽然从一开始的 0-click 变成了 1-click)
从作者引用的 PR 来看,我更倾向于认为这其实是两个 bug:
第二个 bug 可能最后被认为是预期行为,但是我个人倾向于认为是 bug。如果能找到不在白名单中的可执行文件后缀,加上这个 bug 又能再次实现 RCE。
事实上这种『缺乏对可执行文件的正确处理』的 bug 已经不是第一次出现了,详细可以查看:
https://evilpan.com/2021/09/23/macos-rce/#:~:text=%E7%9C%9F%E6%AD%A3%E7%9A%84%20RCE%E3%80%82-,%E7%9C%9F%20%C2%B7%20macOS%20RCE,-%E7%BD%91%E4%B8%8A%E4%B8%8B%E8%BD%BD%E7%9A%84
大部分加群验证机器人都是在有人进群的时候在群里发一条消息要求完成人机验证,而不是使用 telegram 的加群审批机制,打扰正常聊天,所以之前一直使用 Telegram Watchdog。
坑点:
1.官方实例经常掉线
2.部分使用 telegram 内置代理的用户尝试验证时打不开验证网页。可能是 iOS 上 webview 不走 telegram 内置代理?
3.部分用户尝试验证显示 Access denied。可能是使用的客户端版本过旧被服务器拦截,但是没有人配合测试,无法确认原因
4.在群组内有两只 watchdog 的情况下,部分用户反馈只收到一条验证消息(而且还过不去),不清楚原因
可能还有其他坑点,但是一直没有人配合调查,结果就是每天都有几十个人申请加群却过不了验证
后来 Rose @MissRose_bot 支持了新的加群批准,大喜,以为终于能摆脱坑了,然后踩进更大的坑
1.rose 的加群审批要开欢迎消息才能用,用户被批准进群后还会在群里再看见一条人机验证,完全失去优势
2.没有跟 rose 说过话的用户尝试验证会提示 bot 无法主动向用户发起私聊
实在不行了,Watchdog 和 Rose 一起开吧,能用哪个用哪个,总可以了吧?
大坑:
1.这种情况下,被 watchdog 批准的用户会被 rose 自动禁言,还要完成 rose 在群里发的验证(然后还设置了几分钟后自动删除)。经过测试,发现即使是被管理员手动批准的人也会被禁言,6…
2.如果之前已经被禁言,即使退群再通过 Rose 加群,进群之后仍然是禁言状态,必须再完成群里那个验证才能解除
跨频道联动:https://t.me/real5ec1cff/194
Android 2024 年 6 月安全补丁修复了一个由我发现并报告的漏洞 CVE-2024-31318 (漏洞补丁: https://android.googlesource.com/platform/frameworks/base/+/b68b257d56a8600d53b4d2d06fb82aa44086a4a5 )
回答思考题第 0 题:显然还是以 app uid 身份调用。但如果系统开发者忽略了 app 也可以调用 shell command 这一点,就可能造成安全漏洞。此漏洞本质上还是缺权限检查,不赘述。关于这一类漏洞的技术细节我会在本月博客上的安全补丁分析里说明。
那么为什么技术高超的 Google 程序员也能犯这种错误?
通过分析提交历史,我发现这个函数以前其实是有一个权限检查的,但是在 Android 14 的一个提交 https://cs.android.com/android/_/android/platform/frameworks/base/+/7a8f22792e45630bff14eb8b276c7649b0d79097 里被人删掉了。所以这其实是一个只影响 Android 14 的漏洞(这下新版本魔人大失败了)。
由于我不是 Google 员工,没法直接知道这个人这么做的原因,我这里只能猜测一下:可能是眼花了把这里看成已经在用 handleShellCommand 了,可能是觉得权限检查重复(Android 12 的时候这块代码在 ShellCmd 构造函数里),或者干脆就是 git 出了 bug 把这行给意外移除了,类似那个 gotofail 漏洞。
继续追踪提交历史,我发现了一个更搞笑的:2020 年,同样的系统服务,同样的 onShellCommand,曾经出现过一个一模一样的漏洞 CVE-2020-0227 https://android.googlesource.com/platform/frameworks/base/+/84cccfe6cdbc57ee372ee1a0fea64c7a11c53766^!/#F1 。
嗯,让你不写回归测试,白给赏金了这下。
时间线:
2023.10.4 Android 14 正式发布
2023.11.25 我注意到此漏洞
2023.11.26 构建了 PoC 并向 Android 安全团队反馈
2024.2.10 Google 确认此漏洞并将严重程度评级为高。对,你没看错,两个半月
2024.5.21 Google 通知我补丁将在下个月发布,并分配 CVE-2024-31318
2024.6.3 已经过去了 190 天,补丁终于发布
P.S. 从 Android 14 QPR2 开始,ActivityManagerService onShellCommand 中添加了检查,只允许 root/shell uid 调用,所以 app uid 无法再使用 am 或 cmd activity 系列命令。具体提交可见 https://android.googlesource.com/platform/frameworks/base/+/9e0c05e36afe0109b1df0d1bc375ade722138c81^!/#F0 ~
https://android.googlesource.com/platform/frameworks/base/+/1149dbb04b5a367c46bcfa5fcc0083dc2767a8eb
继对 system server 及部分系统应用开启 R8、Android 15 strip libart.so 后,Google 计划对 system server 开启完全 R8 优化。预计系统模块将可能会大规模失效。为啥以前机子存储空间小的时候不在意,反而现在开始扣大小?搞不懂搞不懂
(我自己在 Android 14 就被影响过一次了,虽然当时是 SystemUI)
给逝去的日子简单点首歌:
https://www.bilibili.com/video/BV13k4y1n7bd
转发自 易然个人频道
爱哭鬼 || 银教授
人活着这么辛苦,为什么还要活着?
是为了比一比谁更不辛苦,如果你的辛苦程度比别人低,嘻嘻,瞬间就开心了有没有?
就拿李建军来说,一场车祸,李建军失去了双腿,很辛苦了对吧?但是他的同学王褶容,失去了双亲。 每次想到这里李建军都忍不住笑出声。
如果你的人生都忍不住笑出声了,试问你还想死吗?一般都不会。
但也有人因为太辛苦而想自杀的,有一次我在天台抽烟,看到一个女孩站在天台上打算跳楼,我问:“你为什么跳楼?是感情不顺吗?”
女孩说:“女孩的心思男孩你别猜。”
如果一个女孩动不动就说“女孩的心思男孩你别猜”,那么肯定有感情问题。
我问:“你可以告诉是什么事情吗,说不定我可以帮你。”
女孩叙述了事情的经过:
就在刚才,她和男友吵架,
女孩对男孩说: “你根本不知道我在想什么!”
男孩:“你不说我怎么知道?”
女孩:“你不会猜吗?”
男孩:“那我猜猜。”
女孩:“女孩的心思男孩你别猜!”
我:然后呢?
女孩:然后他沉默。于是我就想死了,因为我最怕空气突然安静。
我:我觉得想死的应该是你男友。 他人呢?
女孩:在楼下。
我:为什么不上来?
女孩:刚跳下去。
我:那你为什么要跳呢?
女孩:我想和他双宿双飞。
我:人都死了,还想着双飞。
女孩:嘻嘻,真幽默。你有对象吗?
我:没有。
女孩:那你怎么还不去死?
我:死了也没有对象,那我为什么要去死。
女孩:也不是没有道理。
我:不过有时候的确想死。一个人久了,什么事都是自己做,就算自焚连个递打火机的人都没有,太苦了。
女孩:是的,我现在想跳楼,连个推我的人都没有。
我:要不我推你一把?
女孩:好呀!
于是我把手放在女孩腰间。
女孩咯咯咯笑了,她说:不能放这里,太痒了,我会笑的。
我:笑不好吗?可以含笑九泉。
女孩:我笑起来不好看。
我:不,你笑起来很美。
女孩:谢谢你。你真好。我男朋友从来没夸过我。
我:开心吗?
女孩:开心。现在我又不想死了。我觉得只要还能开心,就没必要死。
我叹了口气。
女孩:叹气干什么。
我:你已经死了。
女孩:什么意思?
我:三年前我在这里跳楼,跳完我就变成了鬼。
人在刚变成鬼时,并不知道自己是鬼,所以我以为自己还没死。
当时我站在天台上,看着太阳升起,突然不想死了,于是我就下楼回家。
回家后,我发现大家都看不到我,无论我跟谁说话,都没人理我。
我对着我的亲人大喊大叫,声嘶力竭,但我好像是一团空气。
那种无力感你知道吗?就是用尽所有的力气却没有任何作用。
后来我才意识到,我已经死了。
听完我的话,这个女孩继续哭。
哭了很久很久都没有停下来,也许她就是传说中的爱哭鬼吧。
这三年来,我见过很多自杀而死的鬼魂,大多数都很后悔。
活得不开心,可以换一种活法。但是死得不开心,就没法重新死了。
经常看见有人上传一份 magisk 日志就来反馈问题,然后被禁言又在那里抱怨说“我提供了日志啊”
那就来看一下,magisk app 底栏上那个“日志”里面保存下来的到底是什么东西
它大概包含这些玩意:
第一部分:设备基础信息,内核版本
第二部分:系统属性,注意这里不是 root 获取的,所以只包含 untrusted_app 有权限访问的
第三部分:环境变量
第四部分:app 的 mountinfo
第五部分:magisk 自己产生的 log,即 /data/cache/magisk.log 或 /cache/magisk.log。注意,它只包含 magisk 自己主动打出来的日志,其他日志,比如崩溃日志,不会被记录下来
第六部分:app 自己运行 logcat 读到的日志,只能读到自己 uid 产生的
接下来设想几个情况
场景一:开不了机。很明显根本进不去 app,即使运气好有 adb,如果没有提前授权 root,也拿不到 magisk.log。就算拿到了,它只包含 magiskd 自己主动打出来的日志,不包含崩溃日志,里面几乎不会有什么有用的东西。不如一句 adb logcat 有用。
场景二:magisk app 显示“无法获取”,即所谓的“掉 root”。这种情况有太多种原因,然而无论是哪种,由于 magisk app 自己没有 root,它能读到的东西基本上不会有什么用。不如一份 logcat 或者 bugreport 有用。
(题外话,如果是因为 magiskd 崩溃引起的,由于它会 block 所有信号,崩溃的时候不会有任何记录,静悄悄的退出)
场景三:zygote 崩溃太多次,触发 zygisk 自动关闭。magisk.log 不会记录崩溃日志,自然也记录不到 zygote 崩溃日志。不如 logcat 有用。
场景四:模块工作不正常。magisk.log 只会记录自己主动产生的日志,模块自己出的问题当然和它没关系。不如一份 logcat。
很多人说日志太多了,我觉得恰恰相反,是太少了以至于它自己的问题都难以调试。感兴趣的可以看一下我 debug 这个问题的艰难过程:https://github.com/topjohnwu/Magisk/issues/4174
https://github.com/canyie/MagiskEoP/blob/main/screen-20220302-093745.mp4
Demo video for exploiting a vulnerability in Magisk that allows local app to gain root access without any confirmation or acceptance and execute arbitrary code with root privileges. It demonstrates silently obtaining root privileges and silently granting root to any app.
演示视频,利用 Magisk 中的一个漏洞静默获取 root 权限并以 root 特权执行任意代码而无需用户确认。我们同时展示了如何利用此漏洞获取 root 后向任意 app 静默授权 root。
Exploit source code and writeup is now available at https://github.com/canyie/MagiskEoP
本来还想着要多久才能有人发现这是 app 问题的,结果当天晚上就被吴自己指出来了,没意思
不会 Android 开发的人,能不能挖到 Android 系统的漏洞?
先说结论,可以,但是能挖到的漏洞类型肯定有局限
其实我觉得关键的反而不是技术实力,是能不能判断出漏洞
很多人都觉得,系统安全漏洞这种东西,肯定很复杂,肯定都是内存破坏什么的,都是什么缓冲区溢出、释放后使用这种一听就很高大上的东西,包括我自己以前也这么以为
其实 Android 系统很多漏洞都不是内存问题,反而有很多的 UI 层漏洞,有些问题甚至不用写代码就能触发,看你对系统的熟悉程度
举个例子,2022 年那个价值 7 万美元的锁屏密码绕过漏洞 CVE-2022-20465,这就是纯粹的 UI 层漏洞,不用写一行代码就能触发,能在没有锁屏密码的情况下解锁设备,很明显这是漏洞,对吧?那其他看着没那么明显的东西,有没有可能也是漏洞?
今年八月有个漏洞 CVE-2024-34734,触发方式是在设备锁屏的时候下拉状态栏,里面有个“活跃的应用”,旁边有个“停止”按钮,用这种方式可以在没有密码的情况下杀掉 VPN 应用。可能看起来它不像漏洞,但是它能让没有密码的人停止掉 VPN,假如机主没有注意到 VPN 已经停止,继续使用网络,这个时候是不是就在用非预期的不安全网络?
Android 系统还有一个功能叫多用户,效果很明显,可以让多个人共用一台手机。NFC 设置里有个选项,只允许锁屏解锁之后使用 NFC,术语叫 secure nfc。假如机主打开了 secure nfc,切到访客用户然后给另一个人借用手机,这个人进设置里关掉了 secure nfc,然后切到机主用户,不输密码,是不是也能用机主的 NFC 支付了(CVE-2021-39807)?类似的还有访客用户帮你降级系统应用、添加 WIFI 网络等等。
Android 12 开始有个功能,有应用在录音或者录像的时候,状态栏右边会显示一个绿色的小点来提醒你,正式的名称叫“隐私指示器”。假如你平常用手机的时候,发现在某个应用里录音或者拍照的时候,这个指示器没出来,那你也可以去报漏洞。更进一步,这个指示器是 SystemUI 显示的,假如录音到一半 SystemUI 进程死掉了,那重启之后这个绿点还会不会显示(CVE-2024-0019)?
还有个功能叫屏幕固定,英语叫 app pinning,作用是借给别人手机的时候把手机固定在某个应用,比如借给别人打电话的时候你肯定不想让他进你支付宝里转钱。还可以设置退出这个状态时必须输入密码。那如果有办法在无密码的时候退出这个状态,也会被认为是漏洞。那假如说在这个状态下,被固定的应用被卸载了会发生什么(CVE-2020-0024)?
上面这种情况还有很多,比如如果在锁屏页面能查看隐藏起来的通知,那也算漏洞,看你的想象力够不够丰富。还可以玩排列组合,比如 Secure NFC 那个漏洞,访客用户不允许去改这个设置,那普通的第二用户应不应该去改(CVE-2023-21086)?锁屏的时候不能断开 VPN 了,那访客用户能不能断开主用户的 VPN?用屏幕固定这个功能固定了一个应用,那能不能下拉状态栏,在“活跃的应用”里停止当前应用,从而退出屏幕固定?
所以其实我认为关键点在于:1. 能不能想象到威胁场景 2. 看见一个东西能不能判断出它有没有安全风险。Android 给的漏洞赏金还是挺多的,高质量的高危漏洞报告基本上就是 7000 美刀。打个五折,不算税费,还有 3500 刀,按今天的汇率换算成人民币大概是 25000,一个月花 1000 也够花两年多了。如果真的有人对这方面感兴趣,可以关注我的博客跟频道,后续也会推送相关内容。
这里有一张照片但是我懒得放到博客里 自己想象吧(
配文:
洗完头没梳头 懒得梳
感觉不如把头发全拨到前面扮贞子
反正刚好也在床底下 还可以喊我床底下怎么有人
一年之后:当我在放屁
读大学有啥用啊 还不如直接出来进厂
引用 https://t.me/newqianzhuang/24
从 Android 14 开始,普通应用将无法读取 ro.debuggable 和 ro.secure 两个系统属性[2][3]。这对使用第三方 ROM 的隐藏魔人来说,无疑是个好消息:许多应用通过这两个属性来判断系统是否为 userdebug 或 eng 构建。
续前文,其实我们当时还发现了另一种方法在 AOSP 上绕过此限制:使用 app zygote。
AOSP 中这个限制是使用的 SELinux 规则来做:
1 | get_prop({domain -untrusted_app_all -isolated_app_all -ephemeral_app }, userdebug_or_eng_prop) |
对 domain 授予权限,但排除 untrusted_app_all、isolated_app_all、ephemeral_app 这三个域。也就是说,这条规则会对除不可信应用外的其他所有域授予读取权限。但是实际上,app zygote 进程运行在 app_zygote 域下,而 app_zygote 并不属于上面提到的任何一个域,所以其实用 app zygote 就能直接绕过限制。
我们给 AOSP 提了修复,很简单,直接在上面的规则里加上 -app_zygote 即可。预计应该是 Android 16 才会包含这个修复。
Android 15 默认开启了 Sdk Sandbox ~
勘误:被文档和其他人误导了,没有默认开启,到目前 Android 16 DP1 仍然处于默认禁用状态
官方文档:https://developers.google.com/privacy-sandbox/private-advertising/sdk-runtime
研究记录:
<application> 下设置的 processName 加上后缀 _sdk_sandbox 作为 service 的 instance name,由于 retrieveServiceLocked 会使用这个 instance name 查找 ServiceRecord,如果多个应用(这里不考虑多个应用共享进程的情况)同时调用同一个 sdk,由于进程名不同,instance name 也不同,即使该 sdk 已经有进程在运行也不会被复用 3 4细节还是挺有意思的,当然也有未考虑到的地方,如有错误不吝赐教。目前 Magisk 的 denylist 还没处理这种情况。
复活一个半年前就被修复的漏洞?我把三月份就应该被修复的 CVE-2024-0044 续命了半年
PoC & writeup:
https://github.com/canyie/CVE-2024-0044
这个漏洞已知在被取证公司积极利用,不想被取证的用户建议尽快升级。看热闹不嫌事大的可以关注各取证厂商,估计很快就会说自己突破了提权技术难关之类的了。
陪同残疾人士 乘坐东方航空航班 广州白云->上海虹桥 体验
一定一定一定一定一定要让人早点到机场!!!16:30起飞的飞机,我14点到机场,然后一直没值机,就是为了等人,结果人15:35才来,给我气炸了
虽然来得比较晚,但是提前预约了东航的无障碍服务,各项照顾还是很到位的,比如下机用无障碍登机车,机场有专人帮忙推轮椅到机场出口等
虽然预约了东航无障碍 但是没约白云机场的无障碍…然后到现场之后临时约,无障碍登机车是没了只能爬登机梯,然后因为登机即将截止,机场小姐姐帮忙全速推轮椅终于赶上飞机,在这里给白云机场工作人员点个好评(
提前预约东航无障碍服务会导致他们给你提前订好一个座位 然后我值机的时候想坐一起 尝试选旁边座位没成功 所以有相关需求的旅客建议提前预选好座位 虽然这次航班机组直接给免费升了超级经济舱(
总结:1.早点到机场 2.需要特殊服务早点预约 3.座位早点选
附1:上海地铁好几个站的无障碍电梯是在付费区外然后直接进入站台的 导致两个问题 1.进站之后想用无障碍电梯需要先找工作人员出站然后按求助按钮让工作人员给你开电梯 2.从站台坐电梯上去会直接出付费区,需要找工作人员帮忙刷卡出闸,否则系统里没有出闸记录
附2:预订酒店时应该提前确认该酒店是否无障碍友好,否则就可能像我们一样,到了酒店发现房间是复式的,分为多层,需要走楼梯才能上床,然后只能默默退房找了间汉庭住
总体挺好的 就是这个会场有点伤眼睛
省流:
https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md
才发现竟然有这种文档,不知道是不是我火星了。里面 Correct soname/path handling 这个问题是当年 Magisk 还支持 Android 5.0 的时候就遇到过的。
去食堂打饭 阿姨打的饭嫌多 平均只能吃掉一半
去外面吃饭 吃啥都嫌多 一碗啥都不加的螺蛳粉吃完还剩一半粉
在家天天被念叨让多吃一点
水喝多了都嫌撑
碰上聚餐/花钱比较多的情况更是不得了 只能本着钱都花了不能浪费的原则往嘴里塞
然后代价就是胃疼/反胃/反酸 不敢平躺 睡不着
到底哪里才有适合我这种饭量的人的饭啊 难道我只配一直啃包子/馒头/面包吗
https://blog.canyie.top/2024/11/05/android-platform-common-vulnerabilities/
新博客,介绍一下挖 AOSP 漏洞的时候可以挖到哪些。
这篇博客本身有没有用我还不知道,但是编写它让我发现了一个高危 CVE-2024-43088。谷歌在 11 月补丁中终于修复了它,也让这篇文章终于能够被大家看见。
另:11 月补丁中修复了我的另外三个漏洞 CVE-2024-43080 CVE-2024-43081 CVE-2024-43090 ,同时修复了 LSPosed 团队其他成员报告的 CVE-2024-43093 。感兴趣的可以看看。
这个问题被分配了 CVE-2024-48336。
这里给出一个额外提醒,就是很多 app 使用了类似的代码,但没有正确修复这个问题,比如 FoxMagiskModuleManager 1 和 KeyAttestation 2。用同样的方法可以注入任意代码进受害 app,然后利用该 app 被授权的额外权限比如 root。能做的事情就很多了。
当然你还可以搞一个什么 “密钥认证一键修复 app”然后发去小绿书(
有效法律证据形式
根据 GA/T 1564-2019《法庭科学 现场勘查电子物证提取技术规范》,应对现场、屏幕进行拍照或录像,记录物证的系统时间和北京时间;对有密码保护的数据提取并保存在有唯一性编号的专用存储介质中。
根据《公安机关办理刑事案件电子数据取证规则》第八条,需要及时固定相关证据时,可采用打印、拍照或录像等方式。第二十三条,对公开发布的电子数据、境内远程计算机信息系统上的电子数据,可以通过网络在线提取。
取证要点难点
数据解密(Android 上应用数据被 FDE/FBE 保护,开机第一次输入密码后才会解密数据),数据保持,数据防销毁
分点解析
由于 Telegram 功能特性,聊天的一方可以为另一方删除聊天记录,扣押到检材后需要立刻断开网络,不要轻易重新连接网络,以免证据被远程删除;可重点关注被设置了定时删除或加密的聊天;可以通过截图、录屏等方式保存证据,对获取到的数据计算哈希值校验并留存。通过 Telegram Desktop 也可以直接导出嫌疑账号数据,但是需要注意账号新登录官方版 telegram desktop 后尝试直接导出数据会提示需要等待24小时,并且该操作会向其他登录会话发送提醒。也有其他第三方 telegram 专用取证软件可用,但一定注意提取范围不要设置过大,避免数据量过大触发服务端安全保护。
对于群聊数据遭到批量损毁的情况,若被控制账号有群聊管理员权限,可使用脚本导出群聊近期操作记录,如 https://gist.github.com/avivace/4eb547067e364d416c074b68502e0136
根据设备类型不同,也有第三方数据提取软件可用,如针对 Android 平台的多个取证软件,这些取证工具一般使用漏洞提升权限然后读取目标应用的私有数据,常见的被利用漏洞有 CVE-2024-0044(AOSP 框架漏洞,由 Meta Red Team X 及我报告)、CVE-2024-31317(AOSP 框架漏洞,由 Meta Red Team X 报告)、CVE-2024-4610(Arm GPU 驱动漏洞,影响除高通平台外大部分平台)及部分厂商如三星自己的漏洞等。取证公司仍在持续挖掘漏洞并转化为利用,如奇安信旗下盘古石取证团队近日宣布再次突破 Android 11 - Android 14 最新安全补丁提权:https://mp.weixin.qq.com/s/MorsW-Vx_Eb_WnqFtj_T5Q
部分设备可能存在设备管理 app 等,可能导致检材上的数据被擦除,可以使用漏洞对相关管理 app 进行禁用或无效化处理。除了传统的垂直提权漏洞,其他类型的漏洞也有可能被利用。本月 Android 安全补丁就修复了我发现的一个可使设备管理机制完全失效的漏洞 CVE-2024-43081,可能会被积极利用。
部分第三方系统存在额外安全保护机制,如设备闲置过指定时间后启动额外的数据保护机制如重启,应阻止设备休眠。
仅做备份处理,希望大家都用不到。
https://blog.canyie.top/2024/11/07/self-changing-data-type/
之前十月补丁分析没给出 CVE-2024-40676 这个漏洞的细节,原本以为可以安安静静当谜语人的,结果还挺多人对它挺感兴趣的,那顺便把之前分析的结果公开到博客上。准备以后抽空把之前挖的坑全填上。
另:总感觉我的博客浏览起来比其他博客更卡,有人有同样感觉的吗?似乎该花点时间再优化下体验了
最近认识了很多人 感谢各位大佬的引荐 才能让我认识这么多大佬
很多人认识我的第一句话是 “你好年轻” “还有这么年轻的研究员” 之类的
类似的话我已经听了六七年了 但是每过一年听 都有不一样的感觉
今年20岁了 现在更像一种怀念 怀念我真正年轻的时候
作为一名研究员 我发现过很多漏洞 用一年时间打进了全球前二十
但是我觉得论这些洞的巧妙程度 元反射是当之无愧的王
提出它的那一年我14岁 初二
没有现在这么多的知识积累 纯靠脑力 从最基本的逻辑出发 以子之矛攻子之盾 用最简单的方法击碎谷歌精心布局设下的防御
即使它根本就不是个安全漏洞 我也觉得它是我提出过的最好最有创造力的 exp
跟它相比 我后面写的东西挖的洞都一文不值
“天才”描述的是一个人有极强的“跳跃式”的理解能力和创造力
而“工匠精神”的“工匠”强调的是一个人追求技能的极致完美并付出行动去打磨它
两者的区别是 工匠的成长过程是重复的 线性的 而天才是非线性的
天才不需要多少知识储备就能抓住事物的本质并打破传统思维路径提出创新
这是天赋 是上天给的 后天补不了的 也是我永远都不可能再有的
所以“工匠精神”被传颂 被称赞 被学习 却没有人宣传“天才精神”让大家学习当天才的
自那以后 我再没有提出过如此精巧令人惊叹的创新
我怀念我的14岁 我怀念我没被禁锢的 真正年轻真正有活力的头脑
14岁 2018年
那一年 还没有疫情
那一年 《学猫叫》火遍大街小巷
那一年 我初二 现在大二
那一年 没有成就 没有作品 甚至连电脑都没有 只有一颗活跃的大脑
那一年 像是被灌输了无穷的青春活力的一年
那一年 只能留在回忆里 永远也回不去了
人类的有些反应是刻在大脑里的。
但是人们都不愿意说出来。因为说出来显得自己很不理智,不符合社会对一个成年人的期望。
理由,或者说借口,就是这样衍生出来的。说白了就是掩饰自己的原始欲望而已。
人们嘲笑胖猫是因为胖猫抢了自己的饭碗,或者胖猫投河污染了自己的水源吗?
人们嘲笑胖猫是因为想。
这里胖猫只是个符号而已,什么符号?被嘲笑的符号。至于胖猫自己到底是谁干了啥已经不重要了。有瓜不吃不嘲笑就失去了这两个字的意义。
中文互联网流行给别人名字冠上牢字辈。不知道胖猫有没有获此殊荣。
你小时候哭,家长有的时候会哄你,等你长大了再哭,家长就会教育你“大丈夫流血不流泪”。
他们是希望你用流血代替流泪吗?他们是不耐烦你不想看你哭。
要是小孩真的去用流血代替流泪,用自残发泄情绪,他们就会求你别这样干了让你想想你的父母。
别问我怎么知道的。
把人类历史往前推百万年也一样。
生活在四百万年前的南方古猿,或者现在流行叫吗喽,能繁殖延续这么久,难道是为了保护生态圈防止种族灭绝吗?
吗喽繁殖是因为想。繁殖了它就爽。
想体验一把吗喽的原始快乐怎么办?
有一个网上流传的方法,找个甜的橙子洗干净,去浴室,关门,开热水淋浴,直到把全身都打湿,直到浴室里充满蒸腾的水汽。
这个时候咬一口橙子。
品就好了,不需要全吃下去,让汁水从嘴边混着热水流下去也行的。
没条件试的可以上 b 站搜“洗澡吃橙子”,赛博体验一下。
你看,事情就这么简单。刻在基因里的想。
其他什么理由什么借口都只是人类文明给生物本能加上的华丽修辞。
说好听点叫华丽,说难听点叫虚伪。
当然我也并不是什么好人。从吗喽继承过来的本能我也有呢。
人类的行为没有原因。也不是万事都需要原因。
生物学上的平等才是真正的平等。
感谢生物学,感谢进化论。
不过你要追究其原因,当然也是可以的。
从弗洛伊德的精神分析理论去看待,它可以被解释为“合理化”或者“压抑”的“防御机制”。
再更进一层,它可能是什么神经元什么神经递质层面的反应。
这样探究下去就无止境了。在有原因和没有原因之间反复横跳。
可惜我不懂这么高深的知识。我也没义务去给所有人做心理治疗。
偶然看见去年 Pwn2Own 上攻破小米 13 pro 的一个团队公开相关信息了,刚把 ppt 看完,觉得挺有意思的,不过最有意思的部分不是漏洞细节
演讲视频:https://www.youtube.com/watch?v=B0A8F_Izmj0&ab_channel=DEFCONConference
相关材料:https://github.com/Yogehi/cve-2024-4406-xiaomi13pro-exploit-files
省流:小米在 Pwn2Own 期间故意进行针对性干扰以阻止其产品被选手攻破,相关干扰措施仅在 Pwn2Own 期间生效,比赛结束后即被移除
其描述的相关细节让我觉得似曾相识。扩展阅读:https://xuanxuanblingbling.github.io/iot/2022/09/16/mi/
怎么说呢,鉴于小米产品在“各类黑客比赛上/期间”表现出“特别”突出的安全性,建议研究人员不要将小米产品作为目标
(长文预警)
2021年9月至12月5日,我刚满17岁,因学校强制要求实习,我和班上大部分刚满16岁的同学一起先后在两家电子厂当普工。第一家电子厂在河源,我只待了一个多星期,后跟随学校转场到另外一间位于东莞大朗的电子厂。
这间厂是造手机的代工厂,我在流水线上干了三个月,换了三间车间,每个车间代工不同品牌手机。
可能有人不知道流水线的工作是咋样的,大概就是每个工位只负责做自己固定的任务,比如装摄像头等,装完传给下一个。所有操作都被标准化规定好,工位上还有标准作业程序(简称 SOP)。我进的厂入职还有考试,内容就是防静电操作等。我上班的厂给每个工位都配备了凳子,但是我基本上都是站着干活,因为坐着根本干不过来。然后还有 IPQC 和 FQC 负责监督你干活还有干活的质量。
流水线在工厂里叫“拉”,相应的“线长”就叫“拉长”。两班倒(除部分车间),七点四十五之前要到车间,有几率要站那里听车间主任或者拉长开会。然后八点正式开始干活。每天的任务不同,一般一条线一天要下 1000 至 2000 台手机。(这里不用“生产”是因为厂里除了组装线还有测试线、包装线以及测包线)
下班时间看你干活的速度,早上八点上班的话基本上都是晚上九点左右下班。中午和下午各有一个小时吃饭时间,但实际上还有一个叫做“连班”的东西,即下午的班跟晚上的班连着上,中间不给你休息时间也就不用想吃饭。我三个车间的工作都在拉尾所以基本上是最晚下班的,工作时间最长的一次是早上七点四十五上班,晚上十一点二十下班,而且还是连班,晚饭都没吃。休假更是不用想,宣称是单休但实际上连单休都难。中秋节放了一天假就把当周周日的休假取消补回来。其他大部分时候周日也放不了假。国庆放假三天应该是最长的假期。不过也是放过一次双休的,是因为工厂没货干不了活。
至于工资,作为一名光荣的学生工,我们光荣地在东莞这种被广州和深圳夹着的地方获得了高达 9.5 元人民币的时薪。问车间其他员工也大部分表示是 11 至 13 元左右。我知道我该得的工资肯定有一部分进了别人手上。第一个月发了2800,第二个月发了3800,第三个月3500,12月在厂里干了三个晚上给我发了58块钱(不过忘记是不是因为其他因素扣款了)。
我待过的三个车间里绝大部分都是像我这样的未成年学生工。全国各地的都有,最远的见过四川过来的。厂门口有个篮球场,接学生工过来的大巴就停在旁边的路上。我离开的前几天路过那里,都还能看见大巴车跟新来的学生。至于为什么,可能是因为学生好骗好管还不用开太多工资吧。
在厂里工作的三个月,我的感觉就是麻木。每天的生活就是宿舍-食堂-车间,没有时间也没有力气再去干别的什么事。三个月出厂的次数估计不超过十次,唯一的一次双休还因为我头晕而在床上度过。偶尔出去一次,看着厂门口的广告牌写着“诚招普工,单休,月工资6000-8000”就觉得好笑。厂的位置在东莞松山湖,离华为东莞总部只有三四公里,很接近深圳,在天上每天都能看见飞机。可是与我无关。
我到现在还记得工厂里的防静电要求,静电服、静电环、手指套、离子风机样样俱全,酒精上还印着 RoHS 标,虽然上班一个小时之后手指套基本上就破完了,然后就是手指肉去生碰机子,每天下班手指头上都是血。
厂里让我印象深刻的有两件事:
1.12月3号我干活的时候对面工位的同事在纸上给我写了一个 qq 号,但是我在干活暂时没理他,他就把纸条扔进了垃圾桶。我胆小,没敢说话,原本想着4号还能再问问的,结果因为我们学校的学生全部5号走,整个车间4号直接停了。我没能看见他给我留的 qq 号,没能知道他的名字,也再不会有机会见他一面或者跟他聊天了。我其实还记得当年几个拉长还有几个同事的名字,但我这辈子应该也没有机会再见一次他们了。
2.某次我跟其他几个人一起干 MMI 测试,我旁边是个看起来比我还小的小姑娘,她问我为什么有台机子重测了几遍都测不过,我看了一眼上面显示 fingerprint sensor fail 之类的英文,跟她说打个不良标放着,报表上记个不良品,指纹传感器有问题。然后她特别惊奇地跟我说,你看得懂英文?你看得懂英文为什么会在这里?那一瞬间我的心里五味杂陈。
那三个月我甚至不知道我是怎么活下来的。说不定是每天干活能流血感受疼痛还能让我保持点清醒吧,毕竟我现在也经常自残看血流出来,哈哈哈。可能得归功于 lsp 群群友愿意陪我聊天吧。不过也物是人非。当年和我聊天的人里很多都销号了,我还记得的人里有个被某些自命清高的高雅人士逼退网了,有个因为癌症离世了。
三年过去,我也换身份了,从电子厂员工变回学生再变成 framework 开发者再变成安全研究员。我收到第一笔漏洞奖金的时候第一感觉是惊讶,然后就是在想,卧槽钱原来这么好赚,那我之前的日子,尤其是在电子厂那三个月,是不是都活到狗身上了。我是个小县城长大的孩子,不开玩笑地说,那笔钱直接改变了我对钱的认知。到后面我以世界顶级研究员的身份受邀跟其他大佬见面,见到了之前我代工过的某手机品牌的公司的技术大佬。我特别戏谑地跟他们说,你知道吗,我给你们造过手机,然后解释原因。我们聊天的时候都是笑着的。
三年前,17岁的我是你们品牌代工厂流水线上的一个月工资3000的学生工。三年后,20岁的我用自己的努力和实力以受邀者的身份出现在这里,至少在这张桌子上,我和你们平起平坐。
我怎么活过来的,只有我知道。
哦对了,忘了提一点,当年我是拒了阿里的内推选择跟着学校去电子厂实习的。至于原因,家里人觉得杭州太远,不如跟着学校还安全点。
为电子厂拒阿里,这事我特么能吹一辈子。
我的感想就是人应该多去看看世界的另一部分人是怎么样的,增长下自己的见识。别像我一样在上海世贸大厦底下看着电梯要刷卡才能进去选择在一楼转圈消磨时间,转了几分钟才知道是要找人帮忙刷卡。
然后我去高德上搜了一下那个厂的评价,看起来没变多少。我当时住的是六人间改的八人间,据说厂里在建新宿舍,到时候住宿环境会更好。但是看今年的评论,似乎变成十二人间了。
据报告部分一加设备升级到 Android 15 后出现无法使用 Termux 的情况,相关进程被不明原因杀死。Termux 开发者表示禁用 phantom process killer 后问题仍然存在。有用户报告此问题影响 Magisk 导致无法在 Magisk app 内修补镜像。部分受影响设备安装最新的 ColorOS 更新后问题消失,但似乎仍有部分受影响设备尚未收到更新。
建议一加用户若收到 Android 15 更新且构建日期早于 2024 年 11 月 9 日,谨慎选择安装。若您已受该问题影响,请等待厂商发布更新。
参考:
https://old.reddit.com/r/termux/comments/1gks9mf/announcement_termux_broken_on_android_15_for/
https://github.com/termux/termux-app/issues/4219
https://github.com/topjohnwu/Magisk/issues/8553
版本代号为 Baklava 而非 W 开头,比往常提前了几个月。预计 2025 年将有两个大版本发布 1。
这一次版本代号重新回归到了 B 开始计数,可能是因为 Android 内部开发流程发生较大变更(project trunk stable?)所致 (来源:Mishaal Rahman 2)。作为 project trunk stable 的重要部分,aconfig / feature launch flags 的文档已经上传至 source.android.com 3。
简单刷上去试了一下,感觉 UI 更丑了,有一种没事强行整强调背景色的感觉…… 放了亮色和暗色模式的截图,感兴趣的可以看一下。
系统设置项被重新排列,把 Google 账户放到了第一位,About phone 被放到了中间,Accessibility 跟 Tips & support 放到了最底下…… 感觉让残疾人更难操作了。
Pixel 6 系内核从 5.10 升到了 6.1 好评,其他没感觉到什么大的变更,简单跑了一下梦境,一行代码不用改直接跑通,估计没啥大更改(也有可能是都没开?不过不太可能)
中国很多家庭会在家里供奉神明或者仙人,拜佛烧香。拜文曲星或者观音菩萨的多见,但是好像很少看见有人拜阎王的。可能是觉得跟死亡沾边不吉利,但是清明节去上坟烧香的又不少。另一种解释是拜佛上香火是为了向神明表明自己的虔诚以祈求庇护,而阎王的形象让人感觉拜了也不会得到庇护。民间流传的阎罗王殿贴着的对联有多个不同版本,在这里挑几副供大家欣赏:
“上联:阳世人间,为非作歹任凭你;
下联:阴曹地府,古往今来放过谁?
横批:正要抓你”
“上联:能耐再大,到这里休得施展;
下联:冤深似海,非此处哪能分明?
横批:你可来了”
传说十殿阎罗的第五位是大名鼎鼎的铁面无私包青天,从这里也可以看出人们认为阎王的形象是处罚坏人的,即“惩恶”,而像“扬善”这样的活就交给慈悲为怀的菩萨。朴素的贫苦大众相信恶人无论在阳世间多有钱有权,在另一个世界都会被用油锅烙铁案板屠刀各种刑罚好好对待。但是拜铁面无私的执法者并不能直接给自己带来好处,有限的香火不如供奉其他神明。大家心里是希望好人得到好报而坏人得到坏报的,但在两者之间权衡,似乎让自己得到好处更优先。如果负责“扬善”的神明只需要人用香火去供奉就会给那人以好处,那这“扬”的,还是“善”吗?这样看来,负责“惩恶”的神明又显得有点可怜了。
以上文字写于某位友人离世一周年之际。终于赶在凌晨零点之前发出来了。其实我还想设定时消息,但是 telegram 定时消息有很大延迟。
写到一半才想起来,刚好昨天也是另一位熟人离世一周年。之所以说是熟人,是因为我和她直接接触很少。但她关注了我的某个频道,所以我记着。我也经常偷偷的去看她的频道,但是没关注。
传说中的阎罗王是绝对公平绝对正义的吧,我希望是这样。
我常幻想没有我的日子里,或者说我还不存在和我不会再存在的日子里,的故事。我作为看客,静静地看着斗转星移春去秋来。但我恐怕很害怕看见幸福结尾。我仍想抓住世间事物的一点点痕迹,但我只能看着没续费的博客随着时间的推移不再可以访问,看着太久没登录的账号被注销。看着人来,目送人远去。只是目送。
一直有人想知道我的“成长路径”是啥样的 这里随便写点东西
我出生在一个广东的小县城,简单来说就是穷地方,gdp 在全省是倒数的。小时候就对计算机很感兴趣,四年级的时候学校开了电脑兴趣班,本来因为是教编程就报了,去了之后才发现是教用 flash 画画。四年级的时候身体经常不舒服,后来才知道这个叫躯体化症状,五年级的时候更严重了,从那个时候开始就很少去上学了,初中休学一年但是复学之后也没怎么上学,一直到我上中专。所以我在义务教育阶段有五六年的时间都是没正常上学的。这就是我为什么没参加中考。
除了去看病(包括住院)之外,剩下的时间我一般就是在家待着。我本来就对游戏没什么兴趣(事实上我到现在都没玩过什么流行游戏,什么王者荣耀什么吃鸡我都没玩过),在家待着也挺无聊的,干脆学一下自己一直很感兴趣的做软件(后面才知道有个术语叫编程)。
那个时候我只有一台手机,我还记得型号,是酷派的 Y80d,安卓4.4,家里人只有每天下午到晚上会给我手机,没有电脑。在网上闲逛的时候发现了一个叫做 iapp 的软件,那个时候还是 1.x 的版本,能自己在手机编个小软件出来,然后就喜欢上了,开始学。它支持可视化设计 app 的界面,可以直接点点点然后就可以拖一个按钮出来,用的是自己发明的一个脚本语言,难度不大,语法非常奇怪,但是有判断循环这种简单结构,然后我就这样打包出了第一个 app,然后我发出去别人就能直接安装使用了。我第一次发现原来做个软件这么简单,说真的它很大程度上激发了我的热情,然后我就开始玩了起来。那个时候我最不缺的就是时间。你问我为什么不去学易语言?因为我没电脑。
后面想学点正经的,学了点 js 跟 lua,现在已经完全忘光了,后面觉得还是学 java 好。正好手机上也有个能用 java 编 android app 的软件,叫 aide,然后就学起来了。说实话我不是个聪明的孩子,我当年学 java 耗费了很长的时间,难以理解类跟对象的概念以及它到底有什么用。后面我选择不看什么入门教程了,直接去贴吧找了个简单的项目打开硬生生啃,我也忘记了多久,突然就像开窍了一样,然后算是终于过了 java 这关,然后进入真正的 android app 开发环节。
然后后面我又写腻了,我不知道该写什么项目玩,看着各位大神博客都是分析系统源码,看起来好像也不难的样子,那就开始看这块吧,想到什么地方看什么地方。我英语不好,但是官方的 api 文档都是英文的,很多时候去看文档不开翻译器看不懂,干脆直接去看系统源码,有些时候反而还容易理解一些。那个时候 android 很火的技术就是插件化,热修复,kotlin 什么的,kotlin 我在手机上玩不了,就从其他两项入手自己玩玩。
然后我还是不知道干啥,我觉得自己基础的都会了,但是自己搓的东西跟别人开源的库根本比不了。客户端技术实在是变化太快了,后面流行什么 databinding,还有 ReactNative 跨平台这些,我只有个手机根本就没法玩。(这里加一句,当年写跨平台的公众号现在都开始发鸿蒙开发了,可见当年跨平台搞得到底怎么样。)我那个时候很浮躁,很想搞点大名堂,像 weishu 的 VirtualXposed 那样,但是又不知道干啥。一直到后面 android 9.0 测试版,引入了 hidden api 限制,对我个玩插件化的人来说简直是晴天霹雳,然后赶快去网上搜相关文章。刚好 weishu 也发了个博客,分析 art 源码去绕过,看完之后觉得其实也没那么难,然后自己也提成了两个绕过方法,但是只有一台安卓5.1的手机没法测试,后面还是去找了个群友才验证成功。
上面的经历让我敢于尝试去搞搞 art 相关的,看 weishu 的 VirtualXposed 搞得那么厉害,我也想搞一个玩玩。非常感谢 weishu 以及 YAHFA、SandHook、FastHook 的作者,你们的文章带领我进入了 art 的世界。后面我终于有了一台能跑 android studio 的电脑,终于可以写 c++ 了,然后就边写边在模拟器上测试,终于整出来一个勉强能用的东西,我管这个项目叫梦境。
后面在某个群里碰到了一位老板找人付费写代码,我接了下来,几十分钟写完拿了1000块的报酬。这是我自认为的真正意义上的第一桶金,我拿着这笔钱找我妈说我想买个二手手机(我钱在 qq 上,没银行卡转不去其他地方),然后在淘宝买了个华强北 pixel 3,终于把那部装不了微信的手机换了下来。这是我真正的靠自己买到的第一个想要的东西。我都还记得我第一次摸到 Google 亲儿子,第一次看见运行原生安卓的手机,第一次见到 type c 充电口,用卖家送的充电线充电的兴奋感。
到了中考,班主任问我去不去,我选择直接放弃报名。我的义务教育阶段结束了。但是我家很想让我继续读书,上个电大也行,去找县里的中职被拒了,最后联系到一家市里的民办中职。那个暑假我在网上查什么是中等职业学校,搜到了中职生也是有自己的升学渠道的,突然我就又想升上来大学看看究竟是什么样的了。我第一次去市里上学,第一次吃食堂,第一次住集体宿舍。可能因为课程比较简单压力很小,我竟然能坚持上这个学,竟然真的为了升学准备文化课。我的上学生活又开始了。那个时候还在开发 EdXposed 的西大师和 ksm 找到我讨论 art 相关的问题,后面他们创立了 LSPosed,把我也拉进去了。
后面就是无聊的日常。中专二年级学校强制要求送人进厂实习,在电子厂打工真的是个折磨,我想做点自己喜欢的东西,然后我开始给 magisk 提交 pr。然后折腾折腾就变成了 collaborator。
从电子厂回来之后就是上学,考完高职高考之后学校又想送我进厂,我直接玩消失。去了个小公司搞 android framework,也是变成自己小时候梦寐以求的系统开发工程师了。到开学的时候了,踏进了大学的校门,我变成了一个本科在读生。
在学校里就没经济来源了,我想经济独立。想起来搞之前上班的时候发现过漏洞,也开始无聊翻源码希望有收获。一开始我只是翻着无聊玩的,结果后面发现他们给的实在是太多了,就开始投入更多时间精力搞这块。一年下来也算有点收获,在全球的排行榜上排个前十几,不算亏。
这就是故事的全部。你可以发现我对未来没什么计划。我不是一个聪明的孩子,我要是聪明的话就学 OI 打比赛去了,感谢上天愿意赐我一条生路。我也不是一个擅长预测风口的人,电商网购直播短视频等等风口我一个都没预料到,我做事纯凭兴趣,小时候看着 kingroot 觉得很厉害也想搞的小孩也不会想到长大之后是这样。现在回过头来看,我可能应该开个公众号,把人引流过去,然后接广告或者开知识星球来变现,再或者去视频平台投个《20岁谷歌认证世界顶级研究员的一天是什么样的》给自己出道。不过我最后还是没干就是了。
然后我随便总结了点经验:
0. 有些东西没想象中那么难 不试试怎么知道
2025 了,首先祝大家新年快乐哈
今年发生了挺多事情的,感觉脑袋快烧了,感谢大家一年的陪伴
上学是真没意思,要干的活还多
今年抽了点课外时间花在 android 安全上,做了一点点微薄的贡献,现在勉强在 Android Program 排行榜上排了个第 10 名,整个 Google BugHunters 平台第 55 名。今年 3 月之前排名还是 N/A,感谢各位大佬的谦让哈,让我这种无名小卒也能参与这种大项目
本来今天想把 2024 年度排名一起发出来的,结果到现在都还没刷新下来,等它出来了再发吧
我心里知道我跟真正的大佬还是没法比,Chrome VRP 一给就是三万刀五万刀,我个只玩 Android VRP 的怎么比,没办法
今年十二月的 swag 也没拿到
我不会忘记我的出身,也感谢大家这一年的支持,学到很多,感谢给我这个机会去给一个操作系统安全添砖加瓦
郭德纲有句话很有名,“江山父老能容我,不使人间造孽钱”,我想在后面加一句,“心中自有青天在,愿行千山不染尘”
再次感谢大家支持哈,要滚回去复习了,考试快挂了
P.S. 这段文字是提前写好的,本来想留时间出来复习的,真的到元旦了发现自己一点都不想碰学校课程。新的一年第一天请大家吃预制菜寓意一年遇见智慧的人(
https://android.googlesource.com/platform/frameworks/base/+/2ce74e2d84777657f11b5cbabc501e6d79c86337
翻了一下连 15 都没进
估计最多活了一个测试版
没啥用 发出来给大家乐呵乐呵
昔日 Mismatch 今犹在,不见当年 PDD
看着换对联,贴福字,摆灶神,搞卫生,心里没有一点波澜,手机上 app 的红色新年活动页面也懒得点开,还记得很久以前花一堆时间刷 qq 红包跟支付宝集五福,现在只觉得闹心,还不如去领红包封面
下午出去街上逛了一圈,虽然有点心理预期(县城人过年一般晚上才出来散步),冷清程度让我怀疑是不是回到了2020年疫情封城那个时候,紧闭的商铺大门,偶尔能看见贴着福字,旁边一个满满的垃圾桶,最顶上的是刚撕下来的福字对联,偶尔从遥远处传来一两声烟花爆竹爆炸的声音,对比出一种荒谬感,跟小时候记忆里的景象没有一点关联
可能长大了感觉不同吧,小时候期盼家人团聚,现在只觉得团聚了也是听吵架没意义。看我妹也只是拿着手机刷了一天抖音,跟其他不用上学的日子没有任何不同。
今年这节日不如改名叫 DeepSeek 节,给我的触动还不如我妹在我面前外放奶龙带来的感觉大
我浪费生命 我好
有没有人教一下怎么高效、稳定、节能、可持续地浪费生命
指开学了还能继续躺着啥也不干
如果你有一些欠你钱不还的青少年朋友 可以这个时候试试催
一般来说这个时候他们该收的压岁钱都收完了 而该奢侈花的钱还没来得及花出去
比如 CVE-2024-31318 这个漏洞
刚开始知道评了 high severity 的时候还挺开心的 那个时候是纯小白
结果后面才知道类似洞可以评 critical
(CVE-2024-31320 给了 critical)
然后过了一年之后才又有勉强能摸着 critical 边的洞 CVE-2025-0100
影响是可以用户无授权录制设备屏幕
应该也是最开始评的 critical 满足降级规则被降成 high
下一个不知道是什么时候了
我还想拿 CVE-2025-0001 这种数字的 比较有纪念意义 又得等一年才能碰运气了
(你不如拿个 114514 更有纪念意义)
原理很简单,用户通过支付宝做了特定操作之后,第二天蚂蚁森林会产生特定数值的能量球
比如通过支付宝网购火车票会产生 136g 能量,购买电影票会产生 180g 能量,每天运动则会根据步数产生 0~296g 不等的能量
所以可以根据好友的蚂蚁森林能量球上的数值大概猜测前一天干了什么 不过实际利用效果受各种因素限制 比如如果对方提前把能量全收了你就看不见了
(以前用过这个方法猜测了一个没给我开放步数权限的朋友的一天运动量 别问我为啥)
如果对隐私实在在意的 可以在支付宝蚂蚁森林设置里关掉“向好友展示能量球数值”
如果有人想知道 取证人员都能提取出什么数据的话 可以看一下这个 虽然不是真实环境
https://mp.weixin.qq.com/s/Mjuv81xJ1SVc0Pte-0eHQA
搜了一下发现这家搞的有意思的东西还挺多的:
推销自己的工具,可以实现“三星、华为、OPPO、VIVO、小米、魅族、锤子、美图、360、努比亚、金立、乐视、海信、朵唯等国内外300余个品牌、数千款机型的锁屏密码破解与镜像获取。针对安卓2.0至10.0均有专业的锁屏密码绕过,权限获取(ROOT)方案、手机全盘加密及文件加密的密码绕过方案”,且不会导致“数据丢失或触发恢复出厂”
https://mp.weixin.qq.com/s/l2ciZrOBc8HMGu1hSgZ6DQ
(这里有提到华为 FDE 机型提到权限之后可以直接导出全部数据,这个我之前也做过一点分析,可以看 https://t.me/CanyieChannel/83 )
OPPO 手机恢复出厂后残留数据取证
https://mp.weixin.qq.com/s/hJVbCmsFkWlLLtmbJGbJBw
爆破华为隐私空间密码
https://mp.weixin.qq.com/s/bs7nMsiWw-F753kPUxOfWg
其他厂商活也挺多的:
取证厂商五五安科表示自己支持“OPPO、VIVO FBE 机型绕过屏幕锁定密码提取文件系统”,“搭载部分芯片的 FBE 设备计算锁屏密码”(虽然这个在群里面发过但不妨再发一次)
https://mp.weixin.qq.com/s/XUpeMM7cJO7GVN0uEhNCIA
上网冲浪的时候无意间刷到了初中时候的自己原创的笑话
老个毛线 医生让住院都让住儿少科
1 | public static String getFileLocation(Class<?> cls) { |
需要关闭 hidden api 限制
只在 Android 12 上测试过
清晨八点多,你从睡梦中自然醒来。
这一夜你睡得很好,没有在三四点的时候睁眼望着天花板,也没有往常早晨醒来时的疲惫感。
昨晚刚下了一场雨,植物的叶片还挂着水滴,清晨的阳光从窗外透进来,照得你浑身暖洋洋的。你知道,冬天已经过去了。
身体传来的不是躯体化带来的疼痛或疲惫,而是少见的饥饿感。
洗漱完出门,早餐店的叔叔阿姨早已经开始了一天的忙碌。你点了往常最爱吃的肉包,鲜嫩的肉汁在你嘴里绽放。你好久好久没有细细地品味过你最爱吃的东西了。
眼前的世界是真实的,笼罩在眼前似有似无的黑幕已经消散,灵魂重新匹配身体,而身体又实实在在地触摸着世界,路边的红绿灯再也不会在视野里突然消失。
你看见一片还带着露珠的叶子,翠绿的颜色,水珠反射着太阳的光芒。你感觉它焕发着生命的气息。你喜欢它。你可以没来由地喜欢一件事物。
你突然觉得其实有些事情也没有那么难做。好像有好多事情一直放在 TODO list 里,打扫房间、跟许久不见的朋友一起逛街,或是去听曾经很喜欢的歌手的演唱会。有空可以清理一下 TODO 了,你想。
从这一天开始,你内心的刑期悄然结束了。夜晚,你不再辗转反侧,也不会凌晨三点醒来。你开始对事物产生兴趣,重新有了自己喜欢的东西。你慢慢停掉了药物。不知道持续了多少时间的冬天自己过去了,春天自己会来。
转发自 https://t.me/cxplayworld/4481
如果你用 Telegram, 以防你不知道有人已经索引了所有人在公开群组和频道的发言记录了.
打开机器人选择语言后发送 /me 命令查询, 选择菜单里的 Groups 或者 Channels 就能看到喽.
转发自 https://t.me/qingmingjian123/295
https://github.com/bron1e/clash-verge-rev-privilege-escalation-poc
Clash Verge Rev默认强制安装系统服务(Clash Verge Service),并通过未授权 HTTP API /start_clash 暴露关键功能,允许本地用户提交任意 bin_path 参数,直接传递给服务进程执行,导致本地提权
影响范围:Clash Verge Rev<=v2.2.3(Windows/Linux/MacOS)
FlClash 似乎也受影响
https://github.com/chen08209/FlClash/issues/1131
据 Securelist 报道,部分电商平台上存在假冒手机,其固件内置木马,可执行各种针对性的复杂攻击,包括但不限于盗取各大平台(Telegram、Instagram、Line、Skype、Tiktok、Facebook 等)账号、使用受害者 WhatsApp 账号发送任意消息、发送任意短信、将剪贴板内加密货币钱包地址替换为攻击者的地址等。
原文链接:https://securelist.com/triada-trojan-modules-analysis/116380/
中文翻译:https://mp.weixin.qq.com/s/itrYPTDKwoGBQPFF4_idHA
那就有个很好玩的事情了,这些假机子能过 play integrity 认证吗?
https://mp.weixin.qq.com/s/gxTkcmDtyFeZ42XkcpTeJg
AI 技术驱动的智能取证机器人,宣传称其可自动分析聊天记录并可自动标记敏感信息、智能统计涉案金额、串联证据链条等。
已于 6 月 5 日在 BCS2025 (北京网络安全大会)网络犯罪治理论坛上首发,预计 7 月底全面上线。
为什么每次这个频道发取证相关的东西都会有一堆我看不见的转发…?关注这频道的都什么成分(
既然大家喜欢的话那就再来一个:现在的取证技术很多是利用 USB 相关的漏洞解锁设备。Android 12 开始其实支持从软件层面禁用 USB 数据信号传输(需要 HAL 支持),但是系统里并没有开关给你操作,只有手动进入 lockdown mode 或在 Advanced Protection mode 启用时锁定设备 1 时会阻断 USB 连接。
相关 API 其实是已经暴露出来了,可供设备管理应用使用 2。可以下载安装 TestDPC 然后使用 adb 将其配置为 device owner 或 organization-owned profile owner,之后就可以在 TestDPC 里找到 Enable USB data signaling 来手动开关它。
警告:在部分机型上激活设备管理员可能存在风险 3,禁用 USB 后无法使用基于 USB 的 adb,若设备后续变砖可能严重影响救砖能力,请谨慎考虑。
疑似 Google 大手子开始云控发力,通过 Google Play 服务远程开关设备配置,手上的 Pixel 6a Android 16 已经是默认开启状态,另一台跑着 Android 14 的一加机子也是已经打开但不知道为何 global_kill_switch 是 true,实测 SDK 相关功能是能正常用的,不知道为啥
命令:
1 | adb shell device_config get adservices disable_sdk_sandbox |
欢迎大家把自己设备的结果晒在评论区
时隔四年再次来到东莞,感谢华为邀请,身份从流水线工人变成受邀嘉宾,终于能进来这个曾经没机会来的地方看看
华为园区真的很漂亮,所有照片都是原图直出,既饱眼福又饱口福
这两天东莞本来下雨的,我们一到松山湖雨就停了,连续两天都是这样,感谢天公作美让我有机会看看美景
就是可惜华为小火车没坐到,一查才知道在溪流背坡村,三丫坡没有,看看明年能不能补上这个遗憾
哦对了 还被人线下认出来了
坐在椅子上旁边突然有人问“哎你是残页吧 我关注了你频道看见过你照片”
下次再也不敢发照片了
https://taptrap.click/
利用 activity 跳转动画劫持,CVE-2021-0339 再现,只不过这次是用透明度
https://nvd.nist.gov/vuln/detail/cve-2021-0339
https://android.googlesource.com/platform/frameworks/base/+/36bcc77337814d4d36e2b10eb062ac417d91611e
其实我们之前也报过一个手法可以让用户误触某些按钮,之前搞了个直接恢复出厂设置清除用户所有数据的 poc 当漏洞报上去,经过了半年的审核给我 wontfix 了。
如果有人感兴趣的话我可以发出来给大家看看(
需要几百年才能降解,做的厚一点能重复利用很多次,但是大部分时候被使用一次就被当成垃圾扔掉了
古代人用竹子、梅花啥的象征坚韧不屈的精神,我觉得是因为古代没有塑料,否则应该会出现一堆《咏塑料》之类的诗歌
这么坚韧的东西却只需要几分钱几毛钱就能买到,大部分是作为一次性容器,用完就扔掉,说不定这些人类自己都不吃的东西还会进海洋里被某个幸运海洋生物吞进肚子里,然后还要因为人类的行为背上一个“污染环境”“毒害海洋生物”的骂名,真的好冤好可怜
所以我都倾向于使用能重复利用的东西,比如选择到店吃而不是点外卖,签器官捐献+遗体捐献志愿,用过的塑料袋留着拿来套垃圾桶之类的,真的完全用不上的快递箱之类的也完全舍不得扔
CVE-2025-31229:密码可能会被大声读出
https://support.apple.com/en-us/124147
这个功能附带一个 UI ,可以用
1 | adb shell am start -n com.android.devicediagnostics/.MainActivity |
拉起来,然后使用另一台设备通过二维码完成验证。有密钥认证担保,这才是它应该有的使用场景嘛
文档 https://source.android.com/docs/core/perf/trade-in-mode?hl=zh-cn#gather
另外这个页面还支持检测屏幕坏点和触控,把工厂流水线的 MMI app 功能复制过来了?这一套组合拳是为了方便转转上门收手机吗
“搭载 Android 16(或更高版本)的设备在启动时会进入以旧换新模式。在这种模式下,您可以使用 adb 连接到设备,并可以使用命令获取设备相关信息。”
很有意思的功能,换句话说,Android 16 设备恢复出厂设置后,在没有网络连接且未完成设置向导时,会允许 adb 连接并运行受限命令。注意这种情况不需要打开开发者选项,也不需要手动授权调试。
两层机制保证安全:
adb shell tradeinmode 命令。源码: https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/adb/daemon/tradeinmode.cpp;l=86在该模式下,运行 adb shell tradeinmode evaluate 可以进入评估模式,正常使用所有 adb 命令。进入评估模式会创建 /metadata/tradeinmode/wipe 文件,下次开机时 init 看见有这个文件会将设备恢复出厂设置以避免任何东西残留。
Android 终于开始修复我之前发现的一批和 SDK Sandbox 这个有趣的新功能相关的漏洞,9 月补丁里修复了两个,在这里放补丁链接抛砖引玉,各位大佬有什么新的想法欢迎和我交流下,不吝赐教
CVE-2025-48524 https://android.googlesource.com/platform/packages/modules/Wifi/+/298745e0cb23cbef631aff1977b284155384bbf0
CVE-2025-48545 https://android.googlesource.com/platform/frameworks/base/+/66ac17909252c80b0edf7f4ae282bce4579410ad
CVE-2024-34740,本地 app 提权至 system_server
https://github.com/michalbednarski/AbxOverflow
CVE-2024-49746,本地 app 提权至 system uid
https://github.com/michalbednarski/ThisSeemsWrong
CVE-2025-22441,本地 app 提权至 SystemUI(由于 PoC 使用了 WebView 因此无法注入进 Settings 等 system uid app)
https://github.com/michalbednarski/ResourcePoison
误触能造成的危害远不止授权设备管理员,如果误触授权无障碍,恶意应用可以立即显示悬浮窗遮盖界面、读取显示的内容并代替用户操作设备;授权录屏权限则可以立即开始录屏并启动各种聊天软件,首页显示的对话就会被包含进录屏里。
用户当然可以立即关机并且重启到安全模式来卸载恶意应用,但是已经造成的危害无法清除。人是不可能比机器快的。我给 Google 提过这个问题,Android ID 389091354,似乎 ECM 已经开始限制 device admin 授权,但不清楚他们是否会继续采取措施(我觉得合理的解决方案是打开页面时禁用激活按钮 1 秒确保用户看见了警告不会手抖再允许激活),有权限查看的人可以点进去看看
转发自 https://t.me/zaihuapd/36486
安全研究人员发现一种名为“像素劫持(Pixnapping)”的新型安卓攻击手段。该攻击通过恶意应用调用系统API,无需特殊权限即可读取其他应用显示的像素数据。攻击利用GPU侧信道技术,通过测量像素渲染时间推断屏幕内容,可窃取双重认证码、聊天消息等隐私信息。研究团队在谷歌Pixel 6至9和三星Galaxy S25设备上演示成功,部分设备攻击成功率超过50%。
谷歌已在9月安全公告中发布初步补丁,但研究人员称攻击改良版仍有效,预计12月将有额外修复。攻击每秒仅泄露0.6至2.1个像素,但足以威胁短期有效的2FA认证码。目前未发现实际利用案例,但突显了安卓安全机制的局限性。该技术基于2013年浏览器攻击,显示侧信道风险的持续性。
SDK Sandbox 被弃用。解决了“提权沙盒”这个问题本身
一直知道误触是黑产百试不爽的利用手段,但是事实证明各种我们没想到的攻击手段已经被他们玩出花了。
伪装成屏幕上的头发丝骗用户去碰,我着实没想到。
我比较关心的议题 1:快应用
快应用只需要点一下就能用,通过恶意 deeplink 可以让灰黑产点一下就把用户的手机变成广告蛊场,用户手忙脚乱之下只会打开更多一连串的难以关闭的快应用
议题 2:透明桌面小组件(app widget)
恶意应用诱骗用户添加一开始看似正常的小组件,随后将其设置成透明以防止被用户发现,并利用小组件的特性实现保活、后台弹广告等一系列灰黑产行为
我之前也注意到过小组件的滥用潜力,也报过一些相关漏洞(CVE-2024-43762),但对于 Google 认为没有“安全影响”的问题无可奈何。只能希望未来的 Android 版本能做出进一步限制。
现场视频: https://www.bilibili.com/video/BV19DxFzBE4L
议题 3:多个厂商的 TA 实现不当,存在多种漏洞将 authtoken 暴露给不可信方,导致可被暴力破解手机 PIN 码
同时演讲者演示了在一台刚开机还未输入过密码解锁(即处于所谓的 Before-First-Unlock,BFU 状态,data 分区还未解密)的设备上成功爆破 PIN 码
演讲者也提到这种攻击技术可能已在被取证公司利用
2025年了,activity 生命周期 api 还能出问题,离谱,难道这个功能到现在都没有任何一个人用过吗?
https://android-review.googlesource.com/c/platform/frameworks/base/+/3826768
奖池还在累计
https://android-review.googlesource.com/c/platform/frameworks/base/+/3563923
前段时间跑了三次某国际银行想要开一个内地账户,跑了三次被拒了三次。在我已经有该银行香港地区需要资产门槛才能开贵宾账户的情况下。理由是我是学生,建议等我毕业工作之后再尝试。我说我现在确实是学生,但我有自己的收入来源还纳税,现在已经能养活自己了,为什么非得等到有工作了才能开?如果我毕业之后是自由职业者怎么办?银行的回复把我气笑了:“那不是相当于您这个大学白读了吗,相信自己肯定能找到工作的”。
我只感觉这个世界是如此的荒唐,死的规则把我和所有规则考虑不到的活着的人拦在门外。
被规则忘记的不仅是我。回想起陪同残疾人出行时遇到的种种不便。很多城市进行基础建设的时候就完全没有考虑到残障人士的出行需求,比如早期修建的很多地铁的无障碍电梯是直接连通站厅非付费区和站台(付费区)的,为了防止逃票这些电梯平时是关闭的,有人需要的时候由同行人拿着行李过安检,拿着交通卡去闸机刷卡但不入闸,然后呼叫工作人员打开电梯,然后下到站台乘车。如果目的地也是采用这种设计就需要反着再来一遍。这算是历史遗留问题没办法解决可以理解,但是还有很多城市道路也难以让残障人士通过,比如盲道上的石墩子,只有楼梯可通行还没有扶手的道路,还有坡度大到只能给电瓶车通过的坡。我觉得这就是纯粹的态度问题了。以我带着一个需要使用助行器的人的体验而言,遇到楼梯时我需要拿着他的助行器,然后把我的手或者肩给他当扶手,让他上去之后再把助行器放到地上让他扶。对我们而言再平常不过的道路对他们而言可能是足以致命的陷阱。可能没有经历过这些的人很难理解残障人士的出行困境,高德地图在设置里可以开启无障碍模式(可能很少人知道这个功能,其实不止高德地图,像小红书也是专门适配过无障碍浏览的,为所有付出行动优化体验的软件点赞),然后随便点个附近的目标点尝试导航,看看会收获多少次“无法避开台阶路段”的提示。所以很多时候我们宁愿选择打车。中国有约 8500 万残疾人,除去外表上看不出来的残疾类型,为什么我们日常很少见到残疾人?我想这就是一大原因。媒体报道的残疾人一般都被冠以『坚强』『乐观』这些形容词,但抛开这些与性格相关的形容词,他们不过是受限的普通人。『坚强』是我的优点,但是『不坚强』也不该成为被排除的理由。
这种困境不仅仅局限于残障人士。年老,意外受伤,推婴儿车,甚至只是拉着大行李箱,都会让一个『普通人』对无障碍设施的需求瞬间变得迫切。
多数人的幸福支撑社会的繁荣,少数人的境遇映照社会的温度。虽然我很讨厌『少数群体』这几个字,但是我拙劣的语文水平确实想不出其他的话了。很多人讨厌『少数群体』这个表述是持着“别人都行为什么就你不行”这种想法想让所有人都强行融进自己的框架里,我认为这种忽视个体差异和客观需求的想法无异于把需要时间破茧成蝶才能飞的毛毛虫放进本来就会飞的鸟群里。
最后附上去年缴税的证明,证明下我有经济能力。
转发自 https://t.me/androidMalware/2734
One of top-selling digital picture frames from Amazon’s between March and April 2025 comes:
原来世界上还有数码相框这种设备
经常在各种地方看见精简系统软件的教程或者“去除了系统中不必要组件的精简版 ROM”,这边提醒一下,我个人是不建议随意动系统组件的,即使它看起来完全没用
举个例子,com.android.companiondevicemanager 这个 app 用来在配对配套设备(如手表)的时候弹对话框,似乎对没有外设的用户没用,但在安卓 12 及以上移除这个 app 会造成可以导致电话、联系人、短信、日历、读取通知、控制通话等多个敏感权限被自动授权给恶意软件的严重安全漏洞
有些“教程”的理由是移除一些非必须的 app 可以减少攻击面,让其中可能存在的安全漏洞变得无法被利用。我是觉得不如买手机的时候选个代码质量好然后安全更新频繁的厂商
话说有没有人知道是否真的有什么精简版 ROM 把 com.android.companiondevicemanager 删了?
用户想自测的可以跑一下
1 | pm path com.android.companiondevicemanager |
看看有没有输出
https://www.youtube.com/watch?v=7fGB-hjc2Gc
bilibili: https://www.bilibili.com/video/BV1xYUtB5Evr
感谢群友让我蹭名字
https://blackhat.com/asia-26/briefings/schedule/speakers.html#songzhou-shi-51645
关于最近流传的 Android 16 0 click RCE + 反弹 root shell 的视频
乍一看很唬人 仔细看越看越假 严重怀疑打印出来的内容是 AI 生成的
我把几个我看见的不合理的点列出来
如果一个视频就能卖四百万刀,那我也来发一个演示,拿 root shell + 禁用 selinux,免费公开 exp 源码,保证真实,可以自己跑一遍确认真的拿到了 root shell
1 | #!/system/bin/sh |
需要 magisk
效果:无用户交互自动授权读写联系人、短信、日程、通话记录和语音信箱,拨打电话或接听来电,操纵通话设置,发送通知,读取并操作其他应用发送的通知,控制附近设备,录制声音,读取设备唯一标识符,和绕过后台执行限制。
录屏:https://github.com/canyie/CVE-2024-23700/blob/main/screen-20260120-233400-1768923180588.mp4
漏洞评级(Severity):Critical 最高/严重
PoC 代码:https://github.com/canyie/CVE-2024-23700
下载编译好的 apk:https://github.com/canyie/CVE-2024-23700/releases
和视频里的版本相比优化了几个细节:
视频里尝试提升权限时会有一闪而过的白屏,比较容易被注意到,进行了优化,让利用更隐蔽
支持了静默自动获取录音权限,需要 Android 14+
添加了一个拨号按钮,提权之后可以无用户交互拨打电话,确保提到的权限真的能用
提供的测试 app 在绝大部分设备上都无法安装。如果在你的设备上安装失败,是正常的,说明它目前不受影响(但是你后面又刷了其他 ROM 或者开了什么模块就不一定了)。
后续:去医院治了胃病之后好了 现在变成吃多少都吃不饱了
跟我有一样体验(吃什么都嫌多)的人可以去医院测个幽门螺旋杆菌
https://blog.r0rt1z2.com/posts/exploiting-mediatek-datwo/
分析/审计 kotlin 代码是一种折磨 一种灾难
就算我哪怕知道把它分析完就能拿 $7000 USD 的漏洞奖金 我也完全提不起一丝看它的兴趣
一个语言能设计成这种毫无设计哲学全是语法糖推崇写以后不用 review 的一次性代码的样子也是一般人做不到的
我很想知道让写出 kotlin 一次性代码的人过几年让他自己读能不能读懂
我丝毫不怀疑把 kotlin 代码编译完再反编译成 java 都比读原代码有可读性
我还记得 Android 7.0 的时候 Google 宣布引进 Kotlin 作为正统 Android 开发语言时我的激动之情 那时我还在用手机写代码 期望它能解决 java 的一系列问题
现在我拒绝 kotlin 出现在我项目里的任何地方 包括依赖和编译脚本 当年期望有多大现在失望就有多大
Your community 小页页的胡言乱语 was blocked for violations of the Telegram Terms of Service (https://telegram.org/tos) based on user reports confirmed by our moderators.
Thank you! Your appeal has been successfully submitted. Our team’s supervisors will check it as soon as possible. (No more response)
我是 2025 年 Android VRP 冠军!点这里看我的名字: https://bughunters.google.com/blog/google-vrps-in-review-2025#android-devices
最后更新时间:2026/03/18 更新内容:哼哼啊啊啊啊啊啊啊啊
在野利用漏洞:CVE-2026-21385
CVE-2026-0047 EoP Critical
只影响 16-qpr2 的漏洞。截至发稿,漏洞补丁未公开。漏洞描述:
In dumpBitmapsProto of ActivityManagerService.java, there is a possible way for an app to access private information due to a missing permission check. This could lead to local escalation of privilege with no additional execution privileges needed. User interaction is not needed for exploitation.
根据已经公开的 16 QPR2 源码,可以很明显地看出来提交 https://cs.android.com/android/_/android/platform/frameworks/base/+/0ebd869c069fb58671b947955be1e67241783d73 在 activity manager 引入了 dumpBitmapsProto 这个 aidl 调用,可以获得系统里面正在运行的所有 java 进程里的所有 bitmap 数据而没有任何权限保护,很明显的漏洞。
CVE-2025-32313 EoP High
又放了个无法访问的链接。。。
手动大法,获得这两个:
https://android.googlesource.com/platform/frameworks/base/+/fd4045126ff01cec3d65c053a0c2c01dc231a0f5
https://android.googlesource.com/platform/frameworks/native/+/611b730bade54a0a79dbcc3087d9393086e6dbdf
也就是 Parcel.setDataPosition() 设置的 position 大于 Parcel.dataSize() 时不会正确增长 buffer,造成越界写。通过反序列化 NotificationHistory 对象时使用畸形数据触发。
漏洞描述又是 UsageEvents 里的 OOB write,不知道发什么神经
CVE-2025-48544 EoP High
去年 9 月放过,又放了一遍,懒得重新分析了,看之前的吧
CVE-2025-48567 EoP High
之前 CVE-2024-43093 的后续,MediaProvider 里使用正则过滤敏感路径,需要去除掉路径中的可忽略代码点
CVE-2025-48568 EoP High
https://android.googlesource.com/platform/frameworks/base/+/d8c3d450f77f77232a89ac37c9b9b266e28c0202
切换用户过程中的 race condition,导致锁屏绕过。这个问题我有时候会碰到,不知道修没修好。
CVE-2025-48574 EoP High
WindowManagerService 内对 PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP 的权限检查损坏,在 Binder.clearCallingIdentity() 之后调用了 ActivityTaskManagerService.enforceTaskPermission() 检查权限,里面用的是 checkCallingPermission(),而它依赖 Binder.getCallingUid() 的结果,实际上不会起到任何作用,因此可以拦截用户 drag and drop 传递的数据。
这个漏洞我在 2025 年 7 月 29 日报过,duplicate,看 issue id 可能也就差几天的时间,可惜了
CVE-2025-48578 EoP High
MediaProvider 收到畸形 URI (authority 不正确,或者无法把 id 解析成数字)的时候恢复 binder calling identity 再继续执行。
CVE-2025-48579 EoP High
补丁链接跟 CVE-2025-48578 是一样的。
CVE-2025-48582 EoP High
此漏洞由我发现并报告。
MediaProvider 请求权限的 PermissionActivity 内使用了不安全的 getCallingPackage() 获取调用者身份,可以被伪造导致权限绕过。补丁改成在 createRequest() 的时候记录 calling uid。
CVE-2025-48605 EoP High
SystemUI 显示锁屏的时候移除队列里已有的隐藏锁屏消息,防止残留的请求意外 dismiss 掉锁屏
CVE-2025-48619 EoP High
ContentProvider 被要求打开文件的时候,如果 mode 里没有 w,这个时候 framework 只会检查读权限,过滤掉 truncate bit 和 append bit 避免只有读权限的调用者裁剪文件。
CVE-2025-48634 EoP High
WindowManagerService relayoutWindow 的过程中没有对 private flags 做权限检查,任何 app 都能使用 PRIVATE_FLAG_TRUSTED_OVERLAY PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP 等敏感 flag。
CVE-2025-48635 EoP High
此漏洞由我发现并报告。
补丁:https://android.googlesource.com/platform/frameworks/base/+/36e65fce2d5119ad1d62b4696c003f93df649e52
问题跟 CVE-2025-0098 基本是一样的,当时只修了 android 15,但是有问题的代码其实在 android 14 就存在了,然后我又报了一个。
CVE-2025-48645 EoP High
加载 device admin info 的 description 时 catch OOM,避免超大字符串导致崩溃
CVE-2025-48646 EoP High
https://konata.github.io/posts/identity-squashing/
CVE-2025-48654 EoP High
系统开机的时候移除所有已被 revoke 的 companion device associations
CVE-2026-0007 EoP High
往 parcel 写入 WindowInfo.name 的时候截断超长字符串,这个涉及到我之前提出的一种新攻击手段,后续会发文章介绍
CVE-2026-0010 EoP High
drmserver 中的越界写/栈上缓冲区溢出
CVE-2026-0011 EoP High
修复 shared user id 的系统 app 卸载更新然后重新启用时没有重用现有的状态会被重新分配一个新的 uid 的 bug。
CVE-2026-0013 EoP High
DocumentsUI PickActivity 重用来源 intent 启动 activity 之前先清掉 selector,避免用 DocumentsUI 的权限启动任意 activity
CVE-2026-0020 EoP High
解析权限的时候去除名字里的头尾空格,看描述是能绕过授权弹窗
CVE-2026-0023 EoP High
安装 app 时忽略外部传来的 INSTALL_FROM_MANAGED_USER_OR_PROFILE 标志
CVE-2026-0026 EoP High
补丁:
https://android.googlesource.com/platform/frameworks/base/+/0ead58f69f5de82b00406316b333366d556239f1
https://android.googlesource.com/platform/frameworks/base/+/528a87e90ff9354581d54fd37fbe9f95cccbcdb1
之前的 CVE-2023-20971,不知道为啥重新给了一个 CVE,终于发现之前给的 CVE 不对了吗?
CVE-2026-0034 EoP High
限制最多只能激活 100 个 notification listener service / condition provider service,避免序列化太长的字符串导致异常
CVE-2025-48630 ID High
绘制模糊区域时使用边界图层进行裁剪,防止超出图层边界。看起来是之前 CVE-2025-48561 (Pixnapping) 的后续,https://www.pixnapping.com/
CVE-2026-0012 ID High
官方公告放少了一个补丁所以看起来怪怪的,应该需要以下两个补丁才对:
https://android.googlesource.com/platform/frameworks/base/+/f275f865d49559a6bb3ef9cecf0ab1dd7a7a0bc3
https://android.googlesource.com/platform/frameworks/base/+/e93d4b015c283e55cb08d68a499aab41f03e1272
所以是动画导致的 contact name leak?
CVE-2026-0025 ID High
Notification 从 extras 里还原 EXTRA_MESSAGES 和 EXTRA_HISTORIC_MESSAGES 没有类型限制,可以往里添加一个 ParceledListSlice,因为 ParceledListSlice 反序列化时需要调用回对端提供的 binder,在 system server 去 visit uri 的时候 app 可以返回畸形数据,让 system server 反序列化 messages 时 ParceledListSlice 抛出异常导致整项都反序列化失败,然后 defuse 返回 null,因此被 visit uri 跳过;在 SystemUI 去读的时候就返回可被解析的数据,让 messages 可以被 SystemUI 正常读取和渲染。补丁就是限制了 EXTRA_MESSAGES 和 EXTRA_HISTORIC_MESSAGES 数组的每一项都必须是 bundle。
CVE-2025-48644 DoS High
解析输入法 metadata 的时候限制里面 string 的大小,防止超过 binder 传输大小。
CVE-2026-0014 DoS High
此漏洞由我发现并报告。
AppOpsService 内信任一切安装在 system image 上的 app 提供的 AttributionTag,这个检查可以被 SDK Sandbox 绕过,跟 CVE-2025-48524 CVE-2025-48545 是类似的。
CVE-2026-0015 DoS High
AppOpsService 内忽略不可信 proxy 提供的无效 proxied attribution tag,之前的代码里如果提供的 proxied attribution tag 在被代理的 package 里找不到但是 proxy 里能找到还是会认为它有效,现在即使 proxy 里能找到,如果请求来自不可信 proxy 也会忽略掉它。
CVE-2026-0006 RCE Critical
libopenapv 中的越界读写/堆上缓冲区溢出,把它更新到 v0.2.0.0。只影响 16
CVE-2025-48631 DoS Critical
去年 12 月的 CVE-2025-48631 重新放一遍,当时 16 QPR2 没修好
CVE-2025-48577 EoP High
SystemUI 切换用户时如果收到生物认证或者解除锁屏请求,可能会因为 race condition 导致发生在错误的用户上。添加用户 id 验证以避免这些情况。
CVE-2025-48602 EoP High
用户切换的时候取消还在队列里的播放锁屏退出动画的请求。
CVE-2025-48641 EoP High
nfc 中多线程访问造成的 UAF,需要加锁
CVE-2025-48650 EoP High
MmsProvider/SmsProvider/MmsSmsProvider 中的 SQL 注入,加了个括号平衡的检查
CVE-2025-48653 EoP High
合并同一个 shared user id 中所有 package 请求的所有权限。如果 Package A 属于 UID U,A 没有请求某个权限 P 但是它的 UID U 有这个权限(比如 U 里的其他 app 请求了它),因为权限检查是基于 uid 的,A 实际上也可以使用这个权限,所以 PermissionController 在查看 A 的权限使用记录的时候也必须包含它使用 P 的记录。
CVE-2026-0017 EoP High
高版本(16+)的“使用生物认证解锁”使用的 Settings.Secure 项和低版本的不同,旧版本更新到 16+ 之后系统只会去读新的 Settings.Secure 项的值,只能获得默认的 ON,即使更新系统之前把这项功能关掉了,更新之后还是可以生物认证解锁手机。添加迁移逻辑避免这个问题。
CVE-2026-0021 EoP High
Settings 如果是 2 pane (大屏设备),AppInfoBase 检查 calling package 的跨用户权限而非 calling uid 的权限,因为 multi pane 的实现需要 Settings 用自己的权限去重新启动 activity,这个过程会导致 calling uid 变成 Settings 自己的,具体见 https://cs.android.com/android/platform/superproject/+/android-16.0.0_r1:packages/apps/Settings/src/com/android/settings/homepage/SettingsHomepageActivity.java;l=678
这个问题我之前看出来了,本来打算有空的时候实验然后提交,结果就忘了。。。这里经过最开始我报的 CVE-2024-43088 后面 CVE-2025-22428,兜兜转转最后又回到原点。不知道以后还有没有
CVE-2026-0035 EoP High
MediaProvider 不允许获得不存在的文件的权限,避免悬空攻击
CVE-2024-43766 ID High
蓝牙里的未加密通信?
CVE-2025-48642 ID High
使用 dc cvac 指令代替 dc cvau,保证数据写入到主存。https://zhuanlan.zhihu.com/p/718112749
CVE-2025-64783 ID High
更新 DNG SDK 到 1.7.1 2410
CVE-2025-64784 ID High
和上面的一样
CVE-2025-64893 ID High
和上面的一样
CVE-2026-0005 ID High
SystemUI crash 重启后重新进入 app pinning 模式。类型给错了吧?应该给 EoP
CVE-2026-0024 ID High
使用 file picker 选择媒体文件的时候检查请求 app 有没有权限从里面读取位置,如果没权限应该去除掉位置信息(比如 EXIF 里可能包含位置)
CVE-2025-48585 DoS High
ProfilingService 里保证传入的包名属于 calling uid,只影响 16
CVE-2025-48587 DoS High
ProfilingService 添加 trigger 的时候校验 trigger 的类型确保是合法的,只影响 16
CVE-2025-48609 DoS High
MmsProvider 里的路径穿越,以 phone 的权限删除任意文件造成电话/短信/彩信功能异常
木大木大,全部木大
CVE-2025-54957 RCE Critical
https://project-zero.issues.chromium.org/issues/428075495
https://projectzero.google/2026/01/pixel-0-click-part-1.html
由于频道被封,整理一下还算有用的内容发到这里来。偏技术向闲聊,发布一些随谈、碎碎念或短篇/价值密度不高等我觉得不适合专门写一篇博客但仍然有留下来的价值的内容,包括但不限于编程想法、系统内部解构、人生感悟等。
有挺多人好奇我的人生经历(见 #303),比如我在我的领域是怎么起步的,还有我作为一个厌学、走职业教育路的差生的故事(#88 #303),这里一并留下来。中考五五分流让一半的学生去读了职校,但现在主流叙事却只把职校学生当成审丑对象来满足自己的优越感,把上普高上本科考研读博考公成为人生赢家当成唯一的定死的路,职校生的评论区充斥着“保送富士康”“和我的准时宝说去吧”等高高在上的刻板印象凝视,他们失去话语权失去主体性成为别人应对学历焦虑、确认自己的努力是值得并感叹“还好我还没有跟他一样”的工具,我只感觉到溢出的社达气息。这里想提供一个不一样的视角。我承认我也在反思职校和职校生自己的缺点,比如学校里所谓的早上七点必须离开宿舍、早读必须多大声等形式主义,还有一方面后悔没考上高中另一方面又不尝试通过高职高考等方式提升学历的同学,但我的反思是为了修正错误,而不是建构所谓的等级体系。很多年轻人受到的教育都是“好好学习改变命运”,“不学习以后就要干又苦又低薪的活”,这种焦虑逼着所有人往上爬。但是,难道所谓底层工作就真的天生低人一等吗?做到尊重与平等,承认工程师和外卖员流水线普工一样光荣,同时保障所有劳动者的权益,才是学历通胀时代的正确解法。
部分我觉得现在没什么用的内容比如纯情感发泄和线下贴贴就不再留着了。另外考虑到这里偏正式,部分条目有修改。
本频道任何消息均不构成医学建议。
频道已创建。
意外发现magisk中某个关键组件存在问题,影响magisk hide的隐蔽性,可以导致riru被轻易检测,各类xposed实现的某个特征无法被用户通过命令隐藏
再次总结:magisk能运行到现在是一个奇迹
给 magisk 提交了一个 pr ,出现 magiskhide 完全或随机失效的可以尝试
https://github.com/topjohnwu/Magisk/pull/4507
https://github.com/topjohnwu/Magisk/blob/v23.0/native/jni/magiskhide/proc_monitor.cpp#L387-L403
妙呀,之前我遇到的那个 raise(SIGSTOP) 停不下来的问题是另一个bug(应该算bug吧)
1 | /* We use a trick to have more optimized code (fewer pointer reloads): |
1 | #define INIT_S() do { \ |
https://github.com/topjohnwu/Magisk/pull/4731
busybox 内置一个神奇优化,把一些变量声明成 const 然后用魔法去改,但是改变 const 在 c 里是 ub,编译器不知道数据依赖关系,会把代码优化成会崩溃的形式…
https://cs.android.com/androidx/platform/frameworks/support/+/c50410874c4f5c64e0089a161a24347e0f39d711
androidx 的兼容方法 ProcessCompat.isApplicationUid(int) 在 API 17-23 上看起来漏了一个 return ,会丢掉已经获取到的结果,固定返回 true;API 16 工作正常。
https://segmentfault.com/a/1190000041412586
Android 4.x 时代的设计规范
http://adchs.github.io/index.html
附带一篇当时对 Holo 和 Android Design 的评价
http://www.geekpark.net/news/179488
https://www.visualsource.net/
生成 git 仓库可视化的开发(施法)过程视频
https://juejin.cn/post/7100079518756552734
血压高了,就这也敢叫 《android 进阶宝典》
简单看了一下,一些明显错误:
其实方法的本质就是arm指令,然后JVM的执行引擎会执行arm指令
arm 的 cpu 直接就能执行 arm 指令,jvm 也不是用来执行 arm 指令的,jvm 只接受字节码。android 上的 dalvik/art 稍有不同,接受 dalvik 字节码指令集(通常称为 smali)。至于所谓的 arm 指令,那是 runtime 在用户手机上生成的,即使没有,程序也可以被解释执行。
arm指令是存在于dex文件中的,也就是说,我们可以从dex文件中取出arm指令,查看一个方式是如何被执行的
dex 里没有 arm 指令。如果要查看被编译后的机器指令,请使用 dex2oat 将其编译为 oat 后再 oatdump 。
JVM的执行引擎会将arm指令从方法区中拿出来,放到虚拟机栈中执行(栈帧的概念,每一个方法对应的dx指令集就是一个栈帧,每一次方法调用都有栈帧入栈和出栈)
这里假设你的”arm 指令“是字节码,它在执行的时候也不会被放到虚拟机栈中再执行。栈是程序执行时的临时数据区,程序通过各种指令操作,放/取数据,而非指令。另外,”dx 指令集“又是什么玩意儿?
同是执行 10 + 20 ,JVM是先创建一个10变量,然后再创建20 ,最后将两个相加然后返回;但是dx指令是直接计算好了,然后创建v0 = 30,直接返回,所以:Android编译器在编译的过程中会做优化,提高执行的效率
首先,你给的 java 字节码里面没有加法指令,是个除法指令,也就是说这不是你给的加法函数编译出来的结果。这种优化叫常量折叠,从理论上来说 javac 也会进行这种优化。
之前我们介绍过阿里的AndFix或者Sophix是通过hook native层修改字节码指令完成,之前我们介绍的arm指令集,就是实现热修复的基础。所以AndFix热修复,就是将正确的arm指令替换调异常的arm指令,等到再次加载这个类执行方法时,执行引擎拿到的是正确的arm指令交由虚拟机栈。
函数入口与指令本身有着本质区别。替换函数入口也不需要了解 arm 指令集。
记录当前方法被调用的次数,如果超过某个限制,那么该方法就被标记为是热方法,热方法是被缓存到一块内存,下次执行到这个方法,不需要压栈,直接返回结果
hotness_count_ 与 JIT 编译相关,当方法未被编译而调用次数达到阈值后,会有专门的 JIT 线程把它编译为机器指令加速执行。“热方法是被缓存到一块内存,下次执行到这个方法,不需要压栈,直接返回结果”,首先非热方法也在内存中,其次压栈与方法调用有本质区别。我觉得你应该是想说 inline 优化,但那与 hotness_count_ 无关。
找到ArtMethod,在JNI层是能够实现的,通过JNIEnv的FromReflectedMethod函数
从 android 11 开始,FromReflectedMethod 返回的可能不是 ArtMethod*。
尤其是通过hook native底层修改arm指令集
你是在说 inline hook?
转发自 南宫雪珊 https://t.me/vvb2060Channel/441
以大小写英文或点(.)开头,后续可以用大小写英文、数字、点(.)和下划线(_)
package(包名)和sharedUserId有额外规则:不是是非法文件名。即不能为 . 或 .. ,以utf8方式转成比特数组后,长度不能大于255。(虽然aapt2连250都不允许……)
需要至少一个点:package,sharedUserId,不以:开头的process。
不要求至少一个点:splitName,以:开头的process。
不以:开头的process如果是system,例外允许。
以:开头的process需要至少两个字符,即不能只有一个:。
https://harrychen.xyz/2022/03/23/hijack-memory-access-using-linux-signal-handler/
https://developer.android.com/ndk/reference/group/libdl
这是 android_dlopen_ext 还有那一堆 flags 的文档。里面只说了 android_dlopen_ext is available since API level 21,没说那些 flags 是什么时候添加的。
以 Android 5.1 为例,有效的 flag 只有这么几个:https://cs.android.com/android/platform/superproject/+/android-5.0.0_r1.0.1:bionic/libc/include/android/dlext.h;l=57-62
1 | /* Mask of valid bits */ |
使用不支持的其他 flag 如 ANDROID_DLEXT_FORCE_LOAD 会直接被 linker 报错拒绝加载。坑人呢
https://github.com/android/ndk/issues/1772
Release 模式的 APP 在非主线程上对 /proc/self/exe 进行 readlink 在旧版本的 Android/(Kernel?)上会触发 Permission denied 错误。把 debuggable 设置为 true 后正常,在主线程进行也正常,在没有 SELinux 的 Android 5.0 AVD 上也正常。
猜测可能是旧版本 Android 的 SELinux 有问题?
这个问题导致了大量旧 Android (5.x/6.x)用户更新 Magisk 25.0 后“卡在开屏页”
应该是 kernel 问题,在非 Android 平台上也有出现
https://github.com/moby/moby/issues/18883
Pixel 6 系列(只看了 6a 但是应该是整个系列都有这个问题)的 Android 13 QPR2 B1/2
boot.img 里的 ramdisk 用的 gzip 压缩,vendor_boot.img 里的 ramdisk 用的 lz4_legacy。
bootloader 解包的时候是把两个 ramdisk 拼起来扔给 kernel 然后 kernel 直接整包解压。这需要两个 ramdisk 起码使用相同的压缩格式。所以 boot.img 里的 ramdisk 从来没有被成功解压过,自然 Magisk 怎么修补都无效。这就是 修补原厂 boot.img 没有反应但是修补 Pixel 7 的 boot 刷入就好了的原因 (https://github.com/topjohnwu/Magisk/issues/6441)
Pixel 6 系列机型 QPR2 用户临时的解决方案:
更新:QPR2 Beta 3 已修复。Pixel 6 系列手机的用户可以正常修补 boot.img 获取 root。
Google:自己写的 文档 ,当然要由自己亲手破坏
Android 7.0.0_r1 SDK24 没有 fd 检查,没有 frameworks/base/core/jni/fd_utils-inl.h
Android 7.1.0_r1 SDK25 没有 fd 检查,没有 frameworks/base/core/jni/fd_utils-inl.h
Android 7.0.0_r29 SDK24 有 fd 检查:https://cs.android.com/android/platform/superproject/+/android-7.0.0_r29:frameworks/base/core/jni/fd_utils-inl.h
Android 7.1.0_r2 SDK25 有 fd 检查:https://cs.android.com/android/platform/superproject/+/android-7.1.0_r2:frameworks/base/core/jni/fd_utils-inl.h
如果你的应用(无论 root 还是 非 root)需要假定 Android 的内部行为,最好不要直接检查 SDK_INT 不然莫名其妙的崩溃就是下场。
Magisk 假定 fds_to_ignore 这个参数不存在就没有 fd 检查,然后在 华为/魅族的 7.0 上崩了。
Pine 根据系统版本假定 kAccCompilerDontBother 的值,然后在官方的 Pixel 2 8.0 ROM 上崩了。
今天意外发现乌云网 www.wooyun.org 已经没有 DNS 解析记录了(以前是访问显示正在升级),分享一个备份 https://wooyun.js.org/
致敬
https://github.com/android/ndk/issues/1751
Android 文档:TypedArray implements AutoCloseable added in API level 1
实际上:直到 Android 11.0.0_r1 这个类都没有实现 AutoCloseable 这个 interface。
所以,如果你很自然的写出了
1 | try (var typedArray = obtainAttributes()) {} |
或者
1 | obtainAttributes().use {} |
之类的代码,在旧版本上会崩溃。没有警告。
同样情况的还有 LocalServerSocket 这个类。直到 8.0 都没有实现 Closeable。
这个类 比 TypedArray 更离谱,TypedArray 大家都知道是用 recycle,而 LocalServerSocket 一直都有 close,但是偏偏一直没去 implements Closeable。
https://juejin.cn/post/7208345469658415159
时隔多年又看见了这种『一个 app 有多少个 XXX』这种问题。备份一下我的评论,以免又被掘金删掉。
首先,hashCode 跟对象地址没有半毛钱关系。确实有部分虚拟机选择将 hashCode 直接实现为内存地址,但是 ART 不是。
ART 的实现在这里:http://aospxref.com/android-13.0.0_r3/xref/art/runtime/mirror/object.cc?fi=GenerateIdentityHashCode#170
很明显可以看出 1103515245 是一个线性同余法生成伪随机数选择的常用魔数(不过整个算法看起来不是典型线性同余)。
至于为什么生成的 Application 对象 hashCode 值相同,可能是因为这些进程都从 Zygote 继承了相同的随机数种子,而 framework 内代码对象创建次数往往相同,经过相同的随机次数后产生一致结果就很正常了。
你可以在 Application 的静态代码块内创建随机数量的对象扰乱结果,应该就能得到不一致的 hashCode。
然后是『获取物理内存地址』,Unsafe 这种方法获取到的依然是虚拟的逻辑地址,且用户空间没有办法获取真实的物理地址(除非利用内核漏洞)。
全部给逻辑地址的好处很多:
1.可以在内存紧张时将未使用的内存空间临时换到硬盘上存储,应用实际访问时再触发缺页中断从硬盘读数据,整个过程对处在用户空间的应用完全没有影响
2.逻辑地址无法直接跨进程使用,增强安全性
3.完全阻止恶意应用读写其他进程的私有内存空间
等等等等。
然后我觉得『一个app到底有多少个 Application』『一个 app 有多少个 Context』这种问题一点意义都没有。如果是想知道『一个 app 的进程有多少个 Context』,可以调用 VMDebug.getInstancesOfClasses 这个方法。
文中忽略了一种情况,就是多个应用跑在同一个进程。当多个应用具有相同的签名,配置的 sharedUserId 相同且 android:process 为相同的共享进程时,会发生这种情况。此时一个进程会创建多个 Application 对象(每个应用一次)。
之前发现在自己的 Android 5.1 kernel 3.10 arm32 设备上调用 mremap 移动内存空间时会奇怪地报出 EINVAL (invalid argument) 错误,怀疑是低版本 kernel 的问题。后面西大师发现 6.0 x86 的 AVD 上也可以复现出这个错误,x86_64 却不会,而且主动使用 linux-syscall-support 这个库调用 mremap 是没问题的,所以猜测是旧版本 bionic 的实现问题。
果然,旧版本 mremap 参数列表里第四个 int 写成了 unsigned long,缺少变长参数 ( http://aospxref.com/android-6.0.1_r9/xref/bionic/libc/include/sys/mman.h#62 ),同时 x86 发起 syscall 的时候也只处理了四个参数( http://aospxref.com/android-6.0.1_r9/xref/bionic/libc/arch-x86/syscalls/mremap.S#18 )
然后找到了这个修复提交 https://android-review.googlesource.com/c/platform/bionic/+/180130
所以如果你的程序用了 mremap 又想兼容 7.0 以前的设备,请不要使用系统自带的 libc 里面的 mremap,自己 syscall 或者使用 linux-syscall-support 代替。
(离谱,好特么坑啊
提醒:想要兼容旧设备,还有其他坑……
android 6.0 以前,系统 libc 的 getmntent 和 getmntent_r 是空实现。
https://cs.android.com/android/_/android/platform/bionic/+/e3c4acf1e3ef36c2ab1f48b1261dec9a1d8330a4
还有,init.rc 的 exec 也是空实现……
http://aospxref.com/android-5.0.2_r3/xref/system/core/init/builtins.c#257
clock_nanosleep 这个函数的行为也不对,在 https://android-review.googlesource.com/c/platform/bionic/+/110652 这个提交之前它在出错时会返回 -1 然后把错误码设置到 errno 里,正确行为应该是直接返回正数的 errno
魅蓝 M3 Note,系统版本 Android 5.1,内核版本 Linux localhost 3.10.72+ #1 SMP PREEMPT Tue Sep 22 18:07:30 CST 2020 aarch64 Android
在这台设备上,syscall getrandom 会返回 0 同时 errno 变为 2 (No such file or directory)
似乎只在 64 位运行时出现,32 位正常。
而 getrandom 这个 syscall 从 Linux 3.17 才开始有,正常情况下它应该失败且返回 -1,errno 设置为 ENOSYS。
手上的其他 3.10 设备都没有这种怪行为。
而很不幸,较新一点的系统 libc 里面有个函数,叫 getentropy,它会尝试循环 syscall getrandom,只有当它返回 -1 的时候才会认为内核不支持这个 syscall 而进行回退。这个函数会在 libc 初始化时被调用。
所以如果你的程序静态链接了新的 libc,在这台设备上运行的时候会在 libc 初始化时调用 getentropy 而陷入死循环,连 main 都没有机会运行。
修复手段也不是没有,在编译时添加选项使用 wrap functions 功能覆盖掉这几个函数,然后处理一下 getrandom 返回 0 的情况。不过我觉得把当时弄出这种东西的魅族工程师拖出来打一顿比较好。
顺带一提,在这台设备上你想运行 lldb-server 也会因为同样原因卡死,strace 也会不明原因卡死,我是去找了一份 gdb 发现能用才发现这个问题的,不然连 backtrace 都拿不到
摘要:在长沙街头碰上人借车费,说晚上就还,然后就被删好友了
图片懒得补了,碎碎念可以补一下:
啊睡不着,瞎扯几句
我 2020 年刚进中职的时候,有个同班同学总是找我借饭卡刷,还有微信借钱,后面还带了另一个人找我借钱。我当时想都没想就借给他们了,到后面滚雪球越滚越多,他们借了我 642 块。后面我找他们要钱的时候他们老是说没钱,再后面这两个人, 一个退了学,一个街头持刀抢劫别人被抓了。就只还了150,他们到现在还欠我差不多500块,而我甚至连他们其中一个人的名字都不知道。
性格缺陷是这样的,害怕又渴望社交,害怕好不容易建立起来的社交关系维持不下去。
这回也是,我不认识这个人,这个人路上见到我说微信限额了帮忙付个 79 块的车费。
我这是善良还是纯圣母呢,我觉得是圣母。
我甚至觉得哪天我挂了去见上帝的时候上帝会说哟豁,好久没见过这么纯净的灵魂了。
大家别学我当这种冤种哦
睡了,明天还有 第 81 届中国教育装备展示会
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/permission/Permissions.md
给系统开发者的权限文档,竟然塞在这种地方,想不到
不过我这里用 Chrome 打开这个页面,Using role for permission protection 这个链接是 blocked,不懂 Google 在搞什么。应该是指向这个链接 https://cs.android.com/android/platform/superproject/+/master:packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/RolePermissionProtection.md
顺便带上一份 Android 13 的权限列表,http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/core/res/AndroidManifest.xml
需要其他版本的,选好版本直接搜索 /core/res/AndroidManifest.xml 就好了
转发自 不存在的世界 https://t.me/illusory_world/4359
https://nano.ac/posts/86257129/
拿到了一台华为 Nova 1 (Android 7.0,EMUI 5.0.4),getprop 显示是全盘加密,然而输密码解锁时这台设备的表现完全不像全盘加密。
在没有输密码解锁时连上 adb,mounts 显示 /data 已经挂载上 f2fs,vold.decrypt = trigger_restart_framework,vold.post_fs_data_done = 1,表明它已经解密完成。
而正常的已经设置密码的 Android 全盘加密设备的解密流程应该是:设备开机 -> 给 /data 挂载上 tmpfs -> 启动 framework -> framework 显示输锁屏密码页面 -> 用户输密码后,解密密钥 -> 关闭 framework,解密 data,挂载真正的东西到 /data -> 再次触发 post-fs-data 正常开机。
查看 dmesg 后发现这台设备在解锁之前用默认密码解密就成功了,锁屏密码似乎就只是锁屏密码。华为对 FDE 设备开机时间过长所做的“优化”?
编写了一个 PoC https://github.com/canyie/BypassKeyguard ,经测试能在设备开机后第一次输入密码前绕过锁屏进入桌面并访问用户数据,侧面印证了上面的猜想。
(为自己读了三年的感想总结,仅作备份)
0.快跑!如果你是 2023 届中考生,不是特殊情况,快去复习!想啥中专!
1.就算你真打算进中专,也一定要去中考考一下,别签那啥自愿放弃中考同意书!有很多好的中专也是要看中考成绩的
2.好好选学校,好的中专跟坏的中专差别很大。中考成绩出来发现没希望上普高的话,没打算复读的话,建议早点选好学校。有很多好的中专是有高考班的,但是学位不多,想报趁早。
亲身经历,咱中考没考,报学校又是等快开学了才去问,结果都没啥学校还有学位,最后进了间民办中职。
3.如果你成功进入中专,在课室里上着课,那么无论如何,恭喜你进入人生新阶段!不过不要觉得进了中专就舒服不用学习了,越垃圾的学校规矩越多还特喜欢整活。以笔者亲身经历来说,这学校能停任何课让你去搞卫生,甚至在离考试还有两三天的时候对我们上一届高考班发出“你们还是高考班,你们连卫生都搞不好你们高个屁的考”这种离谱言论并让他们停课搞卫生。
4.在学校的时候,尽量完善自己的课后生活。有升学的打算的话可以复习文化课和专业课,特别是英语单词,如果你们地区要考英语而你比较差的话建议一开始就狠抓英语。
5.强烈建议报技能竞赛,无论是专业竞赛还是计算机竞赛英语竞赛或者什么禁毒知识竞赛法治知识竞赛,学校没有的话就和学校申请自己代表学校去,无论如何让校领导对你形成两个印象,一是“这是个优秀的好学生”,二是“这个学生能给我学校争到荣誉”
6.强烈建议高一就去考技能证书,尤其是广东学生。个人建议计算机证书和英语证书最好拿到一张。
7.别觉得你的同学有多么善良,尤其是在中职学校。你的很多同学会在一年内选择退学或者被开除。高一的时候,我有个同学借了我六百多到现在都没还,后面这个学生大街上持刀抢劫路人被抓了。我们班还发生过晚自习一群人起哄上台用课室多媒体放黄色视频的事情,这种情况保证自己别被影响到就好了。在一间不怎么样的学校,很难看见希望,但是无论如何相信自己。
8.无论第一年多么苦多么不适应,都请珍惜,第二年随着你们班上大部分学生满了16岁,有些学校会开始以“实习”的名义送学生进厂打螺丝。这个时候竞赛的好处就体现出来了,大部分学校都不会送竞赛生进厂。笔者曾经有幸体验过三个月,那三个月里每天基本上都是因为手指套破损来不及换搞到一手的血,三个月下来拿笔都拿不稳,还高个毛线考。
9.如果你不太好运,已经进厂了,牢记一件事:实习进厂再苦至少拿到毕业证就能离开,没专业技能到社会上不走运的话这就是你以后一辈子的生活。
10.如果打算升学,建议最晚考试前一年开始准备文化课,除非您是技能竞赛保送生。当然任何时候开始学都不晚,各省考纲不同,以笔者广东考生的经验来说学一个学期都能考得很不错了(当然那样绝对累死)。
11.语文的话我其实觉得背那些古诗文没什么必要了,有这时间不如多记几个数学公式。时间充裕的话可以专门去记,不充裕的话那早读的时候读一下就好了,时间紧迫的话直接忽略都没问题。数学最后一道题做不出来就别纠结了,还不如去检查前面的小题,本人就是这样在考场上丢了十分😭
祝所有 2023 届中考生旗开得胜
提醒:近日盗号骗子盛行,请大家注意账号安全,注意以下行为:
强烈建议添加任何人为联系人时取消勾选 “Share my phone number” 选项,同时不要随意截图,需要发送截图时裁剪掉敏感信息。
https://twitter.com/oasisfeng/status/1661046351151665153?s=19
网上随便找了几个包看了下,play 版 6.48.0 target 31 即 Android 12,国内版 6.49.0 target 27 即 Android 8.1,国内版 6.60.0 target 29 即 Android 10。
拿到了实体卡 开心
发个新闻
https://j.eastday.com/m/1685165054031431
存档链接
https://web.archive.org/web/20230530003013/https://j.eastday.com/p/1685165054031431
疑似相关的央视网视频报道
http://m.app.cctv.com/video/detail/5a400b4969334dea87d7b05b0d1fd6a8/index.shtml#0
央视网报道被转发至哔哩哔哩
https://b23.tv/YNmoZR7
https://t.me/TooruchanNews/26896
https://t.me/LetITFlyW/9983
留一个文章链接避免上面频道也被封:https://juejin.cn/post/7338239261194010674
冷知识:从 Android 12 开始,应用可以声明 UPDATE_PACKAGES_WITHOUT_USER_ACTION 权限(是普通权限,用户无法禁止),然后调用新的 PackageInstaller.SessionParams#setRequireUserAction(int) API,来静默更新自己。无需用户确认。
看起来这么流氓的功能为什么没被国内一众流氓软件跟进呢🤔
猜测是要么是不知道,要么是因为 target sdk 限制:此 API 要求被安装的应用至少 target 30 (在 Android 13 及之前)或 31 (Android 14 及之后),并且未来的 Android 版本里还会继续提升这个限制。
PS: MIUI 用户应该是不受影响,在开启 MIUI 优化的情况下,整个 PackageInstaller API 都被完全破坏,无法使用。应该已经修好了
https://source.android.com/docs/core/runtime/signed-config
竟然还有这种东西,我可以理解为官方后门吗?
(注:RCE=远程代码执行 EoP=权限提升 ID=信息泄露 DoS=拒绝服务)
CVE-2021-0693 ID 高危
漏洞成因:Shell 应用错误把一个 provider 设置成其他 app 能访问,导致应用可以访问不应该能访问的数据。
CVE-2021-0314 EoP 高危
漏洞成因:卸载应用的确认弹窗没有设置不能被覆盖,导致恶意应用可以自行弹出悬浮窗遮挡住关键的确认信息,让用户在不知情的情况下卸载应用。
CVE-2017-13242 ID 中危
漏洞成因:蓝牙配对的时候,会弹出一个对话框,里面有一个选项是要不要允许配对设备访问通讯录。这个选项框包含了对端设备的名字,而这是攻击者可控的,然后攻击者可以通过在设备名字里插入换行符把关键的提示信息顶出屏幕。
CVE-2018-9432 EoP 高危
漏洞成因:基本和上面那个一样,攻击者改设备名把关键的确认信息顶出屏幕。
CVE-2021-0691 EoP 中危
漏洞成因:sepolicy 里多加了几行,授予了 system app 写入已安装 apk 的权限。尽管只是个中危漏洞,但它是『魔形女』漏洞链的重要一环,攻击者利用此漏洞可成功将原本数个越权任意写入文件的漏洞转化为任意代码执行。
CVE-2021-39631 ID 高危
漏洞成因:这个漏洞就更离谱了,一个提示消息写得不够清晰,被认定为高危漏洞…… 对应补丁在这里 https://android.googlesource.com/platform/packages/apps/Settings/+/a36d55e8f83e8bf6e50254cda04632e233598f42
CVE-2021-0434 EoP 高危
漏洞成因:警告信息写的不够详细。
CVE-2023-21090 DoS 高危
漏洞成因:没有限制 app 的 uses-permission 里值的最大长度,导致可以写得非常非常长把系统给搞崩溃。
千里之堤,溃于蚁穴。
“我想躺在一张很大很软的床上 想做个好孩子”
好孩子是什么呢
我小学时候奖状能挂满一面墙 我是好孩子吗
我五年级开始发病逃学 我是好孩子吗
我大概五六年级开始自学编程 每天抱着手机就为了学编程 我是好孩子吗
我小学拿缝衣针捅进插座里电自己 拿刀划自己手腕 我是好孩子吗
我小学有两年+初中四年(休过一年学)都几乎没去上学 连我们班任课老师都不认识我 我是好孩子吗
我的同学在发奋图强学习文化课的时候我在惠爱看病 浪费了家里不知道多少钱 我是好孩子吗
我连中考都不敢去参加 最后随便上了所中职 我是好孩子吗
我害怕社交害怕到想吃烤肠拿着钱在店门口徘徊不敢进去 我是好孩子吗
我头发前过眉侧过耳后过颈 我是好孩子吗
好孩子是什么呢
“乖”的、“听话”的,就是好孩子吗
AssetManager.addAssetPath 这个 hidden api 应该很多人都在用,提醒一下这玩意的两个坑:
这个故事告诉我们没事最好别用 hidden api,用这种玩意就是给自己找麻烦。
(以下均为大概时间):
04:30 突然醒了 不知道过了多久才睡着
06:40 醒了 在床上发呆 玩手机
08:30 到了公司开始写代码
09:30 开始发躯体化症状
10:30 持续不能缓解 请假回来休息 然后躺在床上不知道什么时候睡着了
13:40 醒了 然后在床上躺着玩手机
14:30 努力从床上下来去吃饭
15:00 吃完饭回来在床上躺着发呆和玩手机 知道自己要干正经事就是没力气去干
18:00 傍晚了 感觉心理状态明显好转 甚至有点想涩涩 努力逼自己干了急需的正经事情(其实也就只需要十分多钟就能干完 orz)
19:00 从床上下来吃饭 玩手机 洗澡 玩手机
22:30 想着应该尽量拉住自己 然后给自己下单了个智能手环 orz
23:10 睡觉
(然后三点半又醒了在这里打字 emmm)
冷知识测验:在 Java 中,调用 java.lang.Math 类的 abs(int) 方法一定会返回非负数吗?
答:Math.abs(Integer.MIN_VALUE) 会因为 int 不够放它的绝对值而溢出,返回 Integer.MIN_VALUE,负数。
有人问“你会后悔初中没去读吗?你会后悔上一间中职学校吗?”
其实实际上,我妈到现在都也还在不断重复“要是你初中的时候忍忍就好了”之类的观点。
我其实不后悔。我甚至觉得当时做的决定非常正确。可能说唯一有点后悔的是没选到一间比较好的中职学校,进厂打了几个月螺丝。
一方面,我厌学,另一方面,初中阶段很多孩子开始进入青春期,一堆小孩完全不知道自己在干什么,把霸凌当玩笑。再后面大家都为了升学努力,待在这种环境里只会让我心理状况更加恶化。
我自知我的人格是缺损的。所以我甚至很感激 gap 的那几年,我能尝试去把残破的人格补全。那几年里我脱离让我恐惧的学校环境,不用再为“又在学校发病又要麻烦老师把我送回家”这种事情内疚,我可以一点一点学习如何正确和别人相处,还能静心研究自己喜欢的事情。后面到了中职,虽然还是非常非常害怕,但是它至少是个比较轻松的低压环境,我可以尝试去融入它,我可以犯错。
到现在三年中职读完,从第一次住宿舍到一个人跑几百公里去陌生城市实习,感觉真的是个奇迹。虽然现在情况还是不太好,但至少有独立活着的机会了。
所以,如果你刚刚参加完中考,打算读中职的话,不用失望,好好读下去就好了。至于学历,中职学校也是可以升学的,况且如果活不下去,在意学历有啥用?
顺便放首歌:https://www.bilibili.com/video/BV1N64y1B7NZ
打开 https://bughunters.google.com 注册账号,可以阅读里面的 Rules 了解哪些问题会被认定为安全漏洞。还有就是,提交安全问题的报告或者补丁,满足漏洞奖励计划(VRP)的话,是有可能会奖钱的!!一般来说,漏洞本身的影响越大、提交的报告质量越高,获得的赏金也就会越多。所以初次提交建议仔细阅读 Rules 里的内容。
确定发现的问题是安全漏洞之后,就可以进入 Report 页面选择要报告漏洞的影响范围(原文是 “report types”,翻译为 “报告类型” 感觉并不对,不知道怎么翻译才好)。我发现的漏洞位于 AOSP 内,影响 Android 操作系统,所以我选择了 Report a security vulnerability in a Google-owned product 然后点击 Report。
然后它会让你填写你的名字和联系方式,然后会让你写要报告的问题的简要描述(会被当作 Issue 的标题),该漏洞位于哪个地方(我这里是 Android 直接在下拉框里选择 Android 就好了),然后是详细描述你的问题,越详细越好,最好把详细漏洞点和成因都写出来,可以上传一个不超过 50MB 的文件(大家一般都是上传 PoC 之类的吧,我是传了个演示视频)来辅助说明。然后点击确认,它就会在 Google 的内部 Issue Tracker 里为你创建一个对应的 Issue。这个 issue 默认是被保护的,只有你和被指定的 Google 员工可以查看。对了,一个很好的点是,你不一定要用英文!Google 有来自全球不同地区的员工,用你的母语沟通基本上是没问题的!
我是 6.28 提交的漏洞报告,6.29 这个报告就被 triaged 了,给我定的 Priority P2 + Severity S2,然后会有人让你确认有没有签 Google 的 CLA ,还会问你你打算怎么被感谢(我的理解就是怎么在 Android Security Acknowledgements 那个页面的 Researchers 一栏上写你的信息吧,至少我是这样理解然后按这样回复的),然后也会提醒你上传 PoC 之类的。
6.30 我回复了之后,7.13 获得了这样的回复:
Thank you for your submission. This vulnerability has been rated as Moderate severity with Medium Quality and unfortunately does not meet our bar for reward. We will pass this report to a feature team for remediation and will be closing this report and not providing further updates. Thank you for working with the Android Vulnerability Reward Program!
中等质量和没有赏金是意料之中的,毕竟没花时间去详细研究导致报告里的信息不够详细;至于漏洞严重性我一开始评估的是 High 高危,可能是满足了分级调节方式给我降到了 Moderate 中危,其实有点失望,不过也在意料之中。
我当时想着中危应该也会给 CVE 编号吧,看往年的页面说不定也有致谢信息,然后发现了这条:
Additionally, starting May 15th, 2023, Android will no longer assign Common Vulnerabilities and Exposures (CVEs) to most moderate severity issues. CVEs will continue to be assigned to critical and high severity vulnerabilities.
得,连 CVE ID 都没了,再也不相信信息安全了
不建议 更新 Magisk v26.2 (准确来说是 26106 及之后所有的版本一直到最新的 26202),建议等待已知问题都被修复后再尝鲜
花式爆炸
Edit: v26.3 应该把所有 bug 修好了,吧?
想知道详情的可以点击下面几个链接
https://github.com/topjohnwu/Magisk/commit/de00f1d5a94b83ad7bf49b0bdffab310e58db471
https://github.com/topjohnwu/Magisk/issues/7214
https://github.com/topjohnwu/Magisk/issues/7264
https://github.com/topjohnwu/Magisk/issues/7274
所以为什么这种问题只到发版的时候才能发现啊,根本没人用 canary 是吧
翻到了这本神书 是我读中职的时候学校发的
中职教育到底搞的咋样 看看应该就懂了(
我妹是 2017 年出生的,我比她大 13 岁,那个时候已经是初中生,我们这边的儿童游乐园大人陪小孩进去大人是不收钱的,然后你就能看见我打着照顾我妹的旗号在海洋球池里不停扔球而我妹安安静静坐在旁边的景象。
很多人看见大孩子玩这种东西应该都会奇怪,因为他们觉得大孩子应该坐在学校里上课或者就算玩游戏也不该玩这种婴幼儿玩的东西。这其实是人对他人的一种“期望”。
人从小到大都活在“期望”里。我妹出生之后我们期望着她三个月会翻身六个月会坐八个月会爬一岁会站,我们每天和她说话希望她早点学会说话,她不会做幼儿园的算术题的时候我家里人会叹气说这么简单的题都不会以后怎么办。就算到爷爷奶奶这个退休的年纪我们一家也期望着他们身体健康,晚上烧一桌合胃口的饭菜。
但是我觉得人不该只活在期望里。人生的意义不该是为了满足别人对自己的期望。
人生的意义是啥?我觉得该是享受。
享受啥?享受快乐。享受炎炎夏日电视机播着高糖饮料伤身而你拧开一瓶冰镇快乐水灌进嘴里,享受去吃了心心念念好久的龙虾自助发现也不是那么贵,享受你心爱的人说宝宝我爱你然后亲你一口,享受蒸鸡蛋你非要往里试试加可乐会是啥味道的瞬间,享受看见一个笑话你朋友说有他妈这么好笑吗而你笑到肚子疼,享受自己花时间写的东西有人读有人点赞,享受在网上看见有精神病在试图教你人生的意义是什么你觉得很奇特顺手转发给你的朋友。
我们现在的教育搞的快乐像原罪一样,但是我觉得享受快乐是人与生俱来的权力。
碎碎念:突然发现一直都在提出奇奇怪怪的想法 但是大部分最后都是被别人做出来
例子:
native bridge 注入:最后被 Riru ZygiskOnKernelSU 采用,Magisk Zygisk 也计划改成这样实现
MomoHider :从 Shamiko 开始我就没怎么动过了
resetprop 检测:一直知道有这个方法 懒得写 最后被 nullptr 先写出来加进牛头检测器了
重写 zygisk 注入,改成监控 preload-class 并 ptrace zygote:写到一半突然就不想写然后 git reset 了 然后被 ZygiskNext 写出来用上了
该说不愧是 ISFP 吗,绝对不做没有 deadline 的事情(
写了一下 Android 启动过程中 init 这个进程的一些细节,以及 magiskinit 是怎么处理这些不同设备的
可能是你在网上能找到的关于 2SI、 magiskinit 等鬼东西的最详细的文章
https://blog.canyie.top/2023/11/12/android-booting-shenanigans-and-magiskinit-analysing/
Android 14 有一项行为变更,ActivityManager.killBackgroudProcesses() 这个 API 不能结束其他应用的进程了,只能终止自己的后台进程
但是查看 2023-10 安全公告会发现这个补丁实际上被下发到了 Android 11-13,还被授予了 CVE-2023-21266 这个编号,类型是 EoP 权限绕过,定级为高危
之前一直想不明白为什么 Google 会把行为变更当成安全漏洞处理,直到今天突然想到,可以结束其他应用后台进程,会对 RAM 使用量造成影响,那可以判断 kill 前后的 RAM 使用量,如果出现大幅度下降说明 kill 成功,说明 kill 之前这个应用有进程在运行,相当于绕过了权限检查指定软件包是否在运行,是侧信道
信息安全,真他娘的奇妙
其实这样解释也和 Google 其他行为自相矛盾
之前有个漏洞(具体编号忘了 CVE-2023-21377),是任意第三方 app 可以 inotify 其他应用的 apk 路径,对应应用启动的时候一定会 open apk 然后就会收到通知,相当于绕过了“使用记录访问权限”监听对应应用启动
Google 给出的补丁是用 sepolicy 封堵对应权限,然而“为了破坏现有 app,只对 target >= 34 的应用启用此限制”
只能理解为 Google 内部管理混乱
更新:查看了 CVE 描述,发现是能用这个玩意“绕过 play 保护”,也就是能一直杀掉 play protect 的进程。嗯,也挺离谱的……
试了一下小米社区的解锁答题(2023.12.07 更新的)
嗯,非常好,题目非常有质量
成功把我给挡在外面了
公开两个检测 resetprop 的方法:
通过 setprop/getprop 等手段操作property 实际上是操作了位于 /dev/__property__ 下的文件。按 property 各自的 SELinux Context 存储,相同的 context 分为一组,存储在一个文件内。每个文件大小为固定的 128KB。需要使用的 prop_bt prop_info 等对象由一个线性内存分配器实现,每次分配内存时只是简单地 bump 地址,不支持释放内存。
更多细节可以查看 https://blog.canyie.top/2022/04/09/property-implementation-and-isolation/
Magisk 的 resetprop 在删除 property 时,会将 prop_bt 中指向 prop_info 的引用置空,然后清空整个 prop_info 的内存。问题就发生在这里,prop_info 的内存被清空但并没有被释放,这就导致对应内存位置出现一片很大的空区域。通过检测这里,应用可以检测到对应属性区域有属性被删除了,进而推断出设备已经 root(因为正常情况 property 是不支持删除的)。
什么时候会发生删除操作?通过 resetprop 重置 ro 也就是只读属性时。而保存着 bootloader 锁定状态的多个 property 和保存着 native bridge 的 ro.dalvik.vm.native.bridge 还有经常被修改的设备指纹都是只读属性。也就是说,除非避免修改这些属性,否则就会被检测到,而不修改 bootloader 状态的属性又会导致里面直接存着“已解锁”,应用一样可以读到。
在 https://github.com/topjohnwu/Magisk/commit/f41994cb52ca08856216a8da0a28ed148c833f4e 过后,作为副作用,上面的问题刚好被缓解,但还有另一个问题:
prop_info 上有一个字段叫 serial,当这个 prop_info 被更新时,serial 会自增 2。也就是说,prop 被更新的次数 = serial / 2。而对于 ro 属性,它们是只读的,正常情况根本无法被更新,因此 serial 应该始终保持为 0。也就是说,如果发现 serial 不为 0 的只读属性,就代表它被 resetprop 过。
我们调查发现已经有应用在使用这些方法检测 root,Shamiko 1.0+ 已经尽全力隐藏了相关痕迹。我知道有很多人并不愿意使用 Shamiko,而其他隐藏方案的开发者并不知道这两个检测点,也就没有办法处理它,所以我公开了。
阅读以下三篇博客,可以感受三星的代码质量
https://blog.oversecured.com/Two-weeks-of-securing-Samsung-devices-Part-1/
https://blog.oversecured.com/Two-weeks-of-securing-Samsung-devices-Part-2/
https://blog.oversecured.com/Discovering-vendor-specific-vulnerabilities-in-Android/
Android 不为人知的新功能:Financed Device 的原生支持
这个功能做了很久,但是非常低调,我完全找不到文档,甚至没法确定这个功能到底做完没有,唯一能找到的只有这句话:
A financed device is a device purchased through a creditor and typically paid back under an installment plan. The creditor has the ability to lock a financed device in case of payment default.
(Ref: https://cs.android.com/android/platform/superproject/+/android-14.0.0_r1:packages/modules/Permission/framework-s/java/android/app/role/RoleManager.java;l=175 )
简单来说,financed device 指通过分期付款购买的设备,这个功能借用了现有 Android for Work 中设备管理(device owner)的功能,允许债权人自定义的 app 对设备施加使用限制或在逾期不付钱的情况下远程锁定设备。现有 DevicePolicyManagerService 中添加了特定的 FINANCED_DEVICE_OWNER 类型,与传统的完全受管设备(fully-managed devices)区别,限制了 financed device owner 所能执行的操作,更加安全(?)。
从设计上来看,设备第一次开机,设置向导时 DeviceLockController 向自定义的 app 授予 android.app.role.FINANCED_DEVICE_KIOSK 这个 role(Android 14+),app 通过调用新增的 DeviceLockManager API 调用 DeviceLockController 提供的服务,DeviceLockController 验证权限后利用现有设备管理的 lock task 机制锁定设备。而 financed device owner 可以直接调用 DevicePolicyManager API 管理设备。不知道为什么要分两个,可能是允许 OEM 自定义。
以后就可以享受和 iphone 一样的,分期付款逾期不付直接被锁定手机的体验了。
注:搜索可以发现 Google 早在 2020 年就已经在 DeviceLockController 中加入了相关功能,但是并没有在系统底层添加原生支持。添加支持应该是为了方便 OEM 自定义?
https://www.xda-developers.com/google-device-lock-controller-banks-payments
Android 11 中引入的软件包可见性(package visibility, https://developer.android.com/training/package-visibility )可以过滤应用能够访问的应用列表,但实际上是鸡肋功能
一方面,该功能虽然对 PM API 及其他一些 API (如 getDefaultSmsPackage)返回的结果进行了过滤,但系统中仍然存在大量 API 允许应用违反可见性获得未知包,如 AccessibilityManager.getEnabledAccessibilityServiceList() 允许应用获得正在运行的无障碍服务列表,还有 Settings API 允许应用通过读取系统设置的方式获得无障碍服务列表及通知监听器列表等
另一方面,系统中存在大量漏洞允许应用绕过软件包可见性查询指定软件包是否存在,以 CVE-2021-0975 为例,该漏洞允许攻击者通过系统抛出的异常信息中的微小差异判断软件是否已被安装。对应补丁在 https://cs.android.com/android/_/android/platform/frameworks/base/+/bf0d59726a0d9973f6867faedac0fe476c81fe8b
类似的漏洞 Google 给予的评级一直都是 Moderate severity 因此只在 Android 大版本迭代时对其进行修复。这种漏洞还有多少,我简单检索了一下,仅仅只是 Android 14 中修复的有 CVE 编号的漏洞就至少有图上这些。同时,2023 年 5 月起大部分 moderate 漏洞不会再被授予 CVE 编号,被默默修复而不为人所知的漏洞又会有多少呢?
注:即使使用 HideMyApplist 这样的 Xposed 模块,也无法阻止软件通过上述方式违规获得信息。不排除未来会有软件利用这种方式绕过用户安装的 HideMyApplist 等模块获取敏感应用(如 Magisk/KernelSU manager)信息。如果想治住这些软件,稍微靠谱一点的方法是利用多用户,把它们扔一个单独的用户里。注意必须是完全用户,使用 work profile 是不行的。
1、2:把 service 打成了 ervice,少了一个 s,而且是两个 API 的示例代码一起打错。我 debug 了三个多小时才发现!!
https://developer.android.com/reference/android/nfc/cardemulation/HostApduService
https://developer.android.com/reference/android/nfc/cardemulation/OffHostApduService
3:文档里给出的示例代码引用的 API 根本不存在,尝试编译直接报错
https://developer.android.com/reference/android/content/om/OverlayManagerTransaction
4:一个 API,注释里写了可能返回 null,却被标记成 NonNull
https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/content/pm/PackageManager.java;l=7390?q=PackageManager.java
5:已经被修复的一个错误,用 void 表示状态
所谓“系统框架”其实指的就是 system server 进程,其中运行着大量的关键系统服务。虽然应用的进程是由 zygote fork 出来的,但实际上每个应用进程都会先向 system server 注册自己,system server 发回应用的信息,如 apk 路径,然后应用进程继续执行。只要作用于 system server 的模块都有机会篡改这个 apk 路径,打破作用域的限制,向任意应用进程注入代码。
这就完了吗?没有。
如果被注入的应用被授予了 root 权限,那恶意模块就能以该应用作为跳板,进一步拿到 root 权限。
那如果我一个应用都不给 root 呢?很遗憾,你的 root 管理器应用(比如 magisk 的 app)本身就有 root 权限,直接把恶意代码注入进去,就又能拿到 root 了。
强烈建议各位激活任意模块时都小心一点,尤其是当它推荐你选择“系统框架”的时候。
(PS:前几天就想发了,但是刚好碰上愚人节,容易被觉得是愚人节玩笑,所以延后几天)
https://t.me/Rosmontis_Daily/4631
(虽然从一开始的 0-click 变成了 1-click)
从作者引用的 PR 来看,我更倾向于认为这其实是两个 bug:
第二个 bug 可能最后被认为是预期行为,但是我个人倾向于认为是 bug。如果能找到不在白名单中的可执行文件后缀,加上这个 bug 又能再次实现 RCE。
事实上这种『缺乏对可执行文件的正确处理』的 bug 已经不是第一次出现了,详细可以查看:
https://evilpan.com/2021/09/23/macos-rce/#:~:text=%E7%9C%9F%E6%AD%A3%E7%9A%84%20RCE%E3%80%82-,%E7%9C%9F%20%C2%B7%20macOS%20RCE,-%E7%BD%91%E4%B8%8A%E4%B8%8B%E8%BD%BD%E7%9A%84
大部分加群验证机器人都是在有人进群的时候在群里发一条消息要求完成人机验证,而不是使用 telegram 的加群审批机制,打扰正常聊天,所以之前一直使用 Telegram Watchdog。
坑点:
1.官方实例经常掉线
2.部分使用 telegram 内置代理的用户尝试验证时打不开验证网页。可能是 iOS 上 webview 不走 telegram 内置代理?
3.部分用户尝试验证显示 Access denied。可能是使用的客户端版本过旧被服务器拦截,但是没有人配合测试,无法确认原因
4.在群组内有两只 watchdog 的情况下,部分用户反馈只收到一条验证消息(而且还过不去),不清楚原因
可能还有其他坑点,但是一直没有人配合调查,结果就是每天都有几十个人申请加群却过不了验证
后来 Rose @MissRose_bot 支持了新的加群批准,大喜,以为终于能摆脱坑了,然后踩进更大的坑
1.rose 的加群审批要开欢迎消息才能用,用户被批准进群后还会在群里再看见一条人机验证,完全失去优势
2.没有跟 rose 说过话的用户尝试验证会提示 bot 无法主动向用户发起私聊
实在不行了,Watchdog 和 Rose 一起开吧,能用哪个用哪个,总可以了吧?
大坑:
1.这种情况下,被 watchdog 批准的用户会被 rose 自动禁言,还要完成 rose 在群里发的验证(然后还设置了几分钟后自动删除)。经过测试,发现即使是被管理员手动批准的人也会被禁言,6…
2.如果之前已经被禁言,即使退群再通过 Rose 加群,进群之后仍然是禁言状态,必须再完成群里那个验证才能解除
跨频道联动:https://t.me/real5ec1cff/194
Android 2024 年 6 月安全补丁修复了一个由我发现并报告的漏洞 CVE-2024-31318 (漏洞补丁: https://android.googlesource.com/platform/frameworks/base/+/b68b257d56a8600d53b4d2d06fb82aa44086a4a5 )
回答思考题第 0 题:显然还是以 app uid 身份调用。但如果系统开发者忽略了 app 也可以调用 shell command 这一点,就可能造成安全漏洞。此漏洞本质上还是缺权限检查,不赘述。关于这一类漏洞的技术细节我会在本月博客上的安全补丁分析里说明。
那么为什么技术高超的 Google 程序员也能犯这种错误?
通过分析提交历史,我发现这个函数以前其实是有一个权限检查的,但是在 Android 14 的一个提交 https://cs.android.com/android/_/android/platform/frameworks/base/+/7a8f22792e45630bff14eb8b276c7649b0d79097 里被人删掉了。所以这其实是一个只影响 Android 14 的漏洞(这下新版本魔人大失败了)。
由于我不是 Google 员工,没法直接知道这个人这么做的原因,我这里只能猜测一下:可能是眼花了把这里看成已经在用 handleShellCommand 了,可能是觉得权限检查重复(Android 12 的时候这块代码在 ShellCmd 构造函数里),或者干脆就是 git 出了 bug 把这行给意外移除了,类似那个 gotofail 漏洞。
继续追踪提交历史,我发现了一个更搞笑的:2020 年,同样的系统服务,同样的 onShellCommand,曾经出现过一个一模一样的漏洞 CVE-2020-0227 https://android.googlesource.com/platform/frameworks/base/+/84cccfe6cdbc57ee372ee1a0fea64c7a11c53766^!/#F1 。
嗯,让你不写回归测试,白给赏金了这下。
时间线:
2023.10.4 Android 14 正式发布
2023.11.25 我注意到此漏洞
2023.11.26 构建了 PoC 并向 Android 安全团队反馈
2024.2.10 Google 确认此漏洞并将严重程度评级为高。对,你没看错,两个半月
2024.5.21 Google 通知我补丁将在下个月发布,并分配 CVE-2024-31318
2024.6.3 已经过去了 190 天,补丁终于发布
P.S. 从 Android 14 QPR2 开始,ActivityManagerService onShellCommand 中添加了检查,只允许 root/shell uid 调用,所以 app uid 无法再使用 am 或 cmd activity 系列命令。具体提交可见 https://android.googlesource.com/platform/frameworks/base/+/9e0c05e36afe0109b1df0d1bc375ade722138c81^!/#F0 ~
https://android.googlesource.com/platform/frameworks/base/+/1149dbb04b5a367c46bcfa5fcc0083dc2767a8eb
继对 system server 及部分系统应用开启 R8、Android 15 strip libart.so 后,Google 计划对 system server 开启完全 R8 优化。预计系统模块将可能会大规模失效。为啥以前机子存储空间小的时候不在意,反而现在开始扣大小?搞不懂搞不懂
(我自己在 Android 14 就被影响过一次了,虽然当时是 SystemUI)
给逝去的日子简单点首歌:
https://www.bilibili.com/video/BV13k4y1n7bd
转发自 易然个人频道
爱哭鬼 || 银教授
人活着这么辛苦,为什么还要活着?
是为了比一比谁更不辛苦,如果你的辛苦程度比别人低,嘻嘻,瞬间就开心了有没有?
就拿李建军来说,一场车祸,李建军失去了双腿,很辛苦了对吧?但是他的同学王褶容,失去了双亲。 每次想到这里李建军都忍不住笑出声。
如果你的人生都忍不住笑出声了,试问你还想死吗?一般都不会。
但也有人因为太辛苦而想自杀的,有一次我在天台抽烟,看到一个女孩站在天台上打算跳楼,我问:“你为什么跳楼?是感情不顺吗?”
女孩说:“女孩的心思男孩你别猜。”
如果一个女孩动不动就说“女孩的心思男孩你别猜”,那么肯定有感情问题。
我问:“你可以告诉是什么事情吗,说不定我可以帮你。”
女孩叙述了事情的经过:
就在刚才,她和男友吵架,
女孩对男孩说: “你根本不知道我在想什么!”
男孩:“你不说我怎么知道?”
女孩:“你不会猜吗?”
男孩:“那我猜猜。”
女孩:“女孩的心思男孩你别猜!”
我:然后呢?
女孩:然后他沉默。于是我就想死了,因为我最怕空气突然安静。
我:我觉得想死的应该是你男友。 他人呢?
女孩:在楼下。
我:为什么不上来?
女孩:刚跳下去。
我:那你为什么要跳呢?
女孩:我想和他双宿双飞。
我:人都死了,还想着双飞。
女孩:嘻嘻,真幽默。你有对象吗?
我:没有。
女孩:那你怎么还不去死?
我:死了也没有对象,那我为什么要去死。
女孩:也不是没有道理。
我:不过有时候的确想死。一个人久了,什么事都是自己做,就算自焚连个递打火机的人都没有,太苦了。
女孩:是的,我现在想跳楼,连个推我的人都没有。
我:要不我推你一把?
女孩:好呀!
于是我把手放在女孩腰间。
女孩咯咯咯笑了,她说:不能放这里,太痒了,我会笑的。
我:笑不好吗?可以含笑九泉。
女孩:我笑起来不好看。
我:不,你笑起来很美。
女孩:谢谢你。你真好。我男朋友从来没夸过我。
我:开心吗?
女孩:开心。现在我又不想死了。我觉得只要还能开心,就没必要死。
我叹了口气。
女孩:叹气干什么。
我:你已经死了。
女孩:什么意思?
我:三年前我在这里跳楼,跳完我就变成了鬼。
人在刚变成鬼时,并不知道自己是鬼,所以我以为自己还没死。
当时我站在天台上,看着太阳升起,突然不想死了,于是我就下楼回家。
回家后,我发现大家都看不到我,无论我跟谁说话,都没人理我。
我对着我的亲人大喊大叫,声嘶力竭,但我好像是一团空气。
那种无力感你知道吗?就是用尽所有的力气却没有任何作用。
后来我才意识到,我已经死了。
听完我的话,这个女孩继续哭。
哭了很久很久都没有停下来,也许她就是传说中的爱哭鬼吧。
这三年来,我见过很多自杀而死的鬼魂,大多数都很后悔。
活得不开心,可以换一种活法。但是死得不开心,就没法重新死了。
经常看见有人上传一份 magisk 日志就来反馈问题,然后被禁言又在那里抱怨说“我提供了日志啊”
那就来看一下,magisk app 底栏上那个“日志”里面保存下来的到底是什么东西
它大概包含这些玩意:
第一部分:设备基础信息,内核版本
第二部分:系统属性,注意这里不是 root 获取的,所以只包含 untrusted_app 有权限访问的
第三部分:环境变量
第四部分:app 的 mountinfo
第五部分:magisk 自己产生的 log,即 /data/cache/magisk.log 或 /cache/magisk.log。注意,它只包含 magisk 自己主动打出来的日志,其他日志,比如崩溃日志,不会被记录下来
第六部分:app 自己运行 logcat 读到的日志,只能读到自己 uid 产生的
接下来设想几个情况
场景一:开不了机。很明显根本进不去 app,即使运气好有 adb,如果没有提前授权 root,也拿不到 magisk.log。就算拿到了,它只包含 magiskd 自己主动打出来的日志,不包含崩溃日志,里面几乎不会有什么有用的东西。不如一句 adb logcat 有用。
场景二:magisk app 显示“无法获取”,即所谓的“掉 root”。这种情况有太多种原因,然而无论是哪种,由于 magisk app 自己没有 root,它能读到的东西基本上不会有什么用。不如一份 logcat 或者 bugreport 有用。
(题外话,如果是因为 magiskd 崩溃引起的,由于它会 block 所有信号,崩溃的时候不会有任何记录,静悄悄的退出)
场景三:zygote 崩溃太多次,触发 zygisk 自动关闭。magisk.log 不会记录崩溃日志,自然也记录不到 zygote 崩溃日志。不如 logcat 有用。
场景四:模块工作不正常。magisk.log 只会记录自己主动产生的日志,模块自己出的问题当然和它没关系。不如一份 logcat。
很多人说日志太多了,我觉得恰恰相反,是太少了以至于它自己的问题都难以调试。感兴趣的可以看一下我 debug 这个问题的艰难过程:https://github.com/topjohnwu/Magisk/issues/4174
https://github.com/canyie/MagiskEoP/blob/main/screen-20220302-093745.mp4
Demo video for exploiting a vulnerability in Magisk that allows local app to gain root access without any confirmation or acceptance and execute arbitrary code with root privileges. It demonstrates silently obtaining root privileges and silently granting root to any app.
演示视频,利用 Magisk 中的一个漏洞静默获取 root 权限并以 root 特权执行任意代码而无需用户确认。我们同时展示了如何利用此漏洞获取 root 后向任意 app 静默授权 root。
Exploit source code and writeup is now available at https://github.com/canyie/MagiskEoP
本来还想着要多久才能有人发现这是 app 问题的,结果当天晚上就被吴自己指出来了,没意思
不会 Android 开发的人,能不能挖到 Android 系统的漏洞?
先说结论,可以,但是能挖到的漏洞类型肯定有局限
其实我觉得关键的反而不是技术实力,是能不能判断出漏洞
很多人都觉得,系统安全漏洞这种东西,肯定很复杂,肯定都是内存破坏什么的,都是什么缓冲区溢出、释放后使用这种一听就很高大上的东西,包括我自己以前也这么以为
其实 Android 系统很多漏洞都不是内存问题,反而有很多的 UI 层漏洞,有些问题甚至不用写代码就能触发,看你对系统的熟悉程度
举个例子,2022 年那个价值 7 万美元的锁屏密码绕过漏洞 CVE-2022-20465,这就是纯粹的 UI 层漏洞,不用写一行代码就能触发,能在没有锁屏密码的情况下解锁设备,很明显这是漏洞,对吧?那其他看着没那么明显的东西,有没有可能也是漏洞?
今年八月有个漏洞 CVE-2024-34734,触发方式是在设备锁屏的时候下拉状态栏,里面有个“活跃的应用”,旁边有个“停止”按钮,用这种方式可以在没有密码的情况下杀掉 VPN 应用。可能看起来它不像漏洞,但是它能让没有密码的人停止掉 VPN,假如机主没有注意到 VPN 已经停止,继续使用网络,这个时候是不是就在用非预期的不安全网络?
Android 系统还有一个功能叫多用户,效果很明显,可以让多个人共用一台手机。NFC 设置里有个选项,只允许锁屏解锁之后使用 NFC,术语叫 secure nfc。假如机主打开了 secure nfc,切到访客用户然后给另一个人借用手机,这个人进设置里关掉了 secure nfc,然后切到机主用户,不输密码,是不是也能用机主的 NFC 支付了(CVE-2021-39807)?类似的还有访客用户帮你降级系统应用、添加 WIFI 网络等等。
Android 12 开始有个功能,有应用在录音或者录像的时候,状态栏右边会显示一个绿色的小点来提醒你,正式的名称叫“隐私指示器”。假如你平常用手机的时候,发现在某个应用里录音或者拍照的时候,这个指示器没出来,那你也可以去报漏洞。更进一步,这个指示器是 SystemUI 显示的,假如录音到一半 SystemUI 进程死掉了,那重启之后这个绿点还会不会显示(CVE-2024-0019)?
还有个功能叫屏幕固定,英语叫 app pinning,作用是借给别人手机的时候把手机固定在某个应用,比如借给别人打电话的时候你肯定不想让他进你支付宝里转钱。还可以设置退出这个状态时必须输入密码。那如果有办法在无密码的时候退出这个状态,也会被认为是漏洞。那假如说在这个状态下,被固定的应用被卸载了会发生什么(CVE-2020-0024)?
上面这种情况还有很多,比如如果在锁屏页面能查看隐藏起来的通知,那也算漏洞,看你的想象力够不够丰富。还可以玩排列组合,比如 Secure NFC 那个漏洞,访客用户不允许去改这个设置,那普通的第二用户应不应该去改(CVE-2023-21086)?锁屏的时候不能断开 VPN 了,那访客用户能不能断开主用户的 VPN?用屏幕固定这个功能固定了一个应用,那能不能下拉状态栏,在“活跃的应用”里停止当前应用,从而退出屏幕固定?
所以其实我认为关键点在于:1. 能不能想象到威胁场景 2. 看见一个东西能不能判断出它有没有安全风险。Android 给的漏洞赏金还是挺多的,高质量的高危漏洞报告基本上就是 7000 美刀。打个五折,不算税费,还有 3500 刀,按今天的汇率换算成人民币大概是 25000,一个月花 1000 也够花两年多了。如果真的有人对这方面感兴趣,可以关注我的博客跟频道,后续也会推送相关内容。
这里有一张照片但是我懒得放到博客里 自己想象吧(
配文:
洗完头没梳头 懒得梳
感觉不如把头发全拨到前面扮贞子
反正刚好也在床底下 还可以喊我床底下怎么有人
一年之后:当我在放屁
读大学有啥用啊 还不如直接出来进厂
引用 https://t.me/newqianzhuang/24
从 Android 14 开始,普通应用将无法读取 ro.debuggable 和 ro.secure 两个系统属性[2][3]。这对使用第三方 ROM 的隐藏魔人来说,无疑是个好消息:许多应用通过这两个属性来判断系统是否为 userdebug 或 eng 构建。
续前文,其实我们当时还发现了另一种方法在 AOSP 上绕过此限制:使用 app zygote。
AOSP 中这个限制是使用的 SELinux 规则来做:
1 | get_prop({domain -untrusted_app_all -isolated_app_all -ephemeral_app }, userdebug_or_eng_prop) |
对 domain 授予权限,但排除 untrusted_app_all、isolated_app_all、ephemeral_app 这三个域。也就是说,这条规则会对除不可信应用外的其他所有域授予读取权限。但是实际上,app zygote 进程运行在 app_zygote 域下,而 app_zygote 并不属于上面提到的任何一个域,所以其实用 app zygote 就能直接绕过限制。
我们给 AOSP 提了修复,很简单,直接在上面的规则里加上 -app_zygote 即可。预计应该是 Android 16 才会包含这个修复。
Android 15 默认开启了 Sdk Sandbox ~
勘误:被文档和其他人误导了,没有默认开启,到目前 Android 16 DP1 仍然处于默认禁用状态
官方文档:https://developers.google.com/privacy-sandbox/private-advertising/sdk-runtime
研究记录:
<application> 下设置的 processName 加上后缀 _sdk_sandbox 作为 service 的 instance name,由于 retrieveServiceLocked 会使用这个 instance name 查找 ServiceRecord,如果多个应用(这里不考虑多个应用共享进程的情况)同时调用同一个 sdk,由于进程名不同,instance name 也不同,即使该 sdk 已经有进程在运行也不会被复用 3 4细节还是挺有意思的,当然也有未考虑到的地方,如有错误不吝赐教。目前 Magisk 的 denylist 还没处理这种情况。
复活一个半年前就被修复的漏洞?我把三月份就应该被修复的 CVE-2024-0044 续命了半年
PoC & writeup:
https://github.com/canyie/CVE-2024-0044
这个漏洞已知在被取证公司积极利用,不想被取证的用户建议尽快升级。看热闹不嫌事大的可以关注各取证厂商,估计很快就会说自己突破了提权技术难关之类的了。
陪同残疾人士 乘坐东方航空航班 广州白云->上海虹桥 体验
一定一定一定一定一定要让人早点到机场!!!16:30起飞的飞机,我14点到机场,然后一直没值机,就是为了等人,结果人15:35才来,给我气炸了
虽然来得比较晚,但是提前预约了东航的无障碍服务,各项照顾还是很到位的,比如下机用无障碍登机车,机场有专人帮忙推轮椅到机场出口等
虽然预约了东航无障碍 但是没约白云机场的无障碍…然后到现场之后临时约,无障碍登机车是没了只能爬登机梯,然后因为登机即将截止,机场小姐姐帮忙全速推轮椅终于赶上飞机,在这里给白云机场工作人员点个好评(
提前预约东航无障碍服务会导致他们给你提前订好一个座位 然后我值机的时候想坐一起 尝试选旁边座位没成功 所以有相关需求的旅客建议提前预选好座位 虽然这次航班机组直接给免费升了超级经济舱(
总结:1.早点到机场 2.需要特殊服务早点预约 3.座位早点选
附1:上海地铁好几个站的无障碍电梯是在付费区外然后直接进入站台的 导致两个问题 1.进站之后想用无障碍电梯需要先找工作人员出站然后按求助按钮让工作人员给你开电梯 2.从站台坐电梯上去会直接出付费区,需要找工作人员帮忙刷卡出闸,否则系统里没有出闸记录
附2:预订酒店时应该提前确认该酒店是否无障碍友好,否则就可能像我们一样,到了酒店发现房间是复式的,分为多层,需要走楼梯才能上床,然后只能默默退房找了间汉庭住
总体挺好的 就是这个会场有点伤眼睛
省流:
https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md
才发现竟然有这种文档,不知道是不是我火星了。里面 Correct soname/path handling 这个问题是当年 Magisk 还支持 Android 5.0 的时候就遇到过的。
去食堂打饭 阿姨打的饭嫌多 平均只能吃掉一半
去外面吃饭 吃啥都嫌多 一碗啥都不加的螺蛳粉吃完还剩一半粉
在家天天被念叨让多吃一点
水喝多了都嫌撑
碰上聚餐/花钱比较多的情况更是不得了 只能本着钱都花了不能浪费的原则往嘴里塞
然后代价就是胃疼/反胃/反酸 不敢平躺 睡不着
到底哪里才有适合我这种饭量的人的饭啊 难道我只配一直啃包子/馒头/面包吗
https://blog.canyie.top/2024/11/05/android-platform-common-vulnerabilities/
新博客,介绍一下挖 AOSP 漏洞的时候可以挖到哪些。
这篇博客本身有没有用我还不知道,但是编写它让我发现了一个高危 CVE-2024-43088。谷歌在 11 月补丁中终于修复了它,也让这篇文章终于能够被大家看见。
另:11 月补丁中修复了我的另外三个漏洞 CVE-2024-43080 CVE-2024-43081 CVE-2024-43090 ,同时修复了 LSPosed 团队其他成员报告的 CVE-2024-43093 。感兴趣的可以看看。
这个问题被分配了 CVE-2024-48336。
这里给出一个额外提醒,就是很多 app 使用了类似的代码,但没有正确修复这个问题,比如 FoxMagiskModuleManager 1 和 KeyAttestation 2。用同样的方法可以注入任意代码进受害 app,然后利用该 app 被授权的额外权限比如 root。能做的事情就很多了。
当然你还可以搞一个什么 “密钥认证一键修复 app”然后发去小绿书(
有效法律证据形式
根据 GA/T 1564-2019《法庭科学 现场勘查电子物证提取技术规范》,应对现场、屏幕进行拍照或录像,记录物证的系统时间和北京时间;对有密码保护的数据提取并保存在有唯一性编号的专用存储介质中。
根据《公安机关办理刑事案件电子数据取证规则》第八条,需要及时固定相关证据时,可采用打印、拍照或录像等方式。第二十三条,对公开发布的电子数据、境内远程计算机信息系统上的电子数据,可以通过网络在线提取。
取证要点难点
数据解密(Android 上应用数据被 FDE/FBE 保护,开机第一次输入密码后才会解密数据),数据保持,数据防销毁
分点解析
由于 Telegram 功能特性,聊天的一方可以为另一方删除聊天记录,扣押到检材后需要立刻断开网络,不要轻易重新连接网络,以免证据被远程删除;可重点关注被设置了定时删除或加密的聊天;可以通过截图、录屏等方式保存证据,对获取到的数据计算哈希值校验并留存。通过 Telegram Desktop 也可以直接导出嫌疑账号数据,但是需要注意账号新登录官方版 telegram desktop 后尝试直接导出数据会提示需要等待24小时,并且该操作会向其他登录会话发送提醒。也有其他第三方 telegram 专用取证软件可用,但一定注意提取范围不要设置过大,避免数据量过大触发服务端安全保护。
对于群聊数据遭到批量损毁的情况,若被控制账号有群聊管理员权限,可使用脚本导出群聊近期操作记录,如 https://gist.github.com/avivace/4eb547067e364d416c074b68502e0136
根据设备类型不同,也有第三方数据提取软件可用,如针对 Android 平台的多个取证软件,这些取证工具一般使用漏洞提升权限然后读取目标应用的私有数据,常见的被利用漏洞有 CVE-2024-0044(AOSP 框架漏洞,由 Meta Red Team X 及我报告)、CVE-2024-31317(AOSP 框架漏洞,由 Meta Red Team X 报告)、CVE-2024-4610(Arm GPU 驱动漏洞,影响除高通平台外大部分平台)及部分厂商如三星自己的漏洞等。取证公司仍在持续挖掘漏洞并转化为利用,如奇安信旗下盘古石取证团队近日宣布再次突破 Android 11 - Android 14 最新安全补丁提权:https://mp.weixin.qq.com/s/MorsW-Vx_Eb_WnqFtj_T5Q
部分设备可能存在设备管理 app 等,可能导致检材上的数据被擦除,可以使用漏洞对相关管理 app 进行禁用或无效化处理。除了传统的垂直提权漏洞,其他类型的漏洞也有可能被利用。本月 Android 安全补丁就修复了我发现的一个可使设备管理机制完全失效的漏洞 CVE-2024-43081,可能会被积极利用。
部分第三方系统存在额外安全保护机制,如设备闲置过指定时间后启动额外的数据保护机制如重启,应阻止设备休眠。
仅做备份处理,希望大家都用不到。
https://blog.canyie.top/2024/11/07/self-changing-data-type/
之前十月补丁分析没给出 CVE-2024-40676 这个漏洞的细节,原本以为可以安安静静当谜语人的,结果还挺多人对它挺感兴趣的,那顺便把之前分析的结果公开到博客上。准备以后抽空把之前挖的坑全填上。
另:总感觉我的博客浏览起来比其他博客更卡,有人有同样感觉的吗?似乎该花点时间再优化下体验了
最近认识了很多人 感谢各位大佬的引荐 才能让我认识这么多大佬
很多人认识我的第一句话是 “你好年轻” “还有这么年轻的研究员” 之类的
类似的话我已经听了六七年了 但是每过一年听 都有不一样的感觉
今年20岁了 现在更像一种怀念 怀念我真正年轻的时候
作为一名研究员 我发现过很多漏洞 用一年时间打进了全球前二十
但是我觉得论这些洞的巧妙程度 元反射是当之无愧的王
提出它的那一年我14岁 初二
没有现在这么多的知识积累 纯靠脑力 从最基本的逻辑出发 以子之矛攻子之盾 用最简单的方法击碎谷歌精心布局设下的防御
即使它根本就不是个安全漏洞 我也觉得它是我提出过的最好最有创造力的 exp
跟它相比 我后面写的东西挖的洞都一文不值
“天才”描述的是一个人有极强的“跳跃式”的理解能力和创造力
而“工匠精神”的“工匠”强调的是一个人追求技能的极致完美并付出行动去打磨它
两者的区别是 工匠的成长过程是重复的 线性的 而天才是非线性的
天才不需要多少知识储备就能抓住事物的本质并打破传统思维路径提出创新
这是天赋 是上天给的 后天补不了的 也是我永远都不可能再有的
所以“工匠精神”被传颂 被称赞 被学习 却没有人宣传“天才精神”让大家学习当天才的
自那以后 我再没有提出过如此精巧令人惊叹的创新
我怀念我的14岁 我怀念我没被禁锢的 真正年轻真正有活力的头脑
14岁 2018年
那一年 还没有疫情
那一年 《学猫叫》火遍大街小巷
那一年 我初二 现在大二
那一年 没有成就 没有作品 甚至连电脑都没有 只有一颗活跃的大脑
那一年 像是被灌输了无穷的青春活力的一年
那一年 只能留在回忆里 永远也回不去了
人类的有些反应是刻在大脑里的。
但是人们都不愿意说出来。因为说出来显得自己很不理智,不符合社会对一个成年人的期望。
理由,或者说借口,就是这样衍生出来的。说白了就是掩饰自己的原始欲望而已。
人们嘲笑胖猫是因为胖猫抢了自己的饭碗,或者胖猫投河污染了自己的水源吗?
人们嘲笑胖猫是因为想。
这里胖猫只是个符号而已,什么符号?被嘲笑的符号。至于胖猫自己到底是谁干了啥已经不重要了。有瓜不吃不嘲笑就失去了这两个字的意义。
中文互联网流行给别人名字冠上牢字辈。不知道胖猫有没有获此殊荣。
你小时候哭,家长有的时候会哄你,等你长大了再哭,家长就会教育你“大丈夫流血不流泪”。
他们是希望你用流血代替流泪吗?他们是不耐烦你不想看你哭。
要是小孩真的去用流血代替流泪,用自残发泄情绪,他们就会求你别这样干了让你想想你的父母。
别问我怎么知道的。
把人类历史往前推百万年也一样。
生活在四百万年前的南方古猿,或者现在流行叫吗喽,能繁殖延续这么久,难道是为了保护生态圈防止种族灭绝吗?
吗喽繁殖是因为想。繁殖了它就爽。
想体验一把吗喽的原始快乐怎么办?
有一个网上流传的方法,找个甜的橙子洗干净,去浴室,关门,开热水淋浴,直到把全身都打湿,直到浴室里充满蒸腾的水汽。
这个时候咬一口橙子。
品就好了,不需要全吃下去,让汁水从嘴边混着热水流下去也行的。
没条件试的可以上 b 站搜“洗澡吃橙子”,赛博体验一下。
你看,事情就这么简单。刻在基因里的想。
其他什么理由什么借口都只是人类文明给生物本能加上的华丽修辞。
说好听点叫华丽,说难听点叫虚伪。
当然我也并不是什么好人。从吗喽继承过来的本能我也有呢。
人类的行为没有原因。也不是万事都需要原因。
生物学上的平等才是真正的平等。
感谢生物学,感谢进化论。
不过你要追究其原因,当然也是可以的。
从弗洛伊德的精神分析理论去看待,它可以被解释为“合理化”或者“压抑”的“防御机制”。
再更进一层,它可能是什么神经元什么神经递质层面的反应。
这样探究下去就无止境了。在有原因和没有原因之间反复横跳。
可惜我不懂这么高深的知识。我也没义务去给所有人做心理治疗。
偶然看见去年 Pwn2Own 上攻破小米 13 pro 的一个团队公开相关信息了,刚把 ppt 看完,觉得挺有意思的,不过最有意思的部分不是漏洞细节
演讲视频:https://www.youtube.com/watch?v=B0A8F_Izmj0&ab_channel=DEFCONConference
相关材料:https://github.com/Yogehi/cve-2024-4406-xiaomi13pro-exploit-files
省流:小米在 Pwn2Own 期间故意进行针对性干扰以阻止其产品被选手攻破,相关干扰措施仅在 Pwn2Own 期间生效,比赛结束后即被移除
其描述的相关细节让我觉得似曾相识。扩展阅读:https://xuanxuanblingbling.github.io/iot/2022/09/16/mi/
怎么说呢,鉴于小米产品在“各类黑客比赛上/期间”表现出“特别”突出的安全性,建议研究人员不要将小米产品作为目标
(长文预警)
2021年9月至12月5日,我刚满17岁,因学校强制要求实习,我和班上大部分刚满16岁的同学一起先后在两家电子厂当普工。第一家电子厂在河源,我只待了一个多星期,后跟随学校转场到另外一间位于东莞大朗的电子厂。
这间厂是造手机的代工厂,我在流水线上干了三个月,换了三间车间,每个车间代工不同品牌手机。
可能有人不知道流水线的工作是咋样的,大概就是每个工位只负责做自己固定的任务,比如装摄像头等,装完传给下一个。所有操作都被标准化规定好,工位上还有标准作业程序(简称 SOP)。我进的厂入职还有考试,内容就是防静电操作等。我上班的厂给每个工位都配备了凳子,但是我基本上都是站着干活,因为坐着根本干不过来。然后还有 IPQC 和 FQC 负责监督你干活还有干活的质量。
流水线在工厂里叫“拉”,相应的“线长”就叫“拉长”。两班倒(除部分车间),七点四十五之前要到车间,有几率要站那里听车间主任或者拉长开会。然后八点正式开始干活。每天的任务不同,一般一条线一天要下 1000 至 2000 台手机。(这里不用“生产”是因为厂里除了组装线还有测试线、包装线以及测包线)
下班时间看你干活的速度,早上八点上班的话基本上都是晚上九点左右下班。中午和下午各有一个小时吃饭时间,但实际上还有一个叫做“连班”的东西,即下午的班跟晚上的班连着上,中间不给你休息时间也就不用想吃饭。我三个车间的工作都在拉尾所以基本上是最晚下班的,工作时间最长的一次是早上七点四十五上班,晚上十一点二十下班,而且还是连班,晚饭都没吃。休假更是不用想,宣称是单休但实际上连单休都难。中秋节放了一天假就把当周周日的休假取消补回来。其他大部分时候周日也放不了假。国庆放假三天应该是最长的假期。不过也是放过一次双休的,是因为工厂没货干不了活。
至于工资,作为一名光荣的学生工,我们光荣地在东莞这种被广州和深圳夹着的地方获得了高达 9.5 元人民币的时薪。问车间其他员工也大部分表示是 11 至 13 元左右。我知道我该得的工资肯定有一部分进了别人手上。第一个月发了2800,第二个月发了3800,第三个月3500,12月在厂里干了三个晚上给我发了58块钱(不过忘记是不是因为其他因素扣款了)。
我待过的三个车间里绝大部分都是像我这样的未成年学生工。全国各地的都有,最远的见过四川过来的。厂门口有个篮球场,接学生工过来的大巴就停在旁边的路上。我离开的前几天路过那里,都还能看见大巴车跟新来的学生。至于为什么,可能是因为学生好骗好管还不用开太多工资吧。
在厂里工作的三个月,我的感觉就是麻木。每天的生活就是宿舍-食堂-车间,没有时间也没有力气再去干别的什么事。三个月出厂的次数估计不超过十次,唯一的一次双休还因为我头晕而在床上度过。偶尔出去一次,看着厂门口的广告牌写着“诚招普工,单休,月工资6000-8000”就觉得好笑。厂的位置在东莞松山湖,离华为东莞总部只有三四公里,很接近深圳,在天上每天都能看见飞机。可是与我无关。
我到现在还记得工厂里的防静电要求,静电服、静电环、手指套、离子风机样样俱全,酒精上还印着 RoHS 标,虽然上班一个小时之后手指套基本上就破完了,然后就是手指肉去生碰机子,每天下班手指头上都是血。
厂里让我印象深刻的有两件事:
1.12月3号我干活的时候对面工位的同事在纸上给我写了一个 qq 号,但是我在干活暂时没理他,他就把纸条扔进了垃圾桶。我胆小,没敢说话,原本想着4号还能再问问的,结果因为我们学校的学生全部5号走,整个车间4号直接停了。我没能看见他给我留的 qq 号,没能知道他的名字,也再不会有机会见他一面或者跟他聊天了。我其实还记得当年几个拉长还有几个同事的名字,但我这辈子应该也没有机会再见一次他们了。
2.某次我跟其他几个人一起干 MMI 测试,我旁边是个看起来比我还小的小姑娘,她问我为什么有台机子重测了几遍都测不过,我看了一眼上面显示 fingerprint sensor fail 之类的英文,跟她说打个不良标放着,报表上记个不良品,指纹传感器有问题。然后她特别惊奇地跟我说,你看得懂英文?你看得懂英文为什么会在这里?那一瞬间我的心里五味杂陈。
那三个月我甚至不知道我是怎么活下来的。说不定是每天干活能流血感受疼痛还能让我保持点清醒吧,毕竟我现在也经常自残看血流出来,哈哈哈。可能得归功于 lsp 群群友愿意陪我聊天吧。不过也物是人非。当年和我聊天的人里很多都销号了,我还记得的人里有个被某些自命清高的高雅人士逼退网了,有个因为癌症离世了。
三年过去,我也换身份了,从电子厂员工变回学生再变成 framework 开发者再变成安全研究员。我收到第一笔漏洞奖金的时候第一感觉是惊讶,然后就是在想,卧槽钱原来这么好赚,那我之前的日子,尤其是在电子厂那三个月,是不是都活到狗身上了。我是个小县城长大的孩子,不开玩笑地说,那笔钱直接改变了我对钱的认知。到后面我以世界顶级研究员的身份受邀跟其他大佬见面,见到了之前我代工过的某手机品牌的公司的技术大佬。我特别戏谑地跟他们说,你知道吗,我给你们造过手机,然后解释原因。我们聊天的时候都是笑着的。
三年前,17岁的我是你们品牌代工厂流水线上的一个月工资3000的学生工。三年后,20岁的我用自己的努力和实力以受邀者的身份出现在这里,至少在这张桌子上,我和你们平起平坐。
我怎么活过来的,只有我知道。
哦对了,忘了提一点,当年我是拒了阿里的内推选择跟着学校去电子厂实习的。至于原因,家里人觉得杭州太远,不如跟着学校还安全点。
为电子厂拒阿里,这事我特么能吹一辈子。
我的感想就是人应该多去看看世界的另一部分人是怎么样的,增长下自己的见识。别像我一样在上海世贸大厦底下看着电梯要刷卡才能进去选择在一楼转圈消磨时间,转了几分钟才知道是要找人帮忙刷卡。
然后我去高德上搜了一下那个厂的评价,看起来没变多少。我当时住的是六人间改的八人间,据说厂里在建新宿舍,到时候住宿环境会更好。但是看今年的评论,似乎变成十二人间了。
据报告部分一加设备升级到 Android 15 后出现无法使用 Termux 的情况,相关进程被不明原因杀死。Termux 开发者表示禁用 phantom process killer 后问题仍然存在。有用户报告此问题影响 Magisk 导致无法在 Magisk app 内修补镜像。部分受影响设备安装最新的 ColorOS 更新后问题消失,但似乎仍有部分受影响设备尚未收到更新。
建议一加用户若收到 Android 15 更新且构建日期早于 2024 年 11 月 9 日,谨慎选择安装。若您已受该问题影响,请等待厂商发布更新。
参考:
https://old.reddit.com/r/termux/comments/1gks9mf/announcement_termux_broken_on_android_15_for/
https://github.com/termux/termux-app/issues/4219
https://github.com/topjohnwu/Magisk/issues/8553
版本代号为 Baklava 而非 W 开头,比往常提前了几个月。预计 2025 年将有两个大版本发布 1。
这一次版本代号重新回归到了 B 开始计数,可能是因为 Android 内部开发流程发生较大变更(project trunk stable?)所致 (来源:Mishaal Rahman 2)。作为 project trunk stable 的重要部分,aconfig / feature launch flags 的文档已经上传至 source.android.com 3。
简单刷上去试了一下,感觉 UI 更丑了,有一种没事强行整强调背景色的感觉…… 放了亮色和暗色模式的截图,感兴趣的可以看一下。
系统设置项被重新排列,把 Google 账户放到了第一位,About phone 被放到了中间,Accessibility 跟 Tips & support 放到了最底下…… 感觉让残疾人更难操作了。
Pixel 6 系内核从 5.10 升到了 6.1 好评,其他没感觉到什么大的变更,简单跑了一下梦境,一行代码不用改直接跑通,估计没啥大更改(也有可能是都没开?不过不太可能)
中国很多家庭会在家里供奉神明或者仙人,拜佛烧香。拜文曲星或者观音菩萨的多见,但是好像很少看见有人拜阎王的。可能是觉得跟死亡沾边不吉利,但是清明节去上坟烧香的又不少。另一种解释是拜佛上香火是为了向神明表明自己的虔诚以祈求庇护,而阎王的形象让人感觉拜了也不会得到庇护。民间流传的阎罗王殿贴着的对联有多个不同版本,在这里挑几副供大家欣赏:
“上联:阳世人间,为非作歹任凭你;
下联:阴曹地府,古往今来放过谁?
横批:正要抓你”
“上联:能耐再大,到这里休得施展;
下联:冤深似海,非此处哪能分明?
横批:你可来了”
传说十殿阎罗的第五位是大名鼎鼎的铁面无私包青天,从这里也可以看出人们认为阎王的形象是处罚坏人的,即“惩恶”,而像“扬善”这样的活就交给慈悲为怀的菩萨。朴素的贫苦大众相信恶人无论在阳世间多有钱有权,在另一个世界都会被用油锅烙铁案板屠刀各种刑罚好好对待。但是拜铁面无私的执法者并不能直接给自己带来好处,有限的香火不如供奉其他神明。大家心里是希望好人得到好报而坏人得到坏报的,但在两者之间权衡,似乎让自己得到好处更优先。如果负责“扬善”的神明只需要人用香火去供奉就会给那人以好处,那这“扬”的,还是“善”吗?这样看来,负责“惩恶”的神明又显得有点可怜了。
以上文字写于某位友人离世一周年之际。终于赶在凌晨零点之前发出来了。其实我还想设定时消息,但是 telegram 定时消息有很大延迟。
写到一半才想起来,刚好昨天也是另一位熟人离世一周年。之所以说是熟人,是因为我和她直接接触很少。但她关注了我的某个频道,所以我记着。我也经常偷偷的去看她的频道,但是没关注。
传说中的阎罗王是绝对公平绝对正义的吧,我希望是这样。
我常幻想没有我的日子里,或者说我还不存在和我不会再存在的日子里,的故事。我作为看客,静静地看着斗转星移春去秋来。但我恐怕很害怕看见幸福结尾。我仍想抓住世间事物的一点点痕迹,但我只能看着没续费的博客随着时间的推移不再可以访问,看着太久没登录的账号被注销。看着人来,目送人远去。只是目送。
一直有人想知道我的“成长路径”是啥样的 这里随便写点东西
我出生在一个广东的小县城,简单来说就是穷地方,gdp 在全省是倒数的。小时候就对计算机很感兴趣,四年级的时候学校开了电脑兴趣班,本来因为是教编程就报了,去了之后才发现是教用 flash 画画。四年级的时候身体经常不舒服,后来才知道这个叫躯体化症状,五年级的时候更严重了,从那个时候开始就很少去上学了,初中休学一年但是复学之后也没怎么上学,一直到我上中专。所以我在义务教育阶段有五六年的时间都是没正常上学的。这就是我为什么没参加中考。
除了去看病(包括住院)之外,剩下的时间我一般就是在家待着。我本来就对游戏没什么兴趣(事实上我到现在都没玩过什么流行游戏,什么王者荣耀什么吃鸡我都没玩过),在家待着也挺无聊的,干脆学一下自己一直很感兴趣的做软件(后面才知道有个术语叫编程)。
那个时候我只有一台手机,我还记得型号,是酷派的 Y80d,安卓4.4,家里人只有每天下午到晚上会给我手机,没有电脑。在网上闲逛的时候发现了一个叫做 iapp 的软件,那个时候还是 1.x 的版本,能自己在手机编个小软件出来,然后就喜欢上了,开始学。它支持可视化设计 app 的界面,可以直接点点点然后就可以拖一个按钮出来,用的是自己发明的一个脚本语言,难度不大,语法非常奇怪,但是有判断循环这种简单结构,然后我就这样打包出了第一个 app,然后我发出去别人就能直接安装使用了。我第一次发现原来做个软件这么简单,说真的它很大程度上激发了我的热情,然后我就开始玩了起来。那个时候我最不缺的就是时间。你问我为什么不去学易语言?因为我没电脑。
后面想学点正经的,学了点 js 跟 lua,现在已经完全忘光了,后面觉得还是学 java 好。正好手机上也有个能用 java 编 android app 的软件,叫 aide,然后就学起来了。说实话我不是个聪明的孩子,我当年学 java 耗费了很长的时间,难以理解类跟对象的概念以及它到底有什么用。后面我选择不看什么入门教程了,直接去贴吧找了个简单的项目打开硬生生啃,我也忘记了多久,突然就像开窍了一样,然后算是终于过了 java 这关,然后进入真正的 android app 开发环节。
然后后面我又写腻了,我不知道该写什么项目玩,看着各位大神博客都是分析系统源码,看起来好像也不难的样子,那就开始看这块吧,想到什么地方看什么地方。我英语不好,但是官方的 api 文档都是英文的,很多时候去看文档不开翻译器看不懂,干脆直接去看系统源码,有些时候反而还容易理解一些。那个时候 android 很火的技术就是插件化,热修复,kotlin 什么的,kotlin 我在手机上玩不了,就从其他两项入手自己玩玩。
然后我还是不知道干啥,我觉得自己基础的都会了,但是自己搓的东西跟别人开源的库根本比不了。客户端技术实在是变化太快了,后面流行什么 databinding,还有 ReactNative 跨平台这些,我只有个手机根本就没法玩。(这里加一句,当年写跨平台的公众号现在都开始发鸿蒙开发了,可见当年跨平台搞得到底怎么样。)我那个时候很浮躁,很想搞点大名堂,像 weishu 的 VirtualXposed 那样,但是又不知道干啥。一直到后面 android 9.0 测试版,引入了 hidden api 限制,对我个玩插件化的人来说简直是晴天霹雳,然后赶快去网上搜相关文章。刚好 weishu 也发了个博客,分析 art 源码去绕过,看完之后觉得其实也没那么难,然后自己也提成了两个绕过方法,但是只有一台安卓5.1的手机没法测试,后面还是去找了个群友才验证成功。
上面的经历让我敢于尝试去搞搞 art 相关的,看 weishu 的 VirtualXposed 搞得那么厉害,我也想搞一个玩玩。非常感谢 weishu 以及 YAHFA、SandHook、FastHook 的作者,你们的文章带领我进入了 art 的世界。后面我终于有了一台能跑 android studio 的电脑,终于可以写 c++ 了,然后就边写边在模拟器上测试,终于整出来一个勉强能用的东西,我管这个项目叫梦境。
后面在某个群里碰到了一位老板找人付费写代码,我接了下来,几十分钟写完拿了1000块的报酬。这是我自认为的真正意义上的第一桶金,我拿着这笔钱找我妈说我想买个二手手机(我钱在 qq 上,没银行卡转不去其他地方),然后在淘宝买了个华强北 pixel 3,终于把那部装不了微信的手机换了下来。这是我真正的靠自己买到的第一个想要的东西。我都还记得我第一次摸到 Google 亲儿子,第一次看见运行原生安卓的手机,第一次见到 type c 充电口,用卖家送的充电线充电的兴奋感。
到了中考,班主任问我去不去,我选择直接放弃报名。我的义务教育阶段结束了。但是我家很想让我继续读书,上个电大也行,去找县里的中职被拒了,最后联系到一家市里的民办中职。那个暑假我在网上查什么是中等职业学校,搜到了中职生也是有自己的升学渠道的,突然我就又想升上来大学看看究竟是什么样的了。我第一次去市里上学,第一次吃食堂,第一次住集体宿舍。可能因为课程比较简单压力很小,我竟然能坚持上这个学,竟然真的为了升学准备文化课。我的上学生活又开始了。那个时候还在开发 EdXposed 的西大师和 ksm 找到我讨论 art 相关的问题,后面他们创立了 LSPosed,把我也拉进去了。
后面就是无聊的日常。中专二年级学校强制要求送人进厂实习,在电子厂打工真的是个折磨,我想做点自己喜欢的东西,然后我开始给 magisk 提交 pr。然后折腾折腾就变成了 collaborator。
从电子厂回来之后就是上学,考完高职高考之后学校又想送我进厂,我直接玩消失。去了个小公司搞 android framework,也是变成自己小时候梦寐以求的系统开发工程师了。到开学的时候了,踏进了大学的校门,我变成了一个本科在读生。
在学校里就没经济来源了,我想经济独立。想起来搞之前上班的时候发现过漏洞,也开始无聊翻源码希望有收获。一开始我只是翻着无聊玩的,结果后面发现他们给的实在是太多了,就开始投入更多时间精力搞这块。一年下来也算有点收获,在全球的排行榜上排个前十几,不算亏。
这就是故事的全部。你可以发现我对未来没什么计划。我不是一个聪明的孩子,我要是聪明的话就学 OI 打比赛去了,感谢上天愿意赐我一条生路。我也不是一个擅长预测风口的人,电商网购直播短视频等等风口我一个都没预料到,我做事纯凭兴趣,小时候看着 kingroot 觉得很厉害也想搞的小孩也不会想到长大之后是这样。现在回过头来看,我可能应该开个公众号,把人引流过去,然后接广告或者开知识星球来变现,再或者去视频平台投个《20岁谷歌认证世界顶级研究员的一天是什么样的》给自己出道。不过我最后还是没干就是了。
然后我随便总结了点经验:
0. 有些东西没想象中那么难 不试试怎么知道
2025 了,首先祝大家新年快乐哈
今年发生了挺多事情的,感觉脑袋快烧了,感谢大家一年的陪伴
上学是真没意思,要干的活还多
今年抽了点课外时间花在 android 安全上,做了一点点微薄的贡献,现在勉强在 Android Program 排行榜上排了个第 10 名,整个 Google BugHunters 平台第 55 名。今年 3 月之前排名还是 N/A,感谢各位大佬的谦让哈,让我这种无名小卒也能参与这种大项目
本来今天想把 2024 年度排名一起发出来的,结果到现在都还没刷新下来,等它出来了再发吧
我心里知道我跟真正的大佬还是没法比,Chrome VRP 一给就是三万刀五万刀,我个只玩 Android VRP 的怎么比,没办法
今年十二月的 swag 也没拿到
我不会忘记我的出身,也感谢大家这一年的支持,学到很多,感谢给我这个机会去给一个操作系统安全添砖加瓦
郭德纲有句话很有名,“江山父老能容我,不使人间造孽钱”,我想在后面加一句,“心中自有青天在,愿行千山不染尘”
再次感谢大家支持哈,要滚回去复习了,考试快挂了
P.S. 这段文字是提前写好的,本来想留时间出来复习的,真的到元旦了发现自己一点都不想碰学校课程。新的一年第一天请大家吃预制菜寓意一年遇见智慧的人(
https://android.googlesource.com/platform/frameworks/base/+/2ce74e2d84777657f11b5cbabc501e6d79c86337
翻了一下连 15 都没进
估计最多活了一个测试版
没啥用 发出来给大家乐呵乐呵
昔日 Mismatch 今犹在,不见当年 PDD
看着换对联,贴福字,摆灶神,搞卫生,心里没有一点波澜,手机上 app 的红色新年活动页面也懒得点开,还记得很久以前花一堆时间刷 qq 红包跟支付宝集五福,现在只觉得闹心,还不如去领红包封面
下午出去街上逛了一圈,虽然有点心理预期(县城人过年一般晚上才出来散步),冷清程度让我怀疑是不是回到了2020年疫情封城那个时候,紧闭的商铺大门,偶尔能看见贴着福字,旁边一个满满的垃圾桶,最顶上的是刚撕下来的福字对联,偶尔从遥远处传来一两声烟花爆竹爆炸的声音,对比出一种荒谬感,跟小时候记忆里的景象没有一点关联
可能长大了感觉不同吧,小时候期盼家人团聚,现在只觉得团聚了也是听吵架没意义。看我妹也只是拿着手机刷了一天抖音,跟其他不用上学的日子没有任何不同。
今年这节日不如改名叫 DeepSeek 节,给我的触动还不如我妹在我面前外放奶龙带来的感觉大
我浪费生命 我好
有没有人教一下怎么高效、稳定、节能、可持续地浪费生命
指开学了还能继续躺着啥也不干
如果你有一些欠你钱不还的青少年朋友 可以这个时候试试催
一般来说这个时候他们该收的压岁钱都收完了 而该奢侈花的钱还没来得及花出去
比如 CVE-2024-31318 这个漏洞
刚开始知道评了 high severity 的时候还挺开心的 那个时候是纯小白
结果后面才知道类似洞可以评 critical
(CVE-2024-31320 给了 critical)
然后过了一年之后才又有勉强能摸着 critical 边的洞 CVE-2025-0100
影响是可以用户无授权录制设备屏幕
应该也是最开始评的 critical 满足降级规则被降成 high
下一个不知道是什么时候了
我还想拿 CVE-2025-0001 这种数字的 比较有纪念意义 又得等一年才能碰运气了
(你不如拿个 114514 更有纪念意义)
原理很简单,用户通过支付宝做了特定操作之后,第二天蚂蚁森林会产生特定数值的能量球
比如通过支付宝网购火车票会产生 136g 能量,购买电影票会产生 180g 能量,每天运动则会根据步数产生 0~296g 不等的能量
所以可以根据好友的蚂蚁森林能量球上的数值大概猜测前一天干了什么 不过实际利用效果受各种因素限制 比如如果对方提前把能量全收了你就看不见了
(以前用过这个方法猜测了一个没给我开放步数权限的朋友的一天运动量 别问我为啥)
如果对隐私实在在意的 可以在支付宝蚂蚁森林设置里关掉“向好友展示能量球数值”
如果有人想知道 取证人员都能提取出什么数据的话 可以看一下这个 虽然不是真实环境
https://mp.weixin.qq.com/s/Mjuv81xJ1SVc0Pte-0eHQA
搜了一下发现这家搞的有意思的东西还挺多的:
推销自己的工具,可以实现“三星、华为、OPPO、VIVO、小米、魅族、锤子、美图、360、努比亚、金立、乐视、海信、朵唯等国内外300余个品牌、数千款机型的锁屏密码破解与镜像获取。针对安卓2.0至10.0均有专业的锁屏密码绕过,权限获取(ROOT)方案、手机全盘加密及文件加密的密码绕过方案”,且不会导致“数据丢失或触发恢复出厂”
https://mp.weixin.qq.com/s/l2ciZrOBc8HMGu1hSgZ6DQ
(这里有提到华为 FDE 机型提到权限之后可以直接导出全部数据,这个我之前也做过一点分析,可以看 https://t.me/CanyieChannel/83 )
OPPO 手机恢复出厂后残留数据取证
https://mp.weixin.qq.com/s/hJVbCmsFkWlLLtmbJGbJBw
爆破华为隐私空间密码
https://mp.weixin.qq.com/s/bs7nMsiWw-F753kPUxOfWg
其他厂商活也挺多的:
取证厂商五五安科表示自己支持“OPPO、VIVO FBE 机型绕过屏幕锁定密码提取文件系统”,“搭载部分芯片的 FBE 设备计算锁屏密码”(虽然这个在群里面发过但不妨再发一次)
https://mp.weixin.qq.com/s/XUpeMM7cJO7GVN0uEhNCIA
上网冲浪的时候无意间刷到了初中时候的自己原创的笑话
老个毛线 医生让住院都让住儿少科
1 | public static String getFileLocation(Class<?> cls) { |
需要关闭 hidden api 限制
只在 Android 12 上测试过
清晨八点多,你从睡梦中自然醒来。
这一夜你睡得很好,没有在三四点的时候睁眼望着天花板,也没有往常早晨醒来时的疲惫感。
昨晚刚下了一场雨,植物的叶片还挂着水滴,清晨的阳光从窗外透进来,照得你浑身暖洋洋的。你知道,冬天已经过去了。
身体传来的不是躯体化带来的疼痛或疲惫,而是少见的饥饿感。
洗漱完出门,早餐店的叔叔阿姨早已经开始了一天的忙碌。你点了往常最爱吃的肉包,鲜嫩的肉汁在你嘴里绽放。你好久好久没有细细地品味过你最爱吃的东西了。
眼前的世界是真实的,笼罩在眼前似有似无的黑幕已经消散,灵魂重新匹配身体,而身体又实实在在地触摸着世界,路边的红绿灯再也不会在视野里突然消失。
你看见一片还带着露珠的叶子,翠绿的颜色,水珠反射着太阳的光芒。你感觉它焕发着生命的气息。你喜欢它。你可以没来由地喜欢一件事物。
你突然觉得其实有些事情也没有那么难做。好像有好多事情一直放在 TODO list 里,打扫房间、跟许久不见的朋友一起逛街,或是去听曾经很喜欢的歌手的演唱会。有空可以清理一下 TODO 了,你想。
从这一天开始,你内心的刑期悄然结束了。夜晚,你不再辗转反侧,也不会凌晨三点醒来。你开始对事物产生兴趣,重新有了自己喜欢的东西。你慢慢停掉了药物。不知道持续了多少时间的冬天自己过去了,春天自己会来。
转发自 https://t.me/cxplayworld/4481
如果你用 Telegram, 以防你不知道有人已经索引了所有人在公开群组和频道的发言记录了.
打开机器人选择语言后发送 /me 命令查询, 选择菜单里的 Groups 或者 Channels 就能看到喽.
转发自 https://t.me/qingmingjian123/295
https://github.com/bron1e/clash-verge-rev-privilege-escalation-poc
Clash Verge Rev默认强制安装系统服务(Clash Verge Service),并通过未授权 HTTP API /start_clash 暴露关键功能,允许本地用户提交任意 bin_path 参数,直接传递给服务进程执行,导致本地提权
影响范围:Clash Verge Rev<=v2.2.3(Windows/Linux/MacOS)
FlClash 似乎也受影响
https://github.com/chen08209/FlClash/issues/1131
据 Securelist 报道,部分电商平台上存在假冒手机,其固件内置木马,可执行各种针对性的复杂攻击,包括但不限于盗取各大平台(Telegram、Instagram、Line、Skype、Tiktok、Facebook 等)账号、使用受害者 WhatsApp 账号发送任意消息、发送任意短信、将剪贴板内加密货币钱包地址替换为攻击者的地址等。
原文链接:https://securelist.com/triada-trojan-modules-analysis/116380/
中文翻译:https://mp.weixin.qq.com/s/itrYPTDKwoGBQPFF4_idHA
那就有个很好玩的事情了,这些假机子能过 play integrity 认证吗?
https://mp.weixin.qq.com/s/gxTkcmDtyFeZ42XkcpTeJg
AI 技术驱动的智能取证机器人,宣传称其可自动分析聊天记录并可自动标记敏感信息、智能统计涉案金额、串联证据链条等。
已于 6 月 5 日在 BCS2025 (北京网络安全大会)网络犯罪治理论坛上首发,预计 7 月底全面上线。
为什么每次这个频道发取证相关的东西都会有一堆我看不见的转发…?关注这频道的都什么成分(
既然大家喜欢的话那就再来一个:现在的取证技术很多是利用 USB 相关的漏洞解锁设备。Android 12 开始其实支持从软件层面禁用 USB 数据信号传输(需要 HAL 支持),但是系统里并没有开关给你操作,只有手动进入 lockdown mode 或在 Advanced Protection mode 启用时锁定设备 1 时会阻断 USB 连接。
相关 API 其实是已经暴露出来了,可供设备管理应用使用 2。可以下载安装 TestDPC 然后使用 adb 将其配置为 device owner 或 organization-owned profile owner,之后就可以在 TestDPC 里找到 Enable USB data signaling 来手动开关它。
警告:在部分机型上激活设备管理员可能存在风险 3,禁用 USB 后无法使用基于 USB 的 adb,若设备后续变砖可能严重影响救砖能力,请谨慎考虑。
疑似 Google 大手子开始云控发力,通过 Google Play 服务远程开关设备配置,手上的 Pixel 6a Android 16 已经是默认开启状态,另一台跑着 Android 14 的一加机子也是已经打开但不知道为何 global_kill_switch 是 true,实测 SDK 相关功能是能正常用的,不知道为啥
命令:
1 | adb shell device_config get adservices disable_sdk_sandbox |
欢迎大家把自己设备的结果晒在评论区
时隔四年再次来到东莞,感谢华为邀请,身份从流水线工人变成受邀嘉宾,终于能进来这个曾经没机会来的地方看看
华为园区真的很漂亮,所有照片都是原图直出,既饱眼福又饱口福
这两天东莞本来下雨的,我们一到松山湖雨就停了,连续两天都是这样,感谢天公作美让我有机会看看美景
就是可惜华为小火车没坐到,一查才知道在溪流背坡村,三丫坡没有,看看明年能不能补上这个遗憾
哦对了 还被人线下认出来了
坐在椅子上旁边突然有人问“哎你是残页吧 我关注了你频道看见过你照片”
下次再也不敢发照片了
https://taptrap.click/
利用 activity 跳转动画劫持,CVE-2021-0339 再现,只不过这次是用透明度
https://nvd.nist.gov/vuln/detail/cve-2021-0339
https://android.googlesource.com/platform/frameworks/base/+/36bcc77337814d4d36e2b10eb062ac417d91611e
其实我们之前也报过一个手法可以让用户误触某些按钮,之前搞了个直接恢复出厂设置清除用户所有数据的 poc 当漏洞报上去,经过了半年的审核给我 wontfix 了。
如果有人感兴趣的话我可以发出来给大家看看(
需要几百年才能降解,做的厚一点能重复利用很多次,但是大部分时候被使用一次就被当成垃圾扔掉了
古代人用竹子、梅花啥的象征坚韧不屈的精神,我觉得是因为古代没有塑料,否则应该会出现一堆《咏塑料》之类的诗歌
这么坚韧的东西却只需要几分钱几毛钱就能买到,大部分是作为一次性容器,用完就扔掉,说不定这些人类自己都不吃的东西还会进海洋里被某个幸运海洋生物吞进肚子里,然后还要因为人类的行为背上一个“污染环境”“毒害海洋生物”的骂名,真的好冤好可怜
所以我都倾向于使用能重复利用的东西,比如选择到店吃而不是点外卖,签器官捐献+遗体捐献志愿,用过的塑料袋留着拿来套垃圾桶之类的,真的完全用不上的快递箱之类的也完全舍不得扔
CVE-2025-31229:密码可能会被大声读出
https://support.apple.com/en-us/124147
这个功能附带一个 UI ,可以用
1 | adb shell am start -n com.android.devicediagnostics/.MainActivity |
拉起来,然后使用另一台设备通过二维码完成验证。有密钥认证担保,这才是它应该有的使用场景嘛
文档 https://source.android.com/docs/core/perf/trade-in-mode?hl=zh-cn#gather
另外这个页面还支持检测屏幕坏点和触控,把工厂流水线的 MMI app 功能复制过来了?这一套组合拳是为了方便转转上门收手机吗
“搭载 Android 16(或更高版本)的设备在启动时会进入以旧换新模式。在这种模式下,您可以使用 adb 连接到设备,并可以使用命令获取设备相关信息。”
很有意思的功能,换句话说,Android 16 设备恢复出厂设置后,在没有网络连接且未完成设置向导时,会允许 adb 连接并运行受限命令。注意这种情况不需要打开开发者选项,也不需要手动授权调试。
两层机制保证安全:
adb shell tradeinmode 命令。源码: https://cs.android.com/android/platform/superproject/main/+/main:packages/modules/adb/daemon/tradeinmode.cpp;l=86在该模式下,运行 adb shell tradeinmode evaluate 可以进入评估模式,正常使用所有 adb 命令。进入评估模式会创建 /metadata/tradeinmode/wipe 文件,下次开机时 init 看见有这个文件会将设备恢复出厂设置以避免任何东西残留。
Android 终于开始修复我之前发现的一批和 SDK Sandbox 这个有趣的新功能相关的漏洞,9 月补丁里修复了两个,在这里放补丁链接抛砖引玉,各位大佬有什么新的想法欢迎和我交流下,不吝赐教
CVE-2025-48524 https://android.googlesource.com/platform/packages/modules/Wifi/+/298745e0cb23cbef631aff1977b284155384bbf0
CVE-2025-48545 https://android.googlesource.com/platform/frameworks/base/+/66ac17909252c80b0edf7f4ae282bce4579410ad
CVE-2024-34740,本地 app 提权至 system_server
https://github.com/michalbednarski/AbxOverflow
CVE-2024-49746,本地 app 提权至 system uid
https://github.com/michalbednarski/ThisSeemsWrong
CVE-2025-22441,本地 app 提权至 SystemUI(由于 PoC 使用了 WebView 因此无法注入进 Settings 等 system uid app)
https://github.com/michalbednarski/ResourcePoison
误触能造成的危害远不止授权设备管理员,如果误触授权无障碍,恶意应用可以立即显示悬浮窗遮盖界面、读取显示的内容并代替用户操作设备;授权录屏权限则可以立即开始录屏并启动各种聊天软件,首页显示的对话就会被包含进录屏里。
用户当然可以立即关机并且重启到安全模式来卸载恶意应用,但是已经造成的危害无法清除。人是不可能比机器快的。我给 Google 提过这个问题,Android ID 389091354,似乎 ECM 已经开始限制 device admin 授权,但不清楚他们是否会继续采取措施(我觉得合理的解决方案是打开页面时禁用激活按钮 1 秒确保用户看见了警告不会手抖再允许激活),有权限查看的人可以点进去看看
转发自 https://t.me/zaihuapd/36486
安全研究人员发现一种名为“像素劫持(Pixnapping)”的新型安卓攻击手段。该攻击通过恶意应用调用系统API,无需特殊权限即可读取其他应用显示的像素数据。攻击利用GPU侧信道技术,通过测量像素渲染时间推断屏幕内容,可窃取双重认证码、聊天消息等隐私信息。研究团队在谷歌Pixel 6至9和三星Galaxy S25设备上演示成功,部分设备攻击成功率超过50%。
谷歌已在9月安全公告中发布初步补丁,但研究人员称攻击改良版仍有效,预计12月将有额外修复。攻击每秒仅泄露0.6至2.1个像素,但足以威胁短期有效的2FA认证码。目前未发现实际利用案例,但突显了安卓安全机制的局限性。该技术基于2013年浏览器攻击,显示侧信道风险的持续性。
SDK Sandbox 被弃用。解决了“提权沙盒”这个问题本身
一直知道误触是黑产百试不爽的利用手段,但是事实证明各种我们没想到的攻击手段已经被他们玩出花了。
伪装成屏幕上的头发丝骗用户去碰,我着实没想到。
我比较关心的议题 1:快应用
快应用只需要点一下就能用,通过恶意 deeplink 可以让灰黑产点一下就把用户的手机变成广告蛊场,用户手忙脚乱之下只会打开更多一连串的难以关闭的快应用
议题 2:透明桌面小组件(app widget)
恶意应用诱骗用户添加一开始看似正常的小组件,随后将其设置成透明以防止被用户发现,并利用小组件的特性实现保活、后台弹广告等一系列灰黑产行为
我之前也注意到过小组件的滥用潜力,也报过一些相关漏洞(CVE-2024-43762),但对于 Google 认为没有“安全影响”的问题无可奈何。只能希望未来的 Android 版本能做出进一步限制。
现场视频: https://www.bilibili.com/video/BV19DxFzBE4L
议题 3:多个厂商的 TA 实现不当,存在多种漏洞将 authtoken 暴露给不可信方,导致可被暴力破解手机 PIN 码
同时演讲者演示了在一台刚开机还未输入过密码解锁(即处于所谓的 Before-First-Unlock,BFU 状态,data 分区还未解密)的设备上成功爆破 PIN 码
演讲者也提到这种攻击技术可能已在被取证公司利用
2025年了,activity 生命周期 api 还能出问题,离谱,难道这个功能到现在都没有任何一个人用过吗?
https://android-review.googlesource.com/c/platform/frameworks/base/+/3826768
奖池还在累计
https://android-review.googlesource.com/c/platform/frameworks/base/+/3563923
前段时间跑了三次某国际银行想要开一个内地账户,跑了三次被拒了三次。在我已经有该银行香港地区需要资产门槛才能开贵宾账户的情况下。理由是我是学生,建议等我毕业工作之后再尝试。我说我现在确实是学生,但我有自己的收入来源还纳税,现在已经能养活自己了,为什么非得等到有工作了才能开?如果我毕业之后是自由职业者怎么办?银行的回复把我气笑了:“那不是相当于您这个大学白读了吗,相信自己肯定能找到工作的”。
我只感觉这个世界是如此的荒唐,死的规则把我和所有规则考虑不到的活着的人拦在门外。
被规则忘记的不仅是我。回想起陪同残疾人出行时遇到的种种不便。很多城市进行基础建设的时候就完全没有考虑到残障人士的出行需求,比如早期修建的很多地铁的无障碍电梯是直接连通站厅非付费区和站台(付费区)的,为了防止逃票这些电梯平时是关闭的,有人需要的时候由同行人拿着行李过安检,拿着交通卡去闸机刷卡但不入闸,然后呼叫工作人员打开电梯,然后下到站台乘车。如果目的地也是采用这种设计就需要反着再来一遍。这算是历史遗留问题没办法解决可以理解,但是还有很多城市道路也难以让残障人士通过,比如盲道上的石墩子,只有楼梯可通行还没有扶手的道路,还有坡度大到只能给电瓶车通过的坡。我觉得这就是纯粹的态度问题了。以我带着一个需要使用助行器的人的体验而言,遇到楼梯时我需要拿着他的助行器,然后把我的手或者肩给他当扶手,让他上去之后再把助行器放到地上让他扶。对我们而言再平常不过的道路对他们而言可能是足以致命的陷阱。可能没有经历过这些的人很难理解残障人士的出行困境,高德地图在设置里可以开启无障碍模式(可能很少人知道这个功能,其实不止高德地图,像小红书也是专门适配过无障碍浏览的,为所有付出行动优化体验的软件点赞),然后随便点个附近的目标点尝试导航,看看会收获多少次“无法避开台阶路段”的提示。所以很多时候我们宁愿选择打车。中国有约 8500 万残疾人,除去外表上看不出来的残疾类型,为什么我们日常很少见到残疾人?我想这就是一大原因。媒体报道的残疾人一般都被冠以『坚强』『乐观』这些形容词,但抛开这些与性格相关的形容词,他们不过是受限的普通人。『坚强』是我的优点,但是『不坚强』也不该成为被排除的理由。
这种困境不仅仅局限于残障人士。年老,意外受伤,推婴儿车,甚至只是拉着大行李箱,都会让一个『普通人』对无障碍设施的需求瞬间变得迫切。
多数人的幸福支撑社会的繁荣,少数人的境遇映照社会的温度。虽然我很讨厌『少数群体』这几个字,但是我拙劣的语文水平确实想不出其他的话了。很多人讨厌『少数群体』这个表述是持着“别人都行为什么就你不行”这种想法想让所有人都强行融进自己的框架里,我认为这种忽视个体差异和客观需求的想法无异于把需要时间破茧成蝶才能飞的毛毛虫放进本来就会飞的鸟群里。
最后附上去年缴税的证明,证明下我有经济能力。
转发自 https://t.me/androidMalware/2734
One of top-selling digital picture frames from Amazon’s between March and April 2025 comes:
原来世界上还有数码相框这种设备
经常在各种地方看见精简系统软件的教程或者“去除了系统中不必要组件的精简版 ROM”,这边提醒一下,我个人是不建议随意动系统组件的,即使它看起来完全没用
举个例子,com.android.companiondevicemanager 这个 app 用来在配对配套设备(如手表)的时候弹对话框,似乎对没有外设的用户没用,但在安卓 12 及以上移除这个 app 会造成可以导致电话、联系人、短信、日历、读取通知、控制通话等多个敏感权限被自动授权给恶意软件的严重安全漏洞
有些“教程”的理由是移除一些非必须的 app 可以减少攻击面,让其中可能存在的安全漏洞变得无法被利用。我是觉得不如买手机的时候选个代码质量好然后安全更新频繁的厂商
话说有没有人知道是否真的有什么精简版 ROM 把 com.android.companiondevicemanager 删了?
用户想自测的可以跑一下
1 | pm path com.android.companiondevicemanager |
看看有没有输出
https://www.youtube.com/watch?v=7fGB-hjc2Gc
bilibili: https://www.bilibili.com/video/BV1xYUtB5Evr
感谢群友让我蹭名字
https://blackhat.com/asia-26/briefings/schedule/speakers.html#songzhou-shi-51645
关于最近流传的 Android 16 0 click RCE + 反弹 root shell 的视频
乍一看很唬人 仔细看越看越假 严重怀疑打印出来的内容是 AI 生成的
我把几个我看见的不合理的点列出来
如果一个视频就能卖四百万刀,那我也来发一个演示,拿 root shell + 禁用 selinux,免费公开 exp 源码,保证真实,可以自己跑一遍确认真的拿到了 root shell
1 | #!/system/bin/sh |
需要 magisk
效果:无用户交互自动授权读写联系人、短信、日程、通话记录和语音信箱,拨打电话或接听来电,操纵通话设置,发送通知,读取并操作其他应用发送的通知,控制附近设备,录制声音,读取设备唯一标识符,和绕过后台执行限制。
录屏:https://github.com/canyie/CVE-2024-23700/blob/main/screen-20260120-233400-1768923180588.mp4
漏洞评级(Severity):Critical 最高/严重
PoC 代码:https://github.com/canyie/CVE-2024-23700
下载编译好的 apk:https://github.com/canyie/CVE-2024-23700/releases
和视频里的版本相比优化了几个细节:
视频里尝试提升权限时会有一闪而过的白屏,比较容易被注意到,进行了优化,让利用更隐蔽
支持了静默自动获取录音权限,需要 Android 14+
添加了一个拨号按钮,提权之后可以无用户交互拨打电话,确保提到的权限真的能用
提供的测试 app 在绝大部分设备上都无法安装。如果在你的设备上安装失败,是正常的,说明它目前不受影响(但是你后面又刷了其他 ROM 或者开了什么模块就不一定了)。
后续:去医院治了胃病之后好了 现在变成吃多少都吃不饱了
跟我有一样体验(吃什么都嫌多)的人可以去医院测个幽门螺旋杆菌
https://blog.r0rt1z2.com/posts/exploiting-mediatek-datwo/
分析/审计 kotlin 代码是一种折磨 一种灾难
就算我哪怕知道把它分析完就能拿 $7000 USD 的漏洞奖金 我也完全提不起一丝看它的兴趣
一个语言能设计成这种毫无设计哲学全是语法糖推崇写以后不用 review 的一次性代码的样子也是一般人做不到的
我很想知道让写出 kotlin 一次性代码的人过几年让他自己读能不能读懂
我丝毫不怀疑把 kotlin 代码编译完再反编译成 java 都比读原代码有可读性
我还记得 Android 7.0 的时候 Google 宣布引进 Kotlin 作为正统 Android 开发语言时我的激动之情 那时我还在用手机写代码 期望它能解决 java 的一系列问题
现在我拒绝 kotlin 出现在我项目里的任何地方 包括依赖和编译脚本 当年期望有多大现在失望就有多大
Your community 小页页的胡言乱语 was blocked for violations of the Telegram Terms of Service (https://telegram.org/tos) based on user reports confirmed by our moderators.
Thank you! Your appeal has been successfully submitted. Our team’s supervisors will check it as soon as possible. (No more response)
最近在 AI 圈里被频繁讨论的一个项目是 OpenClaw。
它属于一类正在兴起的 AI Agent 工具:用户只需要给出指令,AI 就可以自动完成一系列操作,比如控制电脑、整理文件、执行任务流程等。和过去只能对话的 AI 不同,这类工具正在让 AI 从“回答问题”,变成 真正替用户做事。
不过在 OpenClaw 这种“全能型 AI 助手”真正普及之前,其实已经有很多工具在某些场景里悄悄实现了类似的能力,比如——文档处理。

如果你经常需要处理 PDF,就会发现这件事其实非常碎片化:读文档、标重点、改内容、转格式、比版本、找文字……看起来都是小事,但每天加起来其实很花时间。

比如在阅读 PDF 时,可以直接 高亮、批注、添加注释,做文献标记或者资料整理都很方便。很多人读论文或者技术文档的时候,最常用的其实就是这些标注功能。

如果需要修改内容,UPDF 也支持 直接编辑 PDF,包括修改文字、图片或者排版,不用再把文件转成 Word 再改一遍。

另外一个比较实用的是 格式转换。很多资料是 PDF,但后续可能需要在 Word 或 Excel 里继续处理,直接转换就能继续编辑,省去不少复制粘贴的时间。

遇到扫描版文件时,OCR 识别也很重要。比如一些扫描合同或者图片 PDF,原本是无法搜索文字的,通过 OCR 可以把内容识别成可编辑文本,查找和复制都会方便很多。

还有一个比较容易被忽略的功能是 文档对比。如果你经常处理不同版本的文件,比如合同、报告或者方案,对比功能可以直接标出改动内容,比自己逐页检查要快得多。

现在很多工具还加入了 AI 能力。比如可以直接让 AI 总结文档重点、解释某一段内容,甚至生成结构化的思维导图,用来快速理解长文档。

回头看 OpenClaw 这样的项目,其实代表的是一种趋势:
而在现实工作里,很多人每天最频繁的任务之一,就是处理各种文件。
所以在 AI Agent 真正接管电脑之前,像 UPDF这种 AI 文档工具,已经在帮很多人把文档处理这件事变得更简单一点。
邀请好友注册即可免费领取 35天 UPDF 会员,
输入兑换码 WZTG2026,立减20元
国行手机的 esim 功能有较多限制,使用不太方便。
但我们可以使用 esim 适配器,将 esim 转为实体 sim 卡。
esim 适配器就是个 sim 卡,需要占用一个卡槽,可以通过软件将 esim 卡号写入到适配器。
可以写入多个 esim 号码,并且支持切换,但同时只能有一个在线。
适配器有不少品牌,如 estk、5ber、9esim,价格也各不相同,但是我都没怎么试过。
我使用的的适配器是 pdd 购买,20-30元,容量468KB。
一般海外套餐都可以使用,我这里只用于接收短信,故使用 clubsim,成本大概50元。
购买套餐后,运营商会提供二维码,安卓手机通过 OpenEUICC 扫描就可以写入和管理 esim。
如果是 iphone,需要使用 esim 读卡器来管理 esim 号码。
似乎对手机有些兼容性要求,较老的手机无法写卡。
esim 还是挺方便的,用于接收验证码非常够用,还有些免费流量的卡。
但是切换 esim 号码时,可能需要切换飞行模式或者重启手机才能生效,不知是通病还是兼容性问题。
由于安卓操作系统(11+)的 bug,在“移动网络”中禁用 esim 适配器会无法打开。
需要通过 adb 清除移动网络的数据才能恢复
1 | adb shell pm clear com.android.providers.telephony |
如果是小米等手机,清除过程可能会遇到adb权限相关问题
需要额外开启开发者选项中的“OEM解锁”和“USB调试(安全设置)”
1 | adb shell pm clear com.android.providers.telephony |
如果你需要在电脑前录制音频,现在可能不再需要购买专业的麦克风了。
这有一款公根据,可以让你闲置,或者正在服役的安卓设备从当无线麦克风,简单易用。
![MicYou - 将 Android 手机变成电脑无线麦克风[跨平台] 53 MicYou - 将 Android 手机变成电脑无线麦克风[跨平台] 53](https://www.appinn.com/wp-content/uploads/2026/02/cover-1772096382192-1.jpg)
MicYou 是一款开源的 Android 应用,它可以将安卓手机变成电脑的无线麦克风,支持 Windows、macOS 以及 Linux,支持 USB 连接、Wi-Fi 连接。@Appinn
需要使用 adb 方式将手机与电脑连接,可以使用 USB 模式或者 Wi-Fi 模式。
然后分别安装安卓应用与电脑客户端:
![MicYou - 将 Android 手机变成电脑无线麦克风[跨平台] 54 MicYou - 将 Android 手机变成电脑无线麦克风[跨平台] 54](https://www.appinn.com/wp-content/uploads/2026/02/Screenshot-2026-02-26-09.00.51@2x.avif)
![MicYou - 将 Android 手机变成电脑无线麦克风[跨平台] 55 MicYou - 将 Android 手机变成电脑无线麦克风[跨平台] 55](https://www.appinn.com/wp-content/uploads/2026/02/Screenshot-2026-02-26-09.00.57@2x.avif)
设置连接模式后,匹配 Android 应用,就可以当作麦克风使用了。
macOS 下需要额外安装 blackhole-2ch 与 switchaudio-osx
brew install blackhole-2ch --cask brew install switchaudio-osx --formulae
原文:https://www.appinn.com/micyou-android/