Electron 包检查

只读检查一个 Electron 应用包——解析 app.asar 头、提取任意文件(如 main.js)、定位内嵌运行时和启动命令,并顺着日志/进程/端口确认当前跑的是哪一份。

Electron app.asar 只读检查

结论先行

app.asar 不是压缩包,是 16 字节头 + JSON 目录 + 原始文件拼接。读文件只需要算对 数据区起点 + offset,不需要任何依赖。

检查阶段不要写回——写回要重算每个文件的 integrity,属于另一个技能(见 dsh-desktop-wallpaper)。

asar 结构(实测)


[0..3]    UInt32LE = 4             常量
[4..7]    UInt32LE = jsonLen + 8   header pickle 总长
[8..11]   UInt32LE = jsonLen + 4
[12..15]  UInt32LE = jsonLen       JSON 字节长度
[16..]    JSON header(4 字节对齐,尾部空格填充)
[16+headerLen ..]  数据区;JSON 里每个文件的 offset 相对数据区起点

步骤

1. 列目录 + 找目标文件

```powershell

$p='C:\Program Files\sanshan-kaiwu\resources\app.asar'

# 用 Node 一次读头、打印文件树

node -e "const fs=require('fs');const fd=fs.openSync(process.argv[1],'r');const b=Buffer.alloc(16);fs.readSync(fd,b,0,16,0);const n=b.readUInt32LE(12);const h=Buffer.alloc(n);fs.readSync(fd,h,0,n,16);console.log(JSON.stringify(JSON.parse(h.toString('utf8')),null,2).slice(0,4000))" "$p"

```

检查点:能看到 files.src.main.js 之类的节点,带 size / offset / integrity。

2. 提取文件(只读,输出到临时目录)

```powershell

node -e "

const fs=require('fs');

const [asar,entry,out]=process.argv.slice(1);

const fd=fs.openSync(asar,'r');

const b=Buffer.alloc(16); fs.readSync(fd,b,0,16,0);

const n=b.readUInt32LE(12); const h=Buffer.alloc(n); fs.readSync(fd,h,0,n,16);

let node=JSON.parse(h.toString('utf8'));

for (const k of entry.split('/')) node=node.files[k];

const buf=Buffer.alloc(node.size);

fs.readSync(fd,buf,0,node.size,16+n+Number(node.offset));

fs.writeFileSync(out,buf);

console.log('extracted',out,node.size,'bytes');

" "$p" "src/main.js" "$env:TEMP\main.js"

```

3. 读 main.js 里的三个关键点

- runtimeRoot():打包后指向 resources/runtime,开发时指向工程 runtime/。

- 启动子进程的 spawn(...):常见形式是 node.exe <dsh>/lib/bin.js web --no-open --port 0,并注入 DSH_HOME。

- 解析就绪日志的正则:形如 dsh web: (http://127\.0\.0\.1:\d+/\S+),从 stdout 抓端口和 token。

4. 确认当前跑的是哪一份(日志 / 进程 / 端口三角定位)

```powershell

Get-Content "$env:APPDATA\三山开物\logs\dsh.log" -Tail 20

Get-Process | Where-Object { $_.ProcessName -match '三山|electron' } | Select-Object Id,ProcessName,StartTime

netstat -ano | Select-String ':55162'

```

日志里 starting dsh: <路径> 决定"用的是哪份运行时",ready: http://127.0.0.1:<port> 决定"当前窗口连的是哪个端口"。

坑

验收清单

别做的事