Titan is an open-source VMProtect devirtualizer developed for reverse engineering research and education. Originally started as a hobby project in 2018, it went through several complete rewrites as its developer explored different approaches to understanding and reconstructing VMProtect-protected code.
The project is released so researchers and developers can study its implementation, experiment with devirtualization techniques, and contribute improvements. Titan supports VMProtect versions earlier than 3.8, although its output may require additional analysis and refinement.
Titan relies on Triton for instruction emulation, symbolic execution, and lifting. Its main approach is to identify virtual machine handlers by examining their symbolic expressions at the abstract syntax tree (AST) level.
The tool tracks the virtual instruction pointer (VIP) and virtual stack pointer (VSP) as symbolic variables. It also propagates memory loads and stores generated during emulation. Since many VM handlers finish by storing a result to the stack, a VM register, or another memory location, Titan can inspect the resulting Triton AST and compare it against known operation patterns.
For example, the following C++ function identifies an addition operation involving a value fetched through the VSP:
// Match [vsp] + [vsp].
static bool match_add(const triton::ast::SharedAbstractNode& ast)
{
if (ast->getType() == triton::ast::EXTRACT_NODE)
{
return match_add(ast->getChildren()[2]->getChildren()[1]);
}
return ast->getType() == triton::ast::BVADD_NODE
&& is_variable(
ast->getChildren()[1],
variable::vsp_fetch
);
}
Matching symbolic expressions allows Titan to recognize VM handler operations even when their underlying instruction sequences are heavily obfuscated. Once a handler is identified, the tool lifts it into a basic block representation.
After lifting a basic block, Titan calculates its partial control-flow graph. It then performs slicing on the instruction pointer register to determine the address of the next basic block.
This process continues until the analysis discovers no additional basic blocks. Each recovered block is converted into a separate LLVM function. Titan reconstructs the original execution flow by chaining these functions in the appropriate order.
The resulting LLVM representation provides a structured view of the virtualized program, making it easier to inspect operations and understand how the protected code executes.
Titan includes custom LLVM passes to improve the generated representation. These include:
The flag synthesis pass is particularly relevant to reconstructing processor flag behavior in the lifted output. Its absence means the generated bitcode may not represent every operation as cleanly as intended.
Titan accepts three required arguments when processing a VMProtect-protected binary:
Running Titan without the required arguments displays errors indicating which options are missing:
./build/titan titan: for the -i option: must be specified at least once! titan: for the -b option: must be specified at least once! titan: for the -e option: must be specified at least once!
Provide all three options to start the analysis:
./build/titan \ -i intrinsics/vmprotect64.ll \ -b samples/loop_hash.0x140103FF4.exe \ -e 0x140103FF4
Replace the sample paths and entry-point address with values that match the binary under investigation. The supplied intrinsics file must also correspond to the target architecture and expected VMProtect environment.
Titan offers a practical example of combining symbolic execution, AST-based pattern matching, control-flow reconstruction, and LLVM lifting in a devirtualization workflow. Its implementation can help reverse engineers understand how virtual machine handlers operate and how their behavior can be translated into a more recognizable representation.
However, compatibility is limited to VMProtect versions earlier than 3.8, and the developer notes that the generated output is not always ideal. Treat the results as an analysis starting point rather than a guaranteed reconstruction of the original source code. Test only against software you own or have explicit permission to examine.
For related reverse-engineering research, explore Recaf, a Java bytecode editor, which provides another approach to inspecting and modifying compiled program representations.
Explore Titan’s implementation, documentation, and usage instructions in the official repository: