Esempio n. 1
0
R_API RList *r_core_asm_bwdisassemble (RCore *core, ut64 addr, int n, int len) {
	RList *hits = r_core_asm_hit_list_new();
	RAsmOp op;
	// len = n * 32;
	// if (n > core->blocksize) n = core->blocksize;
	ut8 *buf;
	ut64 instrlen = 0, at = 0;
	ut32 idx = 0, hit_count = 0;
	int numinstr, asmlen, ii;
	RAsmCode *c;

	if (len<1) return NULL;
	buf = (ut8 *)malloc (len);
	if (hits == NULL || buf == NULL ){
		if (hits) {
			r_list_free (hits);
		}
		free (buf);
		return NULL;
	}

	if (r_io_read_at (core->io, addr-len, buf, len) != len) {
		if (hits) {
			r_list_free (hits);
		}
		free (buf);
		return NULL;
	}

	for (idx = 1; idx < len; ++idx) {
		if (r_cons_singleton ()->breaked) break;
		at = addr - idx; hit_count = 0;
		c = r_asm_mdisassemble (core->assembler, buf+(len-idx), idx);
		if (strstr(c->buf_asm, "invalid") || strstr(c->buf_asm, ".byte")) {
			r_asm_code_free(c);
			continue;
		}
		numinstr = 0;
		asmlen = strlen(c->buf_asm);
		for(ii = 0; ii < asmlen; ++ii) {
			if (c->buf_asm[ii] == '\n') ++numinstr;
		}
		r_asm_code_free(c);
		if (numinstr >= n || idx > 32 * n) {
			break;
		}
	}
	at = addr - idx;
	hit_count = 0;
	r_asm_set_pc (core->assembler, at);
	at = addr-idx;
	for ( hit_count = 0; hit_count < n; hit_count++) {
		instrlen = r_asm_disassemble (core->assembler, &op, buf+(len-(addr-at)), addr-at);
		add_hit_to_hits(hits, at, instrlen, true);
		at += instrlen;
	}
	free (buf);
	return hits;
}
Esempio n. 2
0
R_API RList *r_core_asm_bwdisassemble (RCore *core, ut64 addr, int n, int len) {
	RList *hits = r_core_asm_hit_list_new();
	RCoreAsmHit dummy_value;
	RAsmOp op;
	ut8 *buf = (ut8 *)malloc (len);
	ut64 instrlen = 0, 
		 at = 0;

	ut32 
	 	 idx = 0,
	 	 hit_count = 0;

	memset (&dummy_value, 0, sizeof (RCoreAsmHit));

	if (hits == NULL || buf == NULL ){
		if (hits) r_list_destroy (hits);
		if (buf) free (buf); 
		return NULL;
	}

	if (r_io_read_at (core->io, addr-len, buf, len) != len) {
		if (hits) r_list_destroy (hits);
		if (buf) free (buf); 
		return NULL;
	}

	for (idx = 1; idx < len; idx++) {
		ut32 current_buf_pos;
		if (r_cons_singleton ()->breaked) break;
		at = addr - idx; hit_count = 0;
		// XXX - buf here. at may be greater than addr if near boundary.

		for (current_buf_pos = len - idx, hit_count = 0; 
			current_buf_pos < len && hit_count <= n; 
			current_buf_pos += instrlen, at += instrlen, hit_count++) {
			r_asm_set_pc (core->assembler, at);
			//XXX HACK We need another way to detect invalid disasm!!
			if (!(instrlen = r_asm_disassemble (core->assembler, &op, buf+(len-(addr-at)), addr-at)) || strstr (op.buf_asm, "invalid")) {
				break;
			} 
		}
		if (hit_count >= n) break;
	}

	if (hit_count == n) {
		at = addr - idx;
		hit_count = 0;
		r_asm_set_pc (core->assembler, at);
		for ( hit_count = 0; hit_count < n; hit_count++) {
			instrlen = r_asm_disassemble (core->assembler, &op, buf+(len-(addr-at)), addr-at);
			add_hit_to_hits(hits, at, instrlen, R_TRUE);
			at += instrlen;
		}
	}

	r_asm_set_pc (core->assembler, addr);
	free (buf);
	return hits;
}
Esempio n. 3
0
static RList * r_core_asm_back_disassemble_all(RCore *core, ut64 addr, ut64 len, ut64 max_hit_count, ut32 extra_padding){
	RList *hits = r_core_asm_hit_list_new ();
	RCoreAsmHit dummy_value;
	RCoreAsmHit *hit = NULL;
	RAsmOp op;
	ut8 *buf = (ut8 *)malloc (len + extra_padding);
	int current_instr_len = 0;
	ut64 current_instr_addr = addr,
		 current_buf_pos = len - 1,
		 hit_count = 0;

	memset (&dummy_value, 0, sizeof (RCoreAsmHit));

	if (hits == NULL || buf == NULL ){
		if (hits) {
			r_list_purge (hits);
			free (hits);
		}
		free (buf);
		return NULL;
	}

	if (r_io_read_at (core->io, addr-(len+extra_padding), buf, len+extra_padding) != len+extra_padding) {
		r_list_purge (hits);
		free (hits);
		free (buf);
		return NULL;
	}

	if (len == 0){
		return hits;
	}

	current_buf_pos = len - 1;

	do {
		if (r_cons_singleton ()->breaked) break;
		// reset assembler
		r_asm_set_pc (core->assembler, current_instr_addr);
		current_instr_len = len - current_buf_pos + extra_padding;
		IFDBG eprintf("current_buf_pos: 0x%"PFMT64x", current_instr_len: %d\n", current_buf_pos, current_instr_len);
		current_instr_len = r_asm_disassemble (core->assembler, &op, buf+current_buf_pos, current_instr_len);
		hit = r_core_asm_hit_new ();
		hit->addr = current_instr_addr;
		hit->len = current_instr_len;
		hit->code = NULL;
		r_list_add_sorted (hits, hit, ((RListComparator)rcoreasm_address_comparator));

		current_buf_pos--;
		current_instr_addr--;
		hit_count++;
	} while ( ((int) current_buf_pos  >= 0) && (int)(len - current_buf_pos) >= 0 && hit_count <= max_hit_count);

	free(buf);
	return hits;
}
Esempio n. 4
0
File: asm.c Progetto: moon2l/radare2
R_API RList *r_core_asm_bwdisassemble (RCore *core, ut64 addr, int n, int len) {
	RCoreAsmHit *hit;
	RAsmOp op;
	RList *hits = NULL;
	ut8 *buf;
	ut64 at;
	int instrlen, ni, idx;

	if (!(hits = r_core_asm_hit_list_new ()))
		return NULL;
	buf = (ut8 *)malloc (len);
	if (!buf) {
		r_list_destroy (hits);
		return NULL;
	}
	if (r_io_read_at (core->io, addr-len, buf, len) != len) {
		r_list_destroy (hits);
		free (buf);
		return NULL;
	}
	for (idx = 1; idx < len; idx++) {
		if (r_cons_singleton ()->breaked)
			break;
		at = addr - idx; ni = 1;
		while (at < addr) {
			r_asm_set_pc (core->assembler, at);
			//XXX HACK We need another way to detect invalid disasm!!
			if (!(instrlen = r_asm_disassemble (core->assembler, &op, buf+(len-(addr-at)), addr-at)) || strstr (op.buf_asm, "invalid")) {
				break;
			} else {
				at += instrlen;
				if (at == addr) {
					if (ni == n) {
						if (!(hit = r_core_asm_hit_new ())) {
							r_list_destroy (hits);
							free (buf);
							return NULL;
						}
						hit->addr = addr-idx;
						hit->len = idx;
						hit->code = NULL;
						r_list_append (hits, hit);
					}
				} else ni++;
			}
		}
	}
	r_asm_set_pc (core->assembler, addr);
	free (buf);
	return hits;
}
Esempio n. 5
0
// TODO: add support for byte-per-byte opcode search
R_API RList *r_core_asm_strsearch(RCore *core, const char *input, ut64 from, ut64 to, int maxhits, int regexp) {
	RCoreAsmHit *hit;
	RAsmOp op;
	RList *hits;
	ut64 at, toff = core->offset;
	ut8 *buf;
	int align = core->search->align;
	RRegex* rx = NULL;
	char *tok, *tokens[1024], *code = NULL, *ptr;
	int idx, tidx = 0, ret, len;
	int tokcount, matchcount, count = 0;
	int matches = 0;

	if (!*input)
		return NULL;
	if (core->blocksize <= OPSZ) {
		eprintf ("error: block size too small\n");
		return NULL;
	}
	if (!(buf = (ut8 *)calloc (core->blocksize, 1)))
		return NULL;
	if (!(ptr = strdup (input))) {
		free (buf);
		return NULL;
	}
	if (!(hits = r_core_asm_hit_list_new ())) {
		free (buf);
		free (ptr);
		return NULL;
	}
	tokens[0] = NULL;
	for (tokcount=0; tokcount<(sizeof (tokens) / sizeof (char*)) - 1; tokcount++) {
		tok = strtok (tokcount? NULL: ptr, ";");
		if (!tok)
			break;
		tokens[tokcount] = r_str_trim_head_tail (tok);
	}
	tokens[tokcount] = NULL;
	r_cons_break (NULL, NULL);
	for (at = from, matchcount = 0; at < to; at += core->blocksize-OPSZ) {
		matches = 0;
		if (r_cons_singleton ()->breaked)
			break;
		ret = r_io_read_at (core->io, at, buf, core->blocksize);
		if (ret != core->blocksize)
			break;
		idx = 0, matchcount = 0;
		while (idx < core->blocksize) {
			ut64 addr = at + idx;
			r_asm_set_pc (core->assembler, addr);
			op.buf_asm[0] = 0;
			op.buf_hex[0] = 0;
			if (!(len = r_asm_disassemble (core->assembler, &op, buf+idx, core->blocksize-idx))) {
				idx = (matchcount)? tidx+1: idx+1;
				matchcount = 0;
				continue;
			}
			matches = true;
			if (!strcmp (op.buf_asm, "unaligned"))
				matches = false;
			if (!strcmp (op.buf_asm, "invalid"))
				matches = false;
			if (matches && tokens[matchcount]) {
				if (!regexp) matches = strstr(op.buf_asm, tokens[matchcount]) != NULL;
				else {
					rx = r_regex_new (tokens[matchcount], "");
					matches = r_regex_exec (rx, op.buf_asm, 0, 0, 0) == 0;
					r_regex_free (rx);
				}
			}
			if (align && align>1) {
				if (addr % align) {
					matches = false;
				}
			}
			if (matches) {
				code = r_str_concatf (code, "%s; ", op.buf_asm);
				if (matchcount == tokcount-1) {
					if (tokcount == 1)
						tidx = idx;
					if (!(hit = r_core_asm_hit_new ())) {
						r_list_purge (hits);
						free (hits);
						hits = NULL;
						goto beach;
					}
					hit->addr = addr;
					hit->len = idx + len - tidx;
					if (hit->len == -1) {
						r_core_asm_hit_free (hit);
						goto beach;
					}
					code[strlen (code)-2] = 0;
					hit->code = strdup (code);
					r_list_append (hits, hit);
					R_FREE (code);
					matchcount = 0;
					idx = tidx+1;
					if (maxhits) {
						count ++;
						if (count >= maxhits) {
							//eprintf ("Error: search.maxhits reached\n");
							goto beach;
						}
					}
				} else  if (matchcount == 0) {
					tidx = idx;
					matchcount++;
					idx += len;
				} else {
					matchcount++;
					idx += len;
				}
			} else {
				idx = matchcount? tidx+1: idx+1;
				R_FREE (code);
				matchcount = 0;
			}
		}

		at += OPSZ;
	}
	r_asm_set_pc (core->assembler, toff);
beach:
	free (buf);
	free (ptr);
	free (code);
	return hits;
}
Esempio n. 6
0
static RList *r_core_asm_back_disassemble (RCore *core, ut64 addr, int len, ut64 max_hit_count, ut8 disassmble_each_addr, ut32 extra_padding) {
	RList *hits;;
	RAsmOp op;
	ut8 *buf = NULL;
	ut8 max_invalid_b4_exit = 4,
		last_num_invalid = 0;
	int current_instr_len = 0;
	ut64 current_instr_addr = addr,
		current_buf_pos = 0,
		next_buf_pos = len;

	RCoreAsmHit dummy_value;
	ut32 hit_count = 0;

	if (disassmble_each_addr){
		return r_core_asm_back_disassemble_all(core, addr, len, max_hit_count, extra_padding+1);
	}

	hits = r_core_asm_hit_list_new ();
	buf = malloc (len + extra_padding);

	if (!hits || !buf ){
		if (hits) {
			r_list_purge (hits);
			free (hits);
		}
		free (buf);
		return NULL;
	}

	if (r_io_read_at (core->io, (addr + extra_padding)-len, buf, len+extra_padding) != len+extra_padding) {
		r_list_purge (hits);
		free (hits);
		free (buf);
		return NULL;
	}

	//
	// XXX - This is a heavy handed approach without a
	// 		an appropriate btree or hash table for storing
	//	 hits, because are using:
	//			1) Sorted RList with many inserts and searches
	//			2) Pruning hits to find the most optimal disassembly

	// greedy approach
	// 1) Consume previous bytes
	// 1a) Instruction is invalid (incr current_instr_addr)
	// 1b) Disasm is perfect
	// 1c) Disasm is underlap (disasm(current_instr_addr, next_instr_addr - current_instr_addr) short some bytes)
	// 1d) Disasm is overlap (disasm(current_instr_addr, next_instr_addr - current_instr_addr) over some bytes)

	memset (&dummy_value, 0, sizeof (RCoreAsmHit));
	// disassemble instructions previous to current address, extra_padding can move the location of addr
	// so we need to account for that with current_buf_pos
	current_buf_pos = len - extra_padding - 1;
	next_buf_pos = len + extra_padding - 1;
	current_instr_addr = addr-1;
	do {
		if (r_cons_singleton ()->breaked) break;
		// reset assembler
		r_asm_set_pc (core->assembler, current_instr_addr);
		current_instr_len = next_buf_pos - current_buf_pos;
		current_instr_len = r_asm_disassemble (core->assembler, &op, buf+current_buf_pos, current_instr_len);

		IFDBG {
			ut32 byte_cnt =  current_instr_len ? current_instr_len : 1;
			eprintf("current_instr_addr: 0x%"PFMT64x", current_buf_pos: 0x%"PFMT64x", current_instr_len: %d \n", current_instr_addr, current_buf_pos, current_instr_len);

			ut8 *hex_str = (ut8*)r_hex_bin2strdup(buf+current_buf_pos, byte_cnt);
			eprintf("==== current_instr_bytes: %s ",hex_str);

			if (current_instr_len > 0)
				eprintf("op.buf_asm: %s\n", op.buf_asm);
			else
				eprintf("op.buf_asm: <invalid>\n");

			free(hex_str);
		}

		// disassembly invalid
		if (current_instr_len == 0 || strstr (op.buf_asm, "invalid")) {
			if (current_instr_len == 0) current_instr_len = 1;
			add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, /* is_valid */ false);
			hit_count ++;
			last_num_invalid ++;
		// disassembly perfect
		} else if (current_buf_pos + current_instr_len == next_buf_pos) {
			// i think this may be the only case where an invalid instruction will be
			// added because handle_forward_disassemble and handle_disassembly_overlap
			// are only called in cases where a valid instruction has been found.
			// and they are lazy, since they purge the hit list
			ut32 purge_results = 0;
			ut8 is_valid = true;
			IFDBG eprintf(" handling underlap case: current_instr_addr: 0x%"PFMT64x".\n", current_instr_addr);
			purge_results =  prune_hits_in_addr_range(hits, current_instr_addr, current_instr_len, /* is_valid */ true);
			if (purge_results) {
				handle_forward_disassemble(core, hits, buf, len, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr);
				hit_count = r_list_length(hits);
			}
			add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, is_valid);
			//handle_forward_disassemble(core, hits, buf, len, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr/*end_addr*/);
			hit_count ++;
			next_buf_pos = current_buf_pos;
			last_num_invalid = 0;
		// disassembly underlap
		} else if (current_buf_pos + current_instr_len < next_buf_pos) {
			ut32 purge_results = 0;
			ut8 is_valid = true;
			purge_results =  prune_hits_in_addr_range(hits, current_instr_addr, current_instr_len, /* is_valid */ true);
			add_hit_to_sorted_hits(hits, current_instr_addr, current_instr_len, is_valid);

			if (hit_count < purge_results ) hit_count = 0; // WTF??
			else hit_count -= purge_results;

			next_buf_pos = current_buf_pos;
			handle_forward_disassemble(core, hits, buf, len - extra_padding, current_buf_pos+current_instr_len, current_instr_addr+current_instr_len, addr);
			hit_count = r_list_length(hits);
			last_num_invalid = 0;
		// disassembly overlap
		} else if (current_buf_pos + current_instr_len > next_buf_pos) {
			//ut64 value = handle_disassembly_overlap(core, hits, buf, len, current_buf_pos, current_instr_addr);
			next_buf_pos = current_buf_pos;
			hit_count = r_list_length (hits);
			last_num_invalid = 0;
		}

		// walk backwards by one instruction
		IFDBG eprintf(" current_instr_addr: 0x%"PFMT64x" current_instr_len: %d next_instr_addr: 0x%04"PFMT64x"\n",
			current_instr_addr, current_instr_len, next_buf_pos);
		IFDBG eprintf(" hit count: %d \n", hit_count );
		current_instr_addr -= 1;
		current_buf_pos -= 1;

		if ( hit_count >= max_hit_count &&
			 (last_num_invalid >= max_invalid_b4_exit || last_num_invalid == 0))
			break;
	} while (((int) current_buf_pos >= 0) && (int)(len - current_buf_pos) >= 0);

	r_asm_set_pc (core->assembler, addr);
	free (buf);
	return hits;
}
Esempio n. 7
0
// TODO: add support for byte-per-byte opcode search
R_API RList *r_core_asm_strsearch(RCore *core, const char *input, ut64 from, ut64 to) {
	RCoreAsmHit *hit;
	RAsmOp op;
	RList *hits;
	ut64 at, toff = core->offset;
	ut8 *buf;
	char *tok, *tokens[1024], *code = NULL, *ptr;
	int idx, tidx = 0, ret, len;
	int tokcount, matchcount;

	if (!*input)
		return NULL;
	if (core->blocksize<=OPSZ) {
		eprintf ("error: block size too small\n");
		return NULL;
	}
	if (!(buf = (ut8 *)malloc (core->blocksize)))
		return NULL;
	if (!(ptr = strdup (input))) {
		free (buf);
		return NULL;
	}
	if (!(hits = r_core_asm_hit_list_new ())) {
		free (buf);
		free (ptr);
		return NULL;
	}
	tokens[0] = NULL;
	for (tokcount=0; tokcount<(sizeof (tokens) / sizeof (char*)) - 1; tokcount++) {
		tok = strtok (tokcount? NULL: ptr, ",");
		if (tok == NULL)
			break;
		tokens[tokcount] = r_str_trim_head_tail (tok);
	}
	tokens[tokcount] = NULL;
	r_cons_break (NULL, NULL);
	for (at = from, matchcount = 0; at < to; at += core->blocksize-OPSZ) {
		if (r_cons_singleton ()->breaked)
			break;
		ret = r_io_read_at (core->io, at, buf, core->blocksize);
		if (ret != core->blocksize)
			break;
		idx = 0, matchcount = 0;
		while (idx<core->blocksize) {
			r_asm_set_pc (core->assembler, at+idx);
			op.buf_asm[0] = 0;
			op.buf_hex[0] = 0;
			if (!(len = r_asm_disassemble (core->assembler, &op, buf+idx, core->blocksize-idx))) {
				idx = (matchcount)? tidx+1: idx+1;
				matchcount = 0;
				continue;
			}
			if (tokens[matchcount] && strstr (op.buf_asm, tokens[matchcount])) {
				code = r_str_concatf (code, "%s", op.buf_asm);
				if (matchcount == tokcount-1) {
					if (tokcount == 1)
						tidx = idx;
					if (!(hit = r_core_asm_hit_new ())) {
						r_list_purge (hits);
						free (hits);
						hits = NULL;
						goto beach;
					}
					hit->addr = at+tidx;
					hit->len = idx+len-tidx;
					if (hit->len == -1) {
						r_core_asm_hit_free (hit);
						goto beach;
					}
					hit->code = strdup (code);
					r_list_append (hits, hit);
					R_FREE (code);
					matchcount = 0;
					idx = tidx+1;
				} else  if (matchcount == 0) {
					tidx = idx;
					matchcount++;
					idx += len;
				} else {
					matchcount++;
					idx += len;
				}
			} else {
				idx = matchcount? tidx+1: idx+1;
				R_FREE (code);
				matchcount = 0;
			}
		}
	}
	r_asm_set_pc (core->assembler, toff);
beach:
	free (buf);
	free (ptr);
	free (code);
	return hits;
}
Esempio n. 8
0
R_API RList *r_core_asm_bwdisassemble (RCore *core, ut64 addr, int n, int len) {
	RList *hits = r_core_asm_hit_list_new();
	RAsmOp op;
	ut8 *buf;
	ut64 buf_addr, instrlen = 0, at = 0;
	ut32 idx = 0, hit_count = 0, buf_len = 0;
	int numinstr, ii;
	RAsmCode *c;

	if (!hits)
		return NULL;
	buf_addr = addr - len;
	buf_len = len;

	buf = (ut8 *)malloc (buf_len);
	if (!buf) {
		r_list_free (hits);
		return NULL;
	}

	if (r_io_read_at (core->io, buf_addr, buf, buf_len) != buf_len) {
		r_list_free (hits);
		free (buf);
		return NULL;
	}
	if (!memcmp (buf, "\xff\xff\xff\xff", R_MIN (4, buf_len))) {
		eprintf ("error reading at 0x%08"PFMT64x"\n", buf_addr);
		r_list_free (hits);
		free (buf);
		return NULL;
	}

	if (n<0) n = -n;

	for (idx = 1; idx < len; idx++) {
		if (r_cons_singleton ()->breaked)
			break;
		at = addr - idx;
		hit_count = 0;
		r_asm_set_pc (core->assembler, at);
		// XXX: the disassemble errors are because of this line. mdisasm must not be used here
		//c = r_asm_mdisassemble (core->assembler, buf+idx, buf_len-idx); //+buf_len-idx, idx);
		c = r_asm_mdisassemble (core->assembler, buf+buf_len-idx, idx);
		// XXX: relaying on string contents in the buf_asm is a bad idea
		if (strstr (c->buf_asm, "invalid") || strstr (c->buf_asm, ".byte")) {
			r_asm_code_free (c);
			continue;
		}
//eprintf ("-->(%x)(%s)\n", at, c->buf_asm);
		for (numinstr = ii = 0; c->buf_asm[ii] ; ii++) {
			if (c->buf_asm[ii] == '\n')
				numinstr++;
		}
//eprintf ("mdisasm worked! for 0x%llx with %d\n", addr-len+idx, numinstr);
		r_asm_code_free (c);
		if (numinstr >= n || idx > 32 * n) {
//eprintf ("idx = %d len = %d ninst = %d n = %d\n", idx, len, numinstr, n);
			break;
		}
//eprintf ("idx = %d len = %d\n", idx, len);
	}
	at = addr - idx;

	hit_count = 0;

	for (hit_count = 0; hit_count < n; hit_count++) {
		if (r_cons_singleton ()->breaked)
			break;
		r_asm_set_pc (core->assembler, at);
		instrlen = r_asm_disassemble (core->assembler,
			&op, buf+buf_len-(addr-at), addr-at); //addr-at);
//		eprintf ("INST LEN = %d\n", instrlen);
		if (instrlen<1) {
			eprintf ("dissasm failed at %llx\n", at);
			instrlen = 1;
//			break;
		}
		add_hit_to_hits (hits, at, instrlen, R_TRUE);
		at += instrlen;
	}
	free (buf);
	return hits;
}
Esempio n. 9
0
R_API RList *r_core_asm_bwdisassemble(RCore *core, ut64 addr, int n, int len) {
	RAsmOp op;
	// len = n * 32;
	// if (n > core->blocksize) n = core->blocksize;
	ut8 *buf;
	ut64 at;
	ut32 idx = 0, hit_count;
	int numinstr, asmlen, ii;
	int addrbytes = core->assembler->addrbytes;
	RAsmCode *c;
	RList *hits = r_core_asm_hit_list_new();
	if (!hits) return NULL;

	len = R_MIN (len - len % addrbytes, addrbytes * addr);
	if (len < 1) {
		r_list_free (hits);
		return NULL;
	}

	buf = (ut8 *)malloc (len);
	if (!buf) {
		if (hits) {
			r_list_free (hits);
		}
		return NULL;
	} else if (!hits) {
		free (buf);
		return NULL;
	}
	len = len > addr ? addr : len;
	if (!r_io_read_at (core->io, addr - len, buf, len)) {
		r_list_free (hits);
		free (buf);
		return NULL;
	}

	for (idx = addrbytes; idx < len; idx += addrbytes) {
		if (r_cons_singleton ()->breaked) break;
		c = r_asm_mdisassemble (core->assembler, buf+(len-idx), idx);
		if (strstr (c->buf_asm, "invalid") || strstr (c->buf_asm, ".byte")) {
			r_asm_code_free(c);
			continue;
		}
		numinstr = 0;
		asmlen = strlen (c->buf_asm);
		for(ii = 0; ii < asmlen; ++ii) {
			if (c->buf_asm[ii] == '\n') ++numinstr;
		}
		r_asm_code_free(c);
		if (numinstr >= n || idx > 16 * n) { // assume average instruction length <= 16
			break;
		}
	}
	at = addr - idx / addrbytes;
	r_asm_set_pc (core->assembler, at);
	for (hit_count = 0; hit_count < n; hit_count++) {
		int instrlen = r_asm_disassemble (core->assembler, &op,
																			buf + len - addrbytes*(addr-at), addrbytes * (addr-at));
		add_hit_to_hits (hits, at, instrlen, true);
		at += instrlen;
	}
	free (buf);
	return hits;
}
Esempio n. 10
0
// TODO: add support for byte-per-byte opcode search
R_API RList *r_core_asm_strsearch(RCore *core, const char *input, ut64 from, ut64 to, int maxhits, int regexp, int everyByte, int mode) {
	RCoreAsmHit *hit;
	RAsmOp op;
	RList *hits;
	ut64 at, toff = core->offset;
	ut8 *buf;
	int align = core->search->align;
	RRegex* rx = NULL;
	char *tok, *tokens[1024], *code = NULL, *ptr;
	int idx, tidx = 0, len = 0;
	int tokcount, matchcount, count = 0;
	int matches = 0;
	const int addrbytes = core->io->addrbytes;

	if (!input || !*input) {
		return NULL;
	}

	ut64 usrimm = r_num_math (core->num, input + 1);

	if (core->blocksize < 8) {
		eprintf ("error: block size too small\n");
		return NULL;
	}
	if (!(buf = (ut8 *)calloc (core->blocksize, 1))) {
		return NULL;
	}
	if (!(ptr = strdup (input))) {
		free (buf);
		return NULL;
	}
	if (!(hits = r_core_asm_hit_list_new ())) {
		free (buf);
		free (ptr);
		return NULL;
	}
	tokens[0] = NULL;
	for (tokcount = 0; tokcount < R_ARRAY_SIZE (tokens) - 1; tokcount++) {
		tok = strtok (tokcount? NULL: ptr, ";");
		if (!tok) {
			break;
		}
		tokens[tokcount] = r_str_trim_head_tail (tok);
	}
	tokens[tokcount] = NULL;
	r_cons_break_push (NULL, NULL);
	char *opst = NULL;
	for (at = from, matchcount = 0; at < to; at += core->blocksize) {
		if (r_cons_is_breaked ()) {
			break;
		}
		if (!r_io_is_valid_offset (core->io, at, 0)) {
			break;
		}
		(void)r_io_read_at (core->io, at, buf, core->blocksize);
		idx = 0, matchcount = 0;
		while (addrbytes * (idx + 1) <= core->blocksize) {
			ut64 addr = at + idx;
			if (addr >= to) {
				break;
			}
			r_asm_set_pc (core->assembler, addr);
			if (mode == 'i') {
				RAnalOp analop = {0};
				if (r_anal_op (core->anal, &analop, addr, buf + idx, 15, 0) < 1) {
					idx ++; // TODO: honor mininstrsz
					continue;
				}
				if (analop.val == usrimm) {
					if (!(hit = r_core_asm_hit_new ())) {
						r_list_purge (hits);
						R_FREE (hits);
						goto beach;
					}
					hit->addr = addr;
					hit->len = analop.size;  //  idx + len - tidx;
					if (hit->len == -1) {
						r_core_asm_hit_free (hit);
						goto beach;
					}
					r_asm_disassemble (core->assembler, &op, buf + addrbytes * idx,
					      core->blocksize - addrbytes * idx);
					hit->code = r_str_newf (r_strbuf_get (&op.buf_asm));
					idx = (matchcount)? tidx + 1: idx + 1;
					matchcount = 0;
					r_list_append (hits, hit);
					continue;
				}
				r_anal_op_fini (&analop);
				idx ++; // TODO: honor mininstrsz
				continue;
			} else if (mode == 'e') {
				RAnalOp analop = {0};
				if (r_anal_op (core->anal, &analop, addr, buf + idx, 15, R_ANAL_OP_MASK_ESIL) < 1) {
					idx ++; // TODO: honor mininstrsz
					continue;
				}
				//opsz = analop.size;
				opst = strdup (r_strbuf_get (&analop.esil));
				r_anal_op_fini (&analop);
			} else {
				if (!(len = r_asm_disassemble (
					      core->assembler, &op,
					      buf + addrbytes * idx,
					      core->blocksize - addrbytes * idx))) {
					idx = (matchcount)? tidx + 1: idx + 1;
					matchcount = 0;
					continue;
				}
				//opsz = op.size;
				opst = strdup (r_strbuf_get (&op.buf_asm));
			}
			if (opst) {
				matches = strcmp (opst, "invalid") && strcmp (opst, "unaligned");
			}
			if (matches && tokens[matchcount]) {
				if (!regexp) {
					matches = strstr (opst, tokens[matchcount]) != NULL;
				} else {
					rx = r_regex_new (tokens[matchcount], "");
					if (r_regex_comp (rx, tokens[matchcount], R_REGEX_EXTENDED|R_REGEX_NOSUB) == 0) {
						matches = r_regex_exec (rx, opst, 0, 0, 0) == 0;
					}
					r_regex_free (rx);
				}
			}
			if (align && align > 1) {
				if (addr % align) {
					matches = false;
				}
			}
			if (matches) {
				code = r_str_appendf (code, "%s; ", opst);
				if (matchcount == tokcount - 1) {
					if (tokcount == 1) {
						tidx = idx;
					}
					if (!(hit = r_core_asm_hit_new ())) {
						r_list_purge (hits);
						R_FREE (hits);
						goto beach;
					}
					hit->addr = addr;
					hit->len = idx + len - tidx;
					if (hit->len == -1) {
						r_core_asm_hit_free (hit);
						goto beach;
					}
					code[strlen (code) - 2] = 0;
					hit->code = strdup (code);
					r_list_append (hits, hit);
					R_FREE (code);
					matchcount = 0;
					idx = tidx + 1;
					if (maxhits) {
						count++;
						if (count >= maxhits) {
							//eprintf ("Error: search.maxhits reached\n");
							goto beach;
						}
					}
				} else if (!matchcount) {
					tidx = idx;
					matchcount++;
					idx += len;
				} else {
					matchcount++;
					idx += len;
				}
			} else {
				if (everyByte) {
					idx = matchcount? tidx + 1: idx + 1;
				} else {
					idx += R_MAX (1, len);
				}
				R_FREE (code);
				matchcount = 0;
			}
			R_FREE (opst);
		}
	}
	r_cons_break_pop ();
	r_asm_set_pc (core->assembler, toff);
beach:
	free (buf);
	free (ptr);
	free (code);
	R_FREE (opst);
	r_cons_break_pop ();
	return hits;
}