Skip to main content

Overview

This guide walks you through analyzing a React Native application for vulnerable dependencies using Hedis. You’ll learn how to disassemble bytecode, extract fingerprints, and match them against a reference database.
1

Get a Hermes bytecode file

You need a .hbc file from a React Native app. You can extract one from an iOS app archive (.ipa) or compile your own.

Option 1: Extract from an IPA

If you have an .ipa file, extract it and locate the bundle file:
# Extract the IPA (it's a ZIP file)
unzip MyApp.ipa -d extracted

# Find the Hermes bytecode file
find extracted -name "*.hbc" -o -name "index.ios.bundle"
The bundle file is typically in Payload/MyApp.app/.

Option 2: Compile your own

If you have a React Native project:
# Install dependencies
cd your-react-native-app
npm install

# Bundle with Metro
npx react-native bundle \
  --platform ios \
  --dev false \
  --entry-file index.js \
  --bundle-output bundle.js

# Compile with Hermes
npx hermesc -emit-binary -out bundle.hbc bundle.js
Hermes must be enabled in your React Native project. Check android/app/build.gradle or ios/Podfile for enableHermes: true.
2

Disassemble the bytecode

Use the disassemble command to convert the bytecode to human-readable output:
cd go/hermes-decompiler
./hermes-decompiler disassemble -i bundle.hbc -o disassembled.txt
This creates a text file containing:
  • Header information (Hermes version, function count)
  • Function definitions with bytecode instructions
  • String literals and object references
./hermes-decompiler disassemble \
  -i bundle.hbc \
  -o output.txt

Disassembly flags

FlagDescription
-i, --hbcInput HBC file (required)
-o, --outputOutput file path
-s, --stringsInclude string table
-f, --functionsInclude functions (default: true)
-j, --objectsInclude object definitions
-z, --function-objectsInclude function objects
-r, --function-objects-irInclude function IR representations
-n, --normalizationNormalization level (0=none, 1=IR1, 2=IR2)
3

Set up the fingerprint database

Before analyzing apps, you need to build a reference database of package fingerprints.

Generate React Native baselines

Baselines are fingerprints of empty React Native apps, used to filter out framework functions:
./hermes-decompiler maintain-database -b
This processes each React Native environment in pipeline/react-natives/ and stores framework fingerprints.

Process npm packages

Index packages from the React Native directory:
./hermes-decompiler maintain-database -p
This runs a parallel pipeline that:
  1. Installs each package in all 11 RN environments
  2. Bundles with Metro and compiles with Hermes
  3. Extracts function fingerprints
  4. Stores hashes in MongoDB
Package processing can take several hours depending on the number of packages. Progress is saved to pipeline_progress.json and can be resumed.

Update security advisories

Download GitHub Security Advisories for known vulnerabilities:
./hermes-decompiler maintain-database -s
Or download all advisories and their associated packages:
./hermes-decompiler maintain-database -g
4

Analyze an app bundle

Now you can analyze an app to identify which packages it contains.

Basic analysis

Analyze a single HBC file against the database:
./hermes-decompiler analyze -b bundle.hbc
This performs exact hash matching against the fingerprint database.

Fuzzy matching

Enable fuzzy matching to catch packages that have minor differences:
./hermes-decompiler analyze \
  -b bundle.hbc \
  -f \
  -c 0.8
The -c flag sets the confidence threshold (0.0–1.0). Higher values require closer matches.
Fuzzy matching uses Levenshtein distance with length-based pre-filtering. It’s slower but catches packages that have been minified or transformed.

Compare specific packages

Compare a specific package directly to an app bundle:
./hermes-decompiler analyze \
  -s \
  -p package.hbc \
  -a app-bundle.hbc \
  -o results.txt
This generates a detailed comparison report showing:
  • Exact hash matches (structural, IR1, IR2)
  • Fuzzy matches with confidence scores
  • Match percentages for each hash type

Analysis flags

FlagDescription
-b, --hbc-fileInput HBC file to analyze
-f, --fuzzy-matchingEnable fuzzy matching
-c, --confidence-thresholdConfidence threshold (default: 0.8)
-s, --specific-analysisCompare specific package to app
-p, --specific-packagePackage HBC file
-a, --compare-to-app-bundleApp bundle HBC file
-o, --output-fileWrite results to file
5

Interpret the results

Hedis matches functions using three hash types:

Hash types

  1. Structural Hash — SHA256 of instruction bigrams (opcode sequences)
    • Detects code structure patterns
    • Resistant to variable renaming
  2. Content IR1 Hash — SHA256 of non-identifier strings
    • Matches string literals and constants
    • Uses trigram shingling for fuzzy matching
  3. Content IR2 Hash — SHA256 of identifiers and object references
    • Matches variable and function names
    • More sensitive to minification

Understanding match percentages

  • High match (>70%) - Package is very likely present
  • Medium match (30-70%) - Partial match, possibly a different version
  • Low match (<30%) - Package may not be present, or heavily modified
Use fuzzy matching with a threshold of 0.8–0.9 for production analysis. Lower thresholds increase false positives.

Example workflow

Here’s a complete example analyzing a React Native app:
# 1. Extract bytecode from IPA
unzip MyApp.ipa -d extracted
cp extracted/Payload/MyApp.app/main.jsbundle bundle.hbc

# 2. Disassemble for inspection
./hermes-decompiler disassemble -i bundle.hbc -o disassembled.txt

# 3. Set up database (first time only)
./hermes-decompiler maintain-database -b  # Generate baselines
./hermes-decompiler maintain-database -g  # Download advisories

# 4. Analyze with fuzzy matching
./hermes-decompiler analyze \
  -b bundle.hbc \
  -f \
  -c 0.85 \
  -o analysis-results.txt

# 5. Review results
cat analysis-results.txt

Next steps

Commands reference

Explore all available commands and options

Architecture

Learn how Hedis works under the hood

Build docs developers (and LLMs) love