移动应用逆向分析全链路:从APK静态侦察到动态Hook与协议逆向

1. 从“逆向分析一切”这个说法说起

第一次看到“逆向分析一切”这个说法,我的反应是:这要么是个标题党,要么背后确实有一套成体系的工具链在支撑。后来陆续接触到一些做移动端安全研究、协议分析、竞品拆解的朋友,才发现这个说法虽然夸张,但它指向的东西是真实存在的——一套围绕移动应用安装包(APK/IPA)展开的静态与动态分析流程,配合抓包、Hook、脱壳、反混淆等手段,确实能把一个App的内部逻辑扒得七七八八。

这里说的“逆向分析”,不是去搞破坏,而是安全研究、协议兼容、竞品功能拆解、接口调试这些正当需求下的技术手段。比如你想知道某个App的登录流程到底走了哪些接口、参数是怎么签名的、本地加密用了什么算法,这些都需要逆向分析的功夫。微信、支付宝、抖音这类国民级App之所以经常被拿来当“靶子”,不是因为它们好欺负,恰恰是因为它们的防护做得足够复杂,能啃下来才说明工具链和方法论到位。

这篇文章我想聊的不是某个具体工具怎么用,而是把这套“逆向分析一切”的完整思路拆开讲清楚:从拿到一个App开始,到最终理解它的核心逻辑,中间要过哪几道坎,每道坎背后的原理是什么,以及我在实际操作中踩过的那些坑。适合有一定开发基础、对移动安全感兴趣、或者工作中需要做协议分析和接口调试的读者。全文会涉及不少工具和命令,但重点在于“为什么这么做”和“什么时候会翻车”。

2. 拿到App之后的第一件事:静态侦察与信息收集

2.1 安装包结构决定了你的分析起点

很多人拿到一个APK,第一反应是直接拖进反编译工具。这个习惯不算错,但效率不高。更合理的做法是先做一轮“侦察”,搞清楚这个包的基本构成,再决定用什么工具、从哪个角度切入。

APK本质上是个ZIP压缩包,改后缀就能解开。解开之后你会看到几个关键目录:classes.dex(Dalvik字节码,Java/Kotlin代码编译后的产物)、lib/(native库,通常是.so文件)、assets/(资源文件,很多App会把配置、模型、甚至加密后的数据放这里)、res/(编译后的资源)、META-INF/(签名信息)。iOS的IPA结构类似,核心是Mach-O可执行文件和Frameworks目录。

侦察阶段我一般会关注这几件事:

  • dex文件数量和大小:如果只有一个classes.dex且体积很小,说明核心逻辑可能在native层或者走了动态加载。如果有多个dex(classes2.dex、classes3.dex...),说明代码量不小,大概率有混淆。
  • lib目录下的.so文件:看名字能猜出用了什么框架。比如libflutter.so说明是Flutter应用,libreactnativejni.so说明是React Native,libhermes.so也是RN的痕迹。这些跨平台框架的逆向思路和原生Android完全不同。
  • assets目录里的可疑文件:有些App会把加密的配置、证书、甚至整个H5页面塞在这里。我见过一个App把核心业务逻辑全放在assets里的一个加密JS文件里,native层只负责解密和加载。
  • 签名信息:META-INF/里的签名文件能告诉你这个包有没有被二次打包,以及用的是V1还是V2/V3签名方案。

提示:侦察阶段不要急着改任何东西,先把包完整备份一份。后面不管怎么折腾,原始包是你回滚的唯一依据。

2.2 反编译工具的选择逻辑

静态分析的核心工具就那么几个,但选哪个、怎么组合,直接决定效率。

Jadx是我用得最多的反编译工具,它能把dex直接转成可读的Java代码,而且自带GUI,搜索、跳转、交叉引用都很方便。Jadx的优点是快、直观,适合快速定位关键类和方法。缺点是遇到复杂混淆或者控制流平坦化的时候,反编译出来的代码可读性会急剧下降。

Apktool走的是另一条路,它把APK拆成smali代码(Dalvik汇编)和资源文件。smali的可读性远不如Java,但它是“ ground truth”——反编译工具可能出错,smali不会。当你需要精确修改某个方法的逻辑,或者Jadx反编译结果明显有问题时,就得回到smali层面。

Ghidra和IDA是native层分析的主力。如果核心逻辑在.so文件里,Jadx和Apktool都帮不上忙,必须上反汇编器。Ghidra免费且功能强大,IDA更成熟但收费。我个人的习惯是先用Ghidra做初步分析,遇到复杂算法再换IDA。

工具选型的一个常见误区是“一把梭”——只用Jadx从头看到尾。实际上,一个完整的分析流程往往是:Jadx定位关键逻辑 → Apktool看smali确认细节 → Ghidra/IDA分析native实现 → Frida动态验证。每个工具解决不同层面的问题,组合使用才能覆盖全链路。

2.3 混淆与反混淆的基本功

国民级App不可能不混淆。ProGuard/R8会把类名、方法名、字段名全部改成a、b、c这种无意义字符,控制流也会被扁平化,让你很难看出原始逻辑。

面对混淆,第一步不是急着反混淆,而是找锚点。锚点就是那些混淆改不掉的东西:字符串常量、系统API调用、第三方库的特征、资源ID。比如你要找登录逻辑,可以搜索"login"、"password"、"token"这些字符串;要找网络请求,可以搜索OkHttp、Retrofit、HttpURLConnection这些库的特征类。

找到锚点之后,顺着调用链往上往下追。Jadx的交叉引用功能在这里特别好用——右键一个方法,看“Find Usages”,能快速定位谁调用了它。追调用链的过程中,你会逐渐还原出核心逻辑的轮廓,即使方法名全是乱码,也能通过参数类型、返回值、内部调用的API猜出它在干什么。

反混淆工具方面,ProGuard的反混淆需要原始的mapping文件(一般拿不到),Simplify、dex2jar+JD-GUI这些工具对简单混淆有效,但面对商业级混淆器(如某数字加固、某梆加固)基本无能为力。这时候要么手动追,要么上动态分析。

3. 动态分析:让App自己把秘密说出来

3.1 Hook框架的选型与部署

静态分析再强,也有看不到的东西——比如运行时才解密的字符串、动态加载的dex、服务器下发的配置。这时候就需要动态分析,让App在运行过程中自己把信息吐出来。

Frida是目前最主流的Hook框架。它的原理是把一个Agent注入到目标进程里,然后通过JavaScript脚本拦截和修改函数调用。Frida的强大之处在于灵活——你可以Hook Java层的方法,也可以Hook native层的函数,还能在运行时修改内存、调用任意函数。

部署Frida分两种情况:有root权限的设备直接跑frida-server,没root的设备需要把Frida Gadget打包进APK里。后者更麻烦但更通用,因为很多测试设备没有root。

Xposed是另一个老牌Hook框架,它通过修改系统启动流程来加载模块,稳定性好但灵活性不如Frida。Xposed适合做长期监控,Frida适合做即时调试。

选型建议:如果是快速验证某个猜想,用Frida写个临时脚本,几分钟就能跑起来。如果是做持续的协议监控,Xposed模块更合适。

3.2 抓包:最直接的信息泄露渠道

很多App的核心逻辑其实不需要反编译就能看懂——只要你能抓到它的网络请求。请求URL、参数、签名、响应结构,这些东西全在抓包结果里。

抓包的工具链一般是mitmproxy或Charles做代理,配合Wireshark做底层分析。但国民级App基本都做了证书绑定(SSL Pinning),普通的代理抓包会被直接拒绝。

绕过SSL Pinning有几种思路:

  • Frida脚本Hook证书校验函数:这是最常用的方法。Android上可以HookX509TrustManager、OkHttpClient的checkServerTrusted等方法,让它们直接返回成功。iOS上可以HookNSURLSession的didReceiveChallenge回调。
  • Xposed模块:有一些现成的模块专门用来绕过SSL Pinning,装上就能用,但更新不及时,新版本App可能失效。
  • 修改APK:把证书校验的代码直接删掉或者改成永远返回true,然后重新打包。这种方法最彻底,但会破坏签名,有些App会检测签名完整性。

注意:绕过SSL Pinning只在你自己拥有或获得授权的设备上进行。未经授权对他人App进行抓包分析可能涉及法律风险。

抓包之后,重点看这几样东西:请求的URL路径(能看出业务模块划分)、请求参数(尤其是签名参数,比如sign、token、timestamp)、请求头(User-Agent、自定义Header往往藏着版本信息和设备指纹)、响应结构(错误码、数据字段)。把这些整理成表格,基本就能还原出App的接口全貌。

3.3 脱壳:对付加固的第一道关卡

国民级App几乎都用了加固方案。加固的原理是把原始dex加密后藏在某个地方,App启动时由一个“壳”dex负责解密和加载。你直接反编译APK,看到的只是壳的代码,真正的业务逻辑根本不在里面。

脱壳就是要把原始dex从内存里dump出来。常见的方法有:

  • Frida脱壳:在App启动后,HookDexFile的加载过程,把解密后的dex从内存里读出来。这种方法通用性好,但需要找到合适的Hook点。
  • Xposed脱壳:类似原理,通过Xposed模块在类加载时dump dex。
  • 内存搜索:直接在进程内存里搜索dex的魔数dex\n035,找到后dump出来。这种方法简单粗暴,但容易dump到不完整的dex。
  • 定制ROM脱壳:修改Android系统源码,在dex加载的关键路径上插桩。这种方法最彻底,但门槛最高。

脱壳的难点在于时机——太早dump不到,太晚dex可能已经被卸载或者内存被覆盖。我的一般做法是:先用Frida脚本在Application的attachBaseContext方法上下Hook,等壳完成解密后再dump。具体脚本网上有很多现成的,但每个加固方案的行为不一样,需要根据实际情况调整。

脱壳之后拿到的dex可能还是不完整的(比如方法体被抽空),这时候需要二次处理,比如用DexRepair之类的工具修复。

4. 协议分析与签名算法的逆向

4.1 签名参数是接口分析的核心

抓包抓到的请求里,最让人头疼的就是签名参数。服务器不认你的请求,往往就是因为签名不对。签名算法的逆向是协议分析里技术含量最高的部分。

签名算法的常见形式:

  • MD5/SHA系列:把参数按某种规则拼接,加上盐(salt),然后做哈希。这种最简单,找到拼接规则和盐就能复现。
  • HMAC:带密钥的哈希,密钥可能硬编码在代码里,也可能动态下发。
  • RSA/AES:非对称或对称加密,通常用于加密关键参数而不是签名。
  • 自定义算法:把上述几种组合起来,加上各种混淆和变形。

逆向签名算法的流程一般是:抓包拿到一个完整的请求 → 在代码里搜索签名参数的名字(比如sign、signature)→ 找到生成签名的函数 → 分析函数的输入和输出 → 用Python或JavaScript复现算法 → 验证复现结果和抓包结果一致。

这个过程说起来简单,实际做起来经常卡在几个地方:签名函数的输入参数可能来自多个地方,需要追很多层调用;盐可能被加密存储,需要先解密;算法可能被混淆得面目全非,需要动态调试才能看懂。

4.2 动态调试native层代码

如果签名算法在native层(.so文件里),静态分析会非常痛苦。这时候需要上动态调试。

GDB和LLDB是native调试的经典工具,但在Android上配置起来比较麻烦。更现代的选择是Frida的native Hook功能,或者IDA的远程调试。

Frida Hook native函数的写法:

// Hook native函数示例 var nativeFunc = Module.findExportByName("libnative.so", "sign"); if (nativeFunc) { Interceptor.attach(nativeFunc, { onEnter: function(args) { console.log("参数1:", args[0].readUtf8String()); console.log("参数2:", args[1].toInt32()); }, onLeave: function(retval) { console.log("返回值:", retval.readUtf8String()); } }); }

这段脚本能让你看到native函数的输入输出,但看不到内部逻辑。要看内部逻辑,需要在IDA里找到函数地址,设置断点,然后单步跟踪。IDA的远程调试功能可以连接Android设备上的android_server,实现源码级的调试体验。

动态调试native层的难点在于:函数可能被混淆(控制流平坦化、指令替换),断点可能被反调试检测到,参数可能是加密的。我的一般策略是:先用Frida看输入输出,确定函数的边界;然后在IDA里静态分析,找到关键的分支和循环;最后用Frida在关键位置插桩,验证静态分析的结论。

4.3 反调试与对抗

国民级App基本都有反调试机制。常见的反调试手段包括:

  • 检测调试器:通过ptrace、/proc/self/status等方式检测是否被调试。
  • 检测Frida:扫描进程内存里是否有Frida的特征字符串,检测常用端口。
  • 检测Xposed:检查/system/framework下是否有Xposed相关文件。
  • 代码完整性校验:运行时校验dex或so的哈希,发现被修改就退出。

对抗反调试的方法也是多种多样:Hook检测函数让它返回“未调试”,修改Frida的特征字符串,用Magisk隐藏root和Xposed,等等。这是一场持续的攻防战,没有一劳永逸的方案。

我的经验是:不要试图一次性绕过所有检测。先跑起来,看它在哪一步退出,然后针对性地绕过那一个检测点。很多时候,App只是在启动时做一次检测,过了那个点就不再检查了。

5. 从分析到理解:还原业务逻辑的完整链路

5.1 把碎片拼成地图

逆向分析的最终目标不是“看懂某个函数”,而是“理解整个业务逻辑”。这需要把静态分析、动态Hook、抓包的结果拼在一起,形成一张完整的调用地图。

我一般会用一个表格来整理分析结果:

模块关键类/函数输入输出备注
登录LoginManager.a()用户名、密码token密码先MD5再RSA
签名SignUtil.b()参数Mapsign字符串盐在assets/config里
加密native-lib.so的encrypt明文密文AES-CBC,密钥动态下发
网络OkHttp拦截器请求响应自定义Header带设备指纹

这张表越详细,你对App的理解就越深。当你能把一次完整的用户操作(比如“下单”)从UI点击到网络请求到数据存储的全链路都画出来的时候,逆向分析就算做到位了。

5.2 常见坑点与规避策略

坑点一:脱壳不完整。dump出来的dex缺少方法体,反编译出来全是native或者空实现。这时候需要换脱壳工具,或者用多种方法交叉验证。

坑点二:签名算法复现失败。明明代码逻辑看懂了,但复现出来的签名和抓包结果不一致。常见原因:参数拼接顺序错了、编码方式不对(UTF-8 vs GBK)、时间戳精度不同、盐值不对。解决方法是逐字节对比,用二分法定位差异点。

坑点三:Hook被检测到。Frida一注入,App就闪退。这时候需要换更隐蔽的注入方式,或者用Magisk Hide之类的工具隐藏痕迹。

坑点四:native函数找不到。.so文件里的函数名被混淆了,或者用了动态注册(JNI_OnLoad里用RegisterNatives注册)。这时候需要分析JNI_OnLoad,找到注册的函数地址。

坑点五:服务器风控。分析过程中频繁请求服务器,触发了风控,账号被封或者IP被拉黑。做协议分析时一定要控制请求频率,必要时用测试账号。

5.3 工具链的自动化与脚本化

手动分析效率低,而且容易出错。把重复性的工作脚本化,能大幅提升效率。

比如,用Frida脚本自动Hook所有网络请求:

Java.perform(function() { var OkHttpClient = Java.use("okhttp3.OkHttpClient"); OkHttpClient.newCall.overload("okhttp3.Request").implementation = function(request) { console.log("URL: " + request.url().toString()); console.log("Method: " + request.method()); console.log("Headers: " + request.headers().toString()); return this.newCall(request); }; });

再比如,用Python脚本自动复现签名算法并验证:

import hashlib import requests def generate_sign(params, salt): sorted_params = "&".join([f"{k}={v}" for k, v in sorted(params.items())]) raw = sorted_params + salt return hashlib.md5(raw.encode()).hexdigest() # 验证 params = {"user": "test", "timestamp": "1234567890"} salt = "found_in_assets" sign = generate_sign(params, salt) print(f"Generated sign: {sign}")

脚本化的好处是:一旦算法复现成功,后续的接口调用可以完全自动化,不用每次都手动构造请求。

6. 这类分析工作的边界与个人体会

做逆向分析这些年,我最大的体会是:技术本身是中性的,但使用技术的方式决定了它的价值。同样的工具链,可以用来做安全研究、协议兼容、竞品分析,也可以用来做不该做的事。区别在于你有没有授权、目的是什么、有没有影响到别人的正常服务。

从技术角度说,“逆向分析一切”这个说法虽然夸张,但确实反映了当前移动安全领域的一个现实:没有绝对安全的App,只有成本足够高的防护。国民级App的防护之所以强,是因为它们投入了大量资源在加固、混淆、反调试、风控上,让逆向的成本变得很高。但对于有经验的分析者来说,这些防护更多是“增加难度”而不是“完全阻止”。

我在实际操作中总结了几条原则:第一,永远在授权范围内做分析,不碰不该碰的数据;第二,控制请求频率,不要对目标服务器造成压力;第三,分析结果只用于学习和研究,不用于商业竞争或非法目的;第四,保持学习心态,因为防护技术在不断进化,今天能用的方法明天可能就失效了。

最后分享一个小技巧:当你卡在某个点上超过两个小时的时候,先停下来,把已经分析清楚的部分整理成文档。很多时候,整理的过程中你会突然发现之前忽略的线索。逆向分析是个耐心活,急不得。

相关新闻

GBase 8c分布式数据库故障定位与运维实践全攻略

GBase 8c分布式数据库故障定位与运维实践全攻略

1. 故障定位的整体思路:先把排查顺序搞对1.1 分布式架构决定了排查链路GBase 8c是典型的shared-nothing分布式架构,一台“数据库”背后站着协调节点、数据节点、全局事务管理组件、集群管理组件等多类角色。这种架构最大的优势是水平扩展能力强&#xff…

2026/10/20 14:50:59 阅读更多 →
具身智能真机评测基准全解析:从仿真到真机的关键挑战

具身智能真机评测基准全解析:从仿真到真机的关键挑战

做具身智能这几年,我反复被一个问题砸中:你的策略到底在真机上表现怎么样?仿真实验再漂亮,日志再完整,一到真机就会被线缆缠住、被金属反光晃到、被重力教做人。所以圈里慢慢形成一个共识——真正有参考价值的对比&…

2026/10/20 14:50:59 阅读更多 →
AI红蓝对抗构建代码质量免疫系统

AI红蓝对抗构建代码质量免疫系统

1. 项目概述:这不是一场“黑客攻防秀”,而是一套可落地的代码质量免疫系统“AI红蓝对抗,自动代码质量流水线验证”——光看标题,很多人第一反应是:又一个炫技的概念包装?是不是在讲大模型写漏洞、再用另一个…

2026/10/20 14:50:59 阅读更多 →

最新新闻

论文被批“AI味”?千笔·降AIGC助手与PaperRed选型对比

论文被批“AI味”?千笔·降AIGC助手与PaperRed选型对比

1. 先说结论:为什么你的论文总被说“机翻味”和“模板腔”本科生写论文被导师退回重写,理由里出现频率最高的三句话,我闭着眼都能背出来:“这段话像机翻的”“这一段完全没有你自己的判断”“每段都是首先、其次、最后&#xff0c…

2026/10/20 18:48:51 阅读更多 →
基于Q-learning的储能调度效益最大化:Matlab实现与参数调试全解析

基于Q-learning的储能调度效益最大化:Matlab实现与参数调试全解析

能源市场里的“效益最大化”,表面上是低买高卖,但真正上手做就会发现难点从来不是“判断价格高低”,而是“做决策序列”:这一小时贪婪地把储能里所有电卖光,下一小时遇到更高价的时段就只能干瞪眼;低谷时段…

2026/10/20 18:48:51 阅读更多 →
Pi 1.0 原生MCP与Durable:终端编程代理从对话到持久化执行

Pi 1.0 原生MCP与Durable:终端编程代理从对话到持久化执行

如果你也在终端里用过 AI 编程代理,应该能感受到一个尴尬:它能写代码、能跑命令,但一关终端,上下文全丢。这个痛点卡了我很久。所以当我看到 Pi 1.0 正式发布,主打原生 MCP 和 Pi Durable 时,第一反应不是“…

2026/10/20 18:48:51 阅读更多 →
context-mode设计实战:从上下文管理到模式切换的工程化落地

context-mode设计实战:从上下文管理到模式切换的工程化落地

1. 从“context-mode”说起:一个被低估的工程概念第一次看到“context-mode”这个词,很多人会下意识地把它归到某个具体框架的配置项里,觉得无非是个开关或者枚举值。但如果你真正在多个项目里跟“上下文”打过交道,就会发现它其实…

2026/10/20 18:48:51 阅读更多 →
面向对象设计实战:从封装多态到SOLID原则落地

面向对象设计实战:从封装多态到SOLID原则落地

1. 对象思维是一道分水岭我面试过不少人,聊到“面向对象的编程设计”,背概念都能背得滚瓜烂熟:封装、继承、多态,三大特征如数家珍。但一旦落到实际项目里,写出来的代码还是一把梭——几百行的方法,到处是i…

2026/10/20 18:48:51 阅读更多 →
EBS采购订单审批API集成实战:工作流、中间件与存储过程设计

EBS采购订单审批API集成实战:工作流、中间件与存储过程设计

做EBS集成的同学对采购订单审批肯定不陌生。标准功能里,审批人每天登录EBS工作台,从一堆待办通知里逐个点开、审批、写意见,流程虽然完整,但一旦公司上了OA、企业微信、钉钉或者供应商协同平台,业务方就会立刻找你&…

2026/10/20 18:47:50 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →