Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
bb9e5b1
Merge pull request #19 from hugo-glez/master
evilsocket Nov 24, 2017
aa85904
Various changes and upgrade
drake-mer Jun 10, 2018
8af1e6e
[utils] add an inspect.py script smali inpsection
drake-mer Jun 10, 2018
238fdde
[utils] add an exec script for execution of special method
drake-mer Jun 10, 2018
b6e7503
refactor source code
drake-mer Jun 10, 2018
12500c0
refactor emulator instanciation
drake-mer Jun 10, 2018
0f20b79
Merge pull request #20 from elijahbal/devel
evilsocket Jun 10, 2018
68a1929
Change int tokenizer:
drake-mer Jun 10, 2018
663a13f
fix example, exec.py script and doc
drake-mer Jun 10, 2018
999005f
various fixes and improvements
drake-mer Jun 10, 2018
5ef5ba8
Merge pull request #21 from elijahbal/devel
evilsocket Jun 11, 2018
c6a10d4
[emulator] refactor param update
drake-mer Jul 4, 2018
7e65768
[opcodes] read array quantity for integers
drake-mer Jul 4, 2018
7791f2b
[opcodes] add-int/2addr and rsub-int
drake-mer Jul 4, 2018
a806ddb
[objects/string] support for String(byte_array)
drake-mer Jul 4, 2018
8eadde8
[opcodes] add neg-int opcode
drake-mer Jul 4, 2018
0a166e6
[opcodes] strip 's' on int values
drake-mer Jul 4, 2018
49ab17d
[opcodes] add rsub-int opcode
drake-mer Jul 4, 2018
a0927d0
[opcodes] fix doctests
drake-mer Jul 4, 2018
b0e144d
code style;
drake-mer Jul 10, 2018
d98ffb7
[return value in init string]
drake-mer Jul 10, 2018
8e358d4
[opcodes] add orint2addr and orintliteral
drake-mer Jul 10, 2018
4002d88
[opcodes] SubInt2Addr + AndInt2Addr
drake-mer Jul 11, 2018
ad713fc
[tests] add static method calls
drake-mer Jul 12, 2018
0f1fa38
[emulator] refactor imports
drake-mer Jul 19, 2018
7ed1980
[string] add docstrings
drake-mer Jul 19, 2018
b452d9c
[tests/data] rename file
drake-mer Jul 19, 2018
a67856d
[parsing] extract attribute list
drake-mer Jul 19, 2018
f3717c8
[tests] add test for class attribute parsing
drake-mer Jul 19, 2018
7f197e3
[tests] update tests
drake-mer Jul 30, 2018
40cb4d4
smali emulator
drake-mer Aug 3, 2018
d04a3cf
[add a bunch of test files
drake-mer Aug 14, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
*.pyc
.pytest_cache
.idea
33 changes: 28 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,43 @@
# Smali Emulator

This software will emulate a [**smali**](https://github.com/JesusFreke/smali) source file generated by apktool, it is intended to be used as a quick and dirty way to defeat various types of encryption and obfuscation while reversing an APK.
This software will emulate a [**smali**](https://github.com/JesusFreke/smali) source file
generated by apktool, it is intended to be used as a quick and dirty way to defeat various
types of encryption and obfuscation while reversing an APK.

You'll find some examples in the `examples` folder of this project.
This project is very much a work in progress, feel free to submit a patch.

[Explanation of the "why" and "how" can be found here.](https://www.evilsocket.net/2016/04/18/how-i-defeated-an-obfuscated-and-anti-tamper-apk-with-some-python-and-a-home-made-smali-emulator/)
As an example, you can run:

```shell
cd utils;
./exec.py -i decryptor.smali -m field5 \
-p '{"p0":[-62,-99,-106,-125,-123,-105,-98,-37,-105,-97,-103,-41,-118,-97,-113,-103,-109,-104,-115,111,98,103,35,52],"p1": 19}'
```

# Testing

The project has recently be migrated to pytest for infrastructure of tests.
To run tests, do:

#### Note
```shell
pytest -v
```

The py3 compatibility has moved up, you should use pytest-3 whenever possible.
However, python2 retrocompatibility should not be discarded, so use the two
test suites (pytest-2, pytest-3) to check the retrocompatibility in your changes.

# Note

[Explanation of the "why" and "how" can be found here.](https://www.evilsocket.net/2016/04/18/how-i-defeated-an-obfuscated-and-anti-tamper-apk-with-some-python-and-a-home-made-smali-emulator/)

This is highly experimental, a very small subset of the Dalvik opcodes is currently supported, see the `smali/opcodes.py` file for more details.

OpCodes List (Feel free to request access)

https://docs.google.com/spreadsheets/d/1RfB_LsBoYnJxOh-lDCSMR0mfLBl1UlwdW9eKw2p03DY/edit?usp=sharing

#### License
# License

Copyright (c) 2016 Simone Margaritelli | [Twitter](https://twitter.com/evilsocket) | [Blog](http://www.evilsocket.net)
Released under the GPL 3 license.
46 changes: 46 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Ultimate goal

The ultimate goal is to be able to load any .smali class file in python
and to instanciate objects of that class as python objects.

Example:

```python
import smali.bridge

>>> ClassToLoad = smali.bridge.loadClass('ClassToLoad.smali') # get the class
>>> myObject = ClassToLoad() # instanciate it
>>> myObjects.methods() # get the list of available methods
['init', 'methodA', 'methodB']
>>> myObjects.fields() # get the list of fields
['fieldA', 'fieldB']
```

However the current architecture is not really oriented toward this goal, because
`smali_emulator` was at the beginning a simple script-like (quite complex for a script)
application, but advanced use cases were not anticipated.

Although there is a lack of long-term anticipation, the architecture is nevertheless quite
useable and it is veryy possible to make it evolve without too much rewriting.

The building block are already existing.

- ObjectMapping class is a dictionary with {className: methodList} functions.
- VM is storing the current execution status of the virtual machine.
- Emulator is running the source code

We should add a support in ObjectMapping for Class objects that are analogous to the
corresponding smali files.

See `smali/objects/metaclass.py`.

One of the problem is that methods in java are all encapsulated into classes, there
is no global variables shared through the code (in principle).

So we need a global state that will map all classes in a package with a specific
context for smali source code.





45 changes: 45 additions & 0 deletions doc/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Dalvik Virtual Machine

The Dalvik Virtual Machine is register based.

It means that, in a given frame, all the registers have a given value.

This documentation may not be necessary up-to-date as we are trying to update
our architecture to answer to more demanding challenges.

# Implementation of static private fields read/write operations

What the capability is of smali_emulator right now is

- take a smali file
- execute a method in that file by passing the argument dict
- get back the result

So far, the behaviour of the emulator has been perfect in this framework. Absolutely
no errors, the software behaves very well. However, we lack many features in order
to be absolutely able to execute arbitrary smali code:

- Cross references through the file are _not_ supported.
- Instanciation of objects is _not_ supported.

There is a real need to be able to instanciate classes « live ». Let
us assume that the class is self-contained.

The need would be then to

- Instanciate the class using its `<init>` method
- Execute some static methods on the object

Problem is:

- how to dynamically create a class at runtime in python

Solution would be:
- use the metaclass capability of python

Process would be:
- parse the smali code
- create dynamically the class object
-


87 changes: 87 additions & 0 deletions doc/SCRIPTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Scripting with smali emulator

Ultimately, scripting the emulator to run methods of a `.smali` file
from a python shell is a desirable goal.

Here we attempt to write a self-explaining document, some of the features
described here may not have been implemented yet, but we are working on it :)

## Script 1

Current state of scripting API allows us to do the following:

```python

import os.path
import smali
import smali.source
import smali.emulator

static_class_path = os.path.join(
os.path.dirname(smali.__file__),
os.pardir, os.pardir, 'tests', 'staticmethod', 'value_cannot_be_null.smali'
)

# create a new emulator
emulator = smali.emulator.Emulator()

# run the *only* method in that file
result = emulator.run_file(static_class_path, {'p0': 1, 'p1': 1, 'p2': -1})

# display the result
print(result)
```

## Script 2

What we would like is to do:

```python

import os.path
import smali
import smali.source
import smali.emulator

static_class_path = os.path.join(
os.path.dirname(smali.__file__),
os.pardir, os.pardir, 'tests', 'staticmethod', 'value_cannot_be_null.smali'
)

# create a new emulator
emulator = smali.emulator.Emulator()

# load all the methods in that file
emulator.load_class(static_class_path)

# exec the method
emulator.exec_method('a', args={'p0': 1, 'p1': 1, 'p2': -1})

# display the result
print(result)
```

# Script 3: invoke init and subsequent methods

We want ultimately the possibility to exec methods on the fly,
especially to call the init method initializing members,
then to call method for the sget/sput/iget/iput support to be really effective.

This is possible through this example (see also `test_scripting_api.py`
for details)


```python
"""Test two successive calls:
- first on '<clinit>' for initializing static fields
- second on 'a' for deciphering some string
"""
emulator = smali.emulator.Emulator()
emulator.load_class(get_file_path('completeclass', 'full_static_class.smali'))
res = emulator.exec_method('<clinit>', args=None) # call the static constructor
res = emulator.exec_method(
'a', args={'p0': p0, 'p1': p1, 'p2': p2},
vm=emulator.vm # need to propagate the vm because it contains
# the static fields initialized from call to <clinit>
)
```
40 changes: 0 additions & 40 deletions examples/decryptor.py

This file was deleted.

2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
addopts = --doctest-modules --ignore=utils
Loading