rea-reverse

Unpack an ASAR File: Extract and Inspect an Electron App

Written for REA 6.4.0Updated 7 min read
On this page

An Electron app keeps its JavaScript, HTML and assets in one file, resources/app.asar. To debug a packaged build of your own app, check what a release actually contains, or study an open-source Electron project, you first need to open that file. This is a quick, practical guide: where to find app.asar on each platform, how to unpack it in the browser or from the command line, and what to read first once it is open. For the full analysis workflow, with REA’s application graph, preload bridges and IPC pairing, see Reverse engineer an Electron app with REA.

Who this is for: Electron developers and reviewers working on their own apps, open-source apps, or apps they are authorised to assess. You need Node.js for the command-line part, and nothing else for the browser part.

The examples use notes-shell, a tiny Electron app written for this guide. It has a main process, a preload script, a renderer page and a placeholder .node file, which the packer was told to keep outside the archive with --unpack "*.node".

What an ASAR file is

ASAR is a simple archive format. It starts with a small binary prefix and a JSON header that describes the directory tree. The file contents follow, stored back to back and uncompressed. Each file entry in the header has a size, an offset (stored as a decimal string) and, in archives written by current versions of @electron/asar, an integrity record with a SHA-256 hash. This is the real header entry for one file of the sample:

{"size":300,"offset":"1219","integrity":{"algorithm":"SHA256","hash":"022ffed9…","blockSize":4194304,"blocks":["022ffed9…"]}}

Some entries are marked "unpacked": true. Their bytes are not in the .asar at all. They live in a sibling folder, app.asar.unpacked/, because they must exist as real files on disk. Native Node add-ons (.node) are the usual case. Keep the archive and that folder together whenever you copy an app for analysis.

Where to find app.asar

The archive is in the app’s resources directory. Typical locations:

  • macOS: /Applications/<App>.app/Contents/Resources/app.asar. Right-click the app and choose Show Package Contents to browse there in Finder.
  • Windows: per-user installs usually go to %LOCALAPPDATA%\Programs\<App>\resources\app.asar, and machine-wide installs to C:\Program Files\<App>\resources\app.asar.
  • Linux: packages often install to /opt/<App>/resources/app.asar. An AppImage has to be unpacked first: run it with --appimage-extract and look under squashfs-root/resources/.

Some apps have no app.asar and ship a plain resources/app/ folder instead. There is nothing to unpack then. Open the folder.

Copy app.asar and app.asar.unpacked/ to a working directory before you start. Your analysis then does not change when the installed app updates itself.

Option 1: Unpack in the browser

Open the ASAR extractor and Electron IPC analyzer and drop in app.asar. The archive is parsed in a Web Worker on your machine and is not uploaded. Only the prefix and the header are read up front, so even a large archive opens fast. You get a searchable file tree, and you can preview or download any packed file without extracting the rest.

For notes-shell, the report shows 7 files, 3 directories and 1 unpacked entry. On top of the file tree, the tool reads the Electron structure for you:

Report section Result for notes-shell
package.json notes-shell 0.3.0, main: src/main.js
Preload scripts src/preload.js, configured at src/main.js:10
Renderer entries renderer/renderer.js, from renderer/index.html
contextBridge notes with keys list, save, onSaved (src/preload.js:3)
Native modules native/fast-hash.node, 30 bytes, unpacked

The IPC channel table lists six rows: notes:list and notes:save handled with ipcMain.handle in src/main.js (lines 18 and 19), notes:saved sent with webContents.send at src/main.js:21, and the matching ipcRenderer.invoke and ipcRenderer.on calls in src/preload.js (lines 4 to 6). Each row shows the direction and the process (main or preload) of the code that makes the call.

The browser route has two limits. It downloads files one at a time, and it cannot give you the bytes of unpacked entries, because they are not in the archive. For a full extraction, use the command line.

Option 2: Unpack with npx @electron/asar

@electron/asar is the packaging library maintained by the Electron project. You can run it without installing anything globally:

npx @electron/asar list app.asar
npx @electron/asar extract app.asar out
npx @electron/asar extract-file app.asar src/preload.js

list prints every path in the archive. For the sample (version 4.3.1):

/native
/native/fast-hash.node
/package.json
/renderer
/renderer/index.html
/renderer/renderer.js
/src
/src/main.js
/src/preload.js
/src/store.js

extract writes the whole tree to out/. It also copies unpacked entries from app.asar.unpacked/, so out/native/fast-hash.node is present. extract-file writes one file into the current directory under its base name, here preload.js.

The same commands work on Windows, macOS and Linux. On Windows, quote paths that contain spaces, for example npx @electron/asar extract "C:\Program Files\Notes\resources\app.asar" out.

A missing .unpacked folder. With only app.asar copied to another directory, extract in version 4.3.1 stops with Error: Unable to extract some files: followed by ENOENT: no such file or directory for app.asar.unpacked/native/fast-hash.node. The packed files are written anyway, but the native module is missing. Copy the folder next to the archive and run it again.

Option 3: Let REA do it

REA, the open-source project by morluto, reads ASAR archives directly. With REA 6.4.0 installed (setup guide):

rea inspect-artifact /absolute/path/work/app.asar --json > inventory.json
rea extract-artifact /absolute/path/work/app.asar --json
rea analyze-javascript-application /absolute/path/work/app.asar --json > app-evidence.json
  • inspect-artifact returns a content-addressed inventory of paths, sizes and SHA-256 digests, with integrity observations and suggested next probes. It does not extract anything.
  • extract-artifact writes all regular files into a fresh temporary directory chosen by REA (rea-extracted-<uuid> under your system temp directory) and reports where. It rejects path traversal and symlink escapes and never overwrites.
  • analyze-javascript-application builds the application graph (entrypoints, modules, imports, preload bridges and IPC) without running the app. The Electron guide explains how to read it.

REA checks each entry against the archive’s declared SHA-256 and fails by default when they do not match. Unpacked companions are hashed too. If a release legitimately changed unpacked files after packaging, for example by signing a native module, add --integrity-policy record-and-continue. REA then keeps the mismatches as explicitly untrusted contradictions instead of hiding them.

What to read first

Once the files are in front of you, this order answers the most questions quickly:

  1. package.json. main names the main-process entry. If it is missing, Node’s default index.js applies. name and version tell you which build you have.
  2. The main entry. Look for new BrowserWindow(...) and its webPreferences: which preload script is used, and whether contextIsolation, sandbox and nodeIntegration are set the way you expect for your app.
  3. The preload script. contextBridge.exposeInMainWorld defines exactly what the web page can call. In the sample, the page can call window.notes.list, save and onSaved, and nothing else.
  4. IPC handlers. Every ipcMain.handle or ipcMain.on channel is an input the main process accepts from the renderer. Check that each handler validates what it receives. In the sample, store.save converts the note text to a string and truncates it.
  5. Source maps and native modules. .map files in the archive can turn minified code back into source. The browser tool counts them. .node files are compiled code; analyse them with a native tool such as Ghidra (see REA with Ghidra).

If the main or preload code is minified, the browser tool’s IPC table may come out mostly empty, because it matches the literal names ipcMain, ipcRenderer and webContents. REA’s analysis works on the syntax tree instead. If the archive also ships .map files, the source map restorer can rebuild the original files, and decoding a stack trace explains how to use them for crash reports from your own app.

Repacking your own build

When you debug your own app, you may want to patch a file and try it in the packaged build:

npx @electron/asar pack out app.asar --unpack "*.node"

That works for quick local experiments. Two Electron features can block it. With the EnableEmbeddedAsarIntegrityValidation fuse on, Electron checks the archive header against a hash recorded when the app was packaged, so a repacked archive is rejected. With OnlyLoadAppFromAsar on, a loose resources/app/ folder is ignored. Both are hardening settings for your release, so do not turn them off to get a patch to run. Fix the source and rebuild with your normal packager (Electron Forge, electron-builder) instead.

FAQ

Can I unpack an ASAR file online?

Yes. The ASAR extractor runs in your browser and does not upload the archive. You can verify that in DevTools’ Network tab. For a full extraction with unpacked files, use npx @electron/asar extract.

Is app.asar encrypted?

No. The format has no encryption. Contents are stored as plain bytes, and the header is JSON. Some apps obfuscate or minify their JavaScript before packing, which is a different thing.

Why does a file show as unpacked but cannot be downloaded?

Its bytes are in app.asar.unpacked/, not in the archive. Open that folder directly.

Which tool should I use?

Use the browser tool for a quick look and the IPC overview, @electron/asar for a full extraction on disk, and REA when you want verified integrity, Evidence you can cite, and the application graph.

Next steps