Android binary XML (AXML) and resource (ARSC) parser in pure Rust, with optional Python bindings (PyO3). Port of androguard/axml.
- AXML — decode binary
AndroidManifest.xml(and other compiled XML) to text, with package / version / permissions - ARSC — parse
resources.arsc, resolve resource IDs to Java names and string values - CLI —
axmlandarscbinaries - Python — same API via
pip install/maturin develop
cargo add axml-parserRequires a Rust toolchain and Python ≥ 3.9.
python3 -m venv .venv && source .venv/bin/activate
pip install maturin
maturin develop --features pythonOr build a wheel:
maturin build --release --features python
pip install target/wheels/axml_parser-*.whl# Decode binary AndroidManifest.xml
cargo run --bin axml -- -i tests/AXML/AndroidManifest.xml
# With metadata (real output from tests/AXML/AndroidManifest-Chinese.xml)
cargo run --bin axml -- -i tests/AXML/AndroidManifest-Chinese.xml -v
# Valid: true
# Package: com.hotel
# Version: {"Name": "1.7.2", "Code": "8"}
# Permissions: ["android.permission.WAKE_LOCK", "android.permission.INTERNET", ...]
cargo run --bin arsc -- -i tests/ARSC/TestActivity_resources.arsc -v
# Packages: ["tests.androguard"]Using the fixtures under tests/:
use axml_parser::{ARSCParser, AXMLPrinter};
fn main() {
// --- AXML: AndroidManifest.xml ---
let data = std::fs::read("tests/AXML/AndroidManifest-Chinese.xml").unwrap();
let ap = AXMLPrinter::new(&data);
assert!(ap.is_valid());
assert_eq!(ap.package(), "com.hotel");
assert_eq!(ap.androidversion().get("Code").map(String::as_str), Some("8"));
assert_eq!(ap.androidversion().get("Name").map(String::as_str), Some("1.7.2"));
// permissions include INTERNET, SEND_SMS, ACCESS_FINE_LOCATION, ...
let xml = String::from_utf8_lossy(&ap.get_xml(true));
assert!(xml.contains(r#"package="com.hotel""#));
// --- ARSC: resources.arsc ---
let arsc_data = std::fs::read("tests/ARSC/TestActivity_resources.arsc").unwrap();
let arsc = ARSCParser::new(&arsc_data).unwrap();
assert_eq!(arsc.get_packages_names(), vec!["tests.androguard".to_string()]);
assert_eq!(arsc.resolve_id(0x7F040001).as_deref(), Some("R.string.app_name"));
assert_eq!(
arsc.id_to_string_value().get(&0x7F040001).map(String::as_str),
Some("TestsAndroguardApplication")
);
assert_eq!(
arsc.id_to_string_value().get(&0x7F040000).map(String::as_str),
Some("Hello World, TestActivity! kikoololmodif")
);
let (res_id, pkg) = ARSCParser::parse_id("@7F040001").unwrap();
assert_eq!(res_id, 0x7F040001);
assert!(pkg.is_none());
}Run the ARSC dump example:
cargo run --example arsc_dump
# packages: ["tests.androguard"]
# 0x7F040001 -> R.string.app_name
# 0x7F040001 = "TestsAndroguardApplication"
# resolve 0x7F040001: Some("R.string.app_name")After maturin develop --features python:
from axml_parser import AXMLPrinter, ARSCParser, decode_axml
# --- AXML ---
ap = AXMLPrinter.from_file("tests/AXML/AndroidManifest-Chinese.xml")
assert ap.is_valid() is True
assert ap.package == "com.hotel"
assert ap.androidversion == {"Code": "8", "Name": "1.7.2"}
assert "android.permission.INTERNET" in ap.permissions
print(ap.get_xml()[:80])
# <?xml version="1.0" encoding="UTF-8"?><manifest xmlns:android="http://schemas...
xml, meta = decode_axml("tests/AXML/AndroidManifest.xml")
assert meta["package"] == "org.t0t0.androguard.TC"
# --- ARSC ---
arsc = ARSCParser.from_file("tests/ARSC/TestActivity_resources.arsc")
assert arsc.get_packages_names() == ["tests.androguard"]
assert arsc.resolve_id(0x7F040001) == "R.string.app_name"
assert arsc.id_to_string_value()[0x7F040001] == "TestsAndroguardApplication"
assert arsc.id_to_string_value()[0x7F040000] == "Hello World, TestActivity! kikoololmodif"
assert ARSCParser.parse_id("@7F040001") == (0x7F040001, None)| Symbol | Role |
|---|---|
AXMLPrinter(bytes) / .from_file(path) |
Decode binary XML |
.package, .androidversion, .permissions |
Manifest metadata |
.get_xml(pretty=True) |
Decoded XML string |
ARSCParser(bytes) / .from_file(path) |
Parse resources.arsc |
.resolve_id(id), .id_to_string_value() |
Resource lookup |
ARSCParser.parse_id("@…") |
Parse @DEADBEEF / @pkg:DEADBEEF |
decode_axml(path) |
Convenience → (xml, meta_dict) |
encode_xml(xml_bytes) |
Encode plain XML → binary AXML |
cargo testPython smoke check (with venv + maturin install):
python -c "from axml_parser import AXMLPrinter; print(AXMLPrinter.from_file('tests/AXML/AndroidManifest.xml').package)"
# org.t0t0.androguard.TCApache-2.0 (same as androguard/axml).