We are pleased to announce that we released Triton v0.8 under the terms of the Apache License 2.0 (same license as before). This new version provides bug fixes, features and improvements: the detailed list can be found on this Github page (there are about 297 changed files with 43,115 additions and 13,579 deletions). We wrote this blog post to highlight the most important changes from v0.7.
What's new in v0.8?
First of all, we would like to thank the following contributors who helped make Triton a bit more powerful every day during the development of v0.8 (thanks all, you are amazing!):
The following sub-sections introduce some major improvements between the v0.7 and v0.8 versions.
1 - Implicit concretization when setting a concrete value
Thread: #808.
Triton keeps at each program point a concrete and a symbolic state. When the user modifies a concrete value at a specific program point, it may imply a de-synchronization between those two states and, before v0.8, the user had to force the re-synchronization by concretizing registers or memory cells. For example, we could have a snippet like this:
ctx.setConcreteRegisterValue(ctx.registers.rax, 0x1234)
ctx.concretizeRegister(ctx.registers.rax) # concretize the register which points to an old symbolic expression
With v0.8 you should have something like this:
ctx.setConcreteRegisterValue(ctx.registers.rax, 0x1234) # implicit concretization
2 - Dealing with the path predicate
Thread: #350.
During the execution, Triton builds the path predicate when it encounters conditional instructions. We provided some new methods which allow the user to deal a bit better with the path predicate. It's now possible to:
remove the last constraint added to the path predicate using popPathConstraint();
add new constraints using pushPathConstraint();
clear the current path predicate using clearPathConstraints().
We also provided a new method which returns the path predicate to target a basic block address if this one is reachable during the execution (do not forget that we are in a dynamic analysis context): getPredicatesToReachAddress().
For example, let's consider at one point we want to add a post condition on our path predicate, such as rax must be different from 0. The snippet of code should look like this:
if inst.getAddress() == [my target address]:
rax = ctx.getRegisterAst(ctx.registers.rax)
ctx.pushPathConstraint(rax != 0)
3 - The CONSTANT_FOLDING optimization
Thread: #835.
We added a new optimization which performs a constant folding at the build time of AST nodes. This optimization is pretty similar to ONLY_ON_SYMBOLIZED except that the concretization occurs at each level of the AST during its construction while ONLY_ON_SYMBOLIZED only checks if a root node of a symbolic expression contains symbolic variables (which does not concretize sub-trees if it is true).
4 - Converting a Z3 expression to a Triton expression
Thread: #850.
It's now possible to convert a Z3 expression into a Triton expression and vice versa using Python bindings. Before v0.8, the conversion from z3 to Triton was only possible with the C++ API.
>>> from triton import *
>>> ctx = TritonContext(ARCH.X86_64)
>>> ast = ctx.getAstContext()
>>> x = ast.variable(ctx.newSymbolicVariable(8))
>>> y = ast.variable(ctx.newSymbolicVariable(8))
>>> n = x + y * 2
>>> print(n)
(bvadd SymVar_0 (bvmul SymVar_1 (_ bv2 8)))
>>> z3n = ast.tritonToZ3(n)
>>> print(type(z3n))
<class 'z3.z3.ExprRef'>
>>> print(z3n)
SymVar_0 + SymVar_1*2
>>> ttn = ast.z3ToTriton(z3n)
>>> print(type(ttn))
<class 'AstNode'>
>>> print(ttn)
(bvadd SymVar_0 (bvmul SymVar_1 (_ bv2 8)))
6 - The quantifier operator: forall
Thread: #860.
After reading a nice blog post about constant synthesizing, we thought it could be interesting to add the quantifier operator: forall. For example, let's assume we want to synthesize the following expression ((x << 8) >> 16) << 8 into x & 0xffff00 where x is a 32-bit vector and the constant 0xffff00 is the unknown. The SMT query looks like this:
(declare-fun C () (_ BitVec 32))
(assert (forall
((x (_ BitVec 32)))
(=
(bvand x C)
(bvshl (bvlshr (bvshl x (_ bv8 32)) (_ bv16 32)) (_ bv8 32))
)
)
)
(check-sat)
(get-model)
The illustrated SMT query can be read as: There exists a constant C such that for all x the expression x & C is equal to ((x << 8) >> 16) << 8. To handle such query in Python with v0.8, you could have a snippet of code like the following:
#!/usr/bin/env python
## -*- coding: utf-8 -*-
##
## $ python ./example.py
## {1: C:32 = 0xffff00}
##
from triton import *
ctx = TritonContext(ARCH.X86_64)
ast = ctx.getAstContext()
x = ast.variable(ctx.newSymbolicVariable(32))
c = ast.variable(ctx.newSymbolicVariable(32))
x.getSymbolicVariable().setAlias('x')
c.getSymbolicVariable().setAlias('C')
print(ctx.getModel(ast.forall([x], ((x << 8) >> 16) << 8 == x & c)))
7 - Changes to the user API
Threads: #812, #864, #865 and #866.
The following v0.7 functions are deprecated and must be replaced by their v0.8 equivalent.
v0.7 | v0.8 |
---|---|
convertExpressionToSymbolicVariable | symbolizeExpression |
convertMemoryToSymbolicVariable | symbolizeMemory |
convertRegisterToSymbolicVariable | symbolizeRegister |
enableMode | setMode |
getPathConstraintsAst | getPathPredicate |
getSymbolicExpressionFromId | getSymbolicExpression |
getSymbolicVariableFromId | getSymbolicVariable |
getSymbolicVariableFromName | getSymbolicVariable |
isMemoryMapped | isConcreteMemoryValueDefined |
isSymbolicExpressionIdExists | isSymbolicExpressionExists |
lookingForNodes | search |
newSymbolicVariable(size, comment="") | newSymbolicVariable(size, alias="") |
symbolizeExpression(id, size, comment="") | symbolizeExpression(id, size, alias="") |
symbolizeMemory(mem, comment="") | symbolizeExpression(mem, alias="") |
symbolizeRegister(reg, comment="") | symbolizeExpression(reg, alias="") |
unmapMemory | clearConcreteMemoryValue |
unrollAst | unroll |
8 - ARMv7 support
Thread: #831.
Last but not least, Triton v0.8 introduces yet another architecture: ARMv7. With this new inclusion, Triton now has support for the most popular architectures, namely: x86, x86-64, ARM32 and AArch64.
The ubiquity of ARM processors is one of the main reasons for adding support for ARMv7 in Triton. ARMv7 is a widely popular architecture, particularly in embedded devices and mobile phones. We wanted to bring the advantages of Triton to this architecture (most tools are prepared to work on Intel x86/x86_64 only). The other reason is to show the flexibility and extensibility of Triton. ARMv7 poses some challenges in terms of implementation given its many features and peculiarities (some of them quite different from the rest of the supported architectures). Therefore, ARMv7 makes a great architecture to add to the list of supported ones.
You can start by checking some of the available samples.
Plans for v0.9
About the v0.9 version, our first plan is to integrate the SMT Array logic which will allow the user to symbolically index memory accesses. This new memory model will not replace the current one dealing with BV only. Our idea is to provide two memory models, BV and ABV, and the user will be able to switch from one to the other according to his/her objectives. Our second plan is to improve the taint analysis integrated in Triton. Currently, the taint engine is mono-color with an over-approximation making it not really usable as a standalone analysis (it is mainly relevant when combined with the symbolic engine). So our idea is to provide a multi-colors and bit-level taint analysis based on the semantics of the Triton IR instead of the instruction semantics or to make it independent of the AST construction.
Conclusion
It has been almost seven months since Triton v0.7. There were a lot of performance improvements regarding the execution speed and the memory consumption and we cannot describe all of them in this blog post but are present in this new version. (you can check them on this Github page). We only highlighted the most notorious changes from the last version. We hope you find the many features and improvements worth the wait. Now it's time for you to give it a try.
Stay tuned for more news on Triton!
Acknowledgments
Thanks to all contributors!
Thanks to all our Quarkslab colleagues who proofread this article.