1 /* radare - LGPL - Copyright 2012-2017 - pancake */
2 
3 #include <r_anal.h>
4 
5 #define MINLEN 1
is_string(const ut8 * buf,int size,int * len)6 static int is_string(const ut8 *buf, int size, int *len) {
7 	int i;
8 	if (size < 1) {
9 		return 0;
10 	}
11 	if (size > 3 && buf[0] && !buf[1] && buf[2] && !buf[3]) {
12 		*len = 1; // XXX: TODO: Measure wide string length
13 		return 2; // is wide
14 	}
15 	for (i = 0; i < size; i++) {
16 		if (!buf[i] && i > MINLEN) {
17 			*len = i;
18 			return 1;
19 		}
20 		if (buf[i] == 10 || buf[i] == 13 || buf[i] == 9) {
21 			continue;
22 		}
23 		if (buf[i] < 32 || buf[i] > 127) {
24 			// not ascii text
25 			return 0;
26 		}
27 		if (!IS_PRINTABLE (buf[i])) {
28 			*len = i;
29 			return 0;
30 		}
31 	}
32 	*len = i;
33 	return 1;
34 }
35 
is_number(const ut8 * buf,int size)36 static int is_number(const ut8 *buf, int size) {
37 	ut64 n = r_mem_get_num (buf, size);
38 	return (n < UT32_MAX)? (int)n: 0;
39 }
40 
is_null(const ut8 * buf,int size)41 static int is_null(const ut8 *buf, int size) {
42 	const char zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
43 	return (!memcmp (buf, &zero, size))? 1: 0;
44 }
45 
is_invalid(const ut8 * buf,int size)46 static int is_invalid(const ut8 *buf, int size) {
47 	if (size < 1) {
48 		return 1;
49 	}
50 	if (size > 8) {
51 		size = 8;
52 	}
53 	return (!memcmp (buf, "\xff\xff\xff\xff\xff\xff\xff\xff", size))? 1: 0;
54 }
55 
56 #define USE_IS_VALID_OFFSET 1
is_pointer(RAnal * anal,const ut8 * buf,int size)57 static ut64 is_pointer(RAnal *anal, const ut8 *buf, int size) {
58 	ut64 n;
59 	ut8 buf2[32];
60 	RIOBind *iob = &anal->iob;
61 	if (size > sizeof (buf2)) {
62 		size = sizeof (buf2);
63 	}
64 	n = r_mem_get_num (buf, size);
65 	if (!n) {
66 		return 1; // null pointer
67 	}
68 #if USE_IS_VALID_OFFSET
69 	int r = iob->is_valid_offset (iob->io, n, 0);
70 	return r? n: 0LL;
71 #else
72 	// optimization to ignore very low and very high pointers
73 	// this makes disasm 5x faster, but can result in some false positives
74 	// we should compare with current offset, to avoid
75 	// short/long references. and discard invalid ones
76 	if (n < 0x1000) return 0;	// probably wrong
77 	if (n > 0xffffffffffffLL) return 0; // probably wrong
78 
79 	if (iob->read_at (iob->io, n, buf2, size) != size) return 0;
80 	return is_invalid (buf2, size)? 0: n;
81 #endif
82 }
83 
is_bin(const ut8 * buf,int size)84 static bool is_bin(const ut8 *buf, int size) {
85 	// TODO: add more magic signatures heres
86 	if ((size >= 4 && !memcmp (buf, "\xcf\xfa\xed\xfe", 4))) {
87 		return true;
88 	}
89 	if ((size >= 4 && !memcmp (buf, "\x7f\x45\x4c\x46", 4))) { // \x7fELF
90 		return true;
91 	}
92 	if ((size >= 2 && !memcmp (buf, "MZ", 2))) {
93 		return true;
94 	}
95 	return false;
96 }
97 
98 // TODO: add is_flag, is comment?
99 
r_anal_data_to_string(RAnalData * d,RConsPrintablePalette * pal)100 R_API char *r_anal_data_to_string(RAnalData *d, RConsPrintablePalette *pal) {
101 	int i, len, mallocsz = 1024;
102 	ut32 n32;
103 
104 	if (!d) {
105 		return NULL;
106 	}
107 
108 	RStrBuf *sb = r_strbuf_new (NULL);
109 	if (!sb || !r_strbuf_reserve (sb, mallocsz)) {
110 		eprintf ("Cannot allocate %d byte(s)\n", mallocsz);
111 		return NULL;
112 	}
113 	if (pal) {
114 		const char *k = pal->offset;
115 		r_strbuf_appendf (sb, "%s0x%08" PFMT64x Color_RESET"  ", k, d->addr);
116 	} else {
117 		r_strbuf_appendf (sb, "0x%08" PFMT64x "  ", d->addr);
118 	}
119 	n32 = (ut32)d->ptr;
120 	len = R_MIN (d->len, 8);
121 	for (i = 0; i < len; i++) {
122 		r_strbuf_appendf (sb, "%02x", d->buf[i]);
123 	}
124 	if (i > 0 && d->len > len) {
125 		r_strbuf_append (sb, "..");
126 	}
127 	r_strbuf_append (sb, "  ");
128 	switch (d->type) {
129 	case R_ANAL_DATA_TYPE_STRING:
130 		if (pal) {
131 			r_strbuf_appendf (sb, "%sstring \"%s\""Color_RESET, pal->comment, d->str);
132 		} else {
133 			r_strbuf_appendf (sb, "string \"%s\"", d->str);
134 		}
135 		break;
136 	case R_ANAL_DATA_TYPE_WIDE_STRING:
137 		r_strbuf_append (sb, "wide string");
138 		break;
139 	case R_ANAL_DATA_TYPE_NUMBER:
140 		if (pal) {
141 			const char *k = pal->num;
142 			if (n32 == d->ptr) {
143 				r_strbuf_appendf (sb, "%snumber %d (0x%x)"Color_RESET, k, n32, n32);
144 			} else {
145 				r_strbuf_appendf (sb, "%snumber %" PFMT64d " (0x%" PFMT64x ")"Color_RESET,
146 						k, d->ptr, d->ptr);
147 			}
148 		} else {
149 			if (n32 == d->ptr) {
150 				r_strbuf_appendf (sb, "number %d 0x%x", n32, n32);
151 			} else {
152 				r_strbuf_appendf (sb, "number %" PFMT64d " 0x%" PFMT64x,
153 						d->ptr, d->ptr);
154 			}
155 		}
156 		break;
157 	case R_ANAL_DATA_TYPE_POINTER:
158 		r_strbuf_append (sb, "pointer ");
159 		if (pal) {
160 			const char *k = pal->offset;
161 			r_strbuf_appendf (sb, " %s0x%08" PFMT64x, k, d->ptr);
162 		} else {
163 			r_strbuf_appendf (sb, " 0x%08" PFMT64x, d->ptr);
164 		}
165 		break;
166 	case R_ANAL_DATA_TYPE_INVALID:
167 		if (pal) {
168 			r_strbuf_appendf (sb, "%sinvalid"Color_RESET, pal->invalid);
169 		} else {
170 			r_strbuf_append (sb, "invalid");
171 		}
172 		break;
173 	case R_ANAL_DATA_TYPE_HEADER:
174 		r_strbuf_append (sb, "header");
175 		break;
176 	case R_ANAL_DATA_TYPE_SEQUENCE:
177 		r_strbuf_append (sb, "sequence");
178 		break;
179 	case R_ANAL_DATA_TYPE_PATTERN:
180 		r_strbuf_append (sb, "pattern");
181 		break;
182 	case R_ANAL_DATA_TYPE_UNKNOWN:
183 		if (pal) {
184 			r_strbuf_appendf (sb, "%sunknown"Color_RESET, pal->invalid);
185 		} else {
186 			r_strbuf_append (sb, "unknown");
187 		}
188 		break;
189 	default:
190 		if (pal) {
191 			r_strbuf_appendf (sb, "%s(null)"Color_RESET, pal->b0x00);
192 		} else {
193 			r_strbuf_append (sb, "(null)");
194 		}
195 		break;
196 	}
197 	return r_strbuf_drain (sb);
198 }
199 
r_anal_data_new_string(ut64 addr,const char * p,int len,int type)200 R_API RAnalData *r_anal_data_new_string(ut64 addr, const char *p, int len, int type) {
201 	RAnalData *ad = R_NEW0 (RAnalData);
202 	if (!ad) {
203 		return NULL;
204 	}
205 	ad->str = NULL;
206 	ad->addr = addr;
207 	ad->type = type;
208 	if (len == 0) {
209 		len = strlen (p);
210 	}
211 
212 	if (type == R_ANAL_DATA_TYPE_WIDE_STRING) {
213 		/* TODO: add support for wide strings */
214 	} else {
215 		ad->str = malloc (len + 1);
216 		if (!ad->str) {
217 			r_anal_data_free (ad);
218 			return NULL;
219 		}
220 		memcpy (ad->str, p, len);
221 		ad->str[len] = 0;
222 		ad->buf = malloc (len + 1);
223 		if (!ad->buf) {
224 			r_anal_data_free (ad);
225 			eprintf ("Cannot allocate %d byte(s)\n", len + 1);
226 			return NULL;
227 		}
228 		memcpy (ad->buf, ad->str, len + 1);
229 		ad->len = len + 1; // string length + \x00
230 	}
231 	ad->ptr = 0L;
232 	return ad;
233 }
234 
r_anal_data_new(ut64 addr,int type,ut64 n,const ut8 * buf,int len)235 R_API RAnalData *r_anal_data_new(ut64 addr, int type, ut64 n, const ut8 *buf, int len) {
236 	RAnalData *ad = R_NEW0 (RAnalData);
237 	int l = R_MIN (len, 8);
238 	if (!ad) {
239 		return NULL;
240 	}
241 	ad->buf = (ut8 *)&(ad->sbuf);
242 	memset (ad->buf, 0, 8);
243 	if (l < 1) {
244 		r_anal_data_free (ad);
245 		return NULL;
246 	}
247 	if (buf) {
248 		memcpy (ad->buf, buf, l);
249 	}
250 	ad->addr = addr;
251 	ad->type = type;
252 	ad->str = NULL;
253 	switch (type) {
254 	case R_ANAL_DATA_TYPE_PATTERN:
255 	case R_ANAL_DATA_TYPE_SEQUENCE:
256 		ad->len = len;
257 		break;
258 	default:
259 		ad->len = l;
260 	}
261 	ad->ptr = n;
262 	return ad;
263 }
264 
r_anal_data_free(RAnalData * d)265 R_API void r_anal_data_free(RAnalData *d) {
266 	if (d) {
267 		if (d->buf != (ut8 *)&(d->sbuf)) {
268 			free (d->buf);
269 		}
270 		free (d->str);
271 		free (d);
272 	}
273 }
274 
r_anal_data(RAnal * anal,ut64 addr,const ut8 * buf,int size,int wordsize)275 R_API RAnalData *r_anal_data(RAnal *anal, ut64 addr, const ut8 *buf, int size, int wordsize) {
276 	ut64 dst = 0;
277 	int n, nsize = 0;
278 	int bits = anal->bits;
279 	int word = wordsize? wordsize: R_MIN (8, bits / 8);
280 
281 	if (size < 4) {
282 		return NULL;
283 	}
284 	if (size >= word && is_invalid (buf, word)) {
285 		return r_anal_data_new (addr, R_ANAL_DATA_TYPE_INVALID, -1, buf, word);
286 	}
287 	{
288 		int i, len = R_MIN (size, 64);
289 		int is_pattern = 0;
290 		int is_sequence = 0;
291 		char ch = buf[0];
292 		char ch2 = ch + 1;
293 		for (i = 1; i < len; i++) {
294 			if (ch2 == buf[i]) {
295 				ch2++;
296 				is_sequence++;
297 			} else {
298 				is_sequence = 0;
299 			}
300 			if (ch == buf[i]) {
301 				is_pattern++;
302 			}
303 		}
304 		if (is_sequence > len - 2) {
305 			return r_anal_data_new (addr, R_ANAL_DATA_TYPE_SEQUENCE, -1,
306 						buf, is_sequence);
307 		}
308 		if (is_pattern > len - 2) {
309 			return r_anal_data_new (addr, R_ANAL_DATA_TYPE_PATTERN, -1,
310 						buf, is_pattern);
311 		}
312 	}
313 	if (size >= word && is_null (buf, word)) {
314 		return r_anal_data_new (addr, R_ANAL_DATA_TYPE_NULL, -1, buf, word);
315 	}
316 	if (is_bin (buf, size)) {
317 		return r_anal_data_new (addr, R_ANAL_DATA_TYPE_HEADER, -1, buf, word);
318 	}
319 	if (size >= word) {
320 		dst = is_pointer (anal, buf, word);
321 		if (dst) {
322 			return r_anal_data_new (addr, R_ANAL_DATA_TYPE_POINTER, dst, buf, word);
323 		}
324 	}
325 	switch (is_string (buf, size, &nsize)) {
326 	case 1: return r_anal_data_new_string (addr, (const char *)buf, nsize, R_ANAL_DATA_TYPE_STRING);
327 	case 2: return r_anal_data_new_string (addr, (const char *)buf, nsize, R_ANAL_DATA_TYPE_WIDE_STRING);
328 	}
329 	if (size >= word) {
330 		n = is_number (buf, word);
331 		if (n) {
332 			return r_anal_data_new (addr, R_ANAL_DATA_TYPE_NUMBER, n, buf, word);
333 		}
334 	}
335 	return r_anal_data_new (addr, R_ANAL_DATA_TYPE_UNKNOWN, dst, buf, R_MIN (word, size));
336 }
337 
r_anal_data_kind(RAnal * a,ut64 addr,const ut8 * buf,int len)338 R_API const char *r_anal_data_kind(RAnal *a, ut64 addr, const ut8 *buf, int len) {
339 	int inv = 0;
340 	int unk = 0;
341 	int str = 0;
342 	int num = 0;
343 	int i, j;
344 	RAnalData *data;
345 	int word = a->bits / 8;
346 	for (i = j = 0; i < len; j++) {
347 		if (str && !buf[i]) {
348 			str++;
349 		}
350 		data = r_anal_data (a, addr + i, buf + i, len - i, 0);
351 		if (!data) {
352 			i += word;
353 			continue;
354 		}
355 		switch (data->type) {
356 		case R_ANAL_DATA_TYPE_INVALID:
357 			inv++;
358 			i += word;
359 			break;
360 		case R_ANAL_DATA_TYPE_NUMBER:
361 			if (data->ptr > 1000) {
362 				num++;
363 			}
364 			i += word;
365 			break;
366 		case R_ANAL_DATA_TYPE_UNKNOWN:
367 			unk++;
368 			i += word;
369 			break;
370 		case R_ANAL_DATA_TYPE_STRING:
371 			if (data->len > 0) {
372 				i += data->len;
373 			} else {
374 				i += word;
375 			}
376 			str++;
377 			break;
378 		default:
379 			i += word;
380 		}
381 		r_anal_data_free (data);
382 	}
383 	if (j < 1) {
384 		return "unknown";
385 	}
386 	if ((inv * 100 / j) > 60) {
387 		return "invalid";
388 	}
389 	if ((unk * 100 / j) > 60) {
390 		return "code";
391 	}
392 	if ((num * 100 / j) > 60) {
393 		return "code";
394 	}
395 	if ((str * 100 / j) > 40) {
396 		return "text";
397 	}
398 	return "data";
399 }
400 
r_anal_datatype_to_string(RAnalDataType t)401 R_API const char *r_anal_datatype_to_string(RAnalDataType t) {
402 	switch (t) {
403 	case R_ANAL_DATATYPE_NULL:
404 		return NULL;
405 	case R_ANAL_DATATYPE_ARRAY:
406 		return "array";
407 	case R_ANAL_DATATYPE_OBJECT: // instance
408 		return "object";
409 	case R_ANAL_DATATYPE_STRING:
410 		return "string";
411 	case R_ANAL_DATATYPE_CLASS:
412 		return "class";
413 	case R_ANAL_DATATYPE_BOOLEAN:
414 		return "boolean";
415 	case R_ANAL_DATATYPE_INT16:
416 		return "int16";
417 	case R_ANAL_DATATYPE_INT32:
418 		return "int32";
419 	case R_ANAL_DATATYPE_INT64:
420 		return "int64";
421 	case R_ANAL_DATATYPE_FLOAT:
422 		return "float";
423 	}
424 	return NULL;
425 }
426