Skip to content

Latest commit

 

History

History
252 lines (181 loc) · 7.49 KB

README.md

File metadata and controls

252 lines (181 loc) · 7.49 KB

pkg unpacker

Unpack any pkg application.

Keep in mind that this tool doesn't give you the full source code if the application was compiled into V8 bytecode. See How it works.

Table of Contents

Support

As of this writing, pkg-unpacker supports the following tools:

Tool Supported Versions Comment
vercel/pkg ✅ 5.0.0 - 5.8.1 N/A
yao-pkg/pkg ✅ 5.0.0 - 6.23.0 Does not include experimental support for Node SEA .
AngaBlue/exe ❌ - N/A
nexe/nexe ❌ - Different bundle format, not pkg snapshots.
leafac/caxa ❌ - Different layout, unmaintained since 2023.
bun compile ❌ - Own bundle format, not pkg snapshots.
Node.js SEA ❌ - Official blob format, not pkg snapshots.

Installation

  1. Install Bun.
  2. Download or clone the project.
  3. Navigate to the project directory.
  4. Install the dependencies:
    bun install
  5. (Optional) Verify the project:
    bun run typecheck
    bun test
  6. (Optional) Build the project:
    bun run build
    Or compile to a single executable:
    bun run compile

Without cloning, add it from GitHub, then use the linked binary.

With Bun:

bun add github:LockBlock-dev/pkg-unpacker
./node_modules/.bin/pkg-unpacker -i ./pkg_app -o ./unpacked

Or in one shot:

bunx github:LockBlock-dev/pkg-unpacker -i ./pkg_app -o ./unpacked

With pnpm:

pnpm add github:LockBlock-dev/pkg-unpacker
./node_modules/.bin/pkg-unpacker -i ./pkg_app -o ./unpacked

Or in one shot:

pnpm dlx github:LockBlock-dev/pkg-unpacker -i ./pkg_app -o ./unpacked

With npm (git fetches need allowing):

NPM_CONFIG_ALLOW_GIT=all npm install github:LockBlock-dev/pkg-unpacker
./node_modules/.bin/pkg-unpacker -i ./pkg_app -o ./unpacked

Usage

As a command line interface

To start the application, run:

bun run start -- -i ./pkg_app -o ./unpacked

Or run the source directly:

bun src/main.ts -i ./pkg_app -o ./unpacked

Node.js compatibility

The src/ code (excluding tests, which are Bun-only via bun:test) also runs on Node.js. Relative imports use .js extensions so both runtimes resolve them.

npm run build:node   # or: bun run build:node  -> emits to dist-node/
node dist-node/main.js -i ./pkg_app -o ./unpacked

As a library on Node.js:

import Unpacker from "pkg-unpacker/unpacker";

--run executes the entrypoint: refused under Bun (V8 bytecode can't run on JavaScriptCore), and on Node.js it requires the host version to match the binary's target, otherwise it fails with an explicit version error.

Here’s an overview of the help command output:

Usage: pkg-unpacker [options]

Options:
  -V, --version          output the version number
  -i, --input <file>     Specify the input binary file path
  -o, --output <folder>  Specify the output folder path (default: ".")
  --run                  Run the unpacked binary (default: false)
  --json                 Output the unpack result as JSON (default: false)
  -h, --help             display help for command

Examples:

  • Unpack a UNIX application:
$ bun run start -- -i ./pkg_app -o ./unpacked
  • Unpack a Windows application:
$ bun run start -- -i ./pkg_app.exe -o ./unpacked
  • Unpack a UNIX application and run it:
$ bun run start -- -i ./pkg_app -o ./unpacked --run

As a library

The main logic of pkg unpacker lies in the Unpacker class.

Examples:

  • Unpack a UNIX application:
import Unpacker from "./src/unpacker.ts";

const main = async () => {
    const unpacker = await Unpacker.create("./pkg_app");
    await unpacker.unpack("./unpacked");
};

main();
  • Unpack a Windows application and run it:
import Unpacker from "./src/unpacker.ts";

const main = async () => {
    const unpacker = await Unpacker.create("./pkg_app.exe");
    await unpacker.unpack("./unpacked", true);
};

main();

With REA

Feed the output directory to REA for analysis:

bun run start -- -i ./pkg_app -o ./unpacked --json > result.json
npx -y rea-agents@latest analyze-javascript-application /absolute/path/to/unpacked --json

Features

  • Detects compression formats (Gzip, Brotli, Zstd)
  • Supports code evaluation
  • Handles symlinks
  • Extracts binaries from all operating systems

How it works

This application does not decompile code. By default, pkg compiles JavaScript into V8 bytecode. Extracted files will remain in this format, except for assets.

Code evaluation works best with small applications as dependencies might be broken.

pkg stores metadata about file names, paths, offsets, lengths, and compression at the end of each binary. This application analyzes those fields to extract and decompress (if necessary) all embedded files.

Examples:

// UNIX app

{"/snapshot/pkg/index.js":{"0":[0,568],"3":[568,118]},"/snapshot/pkg":{"2":[686,12],"3":[698,117]},"/snapshot":{"2":[815,7],"3":[822,117]}} // virtual file system
,
"/snapshot/pkg/index.js" // entrypoint
,
{} // symlinks
,
{} // files dictionnary
,
0 // 0: no compression, 1: Gzip, 2: Brotli, 3: Zstd
// Windows app

{"C:\\snapshot\\pkg\\index.js":{"0":[0,568],"3":[568,118]},"C:\\snapshot\\pkg":{"2":[686,12],"3":[698,117]},"C:\\snapshot":{"2":[815,7],"3":[822,117]}} // virtual file system
,
"C:\\snapshot\\pkg\\index.js" // entrypoint
,
{} // symlinks
,
{} // files dictionnary
,
0 // 0: no compression, 1: Gzip, 2: Brotli, 3: Zstd

Credits

pkg

Copyright

See the license.