A graph-based static-dynamic hybrid DEX code analysis tool
This tool is still in the early stage of development. It's known to be incomplet and incorrekt.
new
or delete
.clang-format
with provided
.clang-format
file before committing to the repository.Jitana uses CMake which supports out-of-source build. In this document, the following directory structure is assumed:
.
├── jitana (source code downloaded)
├── dex (DEX files)
└── build (build directory you make)
Install all the dependencies first. Then
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ../jitana
make -j8
Please refer to Compiling Jitana on Linux.
Please refer to Compiling Jitana on Windows.
Jitana is implemented using the generic programming techniques rather than the traditional object-oriented techniques due to the following ideas:
jitana::virtual_machine
jitana::loader_graph loaders()
jitana::loader_graph_property
jitana::loader_edge_property = jitana::any_edge_property
jitana::loader_vertex_property
jitana::class_loader loader
jitana::dex_file
jitana::class_graph classes()
jitana::class_graph_property
std::unordered_map<jitana::jvm_type_hdl, jitana::class_vertex_descriptor> jvm_hdl_to_vertex
std::unordered_map<jitana::dex_type_hdl, jitana::class_vertex_descriptor> hdl_to_vertex
jitana::class_edge_property = jitana::any_edge_property
jitana::class_vertex_property
jitana::dex_type_hdl hdl
jitana::jvm_type_hdl jvm_hdl
jitana::dex_access_flags access_flags
std::vector<jitana::dex_field_hdl> static_fields
std::vector<jitana::dex_field_hdl> instance_fields
std::vector<jitana::dex_method_hdl> dtable
std::vector<jitana::dex_method_hdl> vtable
uint16_t static_size
uint16_t instance_size
jitana::method_graph methods()
jitana::method_graph_property
std::unordered_map<jitana::jvm_method_hdl, jitana::method_vertex_descriptor> jvm_hdl_to_vertex
std::unordered_map<jitana::dex_method_hdl, jitana::method_vertex_descriptor> hdl_to_vertex
jitana::method_edge_property = jitana::any_edge_property
jitana::method_vertex_property
jitana::dex_method_hdl hdl
jitana::jvm_method_hdl jvm_hdl
jitana::dex_type_hdl class_hdl
jitana::dex_access_flags access_flags
std::vector<jitana::method_param> params
jitana::insn_graph insns
jitana::insn_graph_property
std::unordered_map<uint16_t, jitana::insn_vertex_descriptor> offset_to_vertex
jitana::dex_method_hdl hdl
jitana::jvm_method_hdl jvm_hdl
std::vector<jitana::try_catch_block> try_catches
size_t registers_size
size_t ins_size
size_t outs_size
uint32_t insns_off
jitana::insn_edge_property = jitana::any_edge_property
jitana::insn_vertex_property
jitana::dex_insn_hdl hdl
jitana::insn insn
long long counter = 0
uint32_t off
int line_num = 0
A handle is used to identify a virtual machine object (class, method, instruction, etc.) in Jitana. There are two types of handles:
See include/jitana/hdl.hpp for implementation details.
+--------------------------------+---------------------------------+
| DEX Handle | JVM Handle |
| (Android specific: int based) | (General Java: string based) |
+----------+--------------------------------+---------------------------------+
| Class | struct class_loader_hdl { |
| Loader | uint8_t idx; |
| | } |
+----------+--------------------------------+---------------------------------+
| DEX | struct dex_file_hdl { | N/A |
| File | class_loader_hdl loader_hdl; | (No concept of DEX file in JVM) |
| | uint8_t idx; | |
| | }; | |
+----------+--------------------------------+---------------------------------+
| Type | struct dex_type_hdl { | struct jvm_type_hdl { |
| | dex_file_hdl file_hdl; | class_loader_hdl loader_hdl; |
| | uint16_t idx; | std::string descriptor; |
| | }; | }; |
+----------+--------------------------------+---------------------------------+
| Method | struct dex_method_hdl { | struct jvm_method_hdl { |
| | dex_file_hdl file_hdl; | jvm_type_hdl type_hdl; |
| | uint16_t idx; | std::string unique_name; |
| | }; | }; |
+----------+--------------------------------+---------------------------------+
| Field | struct dex_field_hdl { | struct jvm_field_hdl { |
| | dex_file_hdl file; | jvm_type_hdl type_hdl; |
| | uint16_t idx; | std::string unique_name; |
| | }; | }; |
+----------+--------------------------------+---------------------------------+
| Instruc- | struct dex_insn_hdl { | N/A |
| tion | dex_method_hdl method_hdl; | |
| | uint16_t idx; | |
| | }; | |
+----------+--------------------------------+---------------------------------+
| Register | struct dex_reg_hdl { | N/A |
| | dex_insn_hdl insn_hdl; | |
| | uint16_t idx; | |
| | }; | |
+----------+--------------------------------+---------------------------------+
We have one or more initiating handles and a unique defining handle for each VM object:
virtual_machine::find_*()
.These concepts mirror the defining loaders and the initiating loaders described in the JVM Specification.
For convenience, you should create your own tool under tools/
so that the
build system can read your CMakeLists.txt
automatically. You may use
tools/jitana-graph/
as an example.
#include <jitana/jitana.hpp>
int main()
{
// 1. Create a virtual machine.
jitana::virtual_machine vm;
// 2a. Create and add a system class loader.
{
const auto& filenames = {"dex/system/framework/core.dex",
"dex/system/framework/framework.dex",
"dex/system/framework/framework2.dex",
"dex/system/framework/ext.dex",
"dex/system/framework/conscrypt.dex",
"dex/system/framework/okhttp.dex"};
jitana::class_loader loader(11, "SystemLoader", begin(filenames),
end(filenames));
vm.add_loader(loader);
}
// 2b. Create and add an application class loader.
{
const auto& filenames = {"dex/app/instagram_classes.dex"};
jitana::loader loader(22, "Instagram", begin(filenames),
end(filenames));
vm.add_loader(loader, 11);
}
// 3a. Load a specific class.
// You need to specify fully qualified Java binary name.
{
bool try_to_load = true;
vm.find_class({22, "Ljava/lang/BootClassLoader;"}, try_to_load);
}
// 3b. Or, load everything from a class loader.
vm.load_all_classes(22);
}