unsigned int x86_disasm( unsigned char *buf, unsigned int buf_len, uint32_t buf_rva, unsigned int offset, x86_insn_t *insn ){ int len, size; x86_oplist_t *op_save; unsigned char bytes[MAX_INSTRUCTION_SIZE]; if ( ! buf || ! insn || ! buf_len ) { /* caller screwed up somehow */ return 0; } /* ensure we are all NULLed up */ op_save = insn->operands; memset( insn, 0, sizeof(x86_insn_t) ); insn->operands = op_save; insn->addr = buf_rva + offset; insn->offset = offset; /* default to invalid insn */ insn->type = insn_invalid; insn->group = insn_none; if ( offset >= buf_len ) { /* another caller screwup ;) */ x86_report_error(report_disasm_bounds, (void*)(long)(buf_rva+offset)); return 0; } len = buf_len - offset; /* copy enough bytes for disassembly into buffer : this * helps prevent buffer overruns at the end of a file */ memset( bytes, 0, MAX_INSTRUCTION_SIZE ); memcpy( bytes, &buf[offset], (len < MAX_INSTRUCTION_SIZE) ? len : MAX_INSTRUCTION_SIZE ); /* actually do the disassembly */ /* TODO: allow switching when more disassemblers are added */ size = ia32_disasm_addr( bytes, len, insn); /* check and see if we had an invalid instruction */ if (! size ) { x86_report_error(report_invalid_insn, (void*)(long)(buf_rva+offset) ); return 0; } /* check if we overran the end of the buffer */ if ( size > len ) { x86_report_error( report_insn_bounds, (void*)(long)(buf_rva + offset) ); MAKE_INVALID( insn, bytes ); return 0; } /* fill bytes field of insn */ memcpy( insn->bytes, bytes, size ); return size; }
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 ); }