1 /* radare - LGPL - Copyright 2012-2017 - pancake */
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 
7 #include <r_lib.h>
8 #include <r_util.h>
9 #include <r_flag.h>
10 #include <r_anal.h>
11 #include <r_parse.h>
12 
replace(int argc,const char * argv[],char * newstr)13 static int replace(int argc, const char *argv[], char *newstr) {
14 	int i,j,k;
15 	struct {
16 		char *op;
17 		char *str;
18 	} ops[] = {
19 		{ "rsub-int",   "1 = 2 - 3"},
20 		{ "float-to-double", "1 = (double)(float) 2"},
21 		{ "float-to-long", "1 = (long)(float) 2"},
22 		{ "float-to-int", "1 = (int)(float) 2"},
23 		{ "long-to-float", "1 = (float)(long) 2"},
24 		{ "long-to-int", "1 = (int)(long) 2"},
25 		{ "long-to-double", "1 = (double) 2"},
26 		{ "double-to-long", "1 = (long) 2"},
27 		{ "double-to-int", "1 = (int) 2"},
28 		{ "int-to-double", "1 = (double) 2"},
29 		{ "int-to-long", "1 = (long) 2"},
30 		{ "int-to-byte", "1 = (byte) 2"},
31 		{ "aget-byte", "1 = (byte) 2[3]"},
32 		{ "aget-short", "1 = (short) 2[3]"},
33 		{ "aget-object", "1 = (object) 2[3]"},
34 		{ "sput-wide", "1 = 2"},
35 		{ "sput-object", "1 = 2"},
36 		{ "add-long", "1 = 2 + 3"},
37 		{ "add-double", "1 = 2 + 3"},
38 		{ "mul-long", "1 = 2 * 3"},
39 		{ "const-string/jumbo", "1 = (jumbo-string) 2"},
40 		{ "const-string", "1 = (string) 2"},
41 		{ "const-wide", "1 = (wide) 2"},
42 		{ "const/4", "1 = (wide) 2"},
43 		{ "cmp-int", "1 = (2 == 3)"},
44 		{ "cmp-long", "1 = (2 == 3)"},
45 		{ "cmpl-double", "1 = (double)(2 == 3)"},
46 		{ "cmpl-float", "1 = (float)(2 == 3)"},
47 		{ "cmpl-int", "1 = (int)(2 == 3)"},
48 		{ "cmpg-double", "1 = (2 == 3)"},
49 		{ "cmpg-float", "1 = (2 == 3)"},
50 		{ "or-int/2addr", "1 |= 2"},
51 		{ "or-long", "1 |= 2"},
52 		{ "and-long/2addr", "1 &= (long) 2"},
53 		{ "and-int", "1 &= (int) 2"},
54 		{ "and-byte", "1 &= (byte) 2"},
55 		{ "sub-float/2addr", "1 -= 2"},
56 		{ "sub-float", "1 = 2 - 3"},
57 		{ "sub-int", "1 = (int) 2 - 3"},
58 		{ "sub-long", "1 = (long) 2 - 3"},
59 		{ "sub-long/2addr", "1 -= (long) 2"},
60 		{ "sub-int/2addr", "1 -= 2"},
61 		{ "move", "1 = 2"},
62 		{ "move/16", "1 = 2"},
63 		{ "move-object", "1 = (object) 2"},
64 		{ "move-object/16", "1 = (object) 2"},
65 		{ "move-object/from16", "1 = (object) 2"},
66 		{ "move-wide/from16", "1 = (wide) 2"},
67 		{ "array-length", "1 = Array.length (2)"},
68 		{ "new-array", "1 = new array (2, 3)"},
69 		{ "new-instance", "1 = new 2"},
70 		{ "shr-long/2addr", "1 >>= 2"},
71 		{ "shr-long", "1 = (long) 2 >> 3"},
72 		{ "shr-int", "1 = (int) 2 >> 3"},
73 		{ "ushr-int", "1 = (int) 2 >>> 3"},
74 		{ "ushr-int/2addr", "1 >>>= 2"},
75 		{ "ushr-long", "1 = (long) 2 >>> 3"},
76 		{ "ushl-int/2addr", "1 <<<= 2"},
77 		{ "shl-int/2addr", "1 <<<= 2"},
78 		{ "shl-int", "1 = (int) 2 << 3"},
79 		{ "shl-long", "1 = (long) 2 << 3"},
80 		{ "move/from16", "1 = 2"},
81 		{ "move-exception", "1 = exception"},
82 		{ "move-result", "1 = result"},
83 		{ "move-result-wide", "1 = (wide) result"},
84 		{ "move-result-object", "1 = (object) result"},
85 		{ "const-wide/high16", "1 = 2"},
86 		{ "const/16", "1 = 2"},
87 		{ "const-wide/16", "1 = 2"},
88 		{ "const-wide/32", "1 = 2"},
89 		{ "const-class", "1 = (class) 2"},
90 		{ "const/high16", "1 = 2"},
91 		{ "const", "1 = 2"},
92 		{ "rem-long", "1 = (long) 2 % 3"},
93 		{ "rem-double", "1 = (double) 2 % 3"},
94 		{ "rem-float", "1 = (float) 2 % 3"},
95 		{ "rem-long/2addr", "1 %= 2"},
96 		{ "rem-float/2addr", "1 %= (float) 2"},
97 		{ "rem-double/2addr", "1 %= (double) 2"},
98 		{ "instance-of", "1 = insteanceof (2) == 3"},
99 		{ "aput", "2[3] = 1"},
100 		{ "aput-byte", "2[3] = (byte) 1"},
101 		{ "aput-short", "2[3] = (short) 1"},
102 		{ "aput-object", "2[3] = (object) 1"},
103 		{ "aput-wide", "2[3] = (wide) 1"},
104 		{ "aput-char", "2[3] = (char) 1"},
105 		{ "aput-boolean", "2[3] = (bool) 1"},
106 		{ "aget", "1 = 2[3]"},
107 		{ "aget-wide", "1 = (wide) 2[3]"},
108 		{ "aget-char", "1 = (char) 2[3]"},
109 		{ "aget-boolean", "1 = (boolean) 2[3]"},
110 		{ "sget", "1 = 2"},
111 		{ "sget-char", "1 = (char) 2"},
112 		{ "sget-short", "1 = (short) 2"},
113 		{ "sget-boolean", "1 = (bool) 2"},
114 		{ "sget-object", "1 = (object) 2"},
115 		{ "iput", "2[3] = 1"},
116 		{ "iput-object", "2[3] = (object) 1"},
117 		{ "iput-byte", "2[3] = (byte) 1"},
118 		{ "iput-char", "2[3] = (char) 1"},
119 		{ "iput-boolean", "2[3] = (bool) 1"},
120 		{ "sput-boolean", "2[3] = (bool) 1"},
121 		{ "sput-char", "2[3] = (char) 1"},
122 		{ "iput-int", "2[3] = (int) 1"},
123 		{ "iget", "1 = 2[3]"},
124 		{ "sget-byte", "1 = (byte) 2 [3]"},
125 		{ "iget-byte", "1 = (byte) 2 [3]"},
126 		{ "iget-char", "1 = (char) 2 [3]"},
127 		{ "iget-short", "1 = (short) 2 [3]"},
128 		{ "iget-wide", "1 = (wide) 2 [3]"},
129 		{ "iget-object", "1 = (2) 3"},
130 		{ "iget-boolean", "1 = (bool) 2 [3]"},
131 		{ "+iget-wide-volatile", "1 = (wide-volatile) 2 [3]"},
132 		{ "if-eq", "if (1 == 2) goto 3"},
133 		{ "if-lt", "if (1 < 2) goto 3"},
134 		{ "if-ne", "if (1 != 2) goto 3"},
135 		{ "if-eqz", "if (!1) goto 2"},
136 		{ "if-ge", "if (1 > zero) goto 2"},
137 		{ "if-le", "if (1 <= 2) goto 3"},
138 		{ "if-gtz", "if (1 > 0) goto 2"},
139 		{ "filled-new-array", "1 = new Array(2)"},
140 		{ "neg-long", "1 = -2"},
141 		{ "neg-double", "1 = -2"},
142 		{ "neg-float", "1 = -2"},
143 		{ "not-int", "1 = !2"},
144 		{ "packed-switch", "switch 2"},
145 		{ "sparse-switch", "switch 2"},
146 		{ "invoke-direct", "call 2 1"},
147 		{ "invoke-direct/range", "call 2 1"},
148 		{ "invoke-interface", "call 2 1"},
149 		{ "invoke-static", "call 2 1"},
150 		{ "invoke-super", "call super 2 1"},
151 		{ "invoke-super/range", "call super 2 1"},
152 		{ "invoke-polymorphic", "call polymorphic 2 1" },
153 		{ "invoke-virtual/range", "call 2 1"},
154 		{ "invoke-virtual", "call 2 1"},
155 		{ "+invoke-virtual-quick", "call 2 1"},
156 		{ "+invoke-interface/range", "call 2 1"},
157 		{ "invoke-interface/range", "call 2 1"},
158 		{ "div-float/2addr", "1 /= (float) 2"},
159 		{ "div-double/2addr", "1 /= (double) 2"},
160 		{ "div-double", "1 = (double) 2 / 3"},
161 		{ "div-float", "1 = 2 / 3"},
162 		{ "div-int/lit8", "1 = 2 / 3"},
163 		{ "div-int/lit16", "1 = 2 / 3"},
164 		{ "div-int/2addr", "1 /= 2"},
165 		{ "div-int", "1 = (int)(2 / 3)"},
166 		{ "goto/16", "goto 1"},
167 		{ "goto/32", "goto 1"},
168 		{ "or-int", "1 = (int)(2 | 3)"},
169 		{ "xor-int", "1 = (int)(2 ^ 3)"},
170 		{ "xor-int/2addr", "1 ^= 2"},
171 		{ "xor-byte", "1 = (byte)(2 ^ 3)"},
172 		{ "xor-short", "1 = (short)(2 ^ 3)"},
173 		{ "sub-int", "1 = (int)(2 - 3)"},
174 		{ "if-nez", "if (1) goto 2"},
175 		{ "if-ltz", "if (1 <=) goto 2"},
176 		{ "mul-int", "1 = (int)(2 * 3)"},
177 		{ "mul-int/lit8", "1 = (2 * 3)"},
178 		{ "check-cast", "if (1 instanceof 2)"},
179 		{ "add-int", "1 = (int)(2 + 3)"},
180 		{ "add-int/lit8", "1 = 2 + 3"},
181 		{ "add-int/lit16", "1 = 2 + 3"},
182 		{ "add-int/2addr", "1 += 2"},
183 		{ "add-double", "1 = (double)(2 + 3)"},
184 		{ "add-double/2addr", "1 += (double)2"},
185 		{ "mul-float/2addr", "1 *= 2"},
186 		{ "mul-float", "1 = 2 * 3"},
187 		{ "xor-long", "1 = (long)(2 ^ 3)"},
188 		{ "mul-double", "1 = 2 * 3"},
189 		{ "move-wide", "1 = 2"},
190 		{ "move-wide/16", "1 = 2"},
191 		{ "return-wide", "return (wide) 1"},
192 		{ "return-object", "return (object) 1"},
193 		// { "sget", "1 = 2[3]"},
194 		{ NULL }
195 	};
196 
197 	for (i=0; ops[i].op != NULL; i++) {
198 		if (!strcmp (ops[i].op, argv[0])) {
199 			if (newstr != NULL) {
200 				for (j=k=0;ops[i].str[j]!='\0';j++,k++) {
201 					if (ops[i].str[j]>='1' && ops[i].str[j]<='9') {
202 						const char *w = argv[ ops[i].str[j]-'0' ];
203 						if (w != NULL) {
204 							strcpy (newstr+k, w);
205 							k += strlen(w)-1;
206 						}
207 					} else {
208 						newstr[k] = ops[i].str[j];
209 					}
210 				}
211 				newstr[k]='\0';
212 			}
213 			return true;
214 		}
215 	}
216 
217 	/* TODO: this is slow */
218 	if (newstr != NULL) {
219 		newstr[0] = '\0';
220 		for (i=0; i<argc; i++) {
221 			strcat (newstr, argv[i]);
222 			strcat (newstr, (i == 0 || i== argc - 1)?" ":", ");
223 		}
224 	}
225 
226 	return false;
227 }
228 
parse(RParse * p,const char * data,char * str)229 static int parse(RParse *p, const char *data, char *str) {
230 	int i, len = strlen (data);
231 	char *buf, *ptr, *optr, *ptr2;
232 	char w0[64];
233 	char w1[64];
234 	char w2[64];
235 	char w3[64];
236 	char w4[64];
237 
238 	if (!strcmp (data, "invalid")
239 	||  !strcmp (data, "nop")
240 	||  !strcmp (data, "DEPRECATED")) {
241 		str[0] = 0;
242 		return true;
243 	}
244 
245 	// malloc can be slow here :?
246 	if (!(buf = malloc (len + 1))) {
247 		return false;
248 	}
249 	memcpy (buf, data, len + 1);
250 
251 	r_str_trim (buf);
252 
253 	if (*buf) {
254 		w0[0]='\0';
255 		w1[0]='\0';
256 		w2[0]='\0';
257 		w3[0]='\0';
258 		w4[0]='\0';
259 		ptr = strchr (buf, ' ');
260 		if (!ptr) {
261 			ptr = strchr (buf, '\t');
262 		}
263 		if (ptr) {
264 			*ptr = '\0';
265 			for (++ptr; *ptr == ' '; ptr++) {
266 				;
267 			}
268 			strncpy (w0, buf, sizeof (w0) - 1);
269 			w0[sizeof(w0)-1] = '\0';
270 			strncpy (w1, ptr, sizeof (w1) - 1);
271 			w1[sizeof(w1)-1] = '\0';
272 
273 			optr=ptr;
274 			ptr2 = strchr (ptr, '}');
275 			if (ptr2) {
276 				ptr = ptr2 + 1;
277 			}
278 			ptr = strchr (ptr, ',');
279 			if (ptr) {
280 				*ptr = '\0';
281 				for (++ptr; *ptr == ' '; ptr++) {
282 					;
283 				}
284 				strncpy (w1, optr, sizeof (w1) - 1);
285 				w1[sizeof(w1)-1] = '\0';
286 				strncpy (w2, ptr, sizeof (w2) - 1);
287 				w2[sizeof(w2)-1] = '\0';
288 				optr=ptr;
289 				ptr = strchr (ptr, ',');
290 				if (ptr) {
291 					*ptr = '\0';
292 					for (++ptr; *ptr == ' '; ptr++) {
293 						;
294 					}
295 					strncpy (w2, optr, sizeof (w2) - 1);
296 					w2[sizeof(w2)-1] = '\0';
297 					strncpy (w3, ptr, sizeof (w3) - 1);
298 					w3[sizeof(w3)-1] = '\0';
299 					optr=ptr;
300 // bonus
301 					ptr = strchr (ptr, ',');
302 					if (ptr) {
303 						*ptr = '\0';
304 						for (++ptr; *ptr == ' '; ptr++) {
305 							;
306 						}
307 						strncpy (w3, optr, sizeof (w3) - 1);
308 						w3[sizeof(w3)-1] = '\0';
309 						strncpy (w4, ptr, sizeof (w4) - 1);
310 						w4[sizeof(w4)-1] = '\0';
311 					}
312 				}
313 			}
314 		}
315 		{
316 			const char *wa[] = { w0, w1, w2, w3, w4 };
317 			int nw = 0;
318 			for (i=0; i<4; i++) {
319 				if (wa[i][0] != '\0') {
320 					nw++;
321 				}
322 			}
323 			replace (nw, wa, str);
324 {
325 	char *p = strdup (str);
326 	p = r_str_replace (p, "+ -", "- ", 0);
327 #if EXPERIMENTAL_ZERO
328 	p = r_str_replace (p, "zero", "0", 0);
329 	if (!memcmp (p, "0 = ", 4)) *p = 0; // nop
330 #endif
331 	if (!strcmp (w1, w2)) {
332 		char a[32], b[32];
333 #define REPLACE(x,y) do { \
334 		int snprintf_len1_ = snprintf (a, 32, x, w1, w1); \
335 		int snprintf_len2_ = snprintf (b, 32, y, w1); \
336 		if (snprintf_len1_ < 32 && snprintf_len2_ < 32) { \
337 			p = r_str_replace (p, a, b, 0); \
338 		} \
339 	} while (0)
340 
341 		// TODO: optimize
342 		REPLACE ("%s = %s +", "%s +=");
343 		REPLACE ("%s = %s -", "%s -=");
344 		REPLACE ("%s = %s &", "%s &=");
345 		REPLACE ("%s = %s |", "%s |=");
346 		REPLACE ("%s = %s ^", "%s ^=");
347 		REPLACE ("%s = %s >>", "%s >>=");
348 		REPLACE ("%s = %s <<", "%s <<=");
349 	}
350 	strcpy (str, p);
351 	free (p);
352 }
353 		}
354 	}
355 	free (buf);
356 	return true;
357 }
358 
359 RParsePlugin r_parse_plugin_dalvik_pseudo = {
360 	.name = "dalvik.pseudo",
361 	.desc = "DALVIK pseudo syntax",
362 	.init = NULL,
363 	.fini = NULL,
364 	.parse = parse,
365 };
366 
367 #ifndef R2_PLUGIN_INCORE
368 R_API RLibStruct radare_plugin = {
369 	.type = R_LIB_TYPE_PARSE,
370 	.data = &r_parse_plugin_dalvik_pseudo,
371 	.version = R2_VERSION
372 };
373 #endif
374