Welcome to Pyaxml’s documentation 0.1.0!
PyAxml is a full python tool to play with AXML (Android XML) files. This tool is useful to decode and encode AXML files and manipulate AXML files over a Protocol Buffers object. It is designed to work with Python 3 and Rust only.
Some examples of the use of the tool is provided with the project:
copymanifest.py that allow to decode and reencode the original file
replace_activity_name.py to change the name an activity and replace by an other
If you want to see more example you can dig more on the project apkpatcher that use this library to add some useful permission and inject a library inside the target application. To have a better understanding about how is composed the AXML format a graphic is associated in drawio and svg format: format.drawio, format.drawio.svg
The link of the project https://gitlab.com/MadSquirrels/mobile/pyaxml
QuickStart
To get you started, here is a detailed example of how to replace an activity in an Android AXML file using Python. This script utilizes the pyaxml library to handle the AXML format.
import pyaxml
import click
@click.command()
@click.argument('input_file')
@click.argument('output_file')
@click.argument('activity_name')
@click.argument('new_activity_name')
def replace_activity(input_file, output_file, activity_name, new_activity_name):
filename = input_file
with open(filename, "rb") as f:
axml = pyaxml.AXML.from_axml(f.read())
xml = axml.to_xml()
android_name = "{http://schemas.android.com/apk/res/android}name"
for activity in xml.findall(f"./application/activity/[@{android_name}='{activity_name}']"):
activity.attrib[android_name] = new_activity_name
axml_object = pyaxml.AXML()
axml_object.from_xml(xml)
# Rewrite the file
with open(output_file, "wb") as f:
f.write(axml_object.pack())
if __name__ == "__main__":
replace_activity()
To begin with a more simple example you can use the tool to only encode and decode AXML thanks to 3 available commands:
axml2xml: to decode AXML and print it in XML;
arsc2xml: to decode ARSC and print it in XML;
xml2axml: to encode XML in AXML.
# Python CLI
pyaxml axml2xml -i AndroidManifest.xml
pyaxml arsc2xml -i resources.arsc
pyaxml xml2axml -i AndroidManifest.xml -o AndroidManifest.axml
# Rust CLI (same commands, no Python required)
pyaxml-rs axml2xml -i AndroidManifest.xml
pyaxml-rs arsc2xml -i resources.arsc
pyaxml-rs xml2axml -i AndroidManifest.xml -o AndroidManifest.axml
AXML or ARSC
In Android application development, AXML and ARSC files are key components:
AXML (Android XML): Typically used for AndroidManifest.xml, which contains essential information about the application such as its components and permissions.
ARSC (Android Resource Synchronized Container): Contains compiled resources like strings, styles, and layouts.
To handle these file types, pyaxml provides distinct classes for each:
AXML: Manages AXML files, allowing for parsing and modification of XML data.
ARSC: Handles ARSC files, enabling the manipulation of compiled resource data.
When dealing with files whose type you might not be certain of, pyaxml offers a convenient solution:
AXML_guess: This class includes the from_axml method, which can automatically determine whether a file is an AXML or an ARSC file. Based on this determination, it returns an instance of either the AXML class or the ARSC class.
Example Usage
Here’s how you might use AXML_guess to handle files without knowing their exact type:
import pyaxml
import click
@click.command()
@click.argument('input_file')
def process_file(input_file):
filename = input_file
with open(filename, "rb") as f:
guessed_object = pyaxml.AXML_guess.from_axml(data)
if isinstance(guessed_object, pyaxml.AXML):
print("Processing AXML file")
# Handle AXML file
xml = guessed_object.to_xml()
# Perform operations on XML data
# ...
elif isinstance(guessed_object, pyaxml.ARSC):
print("Processing ARSC file")
# Handle ARSC file
# Perform operations on ARSC data
# ...
else:
print("Unknown file type")
# Write the modified AXML to the output file
with open(output_file, "wb") as f:
f.write(guessed_object.pack())
if __name__ == "__main__":
process_file()