Comprehensive Python toolkit for Android application reverse engineering and security analysis.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Dalvik Executable (DEX) file parsing and bytecode analysis providing access to classes, methods, instructions, and control flow structures. The DEX format contains compiled Android application code in bytecode format.
The main class for DEX file analysis and manipulation, providing comprehensive access to all DEX components including classes, methods, fields, and bytecode instructions.
class DEX:
def __init__(self, buff: bytes, decompiler=None, config=None, using_api: int = None):
"""
Initialize DEX analysis.
Parameters:
- buff: Raw DEX file bytes
- decompiler: Associated decompiler object (optional)
- config: Configuration options (optional)
- using_api: API level to use for analysis (optional)
"""
def get_classes_names(self) -> list[str]:
"""Return list of all class names in the DEX file."""
def get_classes(self) -> list:
"""Return list of all ClassDefItem objects."""
def get_class(self, name: str):
"""
Return specific class by name.
Parameters:
- name: Full class name (e.g., 'Lcom/example/MyClass;')
Returns:
ClassDefItem object or None if not found
"""
def get_methods(self) -> list:
"""Return list of all EncodedMethod objects."""
def get_fields(self) -> list:
"""Return list of all EncodedField objects."""
def get_strings(self) -> list[str]:
"""Return list of all strings in the DEX string pool."""Access class definitions and their metadata within DEX files.
def get_class_manager(self):
"""Return ClassManager for advanced class resolution."""
def get_format_type(self) -> str:
"""Return DEX format type ('DEX' or 'ODEX')."""
def get_dex_object(self, item):
"""Get object representation of DEX item."""
def save(self, filename: str) -> None:
"""
Save DEX file to disk.
Parameters:
- filename: Output file path
"""
def get_raw(self) -> bytes:
"""Return raw bytes of the entire DEX file."""
def get_length(self) -> int:
"""Return length of DEX file in bytes."""Access method definitions, signatures, and bytecode within classes.
def get_method(self, class_name: str, method_name: str, descriptor: str = None):
"""
Get specific method by class and method name.
Parameters:
- class_name: Full class name
- method_name: Method name
- descriptor: Method descriptor (optional)
Returns:
EncodedMethod object or None if not found
"""
def get_method_signature(self, method, predef_sign: str = None) -> str:
"""
Generate method signature string.
Parameters:
- method: EncodedMethod object
- predef_sign: Predefined signature format
Returns:
Method signature string
"""
def get_method_bytecode(self, method):
"""
Get bytecode instructions for method.
Parameters:
- method: EncodedMethod object
Returns:
DalvikCode object with instructions
"""Access field definitions and metadata within classes.
def get_field_signature(self, field, predef_sign: str = None) -> str:
"""
Generate field signature string.
Parameters:
- field: EncodedField object
- predef_sign: Predefined signature format
Returns:
Field signature string
"""
def get_fields_ids(self) -> list:
"""Return list of all FieldIdItem objects."""
def get_methods_ids(self) -> list:
"""Return list of all MethodIdItem objects."""
def get_types(self) -> list:
"""Return list of all TypeIdItem objects."""
def get_protos(self) -> list:
"""Return list of all ProtoIdItem objects."""Access string pools and type information within DEX files.
def get_string(self, idx: int) -> str:
"""
Get string by index from string pool.
Parameters:
- idx: String index
Returns:
String value or empty string if invalid index
"""
def get_type(self, idx: int) -> str:
"""
Get type name by index.
Parameters:
- idx: Type index
Returns:
Type name string
"""
def get_proto(self, idx: int):
"""
Get method prototype by index.
Parameters:
- idx: Prototype index
Returns:
ProtoIdItem object
"""Support for Optimized DEX (ODEX) files with additional optimization metadata.
class ODEX(DEX):
def __init__(self, buff: bytes, odex: bytes = None):
"""
Initialize ODEX analysis.
Parameters:
- buff: Raw ODEX file bytes
- odex: Additional ODEX metadata
"""
def get_optimization_data(self) -> bytes:
"""Return optimization metadata from ODEX file."""
def get_dependencies(self) -> list[str]:
"""Return list of dependency libraries."""
def is_valid_odex(self) -> bool:
"""Return True if ODEX file structure is valid."""Individual class definition and metadata access.
class ClassDefItem:
def get_class_idx(self) -> int:
"""Return class type index."""
def get_access_flags(self) -> int:
"""Return access flags bitmask."""
def get_superclass_idx(self) -> int:
"""Return superclass type index."""
def get_interfaces_off(self) -> int:
"""Return interfaces list offset."""
def get_source_file_idx(self) -> int:
"""Return source filename index."""
def get_annotations_off(self) -> int:
"""Return annotations offset."""
def get_class_data_off(self) -> int:
"""Return class data offset."""
def get_static_values_off(self) -> int:
"""Return static values offset."""
def get_name(self) -> str:
"""Return class name."""
def get_superclassname(self) -> str:
"""Return superclass name."""
def get_interfaces(self) -> list[str]:
"""Return list of implemented interface names."""
def get_methods(self) -> list:
"""Return list of all methods in class."""
def get_fields(self) -> list:
"""Return list of all fields in class."""Individual method definition and bytecode access.
class EncodedMethod:
def get_method_idx(self) -> int:
"""Return method ID index."""
def get_access_flags(self) -> int:
"""Return method access flags."""
def get_code_off(self) -> int:
"""Return code offset."""
def get_name(self) -> str:
"""Return method name."""
def get_descriptor(self) -> str:
"""Return method descriptor."""
def get_class_name(self) -> str:
"""Return containing class name."""
def get_code(self):
"""Return CodeItem with bytecode."""
def is_external(self) -> bool:
"""Return True if method is external/native."""
def is_android_api(self) -> bool:
"""Return True if method is part of Android API."""
def get_length(self) -> int:
"""Return method bytecode length."""
def pretty_show(self, m_a=None) -> str:
"""Return formatted method representation."""Individual field definition and metadata access.
class EncodedField:
def get_field_idx(self) -> int:
"""Return field ID index."""
def get_access_flags(self) -> int:
"""Return field access flags."""
def get_name(self) -> str:
"""Return field name."""
def get_descriptor(self) -> str:
"""Return field type descriptor."""
def get_class_name(self) -> str:
"""Return containing class name."""
def get_init_value(self):
"""Return field initialization value if any."""
def is_static(self) -> bool:
"""Return True if field is static."""
def pretty_show(self, f_a=None) -> str:
"""Return formatted field representation."""Access to individual Dalvik bytecode instructions and their operands.
class Instruction:
def get_name(self) -> str:
"""Return instruction mnemonic."""
def get_op_value(self) -> int:
"""Return opcode value."""
def get_literals(self) -> list:
"""Return literal values in instruction."""
def get_operands(self) -> list:
"""Return operand values."""
def get_output(self, idx: int = 0) -> str:
"""Return formatted instruction output."""
def get_length(self) -> int:
"""Return instruction length in 16-bit code units."""
class DalvikCode:
def __init__(self, class_manager, code_item):
"""
Initialize Dalvik code representation.
Parameters:
- class_manager: ClassManager instance
- code_item: CodeItem with bytecode
"""
def get_instructions(self) -> list[Instruction]:
"""Return list of all instructions."""
def get_instruction(self, idx: int) -> Instruction:
"""Get instruction at specific index."""
def get_length(self) -> int:
"""Return total code length."""
def get_registers_size(self) -> int:
"""Return number of registers used."""
def get_ins_size(self) -> int:
"""Return number of input parameters."""
def get_outs_size(self) -> int:
"""Return number of output parameters."""
def get_tries(self) -> list:
"""Return exception handling try blocks."""from androguard.core.dex import DEX
# Load DEX file
dex = DEX(open("classes.dex", "rb").read())
# Get basic information
print(f"Classes: {len(dex.get_classes())}")
print(f"Methods: {len(dex.get_methods())}")
print(f"Strings: {len(dex.get_strings())}")
# List all classes
for class_name in dex.get_classes_names():
print(f"Class: {class_name}")# Get specific class
target_class = dex.get_class("Lcom/example/MainActivity;")
if target_class:
print(f"Superclass: {target_class.get_superclassname()}")
print(f"Interfaces: {target_class.get_interfaces()}")
# Examine methods
for method in target_class.get_methods():
print(f"Method: {method.get_name()}")
print(f" Descriptor: {method.get_descriptor()}")
print(f" Access flags: {hex(method.get_access_flags())}")
# Get bytecode if available
code = method.get_code()
if code:
dalvik_code = DalvikCode(dex.get_class_manager(), code)
print(f" Instructions: {len(dalvik_code.get_instructions())}")# Find specific method and analyze bytecode
method = dex.get_method("Lcom/example/MainActivity;", "onCreate", "(Landroid/os/Bundle;)V")
if method:
code = method.get_code()
if code:
dalvik_code = DalvikCode(dex.get_class_manager(), code)
print(f"Registers: {dalvik_code.get_registers_size()}")
print(f"Instructions:")
for i, instruction in enumerate(dalvik_code.get_instructions()):
print(f" {i:04x}: {instruction.get_name()} {instruction.get_operands()}")
# Check for string literals
literals = instruction.get_literals()
if literals:
for literal in literals:
if isinstance(literal, int):
string_val = dex.get_string(literal)
if string_val:
print(f" -> '{string_val}'")# Analyze all strings in DEX
strings = dex.get_strings()
print(f"Total strings: {len(strings)}")
# Look for specific patterns
api_calls = []
for i, string in enumerate(strings):
if "android" in string.lower():
api_calls.append((i, string))
print("Potential API calls:")
for idx, call in api_calls[:10]: # Show first 10
print(f" [{idx}] {call}")
# Find methods that use specific strings
target_string = "password"
for i, string in enumerate(strings):
if target_string.lower() in string.lower():
print(f"Found '{string}' at index {i}")
# Find methods that reference this string
for method in dex.get_methods():
code = method.get_code()
if code:
dalvik_code = DalvikCode(dex.get_class_manager(), code)
for instruction in dalvik_code.get_instructions():
if i in instruction.get_literals():
print(f" Used in {method.get_class_name()}->{method.get_name()}")from androguard.core.dex import ODEX
# Load ODEX file
odex = ODEX(open("system_app.odex", "rb").read())
if odex.is_valid_odex():
print("Valid ODEX file")
print(f"Dependencies: {odex.get_dependencies()}")
# ODEX files contain the same DEX analysis capabilities
classes = odex.get_classes_names()
print(f"Classes in ODEX: {len(classes)}")def get_access_flags_string(access_flags: int, flag_type: str) -> str:
"""
Convert access flags bitmask to human-readable string.
Parameters:
- access_flags: Access flags bitmask
- flag_type: Type of flags ('class', 'method', or 'field')
Returns:
Space-separated string of flag names
"""
def clean_name_instruction(instruction_name: str) -> str:
"""
Clean and normalize instruction name.
Parameters:
- instruction_name: Raw instruction name
Returns:
Cleaned instruction name
"""
def get_type(descriptor: str) -> str:
"""
Convert type descriptor to readable type name.
Parameters:
- descriptor: Type descriptor (e.g., 'Ljava/lang/String;')
Returns:
Human-readable type name
"""
def static_operand_instruction(instruction) -> dict:
"""
Get static operand information for instruction.
Parameters:
- instruction: Instruction object
Returns:
Dictionary with operand details
"""Install with Tessl CLI
npx tessl i tessl/pypi-androguard