Introduction to JEB Python Scripting for Android Analysis
JEB Decompiler is a powerful tool for reverse engineering and analyzing Android applications, native binaries, and more. While its interactive GUI offers a rich set of features, the true power of JEB for advanced users and security researchers often lies in its Python scripting API. This API allows for automation of repetitive tasks, large-scale analysis, and custom vulnerability detection, transforming JEB from a manual tool into a programmatic analysis platform.
This tutorial will guide you through creating your first Python script for JEB, focusing on a practical application: identifying hardcoded string literals within an Android application’s DEX files. This foundational skill is crucial for tasks like extracting API keys, URLs, or other sensitive information often embedded directly in an application’s code.
Setting Up Your JEB Scripting Environment
Before diving into code, ensure you have JEB installed and running. JEB comes with an embedded Python interpreter, so you typically don’t need to configure a separate Python environment. Scripts are executed directly within JEB’s context, giving them access to the loaded project and its associated units.
To start, simply create a .py file in your preferred text editor. A basic JEB script always extends the IScript interface and implements the run method. This method receives a JebContext object, which serves as the entry point to JEB’s API.
# my_first_script.py
from jeb.api import IScript
class MyFirstScript(IScript):
def run(self, ctx):
print('Hello from JEB! The context is ready.')
# Your analysis logic will go here
Save this file. We’ll run it later once we’ve built our full script.
Understanding JEB’s Core API Concepts
Interacting with JEB programmatically involves understanding a few core concepts:
The IRuntime Interface (JebContext)
The ctx object passed to your run method is an instance of IRuntime (or JebContext in newer versions, which extends IRuntime). It’s your gateway to the entire JEB application. Through ctx, you can access the currently loaded project, create new units, interact with the UI, and log messages.
# Example: Getting the current project
project = ctx.get_project()
if project:
print(f"Current project: {project.get_name()}")
else:
print("No project currently loaded.")
IUnit and Unit Types
In JEB, an IUnit represents a high-level component of your analyzed file. For an Android APK, common unit types include:
- DEX Units: Represent compiled Android bytecode (
.dexfiles). This is where our string analysis will focus. - APK Units: The top-level container for an Android package.
- Native Units: For shared libraries (
.sofiles) containing ARM, x86, etc., machine code. - XML Units: For AndroidManifest.xml, layouts, etc.
Each unit type has specific interfaces that expose its unique properties and methods. To work with a DEX unit, you’ll cast a generic IUnit to a Dex unit using unit.as_unit(Dex.UNIT_TYPE).
Practical Example: Locating Hardcoded Strings in a DEX Unit
Our objective is to write a script that enumerates all hardcoded string literals within an Android application’s DEX files. This is a common first step in static analysis, often revealing API keys, URLs, sensitive messages, or configuration values.
Step-by-Step Script Development
Step 1: Accessing the Current Project and DEX Units
First, we need to ensure a project is loaded and then iterate through its units to find all DEX units.
from jeb.api import IScript
from jeb.api.dex import Dex # Import the Dex unit type
class HardcodedStringFinder(IScript):
def run(self, ctx):
print("Starting Hardcoded String Finder script...")
project = ctx.get_project()
if not project:
print("No project open. Please open an Android APK first.")
return
found_strings_count = 0
# Iterate through all units in the project
for unit in project.get_units():
# Check if the unit is a DEX unit
if unit.is_a(Dex.UNIT_TYPE):
dex_unit = unit.as_unit(Dex.UNIT_TYPE)
print(f"Analyzing DEX unit: {dex_unit.get_name()}")
# ... further analysis will go here ...
print("Script finished initial scan.")
Step 2: Iterating Through Classes and Methods
Inside each DEX unit, we’ll traverse its classes, and within each class, its methods. This forms the structure of an Android application’s bytecode.
# ... (inside the if unit.is_a(Dex.UNIT_TYPE) block)
for cls in dex_unit.get_classes():
# Each class has methods
for method in cls.get_methods():
# Methods contain bytecode instructions; we need their bodies
body = method.get_body()
if body:
# Now we can iterate through instructions
# ... (next step will go here) ...
Step 3: Extracting String Literals from Instructions
Dalvik bytecode instructions that load string literals into registers are typically const-string or const-string/jumbo. We can check the instruction’s mnemonic and then retrieve the string reference.
# ... (inside the if body: block)
for insn in body.get_instructions():
# Check if it's a const-string instruction
if insn.get_mnemonic().startswith('const-string'):
# Get the string reference object
string_ref = insn.get_string_ref()
if string_ref:
string_value = string_ref.get_value()
print(f" [+] Method: {method.get_signature()} -> String: '{string_value}'")
found_strings_count += 1
Complete Hardcoded String Finder Script
Combining all steps, here is the full script:
from jeb.api import IScript
from jeb.api.dex import Dex
class HardcodedStringFinder(IScript):
def run(self, ctx):
print("Starting Hardcoded String Finder script...")
project = ctx.get_project()
if not project:
print("No project open. Please open an Android APK first.")
return
found_strings_count = 0
for unit in project.get_units():
if unit.is_a(Dex.UNIT_TYPE):
dex_unit = unit.as_unit(Dex.UNIT_TYPE)
print(f"Analyzing DEX unit: {dex_unit.get_name()}")
for cls in dex_unit.get_classes():
for method in cls.get_methods():
body = method.get_body()
if body:
for insn in body.get_instructions():
# Check for 'const-string' or 'const-string/jumbo' instructions
if insn.get_mnemonic().startswith('const-string'):
string_ref = insn.get_string_ref()
if string_ref:
string_value = string_ref.get_value()
print(f" [+] Method: {method.get_signature()} -> String: '{string_value}'")
found_strings_count += 1
print(f"Script finished. Total hardcoded strings found: {found_strings_count}")
if found_strings_count == 0:
print("No hardcoded strings detected in the current project (or no DEX units found). This may indicate obfuscation or a simple application).")
Executing Your Script in JEB
With your .py file saved, follow these steps to run it in JEB:
- Open an Android APK: In JEB, open any Android application (
File -> Open...) so there’s a project to analyze. - Access Scripting Menu: Go to
File -> Scripting -> Execute script...in the JEB menu bar. - Select Your Script: A file dialog will appear. Navigate to where you saved
HardcodedStringFinder.pyand select it. - Observe Output: JEB will execute the script. Any
print()statements from your script will appear in JEB’sLogpane, typically at the bottom of the JEB window.
You should see output similar to:
Starting Hardcoded String Finder script...
Analyzing DEX unit: com.example.app-1.dex
[+] Method: com.example.app.MainActivity->onCreate(Landroid/os/Bundle;)V -> String: 'Hello, JEB Scripting!'
[+] Method: com.example.app.network.ApiHelper->getApiKey()Ljava/lang/String; -> String: 'sk_live_YOUR_SECRET_KEY'
...
Script finished. Total hardcoded strings found: 123
Beyond Hardcoded Strings: Expanding Your Scripting Capabilities
This basic string finder is just the beginning. JEB’s Python API offers extensive capabilities for deeper analysis:
- Automating Renaming: Identify obfuscated method/class names based on analysis patterns (e.g., cross-references, known library calls) and rename them programmatically.
- Call Graph Analysis: Build or visualize call graphs for specific functions or classes to understand execution flow.
- Vulnerability Detection: Scan for common insecure coding patterns, such as insecure crypto implementations, weak random number generation, or improper handling of sensitive data.
- Data Flow Analysis: Trace the flow of data from sources (e.g., user input, sensor data) to sinks (e.g., network transmissions, file writes) to identify potential privacy leaks or injection vulnerabilities.
- Signature Matching: Implement custom YARA-like rules or other signature-based detection for malware families.
Explore the official JEB API documentation (often available via Help -> API Documentation in JEB) for a comprehensive list of classes and methods you can leverage.
Conclusion
You’ve successfully written and executed your first JEB Python script, taking a significant step towards automating and enhancing your Android application static analysis workflow. By leveraging JEB’s powerful API, you can move beyond manual inspection, develop custom analysis tools, and greatly improve your efficiency in reverse engineering tasks. The ability to programmatically interact with an application’s structure and bytecode is an invaluable skill for any serious security researcher or reverse engineer.
Android Mobile Specs & Compare Directory
Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!
Compare Devices Specs →