Rizin
unix-like reverse engineering framework and cli tools
core_dex.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2022 deroad <wargio@libero.it>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_types.h>
5 #include <rz_lib.h>
6 #include <rz_demangler.h>
7 #include <rz_cmd.h>
8 #include <rz_core.h>
9 #include <rz_cons.h>
10 #include <string.h>
11 #include <rz_analysis.h>
12 
13 #include "../format/dex/dex.h"
14 
15 #define name_args(name) (cmd_##name##_args)
16 #define name_help(name) (cmd_##name##_help)
17 #define name_handler(name) (rz_cmd_##name##_handler)
18 #define static_description_without_args(command, summ) \
19  static const RzCmdDescArg name_args(command)[] = { \
20  { 0 }, \
21  }; \
22  static const RzCmdDescHelp name_help(command) = { \
23  .summary = summ, \
24  .args = name_args(command), \
25  }
26 #define rz_cmd_desc_argv_modes_new_warn(rcmd, root, cmd, flags) \
27  rz_warn_if_fail(rz_cmd_desc_argv_state_new(rcmd, root, #cmd, flags, name_handler(cmd), &name_help(cmd)))
28 
30  if (!core) {
31  return NULL;
32  }
33  RzAnalysis *analysis = core->analysis;
34  if (!analysis || !analysis->binb.bin) {
35  return NULL;
36  }
37  RzBin *b = analysis->binb.bin;
38  if (!b->cur || !b->cur->o) {
39  return NULL;
40  }
41  RzBinPlugin *plugin = b->cur->o->plugin;
42  return plugin && !strcmp(plugin->name, "dex") ? (RzBinDex *)b->cur->o->bin_obj : NULL;
43 }
44 
45 static char *decode_access_flags(ut32 access_flags) {
46  char *str = rz_bin_dex_access_flags_readable(access_flags);
47  if (!str) {
48  return strdup("");
49  }
50  for (size_t i = 0; i < strlen(str); ++i) {
51  str[i] = toupper(str[i]);
52  }
53  return str;
54 }
55 
56 static void dex_print_encoded_field(RzBinDex *dex, ut32 index, DexEncodedField *encoded_field) {
57  if (dex->field_ids_size < encoded_field->field_idx) {
58  rz_cons_printf(" #%-14u: unknown id %" PFMT64u "\n", index, encoded_field->field_idx);
59  return;
60  }
61  DexFieldId *field_id = (DexFieldId *)rz_pvector_at(dex->field_ids, encoded_field->field_idx);
62 
63  char *tmp = rz_bin_dex_resolve_type_id_by_idx(dex, field_id->class_idx);
64  rz_cons_printf(" #%-14u: (in %s)\n", index, tmp);
65  free(tmp);
67  rz_cons_printf(" name : '%s'\n", tmp);
68  free(tmp);
70  rz_cons_printf(" type : '%s'\n", tmp);
71  free(tmp);
72  tmp = decode_access_flags(encoded_field->access_flags);
73  rz_cons_printf(" access : 0x%04" PFMT64x " (%s)\n", encoded_field->access_flags, tmp ? tmp : "");
74  free(tmp);
75 }
76 
77 static void dex_print_encoded_method(RzBinDex *dex, ut32 index, DexEncodedMethod *encoded_method) {
78  if (dex->method_ids_size < encoded_method->method_idx) {
79  rz_cons_printf(" #%-14u: unknown id %" PFMT64u "\n", index, encoded_method->method_idx);
80  return;
81  }
82  DexMethodId *method_id = (DexMethodId *)rz_pvector_at(dex->method_ids, encoded_method->method_idx);
83 
84  char *tmp = rz_bin_dex_resolve_type_id_by_idx(dex, method_id->class_idx);
85  rz_cons_printf(" #%-14u: (in %s)\n", index, tmp);
86  free(tmp);
88  rz_cons_printf(" name : '%s'\n", tmp);
89  free(tmp);
91  rz_cons_printf(" type : '%s'\n", tmp);
92  free(tmp);
93  tmp = decode_access_flags(encoded_method->access_flags);
94  rz_cons_printf(" access : 0x%04" PFMT64x " (%s)\n", encoded_method->access_flags, tmp ? tmp : "");
95  free(tmp);
96  rz_cons_printf(" method_idx : %" PFMT64u "\n", encoded_method->method_idx);
97  rz_cons_printf(" code : (%s)\n", encoded_method->code_offset >= RZ_DEX_RELOC_ADDRESS ? "none" : "available");
98 }
99 
100 static void dex_print_class_def(RzBinDex *dex, ut32 index, DexClassDef *class_def) {
101  ut32 j;
102  RzListIter *it;
103  DexEncodedField *encoded_field;
104  DexEncodedMethod *encoded_method;
105  rz_cons_printf("Class #%u header:\n", index);
106  rz_cons_printf("offset : 0x%" PFMT64x "\n", class_def->offset);
107  rz_cons_printf("class_idx : %u\n", class_def->class_idx);
108  rz_cons_printf("access_flags : %u (0x%04x)\n", class_def->access_flags, class_def->access_flags);
109  rz_cons_printf("superclass_idx : %u\n", class_def->superclass_idx);
110  rz_cons_printf("interfaces_off : %u (0x%06x)\n", class_def->interfaces_offset, class_def->interfaces_offset);
111  rz_cons_printf("source_file_idx : %u\n", class_def->source_file_idx);
112  rz_cons_printf("annotations_off : %u (0x%06x)\n", class_def->annotations_offset, class_def->annotations_offset);
113  rz_cons_printf("class_data_off : %u (0x%06x)\n", class_def->class_data_offset, class_def->class_data_offset);
114  rz_cons_printf("static_values_offset: %u (0x%06x)\n", class_def->static_values_offset, class_def->static_values_offset);
115  j = rz_list_length(class_def->static_fields);
116  rz_cons_printf("static_fields_size : %u\n", j);
117  j = rz_list_length(class_def->instance_fields);
118  rz_cons_printf("instance_fields_size: %u\n", j);
119  j = rz_list_length(class_def->direct_methods);
120  rz_cons_printf("direct_methods_size : %u\n", j);
121  j = rz_list_length(class_def->virtual_methods);
122  rz_cons_printf("virtual_methods_size: %u\n\n", j);
123 
124  rz_cons_printf("Class #%-13u-\n", index);
125  char *tmp = rz_bin_dex_resolve_type_id_by_idx(dex, class_def->class_idx);
126  rz_cons_printf(" Class descriptor : '%s'\n", tmp);
127  free(tmp);
128  tmp = decode_access_flags(class_def->access_flags);
129  rz_cons_printf(" Access flags : 0x%04x (%s)\n", class_def->access_flags, tmp ? tmp : "");
130  free(tmp);
132  rz_cons_printf(" Superclass : '%s'\n", tmp);
133  free(tmp);
134  rz_cons_printf(" Interfaces -\n");
135  for (j = 0; j < class_def->n_interfaces; ++j) {
136  tmp = rz_bin_dex_resolve_type_id_by_idx(dex, class_def->interfaces[j]);
137  rz_cons_printf(" #%-15u: '%s'\n", j, tmp);
138  free(tmp);
139  }
140  rz_cons_printf(" Static fields -\n");
141  j = 0;
142  rz_list_foreach (class_def->static_fields, it, encoded_field) {
143  dex_print_encoded_field(dex, j, encoded_field);
144  j++;
145  }
146  rz_cons_printf(" Instance fields -\n");
147  j = 0;
148  rz_list_foreach (class_def->instance_fields, it, encoded_field) {
149  dex_print_encoded_field(dex, j, encoded_field);
150  j++;
151  }
152  rz_cons_printf(" Direct methods -\n");
153  j = 0;
154  rz_list_foreach (class_def->direct_methods, it, encoded_method) {
155  dex_print_encoded_method(dex, j, encoded_method);
156  j++;
157  }
158  rz_cons_printf(" Virtual methods -\n");
159  j = 0;
160  rz_list_foreach (class_def->virtual_methods, it, encoded_method) {
161  dex_print_encoded_method(dex, j, encoded_method);
162  j++;
163  }
164 }
165 
167  if (argc != 1) {
169  }
170 
171  RzBinDex *dex = core_dex_get_class(core);
172  if (!dex) {
173  return RZ_CMD_STATUS_ERROR;
174  }
175 
176  // mimic dexdump output
177  char *tmp = NULL;
178  rz_cons_printf("DEX file header:\n");
179  tmp = rz_bin_dex_version(dex);
180  rz_cons_printf("version : %s\n", tmp);
181  free(tmp);
182  rz_cons_printf("checksum : %08x\n", dex->checksum);
183  rz_cons_printf("signature : %02x%02x...%02x%02x\n", dex->signature[0], dex->signature[1], dex->signature[18], dex->signature[19]);
184  rz_cons_printf("file_size : %u\n", dex->file_size);
185  rz_cons_printf("header_size : %u\n", dex->header_size);
186  rz_cons_printf("link_size : %u\n", dex->link_size);
187  rz_cons_printf("link_off : %u (0x%06x)\n", dex->link_offset, dex->link_offset);
188  rz_cons_printf("string_ids_size : %u\n", dex->string_ids_size);
189  rz_cons_printf("string_ids_off : %u (0x%06x)\n", dex->string_ids_offset, dex->string_ids_offset);
190  rz_cons_printf("type_ids_size : %u\n", dex->type_ids_size);
191  rz_cons_printf("type_ids_off : %u (0x%06x)\n", dex->type_ids_offset, dex->type_ids_offset);
192  rz_cons_printf("proto_ids_size : %u\n", dex->proto_ids_size);
193  rz_cons_printf("proto_ids_off : %u (0x%06x)\n", dex->proto_ids_offset, dex->proto_ids_offset);
194  rz_cons_printf("field_ids_size : %u\n", dex->field_ids_size);
195  rz_cons_printf("field_ids_off : %u (0x%06x)\n", dex->field_ids_offset, dex->field_ids_offset);
196  rz_cons_printf("method_ids_size : %u\n", dex->method_ids_size);
197  rz_cons_printf("method_ids_off : %u (0x%06x)\n", dex->method_ids_offset, dex->method_ids_offset);
198  rz_cons_printf("class_defs_size : %u\n", dex->class_defs_size);
199  rz_cons_printf("class_defs_off : %u (0x%06x)\n", dex->class_defs_offset, dex->class_defs_offset);
200  rz_cons_printf("data_size : %u\n", dex->data_size);
201  rz_cons_printf("data_off : %u (0x%06x)\n\n", dex->data_offset, dex->data_offset);
202 
203  for (ut32 i = 0; i < rz_pvector_len(dex->class_defs); ++i) {
204  DexClassDef *class_def = rz_pvector_at(dex->class_defs, i);
205  dex_print_class_def(dex, i, class_def);
206  }
207 
208  return RZ_CMD_STATUS_OK;
209 }
210 
211 static void dex_print_class_def_exports(RzBinDex *dex, ut32 index, DexClassDef *class_def) {
212  ut32 j;
213  RzListIter *it;
214  DexEncodedField *encoded_field;
215  DexEncodedMethod *encoded_method;
216  rz_cons_printf("Class #%-13u-\n", index);
217  char *tmp = rz_bin_dex_resolve_type_id_by_idx(dex, class_def->class_idx);
218  rz_cons_printf(" Class descriptor : '%s'\n", tmp);
219  free(tmp);
220  tmp = decode_access_flags(class_def->access_flags);
221  rz_cons_printf(" Access flags : 0x%04x (%s)\n", class_def->access_flags, tmp ? tmp : "");
222  free(tmp);
224  rz_cons_printf(" Superclass : '%s'\n", tmp);
225  free(tmp);
226  rz_cons_printf(" Interfaces -\n");
227  for (j = 0; j < class_def->n_interfaces; ++j) {
228  tmp = rz_bin_dex_resolve_type_id_by_idx(dex, class_def->interfaces[j]);
229  rz_cons_printf(" #%-15u: '%s'\n", j, tmp);
230  free(tmp);
231  }
232  rz_cons_printf(" Static fields -\n");
233  j = 0;
234  rz_list_foreach (class_def->static_fields, it, encoded_field) {
235  if ((encoded_field->access_flags & (ACCESS_FLAG_PUBLIC | ACCESS_FLAG_PROTECTED)) != 0) {
236  dex_print_encoded_field(dex, j, encoded_field);
237  }
238  j++;
239  }
240  rz_cons_printf(" Instance fields -\n");
241  j = 0;
242  rz_list_foreach (class_def->instance_fields, it, encoded_field) {
243  if ((encoded_field->access_flags & (ACCESS_FLAG_PUBLIC | ACCESS_FLAG_PROTECTED)) != 0) {
244  dex_print_encoded_field(dex, j, encoded_field);
245  }
246  j++;
247  }
248  rz_cons_printf(" Direct methods -\n");
249  j = 0;
250  rz_list_foreach (class_def->direct_methods, it, encoded_method) {
251  if ((encoded_method->access_flags & (ACCESS_FLAG_PUBLIC | ACCESS_FLAG_PROTECTED)) != 0) {
252  dex_print_encoded_method(dex, j, encoded_method);
253  }
254  j++;
255  }
256  rz_cons_printf(" Virtual methods -\n");
257  j = 0;
258  rz_list_foreach (class_def->virtual_methods, it, encoded_method) {
259  if ((encoded_method->access_flags & (ACCESS_FLAG_PUBLIC | ACCESS_FLAG_PROTECTED)) != 0) {
260  dex_print_encoded_method(dex, j, encoded_method);
261  }
262  j++;
263  }
264 }
265 
267  if (argc != 1) {
269  }
270 
271  RzBinDex *dex = core_dex_get_class(core);
272  if (!dex) {
273  return RZ_CMD_STATUS_ERROR;
274  }
275 
276  for (ut32 i = 0; i < rz_pvector_len(dex->class_defs); ++i) {
277  DexClassDef *class_def = rz_pvector_at(dex->class_defs, i);
278  if ((class_def->access_flags & ACCESS_FLAG_PUBLIC) != 0) {
279  dex_print_class_def_exports(dex, i, class_def);
280  }
281  }
282 
283  return RZ_CMD_STATUS_OK;
284 }
285 
286 static const RzCmdDescHelp dex_usage = {
287  .summary = "Core plugin to visualize dex class information",
288 };
289 
290 static_description_without_args(dexs, "prints the dex structure");
291 static_description_without_args(dexe, "prints the dex exported methods");
292 
293 static bool rz_cmd_dex_init_handler(RzCore *core) {
294  RzCmd *rcmd = core->rcmd;
296  if (!root_cd) {
297  return false;
298  }
299 
300  RzCmdDesc *dex = rz_cmd_desc_group_new(rcmd, root_cd, "dex", NULL, NULL, &dex_usage);
301  if (!dex) {
303  return false;
304  }
305 
308 
309  return true;
310 }
311 
313  .name = "dex",
314  .desc = "Suite of dex commands, type `dex` for more info",
315  .license = "LGPL-3.0-only",
316  .author = "deroad",
317  .version = "1.0",
318  .init = rz_cmd_dex_init_handler,
319 };
320 
321 #ifndef RZ_PLUGIN_INCORE
324  .data = &rz_core_plugin_dex,
326 };
327 #endif
#define RZ_IPI
Definition: analysis_wasm.c:11
lzma_index ** i
Definition: index.h:629
RZ_API RzCmdDesc * rz_cmd_get_root(RzCmd *cmd)
Get the root command descriptor.
Definition: cmd_api.c:230
RZ_API RzCmdDesc * rz_cmd_desc_group_new(RzCmd *cmd, RzCmdDesc *parent, const char *name, RzCmdArgvCb cb, const RzCmdDescHelp *help, const RzCmdDescHelp *group_help)
Create a new command descriptor for a name that is used both as a group but that has a sub-command wi...
Definition: cmd_api.c:2233
RZ_API int rz_cons_printf(const char *format,...)
Definition: cons.c:1202
static const RzCmdDescHelp dex_usage
Definition: core_dex.c:286
static bool rz_cmd_dex_init_handler(RzCore *core)
Definition: core_dex.c:293
RzCorePlugin rz_core_plugin_dex
Definition: core_dex.c:312
static void dex_print_class_def_exports(RzBinDex *dex, ut32 index, DexClassDef *class_def)
Definition: core_dex.c:211
RZ_IPI RzCmdStatus rz_cmd_dexe_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state)
Definition: core_dex.c:266
static char * decode_access_flags(ut32 access_flags)
Definition: core_dex.c:45
RZ_API RzLibStruct rizin_plugin
Definition: core_dex.c:322
static void dex_print_encoded_method(RzBinDex *dex, ut32 index, DexEncodedMethod *encoded_method)
Definition: core_dex.c:77
static void dex_print_encoded_field(RzBinDex *dex, ut32 index, DexEncodedField *encoded_field)
Definition: core_dex.c:56
static RzBinDex * core_dex_get_class(RzCore *core)
Definition: core_dex.c:29
#define rz_cmd_desc_argv_modes_new_warn(rcmd, root, cmd, flags)
Definition: core_dex.c:26
static void dex_print_class_def(RzBinDex *dex, ut32 index, DexClassDef *class_def)
Definition: core_dex.c:100
#define static_description_without_args(command, summ)
Definition: core_dex.c:18
RZ_IPI RzCmdStatus rz_cmd_dexs_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state)
Definition: core_dex.c:166
#define RZ_API
#define NULL
Definition: cris-opc.c:27
uint32_t ut32
RZ_API RZ_OWN char * rz_bin_dex_resolve_string_by_idx(RZ_NONNULL RzBinDex *dex, ut32 string_idx)
Returns the resolved string linked to the given string id.
Definition: dex.c:1963
RZ_API RZ_OWN char * rz_bin_dex_resolve_type_id_by_idx(RZ_NONNULL RzBinDex *dex, ut32 type_idx)
Returns the resolved string linked to the given type id.
Definition: dex.c:1949
RZ_API RZ_OWN char * rz_bin_dex_version(RZ_NONNULL RzBinDex *dex)
Returns the dex version (string format)
Definition: dex.c:2016
RZ_API RZ_OWN char * rz_bin_dex_access_flags_readable(ut32 access_flags)
Definition: dex.c:710
RZ_API RZ_OWN char * rz_bin_dex_resolve_proto_by_idx(RZ_NONNULL RzBinDex *dex, ut32 proto_idx)
Returns the resolved string linked to the given prototype id.
Definition: dex.c:1981
#define RZ_DEX_RELOC_ADDRESS
Definition: dex.h:14
@ ACCESS_FLAG_PROTECTED
Definition: dex.h:43
@ ACCESS_FLAG_PUBLIC
Definition: dex.h:41
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
@ field_id
Definition: parser.c:1736
#define rz_warn_if_reached()
Definition: rz_assert.h:29
enum rz_cmd_status_t RzCmdStatus
@ RZ_CMD_STATUS_OK
command handler exited in the right way
Definition: rz_cmd.h:24
@ RZ_CMD_STATUS_WRONG_ARGS
command handler could not handle the arguments passed to it
Definition: rz_cmd.h:25
@ RZ_CMD_STATUS_ERROR
command handler had issues while running (e.g. allocation error, etc.)
Definition: rz_cmd.h:26
@ RZ_LIB_TYPE_CORE
Definition: rz_lib.h:83
#define PFMT64u
Definition: rz_types.h:395
@ RZ_OUTPUT_MODE_STANDARD
Definition: rz_types.h:39
#define PFMT64x
Definition: rz_types.h:393
static size_t rz_pvector_len(const RzPVector *vec)
Definition: rz_vector.h:231
static void * rz_pvector_at(const RzPVector *vec, size_t index)
Definition: rz_vector.h:236
#define RZ_VERSION
Definition: rz_version.h:8
#define toupper(c)
Definition: safe-ctype.h:147
#define b(i)
Definition: sha256.c:42
RzList * instance_fields
Definition: dex.h:154
RzList * direct_methods
Definition: dex.h:155
ut32 class_data_offset
Definition: dex.h:146
ut32 n_interfaces
Definition: dex.h:150
ut32 access_flags
Definition: dex.h:140
ut32 source_file_idx
Definition: dex.h:144
ut16 * interfaces
Definition: dex.h:151
ut32 annotations_offset
Definition: dex.h:145
ut32 interfaces_offset
Definition: dex.h:143
ut32 static_values_offset
Definition: dex.h:147
ut64 offset
Definition: dex.h:148
ut16 superclass_idx
Definition: dex.h:141
ut16 class_idx
Definition: dex.h:138
RzList * virtual_methods
Definition: dex.h:156
RzList * static_fields
Definition: dex.h:153
ut64 field_idx
Definition: dex.h:110
ut64 access_flags
Definition: dex.h:111
ut64 code_offset
Definition: dex.h:126
ut64 access_flags
Definition: dex.h:117
ut32 name_idx
Definition: dex.h:100
ut16 class_idx
Definition: dex.h:98
ut16 proto_idx
Definition: dex.h:99
Definition: dex.h:160
ut32 data_size
Definition: dex.h:186
ut32 type_ids_offset
Definition: dex.h:177
ut32 string_ids_size
Definition: dex.h:174
ut32 proto_ids_size
Definition: dex.h:178
ut8 signature[20]
Definition: dex.h:166
ut32 class_defs_size
Definition: dex.h:184
ut32 type_ids_size
Definition: dex.h:176
ut32 method_ids_size
Definition: dex.h:182
ut32 checksum
Definition: dex.h:164
ut32 link_offset
Definition: dex.h:172
RzPVector * method_ids
Definition: dex.h:193
ut32 header_size
Definition: dex.h:169
RzPVector * field_ids
Definition: dex.h:192
ut32 data_offset
Definition: dex.h:187
RzPVector * class_defs
Definition: dex.h:194
ut32 link_size
Definition: dex.h:171
ut32 string_ids_offset
Definition: dex.h:175
ut32 method_ids_offset
Definition: dex.h:183
ut32 class_defs_offset
Definition: dex.h:185
ut32 field_ids_offset
Definition: dex.h:181
ut32 field_ids_size
Definition: dex.h:180
ut32 proto_ids_offset
Definition: dex.h:179
ut32 file_size
Definition: dex.h:168
RzBinBind binb
Definition: rz_analysis.h:579
RzBin * bin
Definition: rz_bin.h:807
char * name
Definition: rz_bin.h:509
const char * summary
Definition: rz_cmd.h:289
Represent the output state of a command handler.
Definition: rz_cmd.h:91
const char * version
Definition: rz_core.h:128
const char * name
Definition: rz_core.h:124
RzCmd * rcmd
Definition: rz_core.h:319
RzAnalysis * analysis
Definition: rz_core.h:322
Definition: dis.h:43