Package: pysmali
PySmaliThe main functionalities of this repository cover creating and parsing Smali files with Python3 as well as interpret Smali source code files. There is also an interactive interpreter provided that acts as a Python-CLI.InstallationBy now, the only way to install the python module in this repository is by cloning it and running the following command:$cd./pysmali&&pipinstall.# Or with pip$pipinstallpysmaliUsageFor a more detailed explanation of the Smali Visitor-API use theGithub-Pages Docs.Info: Make sure you are usingpysmali>=0.2.0as it introduces a user-friendly type system to mitigate possible issues from parsing type descriptors.ISmali (Interactive Smali Interpreter)As of version0.1.2the interactive interpreter can be used to execute Smali code directly:$ismaliexample.ssf# or start interactive mode$ismali
>>>vars{'p0':<SmaliObject@195f5c0da90>}Some notes:p0: This register always stores the root-instance where defined fields and methods will be stored.vars: This command can be used to print all registers together with their valuesL<Root>;: The name of the root-context classThe APIdocumentationprovides some usage examples and usage hints.Parsing Smali-FilesThe simplest way to parse code is to use aSmaliReadertogether with a visitor:fromsmaliimportSmaliReader,ClassVisitorcode=""".class public final Lcom/example/Hello;.super Ljava/lang/Object;# One line comment.source "SourceFile" # EOL comment"""reader=SmaliReader()reader.visit(code,ClassVisitor())There are a few options to have in mind when parsing with aSmaliReader:comments: To explicitly parse comments, set this variable to True (in constructor or directly)snippet: To parse simple code snippets without a .class definition, use the 'snippet' variable (or within the constructor). Use this property only if you don't have a '.class' definition at the start of the source codevalidate: Validates the parsed codeerrors: With values"strict"or"ignore"this attribute will cause the reader to raise or ignore exceptionsActually, the code above does nothing as theClassVisitorclass does not handle any notification by the reader. For instance, to print out the class name of a parsed code, the following implementation could be used:fromsmaliimportSmaliReader,ClassVisitor,SVMTypeclassNamePrinterVisitor(ClassVisitor):defvisit_class(self,name:str,access_flags:int)->None:# The provided name is the type descriptor, so we have to# convert it:cls_type=SVMType(name)print('Class:',cls_type.pretty_name)# prints: com.example.Helloreader=SmaliReader()reader.visit(".class public final Lcom/example/Hello;",NamePrinterVisitor())[!TIP]
There is an example Smali file in this repository. If you want to print outalldefined classes, you have to implement another method (based on the example above):classNamePrinterVisitor(ClassVisitor):# ... method from above does not changedefvisit_inner_class(self,name:str,access_flags:int)->ClassVisitor:cls_type=SVMType(name)# same as aboveprint("Inner Class:",cls_type.pretty_name)returnselfWriting Smali-FilesWriting is as simple as parsing files. To write the exact same document the has been parsed, theSmaliWriterclass can be used as the visitor:fromsmaliimportSmaliReader,SmaliWriterreader=SmaliReader()writer=SmaliWriter()reader.visit(".class public final Lcom/example/Hello;",writer)# The source code can be retrieved via a propertytext=writer.codeTo create own Smali files, the pre-definedSmaliWritercan be used again:fromsmaliimportSmaliWriter,AccessTypewriter=SmaliWriter()# create the class definitionwriter.visit_class("Lcom/example/Hello;",AccessType.PUBLIC+AccessType.FINAL)writer.visit_super("Ljava/lang/Object;")# create a fieldfield_writer=writer.visit_field("foo",AccessType.PRIVATE,"Ljava/lang/String")# create the finished source code, BUT don't forget visit_end()writer.visit_end()text=writer.codeImporting classes and execute methodsAs of version0.1.2you can import Smali files and execute defined methods:fromsmali.bridgeimportSmaliVM,SmaliObjectvm=SmaliVM()# Import class definitionwithopen('example.smali','r',encoding='utf-8')asfp:smali_class=vm.classloader.load_class(fp,init=False)# Call <clinit> methodsmali_class.clinit()# Create a new instance of the imported classinstance=SmaliObject(smali_class)# Call the object's constructorinstance.init()# Execute the method 'toString'toString=instance.smali_class.method("toString")# The instance must be always the first element (on# static methods this argument must be None)value=toString(instance)print(value)LicenseDistributed under the GNU GPLv3. SeeLICENSEfor more information.