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
Comprehensive bytecode analysis and formatting utilities for advanced Android reverse engineering. These functions provide visualization, export, and formatting capabilities for Android bytecode analysis.
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
"""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
"""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
"""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
"""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
"""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
"""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)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")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}") # MainActivityfrom 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']}")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}")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']}")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