PySmali is a Python library for parsing and unparsing smali files for programatic modification.
It is a line (not token) based parser. Its primary goal is for parsed files to maintain 100% equality with their original forms when reconstructed.
PySmali's main usage is for smali file patching. You are able to parse, search, extract, replace, and unparse blocks of a smali file.
Parsing is based on the ANTLR files found in the JesusFreke/smali repository.
Since this is a line, and not token, based parser, there are likely to be edge cases where PySmali fails to properly parse or unparse a file. There are currently 6,846 smali files that are used in the tests
folder (tests/tests.tar.xz
).
If you run into a smali file that does not parse or unparse properly, please submit a new issue with the complete smali file(s) attached as a zip
or gz
archive.
pip install smali
import time
from smali import SmaliFile
from smali.statements import Statement
smali_file = SmaliFile.parse_file('/path/to/file.smali')
new_lines = Statement.parse_lines(f'''
# This file was modified by PySmali
# Modified: {time.ctime()}
''')
smali_file.root.extend(new_lines)
with open('/path/to/file.smali', 'w') as f:
f.write(str(smali_file))
[UPCOMING] v0.4.0
[UPCOMING] v0.3.0
Statement
and Block
searching by method and field namesStatement
and Block
extraction and insertionv0.2.5
v0.2.4
Statement
instances
.super Ljava/lang/Object;
would become a single Statement
instancevalue = { LFormat31c; }
would become 4 Statement
instancesvalue
, {
, LFormat31c;
, }
Statement
instance is subclassed based on its type
FieldStatement
or MethodStatement
Statement
can have zero or more StatementAttributes
that indicate its intent and format
BLOCK_START
, ASSIGNMENT_LHS
, or NO_BREAK
Statement
instances can be joined into a Block
and nested where appropriate
Block
example would be a smali method, comprised of beginning, body, and end Statement
instancesStatement
parses its source line, split by whitespaceEndStatement
.
Statement
instances from the input lines. Statement
that can be either a Block
start or a solo line is marked with the MAYBE_BLOCK_START
attributeEndStatement
is generated, and matches a previously marked Statement
, the marked Statement
is switched from MAYBE_BLOCK_START
to BLOCK_START
.Statement
instances that are still marked with MAYBE_BLOCK_START
are switched to SINGLE_LINE
,Statement
instances and groups them into Block
instances and nesting when appropriate based on the SINGLE_LINE
and BLOCK_START
attributes.Statement
stringifies itself using its own local informationSmaliFile
instance uses the attributes of each Statement
to stitch lines together and indent blocks where necessaryLicensed Under: Various Licenses
Smali files used as tests in the tests/tests.tar.xz
archive have been obtained from the following projects: