--- name: re-electron description: > Electron 桌面应用逆向:asar 解包、主/渲染进程 JS、V8 字节码(.jsc)边界、CDP 动态调试、反调试对抗。 触发词:Electron、asar、桌面应用逆向、.jsc、V8 快照、CDP、ELECTRON_RUN_AS_NODE、devtools 检测。 capabilities: [electron-analysis] --- # Electron 桌面应用逆向(asar / CDP / .jsc) ## 何时使用 / 何时不用 - 用:Electron 打包桌面应用——`resources/app.asar` 结构、主/渲染进程 JS 逻辑还原、原生 `.node` 模块、密钥/通信逻辑提取 - 用:V8 字节码 `.jsc` 文件(bytenode 类工具编译产物)的识别与边界判断 - 用:动态调试——主进程 `--inspect`、渲染进程 `--remote-debugging-port`(CDP)、`ELECTRON_RUN_AS_NODE` 以 Node 模式复用运行时 - 用:反调试对抗——devtools / inspect 检测识别与绕过(联动 [[re-evasion]]) - 不用:纯浏览器扩展(走 [[re-browser-ext]]) - 不用:脱离 Electron 场景的混淆 JS/脚本(走 [[re-script-deob]] / [[re-deobfuscate]]) - 不用:`.jsc` 出现在 Cocos 游戏资源场景(那是 Cocos 引擎字节码,走 [[re-game]];本技能只管 Electron 的 V8 字节码) - 不用:仅需通用二进制初勘([[re-binary-core]] 通用底座;本技能只补 Electron 打包层语义) - 注意:**动态执行默认沙箱([[re-analyze/platform-tips]] 最高原则)**——跑应用、连 CDP、加载 `.jsc` 均按动态处理,静态解包可免沙箱 ## 工具准备 所有工具先验证再使用。静态解包可免沙箱;运行应用 / 动态调试默认沙箱 + 网络隔离([[re-analyze/platform-tips]] 最高原则)。Electron 应用多为跨平台打包,工具链以 npm 生态为主、跨 OS 一致。 ### Node.js + npm —— 工具底座(asar / CDP 客户端 / bytenode / fuses) - Linux: 发行版包 `apt install nodejs npm`(Debian/Ubuntu 仓库版本偏旧,V8 版本锁场景用 NodeSource 或 nvm 装新版);macOS: `brew install node`;Windows: 官方安装器或 `choco install nodejs`;跨平台: nvm(`nvm install `)按需切换 Node 版本 - 验证: `node --version && npm --version` - nvm: 官方安装脚本(GitHub nvm-sh/nvm);Windows 用 nvm-windows 或官方安装器 ### @electron/asar —— asar 归档解包(现维护的官方包) - `npm install -g @electron/asar` 或免安装 `npx @electron/asar ...`(npx 首次自动下载;旧包名 `asar` 已弃用但 CLI 兼容仍可用) - 验证: `npx @electron/asar --help`(应列出 `pack / list / extract-file / extract` 子命令) - 用法: `npx @electron/asar extract app.asar out/`(整包解出)、`npx @electron/asar list app.asar`(列目录)、`npx @electron/asar extract-file app.asar path/to/file`(单文件) - 免工具直读:asar 头部内嵌 JSON 目录(`{"files":{...}}`,每文件含 `size`/`offset`/`integrity`),JSON 字符串自偏移 16 起(前 12 字节为 pickle 嵌套大小字段,offset 12 为头字符串长度,均 uint32 LE)——`strings app.asar | grep '"files"'` 或小脚本 `JSON.parse` 定位,无需任何工具 ### strings / grep —— 文本线索 - Linux: binutils 自带(`apt install binutils` 等);macOS: 自带(或 `brew install binutils`);Windows: WSL 内或 Sysinternals strings - 验证: `strings --version` ### chrome-remote-interface —— CDP 客户端(动态调试主力) - 项目内 `npm install chrome-remote-interface`(官方 npm 包,Chrome DevTools Protocol 客户端) - 验证: `node -e "require('chrome-remote-interface')"` 不报错即装好;实际连通见操作步骤 6 - 备选: 纯 curl + Node 内置 ws,无需装包(`curl http://127.0.0.1:/json/list` 拿 `webSocketDebuggerUrl` 后连 WebSocket 发 JSON-RPC) ### bytenode —— .jsc 编译/加载理解工具(验证与对照用) - `npm install -g bytenode` 或项目内安装 - 验证: `npx bytenode --help`(`-c` 编译、`-e/--electron` 编译为 Electron 用、`-ep/--electron-path` 指定 Electron 可执行文件) - 用途:用目标版本 Node/Electron 重编译对照样本 `.jsc` 的魔数与可加载性;本身不是反编译工具(见坑 1) - Electron 42+ 主进程场景(`electronMain`)无 CLI 对应参数,须用 API 调用形态:`require('bytenode').compileFile({ electronMain: true, filename: 'main.js' })`(与坑 1 的 `electronMain` 模式呼应) ### @electron/fuses —— 运行能力开关检查/翻转 - `npm install -g @electron/fuses`(官方包) - 验证: `npx @electron/fuses read --app <应用可执行文件或 .app 路径>`——输出各 fuse 状态(RunAsNode / EnableNodeCliInspectArguments / EnableEmbeddedAsarIntegrityValidation / OnlyLoadAppFromAsar 等) - 翻转: `npx @electron/fuses write --app <路径> RunAsNode=off EnableNodeCliInspectArguments=off`(写前先 read 评估;翻转改动二进制、破坏签名,macOS 需重新签名) - 免工具查看:strings 搜 fuse 哨兵串 `dL7pKGdnNz796PbbjQWNKmHXBZaB9tsX`,其后为 fuse 版本、长度与 wire 字节(`0x30`(0)=禁用、`0x31`(1)=启用、`0x72`(r)=移除) ### 通用反编译器 —— 原生 .node 模块 - Ghidra(官方 release 包,需 JDK;部分发行版仓库有 `apt install ghidra` / `pacman -S ghidra`;macOS `brew install --cask ghidra`;Windows 官方 zip;验证 `analyzeHeadless -help`) - IDA:商业版;Freeware 版架构支持范围以官方页面为准 - `.node` 本质是 ELF/Mach-O/PE 动态库,导入反编译器前先用 `file`/`readelf -h` 确认架构(联动 [[re-format-elf]] / [[re-format-macho]] / [[re-format-pe]]) ### (可选)xvfb-run —— Linux 无显示环境跑 GUI 应用 - Linux: `apt install xvfb` / `dnf install xvfb` / `pacman -S xvfb` - 验证: `xvfb-run -a node --version`;无显示服务器时 `xvfb-run -a electron .` 运行目标 - macOS/Windows 有原生显示,无需 ## 操作步骤 按顺序执行,每步结果存档;动态执行默认沙箱。 1. **识别 Electron 与版本**: ```sh ls resources/ # 打包应用应有 app.asar(+ app.asar.unpacked/) strings <可执行文件> | grep -i -E 'electron|chrome' | head ``` - 判定信号:`resources/app.asar` 结构、进程列表中多进程(主进程 + GPU/渲染子进程)、二进制内 Electron/Chromium 版本串 - 版本确认:打包应用 `--version` 常无输出——可靠途径是动态阶段用 CDP 执行 `process.versions`(electron/chrome/v8/node/modules 全字段);静态只能靠二进制 strings 版本串辅助 - Electron → Chromium/Node 对应关系查官方 electron-timelines 发布表(只列 Chromium/Node,无 V8 列);V8 版本只能运行时 `process.versions.v8` 获取 2. **asar 解包**: ```sh npx @electron/asar list app.asar # 先看目录结构 npx @electron/asar extract app.asar out/ # 整包解出 npx @electron/asar extract-file app.asar package.json # 单文件快速取 ``` - 免工具:JSON 目录自偏移 16 起,`strings app.asar | grep '"files"'` 或脚本按 size/offset 拼接即可还原全部文件 - `app.asar.unpacked/` 目录是未打进归档的原生模块,原样在磁盘上,直接分析 - 改包前先 `npx @electron/fuses read --app <可执行文件>` 看 `EnableEmbeddedAsarIntegrityValidation` / `OnlyLoadAppFromAsar`——完整性校验开启时替换 app.asar 会导致启动失败(见坑 2) 3. **主进程入口与逻辑**: - 解包后读 `out/package.json` 的 `main` 字段 → 主进程入口 JS(默认 `main.js`) - 主进程是 Node 环境:require 链、`app`/`BrowserWindow`/`ipcMain` 调用即业务骨架;IPC handler(`ipcMain.handle/on`)是主/渲染通信枢纽,先列全 - 主进程逻辑可被 `ELECTRON_RUN_AS_NODE=1 <可执行文件> script.js` 以纯 Node 方式复用(同一 V8/Node ABI,见坑 3 的边界)——不依赖 electron API 的部分可离线跑通观察行为 - 主进程打包为 `.jsc` 的场景:`ELECTRON_RUN_AS_NODE` 下 `require('bytenode')` 加载 .jsc(版本必须匹配,见坑 1) 4. **渲染进程 JS 还原**: - 渲染代码一般打包在 `out/` 某子目录(webpack/browserify/rollup bundle,常混淆、压缩成一行) - 还原顺序:确定入口 HTML(BrowserWindow 的 loadFile/loadURL 参数)→ 找 `