1. Smali VM¶
Implementation of a simple Smali emulator named SmaliVM. It supports execution of small code snippets as well as the execution of whole class files.
Debugging can be done by providing a DebugHandler
and enabling the
debug-option wihtin the VM object. It is also possible to use a custom
ClassLoader
to load or define new classes.
As of version 0.1.1
it is possible to import Smali source code files into
the provided SmaliVM
. All classes are stored globally, so there can’t be
two classes with the same type descriptor. To create a simple Smali emulator,
just create a new SmaliVM
instance:
from smali.bridge import SmaliVM
vm = SmaliVM()
Hint
If you want to create a custom import process, just create sub-class of
ClassLoader
and provide an instance of it in the constructor of the
SmaliVM
.
Next, classes are used as prototypes to create new objects of their type. The class creation and object initialization is rather simple:
1from smali.bridge import SmaliClass, SmaliObject, SmaliVM
2
3# Let's assume, the class' source code is stored here
4source = ...
5
6vm = SmaliVM()
7# Load and define the class (don't call the <clinit> method)
8my_class = vm.classloader.load_class(source, init=False)
9
10# To manually initialize the class, call <clinit>
11my_class.clinit()
12
13# Instances can be created by providing the class object
14instance = SmaliObject(my_class)
15
16# Initialization must be done separately:
17instance.init(...)
18
19# Methods are stored in our class object (not in the
20# actual instance)
21toString = my_class.method("toString")
22
23# The first argument of instance method must be the
24# object itself (on static methods, just use None)
25value = toString(instance)
26
27# The returned value behaves like a string
28print("Returned value:", value)
- class smali.bridge.vm.SmaliVM(class_loader: ClassLoader = None, executors: dict = None, use_strict: bool = False)¶
Basic implementation of a Smali emulator in Python.
- __classes: dict[str, SmaliClass] = {}¶
All classes are stored in a dict
- call(method: SmaliMethod, instance, *args, **kwargs) object ¶
Executes the given method in the given object instance.
Before the method will be executed, there is an input parameter check to validate all passed arguments. The required registers will be filled automatically.
Debugging is done via the
DebugHandler
that must be set globally in this object.- Parameters:
method (
SmaliMethod
) – the method to executeinstance (
SmaliObject
) – the smali object
- Raises:
NoSuchMethodError – if no frame is registered to the given method
ExecutionError – if an error occurs while execution
- Returns:
the return value of the executed method
- Return type:
object
- classloader: ClassLoader¶
The class loader used to define classes.
- debug_handler: DebugHandler¶
The debug handler to use.
- executors: dict[str, Executor]¶
External executors used to operate on a single opcode.
- get_class(name: str) SmaliClass ¶
Searches for a class with the given name.
- Parameters:
name (str) – the class name
- Raises:
NoSuchClassError – if no class with the given name is defined
- Returns:
the defined Smali class
- Return type:
- new_class(_SmaliVM__class: SmaliClass)¶
Defines a new class that can be accessed globally.
- Parameters:
cls (SmaliClass) – the class to be defined
- new_frame(method: SmaliMethod, frame: Frame)¶
Creates a new method frame that will be mapped to the method’s signature-
- Parameters:
method (SmaliMethod) – the target method
frame (Frame) – the execution frame
- use_strict: bool = False¶
Tells the VM to throw exceptions on unkown opcodes.
- class smali.bridge.vm.ClassLoader¶
Abstract base class for SmaliClassLoader
- abstract define_class(source: bytes | str | IOBase) SmaliClass ¶
Defines a new SmaliClass by parsing the given source file.
- Parameters:
source (bytes | str) – the source code
- Returns:
the parsed class definition
- Return type:
- abstract load_class(source: str | bytes | IOBase, init=True, lookup_missing=False) SmaliClass ¶
Parses the given source code and initializes the given class if enabled.
- Parameters:
source (str | bytes | IOBase) – the source code
init (bool, optional) – whether
<clinit>
should be executed, defaults to Truelookup_missing (bool, optional) – whether missing classes should be searched before parsing can continue, defaults to False
- Raises:
NoSuchClassError – if the given class is not defined and
lookup_missing
is trueInvalidOpcodeError – if the parsed opcode is invalid
- Returns:
the parsed class definition
- Return type: