npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

androguard-js

v0.1.1

Published

Android file analysis library for JavaScript — DEX, ODEX, APK, binary XML, resources, Dalvik disassembler, decompiler, Frida integration

Readme

androguard-js

A JavaScript library for analyzing Android files, inspired by the Python Androguard project.

Features

  • APK parsing — list files, extract components, read signatures
  • DEX / ODEX parsing — full binary format support (strings, types, protos, fields, methods, class definitions, bytecode)
  • Android binary XML (AXML) — parse AndroidManifest.xml and any compiled XML resource
  • Android resources (ARSC) — parse resources.arsc, look up resource values by ID
  • Dalvik disassembler — complete 224-opcode instruction set with symbol resolution
  • Basic decompiler — convert Dalvik bytecode to readable pseudo-Java
  • Frida integration — attach, hook methods, bypass SSL pinning, trace network traffic
  • SQLite session — persist analysis state across runs with sql.js (no native compilation)

Installation

npm install

Optional — for live dynamic analysis with Frida:

npm install frida
# frida-server must also be running on the target Android device

sql.js is used for the session database (pure WebAssembly, no build tools required).

Quick Start

const { openAPK, openDEX, openSession, FridaHelper } = require('./src');

// ── APK ──────────────────────────────────────────────────────────────────────
const apk = openAPK('app.apk');

const info = apk.getManifestInfo();
console.log(info.packageName);      // "com.example.app"
console.log(info.permissions);      // ["android.permission.INTERNET", ...]
console.log(info.activities);       // ["com.example.MainActivity", ...]

// ── DEX ──────────────────────────────────────────────────────────────────────
const dex = apk.getDex();           // or openDEX('classes.dex')
console.log(dex.summary());         // { version, classes, methods, strings, ... }

// Find a class
const cls = dex.getClass('Lcom/example/CryptoHelper;');

// ── Disassembly ───────────────────────────────────────────────────────────────
for (const { cls, method, code } of dex.allMethods()) {
  if (!code) continue;
  console.log(`${cls.type} -> ${method.name}`);
  console.log(dex.disassembleToString(code));
  break;
}

// ── Decompiler ────────────────────────────────────────────────────────────────
const { decompileClass } = require('./src/decompiler');
console.log(decompileClass(cls, dex._data));

// ── Session ───────────────────────────────────────────────────────────────────
const session = await openSession('analysis.db');
session.setApk({ packageName: info.packageName, path: 'app.apk' });
session.importDex(dex);
session.addNote('Hardcoded AES key in CryptoHelper.encrypt()', { tag: 'crypto' });
session.save();   // flush to disk
session.close();

API Reference

openAPK(source)APK

source is a file path or Buffer.

| Method | Returns | Description | |---|---|---| | listFiles() | Array | All entries in the ZIP with name and size | | getFile(entryName) | Buffer\|null | Raw bytes of any file inside the APK | | getManifest() | { root, strings, namespaces } | Full parsed binary XML tree | | getManifestInfo() | object | Package name, version, SDK versions, permissions, activities, services, receivers, providers | | getDexFiles() | DEX[] | All classes*.dex as DEX instances | | getDex() | DEX | Primary classes.dex | | getResources() | object | Parsed resources.arsc | | lookupResource(resId) | object\|null | Look up a resource by ID (e.g. 0x7f040001) | | getSignatureFiles() | object | Raw bytes of all META-INF/*.RSA / *.DSA / *.EC files | | summary() | object | High-level summary |


openDEX(source)DEX

source is a file path or Buffer. Accepts both DEX (dex\n) and ODEX (dey\n) magic.

| Method | Returns | Description | |---|---|---| | summary() | object | Version, SHA-1, file size, counts | | getClass(descriptor) | object\|null | Find a class by descriptor e.g. "Ljava/lang/String;" | | findClasses(fragment) | Array | Case-insensitive search across all class descriptors | | allMethods() | Generator | Iterate over { cls, method, accessFlags, code } for every method | | disassemble(codeItem) | Instruction[] | Structured array: { offset, mnemonic, operands, text, raw } | | disassembleToString(codeItem) | string | Human-readable disassembly | | dumpDisassembly() | string | All classes and methods disassembled |

Direct tables (arrays on the instance): dex.strings, dex.types, dex.protos, dex.fields, dex.methods, dex.classes


parseAXML(buf){ root, strings, namespaces }

Parse any Android binary XML buffer. Each node:

{
  name: 'activity',
  ns: 'http://schemas.android.com/apk/res/android',
  attrs: { 'android:name': 'com.example.MainActivity', ... },
  children: [ ... ]
}

parseARSC(buf){ globalStrings, packages }

Parse resources.arsc. Use ARSC.lookupResource(arsc, resId) to resolve a resource ID to its value and type.


Disassembler

const { disassemble, disassembleToString } = require('./src/disassembler');

const instructions = disassemble(codeItem, dex._data);
// [
//   { offset: 0,  mnemonic: 'const-string', operands: 'v0, "Hello"', text: 'const-string v0, "Hello"' },
//   { offset: 4,  mnemonic: 'sget-object',  operands: 'v1, java.lang.System->out:java.io.PrintStream', ... },
//   { offset: 8,  mnemonic: 'invoke-virtual', ... },
//   { offset: 12, mnemonic: 'return-void', operands: '', text: 'return-void' }
// ]

Symbols (strings, types, fields, methods) are resolved automatically when dex is provided.


Decompiler

const { decompileMethod, decompileClass } = require('./src/decompiler');

// Single method
const code = decompileMethod(codeItem, methodInfo, dex._data);

// Whole class
const code = decompileClass(classInfo, dex._data);

Output is pseudo-Java. Each statement is annotated with its byte offset for cross-referencing with the disassembly.


Frida Integration

Script generation (no device required)

const { FridaHelper } = require('./src/frida');

// Hook a method and log all calls
const script = FridaHelper.generateHookScript(
  'Lcom/example/CryptoHelper;',
  'encrypt',
  { logArgs: true, logReturn: true }
);

// Bypass SSL certificate pinning
const bypass = FridaHelper.generateSslPinBypassScript();

// Trace all network calls
const netTrace = FridaHelper.generateNetworkTraceScript();

// Dump all loaded classes matching a pattern
const dump = FridaHelper.generateClassDumpScript('com.example');

Live dynamic analysis (requires frida package + frida-server on device)

const helper = new FridaHelper.FridaHelper();

// Attach to a running process
await helper.attach('com.example.app');

// Or spawn it
await helper.spawn('com.example.app');

// Hook a method
await helper.hookMethod('Lcom/example/CryptoHelper;', 'encrypt');

// Trace all methods in a class
await helper.traceClass('Lcom/example/NetworkManager;');

// Install SSL pinning bypass
await helper.bypassSslPinning();

// Run arbitrary Frida script
await helper.loadScript(myScript, msg => console.log(msg));

await helper.detach();

Session

Analysis sessions are backed by SQLite via sql.js (pure WebAssembly).

// Open (creates file if it doesn't exist)
const session = await openSession('analysis.db');

// Register the APK being analysed
session.setApk({
  path:        'app.apk',
  packageName: 'com.example.app',
  versionName: '3.1.2',
  sha1:        'abc123...',
  minSdk:      21,
  targetSdk:   33,
});

// Import all classes and methods from a DEX
session.importDex(dex, {
  saveDisasm:     false,   // store disassembly text (can be large)
  saveDecompiled: false,   // store decompiled text
});

// Permissions
session.addPermissions(info.permissions);

// Strings of interest
session.addString('AIzaSy...', 'hardcoded API key', classId);

// Analyst notes
session.addNote('Uses custom AES mode without IV', { tag: 'crypto' });
session.addNote('Sends IMEI to third-party server',  { tag: 'privacy' });

// Query
const cryptoNotes  = session.listNotes({ tag: 'crypto' });
const cryptoClass  = session.getClass('Lcom/example/CryptoHelper;');
const allMethods   = session.getMethodsForClass(cryptoClass.id);
const keyStrings   = session.searchStrings('AIza');

// Persist to disk
session.save();           // saves to the path given at open()
session.save('copy.db'); // or to an explicit path

console.log(session.stats());
// { apk: {...}, classes: 312, methods: 2847, strings: 14, permissions: 6, notes: 2 }

session.close();

Project Structure

src/
├── index.js                  Main entry point
├── utils.js                  ULEB128/SLEB128, descriptor helpers
├── apk/index.js              APK (ZIP) parser
├── axml/index.js             Android binary XML parser
├── arsc/index.js             resources.arsc parser
├── dex/
│   ├── parser.js             DEX/ODEX binary parser
│   └── index.js              DEX high-level wrapper
├── disassembler/
│   ├── opcodes.js            Full Dalvik opcode table (224 opcodes)
│   └── index.js              Instruction decoder and formatter
├── decompiler/index.js       Pseudo-code generator
├── frida/index.js            Frida helpers and script generators
└── session/index.js          SQLite session (sql.js)

examples/
└── basic.js                  Usage demo

Running the Example

node examples/basic.js app.apk          # full APK analysis
node examples/basic.js classes.dex      # DEX / ODEX only
node examples/basic.js AndroidManifest.xml  # binary XML
node examples/basic.js                  # Frida scripts + session demo only

Supported Formats

| Format | Support | |---|---| | DEX 035 / 036 / 037 / 038 / 039 | Full | | ODEX (Dalvik, dey\n) | Full (unwraps embedded DEX) | | APK | Full (ZIP + sub-parsers) | | Android Binary XML | Full | | resources.arsc | Full (simple + complex entries) | | ART/OAT ODEX | Not yet supported |

Dependencies

| Package | Purpose | |---|---| | adm-zip | APK (ZIP) extraction | | sql.js | SQLite session (pure WASM) | | frida (optional) | Live dynamic analysis |

License

MIT