in tools/redex-tool/DexSqlDump.cpp [196:381]
void dump_sql(FILE* fdout,
DexStoresVector& stores,
ProguardMap& pg_map,
const char* prefix) {
fprintf(fdout,
R"___(
DROP TABLE IF EXISTS %1$sfield_string_refs;
DROP TABLE IF EXISTS %1$smethod_string_refs;
DROP TABLE IF EXISTS %1$smethod_field_refs;
DROP TABLE IF EXISTS %1$smethod_method_refs;
DROP TABLE IF EXISTS %1$smethod_class_refs;
DROP TABLE IF EXISTS %1$sstrings;
DROP TABLE IF EXISTS %1$sfields;
DROP TABLE IF EXISTS %1$sis_a;
DROP TABLE IF EXISTS %1$smethods;
DROP TABLE IF EXISTS %1$sclasses;
CREATE TABLE %1$sclasses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
dex TEXT NOT NULL, -- dex identifiers look like "<store>/<dex_id>"
name TEXT NOT NULL,
obfuscated_name TEXT NOT NULL,
access INTEGER NOT NULL
);
CREATE TABLE %1$smethods (
id INTEGER PRIMARY KEY AUTOINCREMENT,
class_id INTEGER, -- fk:classes.id
name TEXT NOT NULL,
obfuscated_name TEXT NOT NULL,
access INTEGER NOT NULL,
code_size INTEGER NOT NULL
);
CREATE TABLE %1$sis_a (
id INTEGER PRIMARY KEY AUTOINCREMENT,
class_id INTEGER, -- fk:classes.id
is_a_class_id INTEGER -- fk:classes.id
);
CREATE TABLE %1$sstrings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL
);
CREATE TABLE %1$sfields (
id INTEGER PRIMARY KEY AUTOINCREMENT,
class_id INTEGER, -- fk:classes.id
name TEXT NOT NULL,
obfuscated_name TEXT NOT NULL,
access INTEGER NOT NULL
);
CREATE TABLE %1$sfield_string_refs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
field_id INTEGER NOT NULL, -- fk:fields.id
ref_string_id INTEGER NOT NULL -- fk:strings.id
);
CREATE TABLE %1$smethod_class_refs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
method_id INTEGER, -- fk:methods.id
ref_class_id INTEGER NOT NULL, -- fk:classes.id
opcode INTEGER NOT NULL
);
CREATE TABLE %1$smethod_method_refs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
method_id INTEGER, -- fk:methods.id
ref_method_id INTEGER NOT NULL, -- fk:methods.id
opcode INTEGER NOT NULL
);
CREATE TABLE %1$smethod_field_refs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
method_id INTEGER, -- fk:methods.id
ref_field_id INTEGER NOT NULL, -- fk:fields.id
opcode INTEGER NOT NULL
);
CREATE TABLE %1$smethod_string_refs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
method_id INTEGER, -- fk:methods.id
ref_string_id INTEGER NOT NULL, -- fk:strings.id
opcode INTEGER NOT NULL
);
)___",
prefix);
int next_class_id = 0;
int next_method_id = 0;
int next_field_id = 0;
int next_string_id = 0;
// Dump all dex items
fprintf(fdout, "BEGIN TRANSACTION;\n");
for (auto& store : stores) {
auto store_name = store.get_name();
auto& dexen = store.get_dexen();
apply_deobfuscated_names(dexen, pg_map);
for (size_t dex_idx = 0; dex_idx < dexen.size(); ++dex_idx) {
auto& dex = dexen[dex_idx];
GatheredTypes gtypes(&dex);
auto strings = gtypes.get_cls_order_dexstring_emitlist();
for (auto dexstr : strings) {
int id = next_string_id++;
string_ids[dexstr] = id;
// Escape string before inserting. ' -> ''
std::string esc(dexstr->c_str());
boost::replace_all(esc, "'", "''");
fprintf(fdout,
"INSERT INTO %sstrings VALUES(%d, '%s');\n",
prefix,
id,
esc.c_str());
}
std::string dex_id_str(store_name + "/" + std::to_string(dex_idx));
const char* dex_id = dex_id_str.c_str();
for (const auto& cls : dex) {
int class_id = next_class_id++;
dump_class(fdout, prefix, dex_id, cls, class_id);
class_ids[cls] = class_id;
for (auto field : cls->get_ifields()) {
int field_id = next_field_id++;
field_ids[field] = field_id;
dump_field(fdout, prefix, class_id, field, field_id);
}
for (auto field : cls->get_sfields()) {
int field_id = next_field_id++;
field_ids[field] = field_id;
dump_field(fdout, prefix, class_id, field, field_id);
}
for (const auto& meth : cls->get_dmethods()) {
int meth_id = next_method_id++;
method_ids[meth] = meth_id;
dump_method(fdout, prefix, class_id, meth, meth_id);
}
for (auto& meth : cls->get_vmethods()) {
int meth_id = next_method_id++;
method_ids[meth] = meth_id;
dump_method(fdout, prefix, class_id, meth, meth_id);
}
}
}
}
fprintf(fdout, "END TRANSACTION;\n");
// Dump references
fprintf(fdout, "BEGIN TRANSACTION;\n");
for (auto& store : stores) {
auto& dexen = store.get_dexen();
for (size_t dex_idx = 0; dex_idx < dexen.size(); ++dex_idx) {
auto& dex = dexen[dex_idx];
for (const auto& cls : dex) {
for (const auto& meth : cls->get_dmethods()) {
int meth_id = method_ids[meth];
dump_method_refs(fdout, prefix, meth, meth_id);
}
for (auto& meth : cls->get_vmethods()) {
int meth_id = method_ids[meth];
dump_method_refs(fdout, prefix, meth, meth_id);
}
for (const auto& field : cls->get_sfields()) {
int field_id = field_ids[field];
dump_field_refs(fdout, prefix, field, field_id);
}
for (const auto& field : cls->get_ifields()) {
int field_id = field_ids[field];
dump_field_refs(fdout, prefix, field, field_id);
}
}
}
}
fprintf(fdout, "END TRANSACTION;\n");
// Dump hierarchy
auto scope = build_class_scope(stores);
ClassHierarchy ch = build_type_hierarchy(scope);
int next_is_a_id = 0;
fprintf(fdout, "BEGIN TRANSACTION;\n");
for (auto& cls : scope) {
TypeSet results;
get_all_children_or_implementors(ch, scope, cls, results);
for (auto type : results) {
auto type_cls = type_class(type);
if (type_cls) {
fprintf(fdout,
"INSERT INTO %sis_a VALUES(%d, %d, %d);\n",
prefix,
next_is_a_id++,
class_ids[type_cls],
class_ids[cls]);
}
}
}
fprintf(fdout, "END TRANSACTION;\n");
}