unsigned int x86_disasm_range( unsigned char *buf, uint32_t buf_rva, unsigned int offset, unsigned int len, DISASM_CALLBACK func, void *arg ) { x86_insn_t insn; unsigned int buf_len, size, count = 0, bytes = 0; /* buf_len is implied by the arguments */ buf_len = len + offset; while ( bytes < len ) { size = x86_disasm( buf, buf_len, buf_rva, offset + bytes, &insn ); if ( size ) { /* invoke callback if it exists */ if ( func ) { (*func)( &insn, arg ); } bytes += size; count ++; } else { /* error */ bytes++; /* try next byte */ } x86_oplist_free( &insn ); } return( count ); }
char *ropit_x86_list_disasm (uint8_t *bytes, int len) { int pos = 0; // current position in buffer int size; // size of instruction x86_insn_t insn; // instruction char line[4096] = {0}; int linelen = 4096; char *listing = NULL; listing = calloc(2048, sizeof(*listing)); x86_init(opt_none, NULL, NULL); while ( pos < len ) { // disassemble address size = x86_disasm(bytes, len, 0, pos, &insn); if ( size ) { // print instruction x86_format_insn(&insn, line, linelen, intel_syntax); // printf("%s\n", line); strcat(listing, line); strcat(listing, "\n"); pos += size; } else { pos++; } x86_oplist_free(&insn); } x86_cleanup(); return listing; }
// disasm 1 instruction char *ropit_x86_disasm (uint8_t *bytes, int len, int *sz_dis) { int sz_inst, len_disasm; /* sz_inst of instruction */ x86_insn_t insn; /* instruction */ char line[1024]; int sz_line = 1024; char *disasm; if (!bytes || len <= 0 || !sz_dis) { debug_printf (MESSAGE_ERROR, stderr, "error: ropit_x86_disasm(): Bad parameter(s)\n"); return NULL; } len_disasm = 0; x86_init(opt_none, NULL, NULL); sz_inst = x86_disasm (bytes, len, 0, 0, &insn); if (sz_inst > 0) { len_disasm = x86_format_insn (&insn, line, sz_line, intel_syntax); *sz_dis = sz_inst; } x86_oplist_free (&insn); x86_cleanup(); if (len_disasm == 0) return NULL; disasm = calloc (len_disasm, sizeof(*disasm)); if (!disasm) { debug_printf (MESSAGE_ERROR, stderr, "error: ropit_x86_disasm(): Failed disasm alloc\n"); return NULL; } memcpy (disasm, line, len_disasm); return disasm; }
unsigned int x86_disasm_forward( unsigned char *buf, unsigned int buf_len, uint32_t buf_rva, unsigned int offset, DISASM_CALLBACK func, void *arg, DISASM_RESOLVER resolver, void *r_arg ){ x86_insn_t insn; x86_op_t *op; int32_t next_addr; uint32_t next_offset; unsigned int size, count = 0, bytes = 0, cont = 1; while ( cont && bytes < buf_len ) { size = x86_disasm( buf, buf_len, buf_rva, offset + bytes, &insn ); if ( size ) { /* invoke callback if it exists */ if ( func ) { (*func)( &insn, arg ); } bytes += size; count ++; } else { /* error */ bytes++; /* try next byte */ } if ( follow_insn_dest(&insn) ) { op = x86_get_dest_operand( &insn ); next_addr = -1; /* if caller supplied a resolver, use it to determine * the address to disassemble */ if ( resolver ) { next_addr = resolver(op, &insn, r_arg); } else { next_addr = internal_resolver(op, &insn); } if (next_addr != -1 ) { next_offset = next_addr - buf_rva; /* if offset is in this buffer... */ if ( next_addr >= buf_rva && next_offset < buf_len ) { /* go ahead and disassemble */ count += x86_disasm_forward( buf, buf_len, buf_rva, next_offset, func, arg, resolver, r_arg ); } else { /* report unresolved address */ x86_report_error( report_disasm_bounds, (void*)(long)next_addr ); } } } /* end follow_insn */ if ( insn_doesnt_return(&insn) ) { /* stop disassembling */ cont = 0; } x86_oplist_free( &insn ); } return( count ); }
void IMG_addrlabels(Image_t *img, int secid) { assert(img != NULL); Section_t *sec; x86_insn_t insn; sec = IMG_getsection(img, secid); if (sec->plan == NULL) { return; } #if 0 sec->data = (uint8_t *)BUF_getptr(sec->buf_data); printf("%d %02X\n", secid, sec->data[0]); printf("%d %02X\n", 1, *((uint8_t *)IMG_getptr(img, uaddr_mk(1, 0)))); return; #endif uaddr_t min_target = uaddr_mk(secid, 0); uaddr_t max_target = uaddr_mk(secid, IMG_getsecsize(img, secid)); IMG_begintransaction(img); //for (int pos = 0; pos < 349; pos++) { int count = 0; for (int pos = 0; pos < sec->size; pos++) { int len = plan_size(sec->plan, pos); if (PLAN_ISCODE(sec->plan, pos)) { x86_disasm((unsigned char *)sec->data, sec->size, uaddr_mk(secid, 0), pos, &insn); x86_op_t *op = x86_get_branch_target(&insn); int rel; int relsize = 0; bool found = false; // ve se essa instrucao tem algum operando if (op != NULL) { // so nos interessam operandos relativos (jumps) if (op->type == op_relative_near) { found = true; rel = (int)op->data.relative_near; relsize = 1; } else if (op->type == op_relative_far) { found = true; rel = op->data.relative_far; relsize = 4; //// FIXME pode ser 2 em 16 bits } } if (found) { int disp = 0; uaddr_t target = insn.addr + insn.size + rel; //printf("%d ADD LABEL L%08X\n", pos, target); //IMG_addlabel(img, target, NULL); // Se necessário, desloca o label até o início de uma instrução if ((target < min_target) || (target >= max_target)) { printf("ERROR: relative jump/call at %08X points to %08X\n", uaddr_mk(secid, pos), target); x86_oplist_free(&insn); IMG_endtransaction(img); return; } #if 1 for (;;) { uint8_t uuu = sec->plan[uaddr_off(target)]; //if (!((uuu & CP_INSIDE) || (uuu == CP_DATA2))) { if (!(uuu & PLAN_INSIDE)) { break; } disp++; target--; } #endif //printf("%d\n", disp); //printf("%08X %08X\n", uaddr_mk(secid, pos), target); //printf("%08X %08X\n", uaddr_mk(secid, pos), target); #if 1 uaddr_t afrom = uaddr_mk(secid, pos) + 1; if (sec->data[pos] == 0x0F) { afrom += 1; } IMG_addreloc(img, afrom, target, relsize, disp, RELOC_REL); // FIXME::: SIZE 0?? #endif count++; } x86_oplist_free(&insn); } pos += len - 1; } IMG_endtransaction(img); //printf("; %d labels added\n", count); }
// find valid instructions offsets before ret int _ropit_x86_find_gadgets (uint8_t *bytes, int len, int64_t *rets, int n_rets) { int sz_inst; /* size of instruction */ x86_insn_t insn; /* instruction */ int idx_ret, sz_ret; int valid_gadget; // back track instruction count int n_backtrack_inst, n_backtrack_bytes; // start for rop search uint8_t *start, *gadget_start; // disassemble int len_disasm; int sz_dst; char disassembled[DISASSEMBLED_SIZE_MAX] = {0}; // cache FILE *fp_cache; struct cache_t *caches; int idx_caches, n_caches; struct gadget_t *gadgets; int idx_gadgets, n_gadgets; // cache queue struct gadget_cache_queue_t *cache_queue; // count int count_gadgets; // check params if (!bytes || len <= 0) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Bytes null or len <= 0\n"); return NULL; } // search rets if (!rets || n_rets <= 0) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): No rets\n"); return NULL; } // init gadget_cache fp_cache = fopen("tmp/gadget_cache", "w"); if (!fp_cache) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed open (w)\n"); return NULL; } // init cache_queue cache_queue = NULL; if (!gadget_cache_queue_init(&cache_queue)) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Cache queue allocation failed\n"); return NULL; } gadget_cache_queue_set_file (cache_queue, fp_cache); // init gadgets n_gadgets = 1024; gadgets = calloc(sizeof(struct gadget_t), n_gadgets); if (!gadgets) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed allocating caches\n"); return NULL; } for (idx_gadgets = 0; idx_gadgets < n_gadgets; idx_gadgets++) gadget_init(&(gadgets[idx_gadgets]), DISASSEMBLED_SIZE_MAX); // init caches n_caches = 1; caches = calloc(sizeof(struct cache_t), n_caches); if (!caches) { debug_printf (MESSAGE_ERROR, stderr, "error: _ropit_x86_find_gadgets(): Failed allocating caches\n"); return NULL; } for (idx_caches = 0; idx_caches < n_caches; idx_caches++) { cache_init(&(caches[idx_caches]), 1024); } // init disasm x86_init(opt_none, NULL, NULL); idx_caches = 0; idx_gadgets = 0; count_gadgets = 0; for (idx_ret = 0; idx_ret < n_rets; idx_ret++) { start = bytes + rets[idx_ret]; n_backtrack_inst = 0; n_backtrack_bytes = 0; while ( bytes <= start && start <= bytes + len ) { /* disassemble address */ sz_inst = x86_disasm(start, len - (start - bytes), 0, 0, &insn); x86_oplist_free(&insn); if (sz_inst <= 0) { // printf("not found inst\n"); n_backtrack_bytes++; } else { // printf("found inst\n"); n_backtrack_bytes = 0; valid_gadget = 0; // gadget_start = start; if (gadget_start == bytes + rets[idx_ret]) valid_gadget = 1; else { n_backtrack_inst = 0; // check gadget validity while (bytes <= gadget_start && gadget_start <= bytes + rets[idx_ret]) { /* disassemble address */ sz_inst = x86_disasm(gadget_start, gadget_start - bytes, 0, 0, &insn); x86_oplist_free(&insn); if (sz_inst <= 0) break; else { n_backtrack_inst++; gadget_start += sz_inst; if (gadget_start == bytes + rets[idx_ret]) { valid_gadget = 1; break; } } } } if (valid_gadget == 1) { // ++count_gadgets; // get ret size sz_ret = x86_disasm(bytes + rets[idx_ret], 10, 0, 0, &insn); x86_oplist_free(&insn); // fill gadget structure gadgets[idx_gadgets].ret_addr = rets[idx_ret]; gadgets[idx_gadgets].ret_bytes = rets[idx_ret] + bytes; gadgets[idx_gadgets].address = start - bytes; gadgets[idx_gadgets].len_bytes = (rets[idx_ret] - (start - bytes)) + sz_ret; if (gadgets[idx_gadgets].sz_bytes < gadgets[idx_gadgets].len_bytes) { gadgets[idx_gadgets].bytes = realloc (gadgets[idx_gadgets].bytes, gadgets[idx_gadgets].len_bytes); gadgets[idx_gadgets].sz_bytes = gadgets[idx_gadgets].len_bytes; } memcpy(gadgets[idx_gadgets].bytes, start, gadgets[idx_gadgets].len_bytes); if (cache_add (&(caches[idx_caches]), &(gadgets[idx_gadgets])) == -ERR_CACHE_FULL) { gadget_cache_queue_add (cache_queue, &(caches[idx_caches])); gadget_cache_queue_fwrite_worker (cache_queue); cache_reset (&(caches[idx_caches])); } idx_gadgets = (idx_gadgets + 1) % n_gadgets; } } --start; // maximum intel instruction size is 15 // maximum instructions in a gadget is hardcoded to 8 here /* TODO : Get more gadgets with n_backtrack_inst instructions * Effectively, we stop at the first gadget which has * n_backtrack_inst instructions while there might be multiple * possibilities. */ if (n_backtrack_bytes >= 15 || n_backtrack_inst == 8) break; } } x86_cleanup(); // write remaining gadgets gadget_cache_queue_add (cache_queue, &(caches[idx_caches])); gadget_cache_queue_fwrite_worker (cache_queue); cache_reset (&(caches[idx_caches])); // clean up for (idx_caches = 0; idx_caches < n_caches; idx_caches++) free(caches[idx_caches].objects); free(caches); for (idx_gadgets = 0; idx_gadgets < n_gadgets; idx_gadgets++) { // gadget_free(&(gadgets[idx_gadgets])); // free (gadgets[idx_gadgets].repr); free (gadgets[idx_gadgets].bytes); } free(gadgets); gadget_cache_queue_destroy (&cache_queue); fclose (fp_cache); return count_gadgets; }