CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-androguard

Comprehensive Python toolkit for Android application reverse engineering and security analysis.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

bytecode-utilities.mddocs/

Bytecode Utilities

Comprehensive bytecode analysis and formatting utilities for advanced Android reverse engineering. These functions provide visualization, export, and formatting capabilities for Android bytecode analysis.

Capabilities

Method Visualization

Generate visual representations of method control flow and structure.

def method2dot(mx: MethodAnalysis, colors: dict = None) -> str:
    """
    Generate DOT graph representation of method control flow.
    
    Parameters:
    - mx: MethodAnalysis object to visualize
    - colors: Optional color mapping dictionary for nodes
    
    Returns:
        str: DOT format graph representation
    """

def method2format(filename: str, format: str, mx: MethodAnalysis, colors: dict = None) -> None:
    """
    Export method visualization to various formats.
    
    Parameters:
    - filename: Output file name
    - format: Output format ('png', 'svg', 'pdf', 'dot')
    - mx: MethodAnalysis object to export
    - colors: Optional color mapping for visualization
    """

def method2png(filename: str, mx: MethodAnalysis, colors: dict = None) -> None:
    """
    Export method control flow as PNG image.
    
    Parameters:
    - filename: Output PNG file name
    - mx: MethodAnalysis object to export
    - colors: Optional color mapping for nodes
    """

JSON Export

Convert bytecode analysis results to structured JSON format.

def method2json(mx: MethodAnalysis, colors: dict = None) -> str:
    """
    Convert method analysis to JSON representation.
    
    Parameters:
    - mx: MethodAnalysis object to convert
    - colors: Optional color information to include
    
    Returns:
        str: JSON representation of method analysis
    """

def class2json(cx: ClassAnalysis) -> str:
    """
    Convert class analysis to JSON representation.
    
    Parameters:
    - cx: ClassAnalysis object to convert
    
    Returns:
        str: JSON representation of class analysis
    """

def analysis2json(dx: Analysis) -> str:
    """
    Convert complete analysis to JSON representation.
    
    Parameters:
    - dx: Analysis object to convert
    
    Returns:
        str: JSON representation of complete analysis
    """

Class Name Formatting

Format Android class names for different target languages and conventions.

def FormatClassToJava(class_name: str) -> str:
    """
    Format Android class name to Java-style notation.
    
    Parameters:
    - class_name: Android internal class name (e.g., 'Lcom/example/App;')
    
    Returns:
        str: Java-style class name (e.g., 'com.example.App')
    """

def FormatClassToPython(class_name: str) -> str:
    """
    Format Android class name to Python-style notation.
    
    Parameters:
    - class_name: Android internal class name
    
    Returns:
        str: Python-style class name with underscores
    """

def FormatClassToSmali(class_name: str) -> str:
    """
    Format class name to Smali notation.
    
    Parameters:
    - class_name: Input class name
    
    Returns:
        str: Smali-format class name
    """

Package and Class Analysis

Utilities for analyzing package structures and class relationships.

def get_package_class_name(class_name: str) -> tuple[str, str]:
    """
    Extract package and class name from full class name.
    
    Parameters:
    - class_name: Full Android class name
    
    Returns:
        tuple: (package_name, simple_class_name)
    """

def split_package_class(full_name: str) -> dict:
    """
    Split full class name into components.
    
    Parameters:
    - full_name: Full class name to analyze
    
    Returns:
        dict: Dictionary with 'package', 'class', and 'inner_classes' keys
    """

def get_class_hierarchy(cx: ClassAnalysis) -> list[str]:
    """
    Get inheritance hierarchy for a class.
    
    Parameters:
    - cx: ClassAnalysis object
    
    Returns:
        list: List of parent class names in hierarchy order
    """

Bytecode Statistics

Generate statistical information about bytecode structure and complexity.

def get_method_complexity(mx: MethodAnalysis) -> dict:
    """
    Calculate complexity metrics for a method.
    
    Parameters:
    - mx: MethodAnalysis object
    
    Returns:
        dict: Complexity metrics including cyclomatic complexity, instruction count, etc.
    """

def get_class_statistics(cx: ClassAnalysis) -> dict:
    """
    Generate statistics for a class.
    
    Parameters:
    - cx: ClassAnalysis object
    
    Returns:
        dict: Class statistics including method count, field count, complexity metrics
    """

def get_package_metrics(dx: Analysis, package_name: str) -> dict:
    """
    Calculate metrics for an entire package.
    
    Parameters:
    - dx: Analysis object
    - package_name: Target package name
    
    Returns:
        dict: Package-level metrics and statistics
    """

Control Flow Utilities

Advanced control flow analysis and manipulation utilities.

def get_basic_blocks(mx: MethodAnalysis) -> list:
    """
    Extract basic blocks from method analysis.
    
    Parameters:
    - mx: MethodAnalysis object
    
    Returns:
        list: List of basic block objects
    """

def analyze_control_flow(mx: MethodAnalysis) -> dict:
    """
    Perform detailed control flow analysis.
    
    Parameters:
    - mx: MethodAnalysis object
    
    Returns:
        dict: Control flow analysis results
    """

def detect_patterns(mx: MethodAnalysis) -> list[str]:
    """
    Detect common code patterns in method.
    
    Parameters:
    - mx: MethodAnalysis object
    
    Returns:
        list: List of detected pattern names
    """

Usage Examples

Method Visualization

from androguard.core.bytecode import method2dot, method2png, method2format
from androguard.misc import AnalyzeAPK

# Analyze APK
a, d, dx = AnalyzeAPK("app.apk")

# Find a specific method
target_method = None
for cls in dx.get_classes():
    for method in cls.get_methods():
        if method.name == "onCreate":
            target_method = method
            break
    if target_method:
        break

if target_method:
    # Generate DOT graph
    dot_graph = method2dot(target_method)
    print("DOT Graph:")
    print(dot_graph)
    
    # Export as PNG
    method2png("onCreate_flow.png", target_method)
    
    # Export in multiple formats
    method2format("onCreate_flow", "svg", target_method)
    method2format("onCreate_flow", "pdf", target_method)

JSON Export and Analysis

from androguard.core.bytecode import method2json, class2json, analysis2json
import json

# Convert method to JSON
if target_method:
    method_json = method2json(target_method)
    method_data = json.loads(method_json)
    
    print("Method Analysis JSON:")
    print(json.dumps(method_data, indent=2))

# Convert entire class to JSON
target_class = target_method.get_class_analysis() if target_method else None
if target_class:
    class_json = class2json(target_class)
    class_data = json.loads(class_json)
    
    print(f"Class '{target_class.name}' has {len(class_data['methods'])} methods")

# Export complete analysis
full_analysis = analysis2json(dx)
print(f"Full analysis size: {len(full_analysis)} characters")

Class Name Formatting

from androguard.core.bytecode import FormatClassToJava, FormatClassToPython, get_package_class_name

# Format class names
internal_name = "Lcom/example/myapp/MainActivity;"
java_name = FormatClassToJava(internal_name)
python_name = FormatClassToPython(internal_name)

print(f"Internal: {internal_name}")
print(f"Java: {java_name}")        # com.example.myapp.MainActivity
print(f"Python: {python_name}")    # com_example_myapp_MainActivity

# Extract package and class
package, class_name = get_package_class_name(internal_name)
print(f"Package: {package}")       # com.example.myapp
print(f"Class: {class_name}")      # MainActivity

Bytecode Statistics

from androguard.core.bytecode import get_method_complexity, get_class_statistics, get_package_metrics

# Method complexity analysis
if target_method:
    complexity = get_method_complexity(target_method)
    print("Method Complexity:")
    print(f"  Cyclomatic complexity: {complexity['cyclomatic']}")
    print(f"  Instruction count: {complexity['instructions']}")
    print(f"  Basic blocks: {complexity['basic_blocks']}")
    print(f"  Branch points: {complexity['branches']}")

# Class statistics
if target_class:
    stats = get_class_statistics(target_class)
    print("Class Statistics:")
    print(f"  Methods: {stats['method_count']}")
    print(f"  Fields: {stats['field_count']}")
    print(f"  Inner classes: {stats['inner_classes']}")
    print(f"  Average method complexity: {stats['avg_complexity']}")

# Package-level metrics
package_metrics = get_package_metrics(dx, "com.example.myapp")
print("Package Metrics:")
print(f"  Total classes: {package_metrics['class_count']}")
print(f"  Total methods: {package_metrics['method_count']}")
print(f"  Package complexity: {package_metrics['total_complexity']}")

Control Flow Analysis

from androguard.core.bytecode import get_basic_blocks, analyze_control_flow, detect_patterns

if target_method:
    # Get basic blocks
    blocks = get_basic_blocks(target_method)
    print(f"Method has {len(blocks)} basic blocks")
    
    # Detailed control flow analysis
    flow_analysis = analyze_control_flow(target_method)
    print("Control Flow Analysis:")
    print(f"  Entry points: {flow_analysis['entry_points']}")
    print(f"  Exit points: {flow_analysis['exit_points']}")
    print(f"  Loops detected: {flow_analysis['loop_count']}")
    print(f"  Conditional branches: {flow_analysis['conditional_branches']}")
    
    # Pattern detection
    patterns = detect_patterns(target_method)
    if patterns:
        print("Detected Patterns:")
        for pattern in patterns:
            print(f"  - {pattern}")

Batch Analysis

from androguard.core.bytecode import method2format, get_method_complexity
import os

# Create output directory
os.makedirs("analysis_output", exist_ok=True)

# Analyze all methods in a class
complexity_report = []
for method in target_class.get_methods() if target_class else []:
    # Export visualization
    safe_name = method.name.replace('<', '').replace('>', '').replace('/', '_')
    output_file = f"analysis_output/{safe_name}"
    
    try:
        method2format(output_file, "png", method)
        
        # Collect complexity data
        complexity = get_method_complexity(method)
        complexity_report.append({
            'method': method.name,
            'complexity': complexity['cyclomatic'],
            'instructions': complexity['instructions']
        })
    except Exception as e:
        print(f"Error analyzing {method.name}: {e}")

# Sort by complexity
complexity_report.sort(key=lambda x: x['complexity'], reverse=True)

print("Top 5 most complex methods:")
for item in complexity_report[:5]:
    print(f"  {item['method']}: complexity={item['complexity']}, instructions={item['instructions']}")

Integration with Other Modules

Combined with Static Analysis

from androguard.core.bytecode import method2json, get_method_complexity
from androguard.core.analysis.analysis import MethodAnalysis
import json

# Find methods with high complexity that call cryptographic APIs
crypto_apis = ["javax.crypto", "java.security", "android.security"]
complex_crypto_methods = []

for cls in dx.get_classes():
    for method in cls.get_methods():
        # Check complexity
        complexity = get_method_complexity(method)
        if complexity['cyclomatic'] > 10:  # High complexity threshold
            
            # Check for crypto API usage
            method_json = method2json(method)
            method_data = json.loads(method_json)
            
            calls_crypto = any(
                any(crypto_api in call.get('target', '') for crypto_api in crypto_apis)
                for call in method_data.get('external_calls', [])
            )
            
            if calls_crypto:
                complex_crypto_methods.append({
                    'class': cls.name,
                    'method': method.name,
                    'complexity': complexity['cyclomatic']
                })

print("Complex methods using cryptographic APIs:")
for method_info in sorted(complex_crypto_methods, key=lambda x: x['complexity'], reverse=True):
    print(f"  {method_info['class']}.{method_info['method']} (complexity: {method_info['complexity']})")

Install with Tessl CLI

npx tessl i tessl/pypi-androguard

docs

apk-processing.md

bytecode-utilities.md

cli-tools.md

decompilation.md

dex-analysis.md

dynamic-analysis.md

index.md

session-management.md

static-analysis.md

utility-functions.md

xml-resources.md

tile.json