ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Electron 应用源码提取实战:baoyu-electron-extract 解包 app.asar 并还原 Source Map 源码

2026/9/20 22:55:03 拓冰建站 浏览量
Electron 应用源码提取实战:baoyu-electron-extract 解包 app.asar 并还原 Source Map 源码 Electron 应用源码提取实战baoyu-electron-extract 解包 app.asar 并还原 Source Map 源码【免费下载链接】baoyu-skills项目地址: https://gitcode.com/gh_mirrors/ba/baoyu-skills本指南以开源仓库 baoyu-skills 中的baoyu-electron-extract技能定义见 SKILL.md为核心系统讲解如何对任意已安装的 Electron 桌面应用Codex、VS Code、Cursor、Discord、Slack、Notion、Obsidian 等完成app.asar解包、源码文件发现与提取当存在.js.map时基于sourcesContent还原原始 TypeScript/JavaScript 源码否则用 Prettier 就地格式化压缩产物。读完本文你将掌握该工具的全部命令参数、跨平台应用发现机制、输出目录结构以及 source-map 路径还原算法在 main.ts 中的具体实现能够直接上手提取并阅读任意 Electron 应用的构建源码。为什么要提取 Electron 应用的app.asarElectron 桌面应用如 ChatGPT Desktop、Codex、Cursor、VS Code 等的界面与业务逻辑通常以 JavaScript/TypeScript 编写打包阶段由 webpack、esbuild、Vite、rollup 等构建工具压缩合并为若干个 bundle再连同资源文件封装进一个名为app.asar的归档文件中该归档可用electron/asar工具读写。对于普通用户app.asar是一个黑盒而当你需要看某个 Electron 应用是怎么实现的还原某个应用的源码结构确认某个应用的构建方式时就需要先解包这个归档再对内部的压缩代码做恢复处理。baoyu-electron-extract正是为此设计的专用技能。它的核心价值在于两点自动发现只需给出应用名或安装路径脚本即可在 macOS / Windows 上自动定位到app.asar无需手动翻找目录源码级还原现代打包器在产出bundle.js的同时通常会生成同名.js.map且大多内嵌sourcesContent字段即每个源文件的原始内容。只要 map 完整脚本就能把压缩 bundle 恢复为接近原始工程的目录树如src/main.ts、src/renderer/app.tsx而不是一堆哈希命名的散文件对于没有 map 的产物则回退为 Prettier 格式化让压缩代码具备可读性。使用前提与运行时解析该技能脚本位于 scripts/main.tsbaoyu-electron-extract的scripts/子目录{baseDir}即 SKILL.md 所在目录。运行时${BUN_X}按以下优先级解析已安装bun→ 直接使用bun仅有npx→ 使用npx -y bun临时拉取 bun两者都不可用 → 需要先安装 bun。所有命令示例中的${BUN_X}与{baseDir}需要在执行时替换为实际值。值得强调的是脚本不做任何全局安装。解包依赖的electron/asar与格式化依赖的prettier都通过npx -y按需解析见 extractAsar 与 formatBatches因此首次运行会因 npx 缓存下载而稍慢但不会污染系统环境。何时使用该技能当用户想查看某个已安装的 Electron 应用内部结构或其打包代码时即可触发典型表达包括extract Electron app、decompile this Electron app、unpack app.asarshow me the source of app、look inside app、how is app builtget the source code of Codex / Cursor / Discord / Slack / VS Code / Notion / Obsidian / ChatGPT desktop提取 Electron 应用、看 app 的源码、反编译 Electron、解包 app.asar、还原 source map输入既可以是应用名如Codex也可以是绝对路径如/Applications/Codex.app、C:\Users\you\AppData\Local\Programs\codex、一个.asar文件本身脚本对两个平台都支持自动发现。完整工作流从提问到拿到源码第一步确定输入用户未给出应用名或路径时先询问若用户希望自定义输出目录一并询问。技能的用户输入遵循运行时工具优先规则优先使用当前 Agent 运行时暴露的内置用户输入工具如AskUserQuestion、request_user_input、clarify、ask_user等若不存在则退化为带编号的纯文本提问支持多问题合并时应一次性合并仅支持单问题时按优先级逐个询问。第二步运行脚本${BUN_X} {baseDir}/scripts/main.ts app [--output dir] [--asar path] [--force]如果不确定自动发现能否命中正确的 bundle先加--dry-run预览它会打印解析到的路径并立即退出不触碰文件系统。第三步处理结果成功→ 报告输出路径与计数extracted / restored / formatted发现多个匹配→ 脚本列出候选并非零退出向用户展示候选、询问选用哪个再用选中的绝对路径重跑输出目录已存在且非空→ 脚本拒绝执行需询问用户是使用--force覆盖还是换一个--output平台不支持 / 无匹配→ 建议用户直接传--asar /full/path/to/app.asar指定归档位置。第四步指引用户查看结果默认输出目录为~/Downloads/AppName-electron-extract/最有价值的子目录取决于发现了什么存在restored/→ 说明已从.js.map重建出原始源码树优先阅读这里只有extracted/无 map→ 其中的 JS/CSS 已被 Prettier 就地格式化从这里阅读。命令行用法与选项详解以下命令均以Codex为例完整命令清单见 SKILL.md 的 Usage 一节# 按应用名提取默认输出~/Downloads/Codex-electron-extract/ ${BUN_X} {baseDir}/scripts/main.ts Codex # 按绝对路径提取支持 .app 包、安装目录、.asar 文件 ${BUN_X} {baseDir}/scripts/main.ts /Applications/Visual Studio Code.app ${BUN_X} {baseDir}/scripts/main.ts C:\Users\you\AppData\Local\Programs\codex ${BUN_X} {baseDir}/scripts/main.ts --asar /Applications/Codex.app/Contents/Resources/app.asar Codex # 自定义输出目录 ${BUN_X} {baseDir}/scripts/main.ts Codex --output ~/work/codex-source # 仅预览发现结果不写入任何文件 ${BUN_X} {baseDir}/scripts/main.ts Codex --dry-run # 覆盖已存在的输出目录 ${BUN_X} {baseDir}/scripts/main.ts Codex --force # 机器可读输出stdout 输出单行 JSON ${BUN_X} {baseDir}/scripts/main.ts Codex --json参数一览表OptionShortDescriptionDefaultapp应用名或绝对路径。除非给了--asar否则必填。—--output-o输出目录~/Downloads/AppName-electron-extract--asar覆盖自动解析出的.asar路径自动发现--force-f允许写入非空的已存在输出目录false--skip-format跳过 Prettier 格式化仅解包false--skip-restore跳过 source-map 还原false--no-unpacked不复制app.asar.unpacked/false--dry-run打印解析路径后退出不写文件false--json在 stdout 输出单行 JSON 摘要抑制常规输出false参数解析实现在 parseArgs未知选项、缺少app且无--asar、或位置参数超过一个都会报错并打印用法说明退出码为 2运行期错误如找不到归档走 fail在--json模式下输出{status:error,error:...}单行。平台差异与路径形式应用名如Codex在 macOS 上扫描/Applications与~/Applications在 Windows 上扫描%LOCALAPPDATA%\Programs、%PROGRAMFILES%、%PROGRAMFILES(X86)%、%APPDATA%。多个匹配时列出候选并要求改传绝对路径绝对路径/Applications/Codex.appmacOS.app包、Windows 安装目录、或直接指向某个.asar文件脚本按路径直接解析Linux 等平台自动发现不支持必须显式传--asar /path/to/app.asar。这一限制来自 resolveApp 对process.platform的显式判断。应用名还会被清洗后用于构造默认输出目录名非法文件名字符\ / : * ? |替换为_、连续空白替换为-见 sanitizeAppName从.app包或app.asar路径推断应用名的逻辑见 appNameFromPath。输出目录布局与报告文件成功运行后输出目录结构如下完整描述见 SKILL.md 的 Output layout 一节~/Downloads/AppName-electron-extract/ ├── extract-report.json # JSON 摘要计数、警告、解析路径 ├── extracted/ # asar 原始内容无 map 时 JS/CSS 已 Prettier 格式化 │ └── ... # node_modules 保持原样跳过格式化 ├── extracted.unpacked/ # 若存在 asar.unpacked/ 则复制而来 │ └── ... # 原生模块.node、大体积资源 └── restored/ # 仅当至少一个 .js.map 可用时出现 └── original/source/tree # 由每个 .js.map 的 sourcesContent 重建其中extract-report.json由 main 在收尾阶段写入结构包含appName与source输入、解析到的asar路径、platform、installRootoutputroot、extracted、unpacked未复制则为 null、restored无还原内容则为 nullcountsextractedFiles、restoredFiles、formattedFiles、skippedNodeModules、unpackedFileswarnings字符串数组记录被跳过的 map、解析失败、写盘失败等警告durationMs本次运行耗时。常规模式下结束时会打印Done in N.Ns及各项计数--json模式下则向 stdout 输出一行{status:ok, ...}完整报告便于脚本化集成。extract-report.json是排查为什么某个源码没有还原的第一入口。源码级原理提取管线如何工作整体管线在 main 中串联大致分为五个阶段解析输入parseArgs读取命令行参数定位归档--asar直接解析否则走resolveApp完成按名发现或按路径解析内部依赖listAppCandidates与findAsarUnderDir输出ResolvedApp应用名、asar 路径、unpacked 目录、安装根目录安全校验与解包assertSafeOutputDir校验输出目录随后extractAsar调用npx -y electron/asar extract asar dest解包到extracted/若存在app.asar.unpacked/Electron 会把原生模块.node与大资源放在这里默认用cpSync复制到extracted.unpacked/--no-unpacked可关闭遍历与分拣walk递归遍历extracted/统计文件数把.js/.mjs/.cjs归入 JS 列表、.css归入 CSS 列表并逐层跳过node_modules目录walk还原与格式化先对每个 JS 尝试用其同名.js.map还原源码剩余 JS 与全部 CSS 交给 Prettier 分批格式化最后汇总写入extract-report.json。源文件发现两种自动解析路径按绝对路径解析resolveByPath直接判断.asar文件、.app目录查找Contents/Resources/app.asar或普通目录通过 findAsarUnderDir 尝试resources/app.asar、Resources/app.asar、app.asar及一层嵌套子目录的resources/app.asar按应用名搜索listAppCandidates按平台扫描上文列出的根目录逐一匹配entry.name与用户输入区分大小写不敏感并兼容.app后缀。当多个应用目录都含有效app.asar时脚本会抛出multiple apps match错误并列出候选resolveApp提示改用绝对路径重跑——这与工作流中Multiple matches分支完全对应。Prettier 格式化分批执行与异常容忍所有无 map 还原的 JS 与全部 CSS 会被收集后交给 Prettier。为避免单条命令行参数过长formatBatches 以 50,000 字符为阈值分批调用npx -y prettier --write某批失败仅记录到 stderr 并继续continuing不会中断整体流程。格式化计数计入counts.formattedFiles。深入解析Source Map 路径还原算法这是该技能最具技术含量的部分核心目标是尽可能保留原始源码名与目录结构。还原规则SKILL.md 定义每个sources[]条目先按sourceRoot若存在解析再相对于extracted/内该.js.map文件所在目录解析折叠打包器常见的相对路径还原为工程树结构。例如.vite/main/index.js.map../../src/main.ts→restored/src/main.ts若源码路径越过了extracted/向上攀升仍保留其可读的剩余路径而非哈希化。例如.vite/main/index.js.map../../../shared/src/lib/foo.ts→restored/shared/src/lib/foo.ts去除源名中的 URL/query 装饰包括常见的webpack://、file://与?loader后缀仅当源名为空或无法化简为安全文件路径时才使用restored/__unknown/hash.ext兜底持续跳过node_modules与webpack/runtime/*条目——它们是打包器/运行时噪声而非应用源码。实现细节路径规范化normalizeSourcePath按以下次序处理sourceWithRoot先用stripSourceDecorations剥掉webpack://、file://及任意scheme://前缀并去掉?query#hashstripSourceDecorations再判断是否需要把sourceRoot拼接到源名前源名本身带协议或已是绝对路径时不拼接sourceWithRoot对以./或../开头的相对源名计算其相对extracted/的归一化路径若越界则走sanitizeEscapedSourcePath——把..段逐个削掉、剥掉盘符与开头的/、再做posix.normalize最后用isSafeRelativePath复核不安全才落入__unknown/hash兜底sanitizeEscapedSourcePath、fallbackUnknownPath其余情况直接对源名做输出路径清洗。整个还原过程中node_modules/与webpack/runtime/前缀的源会被直接跳过shouldSkipRestoredSource。还原写入restoreFromMap读取.js.map并JSON.parse仅当sources与sourcesContent均为数组时才处理长度不一致会记 warning逐条写入最终落盘前用 restoredTargetPath 校验目标路径必须仍位于restored/之内rel不能是空、..或绝对路径越界条目记 warning 并跳过。关键限制source-map 还原仅在.js.map内嵌sourcesContent时生效——这正是现代打包器webpack、esbuild、Vite、rollup的常见做法。若 map 只引用外部.ts/.js文件而未内嵌内容该 map 会被跳过对应.js改为 Prettier 格式化被跳过的 map 会以warnings形式记录在extract-report.json中。测试用例印证仓库测试 main.test.ts 用两个用例锁定了上述行为normalizeSourcePath 三连验证main.test.ts#L9-L42.vite/main/index.js.map场景下../../src/main/agent/claude-agent.ts→src/main/agent/claude-agent.ts越界的../../../shared/src/lib/prompt-classification.ts→shared/src/lib/prompt-classification.ts越界但不哈希带sourceRoot: webpack://moss/的./src/renderer/app.tsx→moss/src/renderer/app.tsxrestoreFromMap 端到端还原main.test.ts#L44-L123构造一份含 7 个 sources 的 map其中../../src/main.ts、../../src/common/ipcChannels.ts、../../../shared/src/lib/prompt-classification.ts、webpack://moss/./src/renderer/app.tsx共 4 个被还原到对应路径而node_modules条目含反斜杠形式的..\..\node_modules\windows-pkg\index.js与webpack/runtime/chunk loading全部被跳过restored计数恰为 4 且无警告。这两组断言直接印证了可读路径优先、哈希仅兜底、runtime/node_modules 一律跳过的设计原则。安全机制与防御性设计脚本对写到哪去有严格约束见 assertSafeOutputDir拒绝把输出目录设为文件系统根/或 Windows 盘符根、用户主目录、或当前工作目录输出目录的 basename 必须包含应用名或electron-extract字样否则拒绝执行已存在且非空的输出目录必须显式--force才允许写入。此外还原路径在落盘前会二次校验必须仍处于restored/内从路径层面杜绝了 source-map 中恶意../把文件写出目录的可能。这些约束共同保证了即使面对来源不明的.asar脚本也不会意外覆盖用户文件。注意事项与适用边界node_modules 一律跳过无论 source-map 还原还是 Prettier 格式化vendored 依赖对应用审查都是噪声source-map 还原依赖内嵌sourcesContent这是能否拿到原始工程结构的分水岭缺失时退化为 Prettier 格式化可读性取决于原 bundle 的压缩程度平台支持范围应用名自动发现仅支持 macOS 与 WindowsLinux 或其他平台需显式--asar。这一限制同时意味着在非 darwin/win32 平台上按应用名提取会直接报错首次运行较慢electron/asar与prettier经npx -y按需解析首跑含缓存下载还原 ≠ 原始工程即使有完整 maprestored/也是接近原始工程可能不含构建配置、资源文件的原始排版等无 map 时只能得到格式化后的 bundle。技能定位是帮助理解与审查应用的构建方式与实现而非逐字节复刻源码。结语baoyu-electron-extract把反编译 Electron 应用这件原本繁琐的事压缩成一条命令自动发现app.asar→electron/asar解包 → 优先以 source-map 还原原始工程结构、否则 Prettier 格式化兜底并全程以extract-report.json记录计数与警告、以路径安全校验兜底。结合 SKILL.md、main.ts 与 main.test.ts 阅读你既能掌握开箱即用的操作流程也能理解每条还原规则背后的路径算法与安全边界——无论是审查依赖、学习知名应用的工程组织方式还是排查自身 Electron 应用的打包产物这一工具链都值得纳入工具箱。【免费下载链接】baoyu-skills项目地址: https://gitcode.com/gh_mirrors/ba/baoyu-skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考