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

xml-resources.mddocs/

XML and Resources

Binary Android XML (AXML) and Android Resource (ARSC) file processing for accessing application resources, layouts, configuration data, and string resources. Android applications store XML files in a binary format for efficiency.

Capabilities

AXML Parser

Binary XML parser for converting Android's binary XML format back to standard XML.

class AXMLPrinter:
    def __init__(self, raw_buff: bytes):
        """
        Initialize AXML parser.
        
        Parameters:
        - raw_buff: Raw AXML file bytes
        """

def get_xml(self, pretty: bool = True) -> bytes:
    """
    Convert AXML to XML format.
    
    Parameters:
    - pretty: Format XML with indentation
    
    Returns:
    XML content as bytes
    """

def is_valid(self) -> bool:
    """Return True if AXML structure is valid."""

def get_xml_obj(self):
    """Return parsed XML as ElementTree object."""

def get_buff(self) -> bytes:
    """Return original AXML buffer."""

AXML Parser Engine

Low-level AXML parsing functionality for detailed binary XML analysis.

class AXMLParser:
    def __init__(self, raw_buff: bytes):
        """
        Initialize low-level AXML parser.
        
        Parameters:
        - raw_buff: Raw AXML file bytes
        """

def next(self) -> int:
    """
    Advance to next XML event.
    
    Returns:
    Event type constant (START_DOCUMENT, START_TAG, etc.)
    """

def get_name(self) -> str:
    """Return name of current XML element."""

def get_text(self) -> str:
    """Return text content of current element."""

def get_attribute_count(self) -> int:
    """Return number of attributes for current element."""

def get_attribute_name(self, i: int) -> str:
    """
    Get attribute name by index.
    
    Parameters:
    - i: Attribute index
    
    Returns:
    Attribute name string
    """

def get_attribute_value(self, i: int) -> str:
    """
    Get attribute value by index.
    
    Parameters:
    - i: Attribute index
    
    Returns:
    Attribute value string
    """

def get_attribute_namespace(self, i: int) -> str:
    """Get attribute namespace by index."""

def get_attribute_resource_id(self, i: int) -> int:
    """Get attribute resource ID by index."""

String Block Access

Access to AXML string pools and string resolution.

class StringBlock:
    def __init__(self, buff: bytes, header: object):
        """
        Initialize string block parser.
        
        Parameters:
        - buff: String block bytes
        - header: AXML header information
        """

def get_string(self, idx: int) -> str:
    """
    Get string by index from string pool.
    
    Parameters:
    - idx: String index
    
    Returns:
    String value or None if invalid
    """

def get_strings_size(self) -> int:
    """Return total number of strings in pool."""

def show(self) -> None:
    """Display string block information."""

Resource Parser (ARSC)

Android Resource (ARSC) file parser for accessing application resources and configurations.

class ARSCParser:
    def __init__(self, raw_buff: bytes):
        """
        Initialize ARSC parser.
        
        Parameters:
        - raw_buff: Raw ARSC file bytes
        """

def get_packages_names(self) -> list[str]:
    """Return list of all package names in resources."""

def get_string_resources(self, package_name: str, locale: str = '\x00\x00') -> dict[str, str]:
    """
    Get string resources for package and locale.
    
    Parameters:
    - package_name: Target package name
    - locale: Locale code (default is default locale)
    
    Returns:
    Dictionary mapping resource names to string values
    """

def get_id(self, package_name: str, ttype: int, name: str) -> int:
    """
    Get resource ID for named resource.
    
    Parameters:
    - package_name: Package name
    - ttype: Resource type ID
    - name: Resource name
    
    Returns:
    Resource ID or None if not found
    """

def get_public_resources(self, package_name: str, ttype: int = None) -> dict:
    """
    Get public resources for package.
    
    Parameters:
    - package_name: Package name
    - ttype: Optional resource type filter
    
    Returns:
    Dictionary of public resource mappings
    """

def get_type_configs(self, package_name: str, type_name: str) -> list:
    """
    Get configurations for resource type.
    
    Parameters:
    - package_name: Package name  
    - type_name: Resource type name
    
    Returns:
    List of configuration objects
    """

Resource Resolution

Resolve resource references and values with configuration support.

class ResourceResolver:
    def __init__(self, android_resources: ARSCParser, config: object = None):
        """
        Initialize resource resolver.
        
        Parameters:
        - android_resources: ARSCParser instance
        - config: Configuration for resolution
        """

def resolve(self, res_id: int) -> tuple:
    """
    Resolve resource ID to value and configuration.
    
    Parameters:
    - res_id: Resource identifier
    
    Returns:
    Tuple of (resource_value, configuration)
    """

def get_string(self, res_id: int) -> str:
    """
    Resolve resource ID to string value.
    
    Parameters:
    - res_id: String resource ID
    
    Returns:
    String value or None if not found
    """

def get_resolved_res_configs(self, res_id: int, config: object = None) -> list:
    """Get all resolved configurations for resource."""

Resource Table Components

Low-level access to resource table structure and metadata.

class ARSCResTablePackage:
    def get_name(self) -> str:
        """Return package name."""
    
    def get_id(self) -> int:
        """Return package ID."""
    
    def get_type_strings(self) -> StringBlock:
        """Return type names string block."""
    
    def get_key_strings(self) -> StringBlock:
        """Return key names string block."""

class ARSCResType:
    def get_package_name(self) -> str:
        """Return containing package name."""
    
    def get_type(self) -> str:
        """Return resource type name."""
    
    def get_config(self) -> object:
        """Return configuration object."""
    
    def get_entries(self) -> dict:
        """Return dictionary of entry ID to entry object mappings."""

class ARSCResTableEntry:
    def get_index(self) -> int:
        """Return entry index."""
    
    def get_key(self) -> str:
        """Return resource key name."""
    
    def get_value(self):
        """Return resource value."""
    
    def is_public(self) -> bool:
        """Return True if resource is public."""
    
    def is_complex(self) -> bool:
        """Return True if entry is complex type."""

Configuration Objects

Resource configuration handling for different device configurations.

class ARSCResTableConfig:
    def get_language(self) -> str:
        """Return language code."""
    
    def get_country(self) -> str:
        """Return country code."""
    
    def get_density(self) -> int:
        """Return screen density."""
    
    def get_orientation(self) -> int:
        """Return screen orientation."""
    
    def get_screen_size(self) -> int:
        """Return screen size category."""
    
    def get_keyboard(self) -> int:
        """Return keyboard type."""
    
    def get_qualifier(self) -> str:
        """Return full configuration qualifier string."""
    
    def match(self, config) -> bool:
        """Check if this config matches another config."""

Usage Examples

Basic AXML Processing

from androguard.core.axml import AXMLPrinter

# Read AXML file
with open("AndroidManifest.xml", "rb") as f:
    axml_data = f.read()

# Parse AXML
axml = AXMLPrinter(axml_data)

if axml.is_valid():
    # Convert to readable XML
    xml_content = axml.get_xml(pretty=True)
    print(xml_content.decode('utf-8'))
    
    # Save as regular XML file
    with open("AndroidManifest_readable.xml", "wb") as f:
        f.write(xml_content)
else:
    print("Invalid AXML file")

Resource Extraction

from androguard.core.axml import ARSCParser

# Load resources.arsc
with open("resources.arsc", "rb") as f:
    arsc_data = f.read()

arsc = ARSCParser(arsc_data)

# Get all packages
packages = arsc.get_packages_names()
print(f"Packages: {packages}")

for package in packages:
    print(f"\nPackage: {package}")
    
    # Get string resources
    strings = arsc.get_string_resources(package)
    print(f"String resources: {len(strings)}")
    
    for name, value in list(strings.items())[:10]:  # Show first 10
        print(f"  {name}: {value}")
    
    # Get public resources
    public_resources = arsc.get_public_resources(package)
    print(f"Public resources: {len(public_resources)}")

Configuration-Specific Resources

# Get resources for different configurations
package_name = "com.example.app"

# Get all type configurations
string_configs = arsc.get_type_configs(package_name, "string")
print(f"String configurations: {len(string_configs)}")

for config in string_configs:
    print(f"Configuration: {config.get_qualifier()}")
    print(f"  Language: {config.get_language()}")
    print(f"  Country: {config.get_country()}")
    print(f"  Density: {config.get_density()}")

# Get strings for specific locale
french_strings = arsc.get_string_resources(package_name, "fr")
if french_strings:
    print("French strings:")
    for name, value in list(french_strings.items())[:5]:
        print(f"  {name}: {value}")

Resource Resolution

from androguard.core.axml import ARSCParser

# Create resolver
resolver = arsc.ResourceResolver(arsc)

# Resolve specific resource IDs
resource_ids = [0x7f040001, 0x7f050002, 0x7f060003]

for res_id in resource_ids:
    try:
        value, config = resolver.resolve(res_id)
        print(f"Resource 0x{res_id:08x}:")
        print(f"  Value: {value}")
        print(f"  Config: {config.get_qualifier() if config else 'default'}")
    except Exception as e:
        print(f"Failed to resolve 0x{res_id:08x}: {e}")

# Resolve string resources
app_name_id = arsc.get_id(package_name, 0x03, "app_name")  # 0x03 = string type
if app_name_id:
    app_name = resolver.get_string(app_name_id)
    print(f"App name: {app_name}")

Advanced AXML Parsing

from androguard.core.axml import AXMLParser

# Low-level AXML parsing
parser = AXMLParser(axml_data)

# Parse events manually
while True:
    event = parser.next()
    
    if event == axml.START_DOCUMENT:
        print("Document started")
    elif event == axml.START_TAG:
        name = parser.get_name()
        print(f"Start tag: {name}")
        
        # Process attributes
        attr_count = parser.get_attribute_count()
        for i in range(attr_count):
            attr_name = parser.get_attribute_name(i)
            attr_value = parser.get_attribute_value(i)
            attr_ns = parser.get_attribute_namespace(i)
            
            if attr_ns:
                print(f"  {attr_ns}:{attr_name}={attr_value}")
            else:
                print(f"  {attr_name}={attr_value}")
    
    elif event == axml.END_TAG:
        name = parser.get_name()
        print(f"End tag: {name}")
        
    elif event == axml.TEXT:
        text = parser.get_text()
        if text.strip():
            print(f"Text: {text}")
            
    elif event == axml.END_DOCUMENT:
        print("Document ended")
        break

Resource Type Analysis

# Analyze different resource types
for package in packages:
    print(f"\nAnalyzing package: {package}")
    
    # Get all resource types
    public_resources = arsc.get_public_resources(package)
    
    # Group by type
    by_type = {}
    for res_id, (res_type, res_name) in public_resources.items():
        if res_type not in by_type:
            by_type[res_type] = []
        by_type[res_type].append((res_id, res_name))
    
    # Display statistics
    for res_type, resources in by_type.items():
        print(f"  {res_type}: {len(resources)} resources")
        
        # Show a few examples
        for res_id, res_name in resources[:3]:
            print(f"    0x{res_id:08x}: {res_name}")

Utility Functions

def format_value(value_type: int, value_data: int, string_block: StringBlock = None) -> str:
    """
    Format resource value based on its type.
    
    Parameters:
    - value_type: Resource value type constant
    - value_data: Raw value data
    - string_block: String block for string resolution
    
    Returns:
    Formatted value string
    """

def complexToFloat(xcomplex: int) -> float:
    """
    Convert complex unit value to float.
    
    Parameters:
    - xcomplex: Complex unit value
    
    Returns:
    Float representation
    """

def get_arsc_info(arsc_file: str) -> dict:
    """
    Get formatted ARSC file information.
    
    Parameters:
    - arsc_file: Path to ARSC file
    
    Returns:
    Dictionary with ARSC analysis results
    """

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