1 /* radare - Apache 2.0 - Copyright 2010-2019 - pancake and
2 Adam Pridgen <dso@rice.edu || adam.pridgen@thecoverofnight.com> */
3
4 #include <string.h>
5
6 #include <r_types.h>
7 #include <r_lib.h>
8 #include <r_anal.h>
9
10 #include "../../../shlr/java/ops.h"
11 #include "../../../shlr/java/code.h"
12 #include "../../../shlr/java/class.h"
13
14 #define DO_THE_DBG 0
15 #define IFDBG if(DO_THE_DBG)
16
17 static ut64 METHOD_START = 0;
18
19 static void java_update_anal_types (RAnal *anal, RBinJavaObj *bin_obj);
20
21 static int java_cmd_ext(RAnal *anal, const char* input);
22
23 static int java_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask);
24
25 static RBinJavaObj * get_java_bin_obj(RAnal *anal);
26
get_java_bin_obj(RAnal * anal)27 static RBinJavaObj * get_java_bin_obj(RAnal *anal) {
28 RBin *b = anal->binb.bin;
29 RBinPlugin *plugin = b->cur && b->cur->o ? b->cur->o->plugin : NULL;
30 ut8 is_java = (plugin && strcmp (plugin->name, "java") == 0) ? 1 : 0;
31 return is_java ? b->cur->o->bin_obj : NULL;
32 }
33
java_get_method_start(void)34 static ut64 java_get_method_start(void) {
35 return METHOD_START;
36 }
37
java_switch_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * data,int len)38 static int java_switch_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len) {
39 ut8 op_byte = data[0];
40 ut64 offset = addr - java_get_method_start ();
41 ut8 pos = (offset + 1)%4 ? 1 + 4 - (offset+1)%4 : 1;
42
43 if (op_byte == 0xaa) {
44 // handle a table switch condition
45 if (pos + 8 + 8 > len) {
46 return op->size;
47 }
48 const int min_val = (ut32)(UINT (data, pos + 4));
49 const int max_val = (ut32)(UINT (data, pos + 8));
50
51 ut32 default_loc = (ut32) (UINT (data, pos)), cur_case = 0;
52 op->switch_op = r_anal_switch_op_new (addr, min_val, max_val, default_loc);
53 pos += 12;
54 if (max_val > min_val && ((max_val - min_val)<(UT16_MAX/4))) {
55 //caseop = r_anal_switch_op_add_case(op->switch_op, addr+default_loc, -1, addr+offset);
56 for (cur_case = 0; cur_case <= max_val - min_val; pos += 4, cur_case++) {
57 //ut32 value = (ut32)(UINT (data, pos));
58 if (pos + 4 >= len) {
59 // switch is too big can't read further
60 break;
61 }
62 int offset = (int)(ut32)(R_BIN_JAVA_UINT (data, pos));
63 r_anal_switch_op_add_case (op->switch_op, addr + pos, cur_case + min_val, addr + offset);
64 }
65 } else {
66 eprintf ("Invalid switch boundaries at 0x%"PFMT64x"\n", addr);
67 }
68 }
69 op->size = pos;
70 return op->size;
71 }
72
73
extract_bin_op(ut64 ranal2_op_type)74 static ut64 extract_bin_op(ut64 ranal2_op_type) {
75 ut64 bin_op_val = ranal2_op_type & (R_ANAL_JAVA_BIN_OP | 0x80000);
76 switch (bin_op_val) {
77 case R_ANAL_JAVA_BINOP_XCHG:return R_ANAL_OP_TYPE_XCHG;
78 case R_ANAL_JAVA_BINOP_CMP: return R_ANAL_OP_TYPE_CMP;
79 case R_ANAL_JAVA_BINOP_ADD: return R_ANAL_OP_TYPE_ADD;
80 case R_ANAL_JAVA_BINOP_SUB: return R_ANAL_OP_TYPE_SUB;
81 case R_ANAL_JAVA_BINOP_MUL: return R_ANAL_OP_TYPE_MUL;
82 case R_ANAL_JAVA_BINOP_DIV: return R_ANAL_OP_TYPE_DIV;
83 case R_ANAL_JAVA_BINOP_SHR: return R_ANAL_OP_TYPE_SHR;
84 case R_ANAL_JAVA_BINOP_SHL: return R_ANAL_OP_TYPE_SHL;
85 case R_ANAL_JAVA_BINOP_SAL: return R_ANAL_OP_TYPE_SAL;
86 case R_ANAL_JAVA_BINOP_SAR: return R_ANAL_OP_TYPE_SAR;
87 case R_ANAL_JAVA_BINOP_OR : return R_ANAL_OP_TYPE_OR;
88 case R_ANAL_JAVA_BINOP_AND: return R_ANAL_OP_TYPE_AND;
89 case R_ANAL_JAVA_BINOP_XOR: return R_ANAL_OP_TYPE_XOR;
90 case R_ANAL_JAVA_BINOP_NOT: return R_ANAL_OP_TYPE_NOT;
91 case R_ANAL_JAVA_BINOP_MOD: return R_ANAL_OP_TYPE_MOD;
92 case R_ANAL_JAVA_BINOP_ROR: return R_ANAL_OP_TYPE_ROR;
93 case R_ANAL_JAVA_BINOP_ROL: return R_ANAL_OP_TYPE_ROL;
94 default: break;
95 }
96 return R_ANAL_OP_TYPE_UNK;
97 }
98
99
100
101
extract_unknown_op(ut64 ranal2_op_type)102 ut64 extract_unknown_op(ut64 ranal2_op_type) {
103 if ((ranal2_op_type & R_ANAL_JAVA_CODEOP_JMP) == R_ANAL_JAVA_CODEOP_JMP) {
104 return R_ANAL_OP_TYPE_UJMP;
105 }
106 if ((ranal2_op_type & R_ANAL_JAVA_CODEOP_CALL) == R_ANAL_JAVA_CODEOP_CALL) {
107 return R_ANAL_OP_TYPE_UCALL;
108 }
109 if ((ranal2_op_type & R_ANAL_JAVA_LDST_OP_PUSH) == R_ANAL_JAVA_LDST_OP_PUSH) {
110 return R_ANAL_OP_TYPE_UPUSH;
111 }
112 return R_ANAL_OP_TYPE_UNK;
113 }
114
extract_code_op(ut64 ranal2_op_type)115 static ut64 extract_code_op(ut64 ranal2_op_type) {
116 ut64 conditional = R_ANAL_JAVA_COND_OP & ranal2_op_type ? R_ANAL_OP_TYPE_COND : 0;
117 ut64 code_op_val = ranal2_op_type & (R_ANAL_JAVA_CODE_OP | 0x1FF);
118 switch (code_op_val) {
119 case R_ANAL_JAVA_CODEOP_CALL: return conditional | R_ANAL_OP_TYPE_CALL;
120 case R_ANAL_JAVA_CODEOP_JMP: return conditional | R_ANAL_OP_TYPE_JMP;
121 case R_ANAL_JAVA_CODEOP_RET: return conditional | R_ANAL_OP_TYPE_RET;
122 case R_ANAL_JAVA_CODEOP_LEAVE: return R_ANAL_OP_TYPE_LEAVE;
123 case R_ANAL_JAVA_CODEOP_SWI: return R_ANAL_OP_TYPE_SWI;
124 case R_ANAL_JAVA_CODEOP_TRAP: return R_ANAL_OP_TYPE_TRAP;
125 case R_ANAL_JAVA_CODEOP_SWITCH: return R_ANAL_OP_TYPE_SWITCH;
126 }
127 return R_ANAL_OP_TYPE_UNK;
128 }
129
extract_load_store_op(ut64 ranal2_op_type)130 ut64 extract_load_store_op(ut64 ranal2_op_type) {
131 if ( (ranal2_op_type & R_ANAL_JAVA_LDST_OP_PUSH) == R_ANAL_JAVA_LDST_OP_PUSH) {
132 return R_ANAL_OP_TYPE_PUSH;
133 }
134 if ( (ranal2_op_type & R_ANAL_JAVA_LDST_OP_POP) == R_ANAL_JAVA_LDST_OP_POP) {
135 return R_ANAL_OP_TYPE_POP;
136 }
137 if ( (ranal2_op_type & R_ANAL_JAVA_LDST_OP_MOV) == R_ANAL_JAVA_LDST_OP_MOV) {
138 return R_ANAL_OP_TYPE_MOV;
139 }
140 if ( (ranal2_op_type & R_ANAL_JAVA_LDST_OP_EFF_ADDR) == R_ANAL_JAVA_LDST_OP_EFF_ADDR) {
141 return R_ANAL_OP_TYPE_LEA;
142 }
143 return R_ANAL_OP_TYPE_UNK;
144 }
145
map_java_op_to_anal_op_type(ut64 t)146 static ut64 map_java_op_to_anal_op_type (ut64 t) {
147 ut64 t2 = extract_bin_op(t);
148 if (t2 != R_ANAL_OP_TYPE_UNK) {
149 return t2;
150 }
151 switch (t) {
152 case R_ANAL_JAVA_NULL_OP: return R_ANAL_OP_TYPE_NULL;
153 case R_ANAL_JAVA_NOP: return R_ANAL_OP_TYPE_NOP;
154 case R_ANAL_JAVA_BINOP_ADD: return R_ANAL_OP_TYPE_ADD;
155 case R_ANAL_JAVA_BINOP_AND: return R_ANAL_OP_TYPE_AND;
156 case R_ANAL_JAVA_BINOP_MUL: return R_ANAL_OP_TYPE_MUL;
157 case R_ANAL_JAVA_BINOP_XOR: return R_ANAL_OP_TYPE_XOR;
158 case R_ANAL_JAVA_BINOP_XCHG: return R_ANAL_OP_TYPE_MOV;
159 case R_ANAL_JAVA_OBJOP_NEW: return R_ANAL_OP_TYPE_UCALL;
160 case R_ANAL_JAVA_OBJOP_SIZE: return R_ANAL_OP_TYPE_UCALL;
161 case R_ANAL_JAVA_ILL_OP: return R_ANAL_OP_TYPE_ILL;
162 default:
163 if (t & R_ANAL_JAVA_UNK_OP) {
164 return extract_unknown_op (t);
165 }
166 if (t & R_ANAL_JAVA_CODE_OP) {
167 return extract_code_op (t);
168 }
169 if (t & R_ANAL_JAVA_REP_OP) {
170 ut64 ret = map_java_op_to_anal_op_type (t & ~R_ANAL_JAVA_REP_OP);
171 return R_ANAL_OP_TYPE_REP | ret;
172 }
173 if (t & (R_ANAL_JAVA_LOAD_OP | R_ANAL_JAVA_STORE_OP)) {
174 return extract_load_store_op(t);
175 }
176 if (t & R_ANAL_JAVA_BIN_OP) {
177 return extract_bin_op (t);
178 }
179 break;
180 }
181 if (R_ANAL_JAVA_OBJOP_CAST & t) {
182 return R_ANAL_OP_TYPE_MOV;
183 }
184 return R_ANAL_OP_TYPE_UNK;
185 }
186
r_anal_java_is_op_type_eop(ut64 x)187 static int r_anal_java_is_op_type_eop(ut64 x) {
188 ut8 result = (x & R_ANAL_JAVA_CODE_OP) ? 1 : 0;
189 return result &&
190 ( (x & R_ANAL_JAVA_CODEOP_LEAVE) == R_ANAL_JAVA_CODEOP_LEAVE ||
191 (x & R_ANAL_JAVA_CODEOP_RET) == R_ANAL_JAVA_CODEOP_RET ||
192 (x & R_ANAL_JAVA_CODEOP_JMP) == R_ANAL_JAVA_CODEOP_JMP ||
193 (x & R_ANAL_JAVA_CODEOP_SWITCH) == R_ANAL_JAVA_CODEOP_SWITCH);
194 }
195
196
java_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * data,int len,RAnalOpMask mask)197 static int java_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) {
198 /* get opcode size */
199 if (len < 1) {
200 op->type = R_ANAL_OP_TYPE_ILL;
201 return 1;
202 }
203 //ut8 op_byte = data[0];
204 ut8 op_byte = data[0];
205 int sz = JAVA_OPS[op_byte].size;
206 if (!op) {
207 op->type = R_ANAL_OP_TYPE_ILL;
208 return sz;
209 }
210 IFDBG {
211 //eprintf ("Extracting op from buffer (%d byte(s)) @ 0x%04x\n", len, addr);
212 //eprintf ("Parsing op: (0x%02x) %s.\n", op_byte, JAVA_OPS[op_byte].name);
213 }
214 op->addr = addr;
215 op->size = sz;
216 op->id = data[0];
217 op->type2 = JAVA_OPS[op_byte].op_type;
218 op->type = map_java_op_to_anal_op_type (op->type2);
219 // handle lookup and table switch offsets
220 if (op_byte == 0xaa || op_byte == 0xab) {
221 java_switch_op (anal, op, addr, data, len);
222 // IN_SWITCH_OP = 1;
223 }
224 /* TODO:
225 // not sure how to handle the states for IN_SWITCH_OP, SWITCH_OP_CASES,
226 // and NUM_CASES_SEEN, because these are dependent on whether or not we
227 // are in a switch, and given the non-reentrant state of opcode analysis
228 // this can't always be guaranteed. Below is the pseudo code for handling
229 // the easy parts though
230 if (IN_SWITCH_OP) {
231 NUM_CASES_SEEN++;
232 if (NUM_CASES_SEEN == SWITCH_OP_CASES) IN_SWITCH_OP=0;
233 op->addr = addr;
234 op->size = 4;
235 op->type2 = 0;
236 op->type = R_ANAL_OP_TYPE_CASE
237 op->eob = 0;
238 return op->sizes;
239 }
240 */
241
242 op->eob = r_anal_java_is_op_type_eop (op->type2);
243 IFDBG {
244 const char *ot_str = r_anal_optype_to_string (op->type);
245 eprintf ("op_type2: %s @ 0x%04"PFMT64x" 0x%08"PFMT64x" op_type: (0x%02"PFMT64x") %s.\n",
246 JAVA_OPS[op_byte].name, addr, (ut64)op->type2, (ut64)op->type, ot_str);
247 //eprintf ("op_eob: 0x%02x.\n", op->eob);
248 //eprintf ("op_byte @ 0: 0x%02x op_byte @ 0x%04x: 0x%02x.\n", data[0], addr, data[addr]);
249 }
250
251 if (len < 4) {
252 // incomplete analysis here
253 return 0;
254 }
255 if (op->type == R_ANAL_OP_TYPE_POP) {
256 op->stackop = R_ANAL_STACK_INC;
257 op->stackptr = 8;
258 }
259 op->direction = R_ANAL_OP_DIR_EXEC;
260 if (op->type == R_ANAL_OP_TYPE_PUSH) {
261 op->stackop = R_ANAL_STACK_INC;
262 op->stackptr = -8;
263 }
264 if (op->type == R_ANAL_OP_TYPE_CJMP) {
265 op->jump = addr + (short)(USHORT (data, 1));
266 op->fail = addr + sz;
267 IFDBG eprintf ("%s jmpto 0x%04"PFMT64x" failto 0x%04"PFMT64x".\n",
268 JAVA_OPS[op_byte].name, op->jump, op->fail);
269 } else if (op->type == R_ANAL_OP_TYPE_JMP) {
270 op->jump = addr + (short)(USHORT (data, 1));
271 IFDBG eprintf ("%s jmpto 0x%04"PFMT64x".\n", JAVA_OPS[op_byte].name, op->jump);
272 } else if ( (op->type & R_ANAL_OP_TYPE_CALL) == R_ANAL_OP_TYPE_CALL ) {
273 op->jump = (int)(short)(USHORT (data, 1));
274 op->fail = addr + sz;
275 //IFDBG eprintf ("%s callto 0x%04x failto 0x%04x.\n", JAVA_OPS[op_byte].name, op->jump, op->fail);
276 }
277
278 //r_java_disasm(addr, data, len, output, outlen);
279 //IFDBG eprintf ("%s\n", output);
280 return op->size;
281 }
282
283
java_update_anal_types(RAnal * anal,RBinJavaObj * bin_obj)284 static void java_update_anal_types (RAnal *anal, RBinJavaObj *bin_obj) {
285 Sdb *D = anal->sdb_types;
286 if (D && bin_obj) {
287 RListIter *iter;
288 char *str;
289 RList * the_list = r_bin_java_extract_all_bin_type_values (bin_obj);
290 if (the_list) {
291 r_list_foreach (the_list, iter, str) {
292 IFDBG eprintf ("Adding type: %s to known types.\n", str);
293 if (str) {
294 sdb_set (D, str, "type", 0);
295 }
296 }
297 }
298 r_list_free (the_list);
299 }
300 }
301
java_cmd_ext(RAnal * anal,const char * input)302 static int java_cmd_ext(RAnal *anal, const char* input) {
303 RBinJavaObj *obj = (RBinJavaObj *) get_java_bin_obj (anal);
304
305 if (!obj) {
306 eprintf ("Execute \"af\" to set the current bin, and this will bind the current bin\n");
307 return -1;
308 }
309 switch (*input) {
310 case 'c':
311 // reset bytes counter for case operations
312 r_java_new_method ();
313 break;
314 case 'u':
315 switch (*(input+1)) {
316 case 't': {java_update_anal_types (anal, obj); return true;}
317 default: break;
318 }
319 break;
320 case 's':
321 switch (*(input+1)) {
322 //case 'e': return java_resolve_cp_idx_b64 (anal, input+2);
323 default: break;
324 }
325 break;
326
327 default: eprintf("Command not supported"); break;
328 }
329 return 0;
330 }
331
332 RAnalPlugin r_anal_plugin_java = {
333 .name = "java",
334 .desc = "Java bytecode analysis plugin",
335 .license = "Apache",
336 .arch = "java",
337 .bits = 32,
338 .op = &java_op,
339 .cmd_ext = java_cmd_ext,
340 0
341 };
342
343 #ifndef R2_PLUGIN_INCORE
344 R_API RLibStruct radare_plugin = {
345 .type = R_LIB_TYPE_ANAL,
346 .data = &r_anal_plugin_java,
347 .version = R2_VERSION
348 };
349 #endif
350