//---------------------------------------------------------------------- void out(void) { char buf[MAXSTR]; // output .org for enties without any labels if ( !has_any_name(uFlag) && helper.altval(cmd.ea) ) { btoa(buf, sizeof(buf), cmd.ip); printf_line(inf.indent, COLSTR("%s %s", SCOLOR_ASMDIR), ash.origin, buf); } init_output_buffer(buf, sizeof(buf)); OutMnem(); out_one_operand(0); if ( cmd.Op2.type != o_void ) { out_symbol(','); OutChar(' '); out_one_operand(1); } if ( isVoid(cmd.ea, uFlag, 0) ) OutImmChar(cmd.Op1); if ( isVoid(cmd.ea, uFlag, 1) ) OutImmChar(cmd.Op2); term_output_buffer(); gl_comm = 1; MakeLine(buf); }
tid_t create_vtbl_struct(ea_t vtbl_addr, ea_t vtbl_addr_end, char* vtbl_name, uval_t idx, unsigned int* vtbl_len) { qstring struc_name = vtbl_name; tid_t id = add_struc(BADADDR, struc_name.c_str()); if (id == BADADDR) { struc_name.clear(); struc_name = askstr(HIST_IDENT, NULL, "Default name %s not correct. Enter other structure name: ", struc_name.c_str()); id = add_struc(BADADDR, struc_name.c_str()); set_struc_cmt(id, vtbl_name, true); } struc_t* new_struc = get_struc(id); if (!new_struc) return BADNODE; ea_t ea = vtbl_addr; int offset = 0; while (ea < vtbl_addr_end) { offset = ea - vtbl_addr; qstring method_name; ea_t method_ea = get_long(ea); if (method_ea == 0) break; if (!isEnabled(method_ea)) break; flags_t method_flags = getFlags(method_ea); char* struc_member_name = NULL; if (isFunc(method_flags)) { method_name = get_short_name(method_ea); if (method_name.length() != 0) struc_member_name = (char*)method_name.c_str(); } add_struc_member(new_struc, NULL, offset, dwrdflag(), NULL, 4); if (struc_member_name) { if (!set_member_name(new_struc, offset, struc_member_name)) { //get_name(NULL, method_ea, method_name, sizeof(method_name)); get_ea_name(&method_name, method_ea); set_member_name(new_struc, offset, struc_member_name); } } ea = ea + 4; flags_t ea_flags = getFlags(ea); if (has_any_name(ea_flags)) break; } return id; }
// check and create a flat 32 bit jump table -- the most common case static void check_and_create_flat32( jump_table_type_t /*jtt*/, switch_info_ex_t &si) { // check the table contents ea_t table = si.jumps; segment_t *s = getseg(table); if ( s == NULL ) return; size_t maxsize = size_t(s->endEA - table); int size = si.ncases; if ( size > maxsize ) size = (int)maxsize; int i; insn_t saved = cmd; for ( i=0; i < size; i++ ) { ea_t ea = table + 4*i; flags_t F = getFlags(ea); if ( !hasValue(F) ) break; if ( i && (has_any_name(F) || hasRef(F)) ) break; ea_t target = segm_adjust_ea(getseg(table), si.elbase + get_long(ea)); if ( !isLoaded(target) ) break; flags_t F2 = get_flags_novalue(target); if ( isTail(F2) || isData(F2) ) break; if ( !isCode(F2) && !decode_insn(target) ) break; } cmd = saved; size = i; // create the table for ( i=0; i < size; i++ ) { ea_t ea = table + 4*i; doDwrd(ea, 4); op_offset(ea, 0, REF_OFF32, BADADDR, si.elbase); ea_t target = si.elbase + segm_adjust_diff(getseg(table), get_long(ea)); ua_add_cref(0, target, fl_JN); } si.flags |= SWI_J32; if ( si.defjump != BADADDR ) si.flags |= SWI_DEFAULT; si.ncases = (uint16)size; si.startea = cmd.ea; set_switch_info_ex(cmd.ea, &si); }
BOOL get_vtbl_info(ea_t ea_address, VTBL_info_t &vtbl_info) { flags_t flags = getFlags(ea_address); if (!(hasRef(flags) || has_any_name(flags) && (isDwrd(flags) || isUnknown(flags)))) return(FALSE); else { BOOL is_move_xref = FALSE; ea_t ea_code_ref = get_first_dref_to(ea_address); if (ea_code_ref && (ea_code_ref != BADADDR)) { do { if (isCode(getFlags(ea_code_ref))) { LPCTSTR disasm_line = get_text_disasm(ea_code_ref); #ifndef __EA64__ if ((*((PUINT)disasm_line) == 0x20766F6D /*"mov "*/) && (strstr(disasm_line + 4, " offset ") != NULL)) #else if ((*((PUINT)disasm_line) == 0x2061656c /*"lea "*/) && (strstr(disasm_line + 4, "rcx") != NULL) && (strstr(disasm_line + 4, "const") != NULL)) #endif { is_move_xref = TRUE; break; } } ea_code_ref = get_next_dref_to(ea_address, ea_code_ref); } while (ea_code_ref && (ea_code_ref != BADADDR)); } if (!is_move_xref) return(FALSE); ZeroMemory(&vtbl_info, sizeof(VTBL_info_t)); // get_name(BADADDR, ea_address, vtbl_info.vtbl_name, (MAXSTR - 1)); f_get_ea_name(&vtbl_info.vtbl_name, ea_address); ea_t ea_start = vtbl_info.ea_begin = ea_address; while (TRUE) { flags_t index_flags = getFlags(ea_address); #ifndef __EA64__ if (!(hasValue(index_flags) && (isDwrd(index_flags) || isUnknown(index_flags)))) #else if (!(hasValue(index_flags) && (isQwrd(index_flags) || isUnknown(index_flags)))) #endif break; #ifndef __EA64__ ea_t ea_index_value = get_32bit(ea_address); #else ea_t ea_index_value = get_64bit(ea_address); #endif if (!(ea_index_value && (ea_index_value != BADADDR))) break; if (ea_address != ea_start) if (hasRef(index_flags)) break; flags_t value_flags = getFlags(ea_index_value); if (!isCode(value_flags)) break; else if (isUnknown(index_flags)) #ifndef __EA64__ doDwrd(ea_address, sizeof(DWORD)); ea_address += sizeof(UINT); #else doQwrd(ea_address, sizeof(UINT64)); ea_address += sizeof(UINT64); #endif }; #ifndef __EA64__ if ((vtbl_info.methods = ((ea_address - ea_start) / sizeof(UINT))) > 0) #else if((vtbl_info.methods = ((ea_address - ea_start) / sizeof(UINT64))) > 0) #endif { vtbl_info.ea_end = ea_address; return(TRUE); } else return(FALSE); } }
tid_t create_vtbl_struct(ea_t vtbl_addr, ea_t vtbl_addr_end, char* vtbl_name, uval_t idx, unsigned int* vtbl_len) { qstring struc_name = vtbl_name; //struc_name.append(qstring("_vtbl_struct")); tid_t id = add_struc(BADADDR, struc_name.c_str()); if (id == BADADDR) { struc_name.clear(); struc_name = askstr(HIST_IDENT, NULL, "Default name %s not correct. Enter other structure name: ", struc_name.c_str()); id = add_struc(BADADDR, struc_name.c_str()); set_struc_cmt(id, vtbl_name, true); } struc_t* new_struc = get_struc(id); if (!new_struc) return BADNODE; ea_t ea = vtbl_addr; ea_t offset = 0; while (ea < vtbl_addr_end) { offset = ea - vtbl_addr; qstring method_name; #ifndef __EA64__ ea_t method_ea = get_long(ea); // get function ea #else ea_t method_ea = get_64bit(ea); #endif if (method_ea == 0) break; if (!isEnabled(method_ea)) break; flags_t method_flags = getFlags(method_ea); char* struc_member_name = NULL; if (isFunc(method_flags)) { method_name = f_get_short_name(method_ea); // this line crash ida when compare qstring with null if (method_name.length() != 0) { struc_member_name = (char*)method_name.c_str(); } } #ifndef __EA64__ add_struc_member(new_struc, NULL, offset, dwrdflag(), NULL, 4); #else add_struc_member(new_struc, NULL, offset, qwrdflag(), NULL, sizeof(UINT64)); #endif if (struc_member_name) { if (!set_member_name(new_struc, offset, struc_member_name)) { //get_name(NULL, method_ea, method_name, sizeof(method_name)); f_get_ea_name(&method_name, method_ea); set_member_name(new_struc, offset, struc_member_name); } } #ifndef __EA64__ ea = ea + 4; #else ea = ea + sizeof(UINT64); #endif flags_t ea_flags = getFlags(ea); if (has_any_name(ea_flags)) break; } return id; }
void idaapi run(int arg) { char buf[MAXSTR]; char cmt[MAXSTR]; char *valid_cmt = NULL; char ext[0x20]; FILE *f = NULL; short checkboxes = OPTION_NAMES | OPTION_COMMENTS; sval_t bank = 1; // default bool first = true; bool hasName = false; flags_t flags; ea_t ea = 0x0; if( AskUsingForm_c( madnes_options, &checkboxes, &bank ) != 1 || checkboxes == 0 ) return; // prepare filename for namelist (.nl) file get_input_file_path( buf, sizeof( buf ) ); qsnprintf( ext, sizeof( ext ),".%X.nl",--bank ); qstrncat( buf, ext, sizeof( buf )-strlen( buf ) ); // (always) create file f = qfopen( buf, "w" ); if( f == NULL ) { warning( "%s could not be created!", buf ); return; } msg( "Writing to file %s..", buf ); while( ea <= 0xFFFF ) { hasName = false; // get flags if( isCode( getFlags( ea ) ) ) flags = getFlags( ea ); else flags = getFlags( get_item_head( ea ) ); // if user either chose to export names or anynames if( ( ( checkboxes & OPTION_NAMES ) && has_name( flags ) ) || ( ( checkboxes & OPTION_ANYNAME ) && has_any_name( flags ) ) ) { // if current item is code or if current item is head of item if( isCode( flags ) || ea==get_item_head( ea ) ) { // get name get_name( ea, ea, buf, sizeof( buf ) ); // write to file qfprintf( f, "$%04X#%s#", ea, buf ); } else // if not code or not head of item (must be an array) { // get name of item start get_name( get_item_head( ea ), get_item_head( ea ), buf, sizeof( buf ) ); // calc displacement, write to file (example: "password+$04") qfprintf( f, "$%04X#%s+$%X#", ea, buf, ea-get_item_head( ea ) ); } hasName = true; } // if user chose to export cross references if( checkboxes & OPTION_XREFS ) { xrefblk_t xb; first = true; // cycle through all xrefs except ordinary flow xrefs for ( bool ok=xb.first_to( ea, XREF_FAR/*XREF_ALL*/); ok; ok=xb.next_to() ) { if( first ) // if first xref { if( !hasName ) // if this location hasn't a name yet, add symbol stub { qfprintf( f, "$%04X##", ea ); hasName = true; } qfprintf( f, "XREFS:\n\\"); // append XREFS first = false; } qfprintf( f, " $%04X\n\\", xb.from ); } } // if user chose to export comments if( checkboxes & OPTION_COMMENTS ) { if( has_cmt( flags ) ) // if current item has comment { // get comment // workaround for get_any_indeted_cmt() // -> unresolved external symbol "char * __stdcall get_any_indented_cmt(unsigned long,unsigned char *)" (?get_any_indented_cmt@@YGPADKPAE@Z) if( get_cmt( ea, false, cmt, sizeof( cmt ) ) == -1 ) get_cmt( ea, true, cmt, sizeof( cmt ) ); // validate comment (replace invalid chars, add room for additional chars) valid_cmt = validate_comment( cmt ); if( valid_cmt != NULL ) { if( !hasName ) { qfprintf( f, "$%04X##", ea ); // add symbol stub if no name yet hasName = true; } qfprintf( f, "%s", valid_cmt ); // write comment to file qfree( valid_cmt ); } } } if( hasName) qfprintf( f, "\n" ); ea++; // get name of each byte } qfclose( f ); msg( "done.\n" ); }
static bool check_for_table_jump(void) { ea_t base = BADADDR, table = BADADDR, defea = BADADDR; int size = 0, elsize = 0; int i; bool ok = false; insn_t saved = cmd; for ( i=0; !ok && i < qnumber(patterns); i++ ) { ok = patterns[i](&base, &table, &defea, &size, &elsize); cmd = saved; } if ( !ok ) return false; if ( table != BADADDR ) table = toEA(cmd.cs, table); if ( base != BADADDR ) base = toEA(cmd.cs, base); if ( defea != BADADDR ) defea = toEA(cmd.cs, defea); // check the table contents int oldsize = size; segment_t *s = getseg(table); if ( s == NULL ) return false; int maxsize = int(s->endEA - table); if ( size > maxsize ) size = maxsize; for ( i=0; i < size; i++ ) { ea_t ea = table+i*elsize; flags_t F = getFlags(ea); if ( !hasValue(F) || (i && (has_any_name(F) || hasRef(F))) ) break; int el = elsize == 1 ? get_byte(ea) : get_word(ea); flags_t F2 = get_flags_novalue(base+el); if ( isTail(F2) || isData(F2) || (!isCode(F2) && !decode_insn(base+el)) ) break; } cmd = saved; size = i; if ( size != oldsize ) msg("Warning: jpt_%04a calculated size of %d forced to %d!\n", cmd.ip, oldsize, size); // create the table if ( size == 0 ) return false; for ( i=0; i < size; i++ ) { ea_t ea = table + i*elsize; (elsize == 1 ? doByte : doWord)(ea, elsize); op_offset(ea, 0, elsize == 1 ? REF_OFF8 : REF_OFF16, BADADDR, base); ua_add_cref(0, base + (elsize==1?get_byte(ea):get_word(ea)), fl_JN); } char buf[MAXSTR]; qsnprintf(buf, sizeof(buf), "def_%a", cmd.ip); // set_name(defea, buf, SN_NOWARN|SN_LOCAL); // temporary kernel bug workaround set_name(defea, buf, SN_NOWARN); qsnprintf(buf, sizeof(buf), "jpt_%a", cmd.ip); set_name(table, buf, SN_NOWARN); return true; }
// Attempt to get information of and fix vftable at address // Return TRUE along with info if valid vftable parsed at address BOOL vftable::getTableInfo(ea_t ea, vtinfo &info) { ZeroMemory(&info, sizeof(vtinfo)); // Start of a vft should have an xref and a name (auto, or user, etc). // Ideal flags 32bit: FF_DWRD, FF_0OFF, FF_REF, FF_NAME, FF_DATA, FF_IVL //dumpFlags(ea); flags_t flags = get_flags_novalue(ea); if(hasRef(flags) && has_any_name(flags) && (isEa(flags) || isUnknown(flags))) { // Get raw (auto-generated mangled, or user named) vft name //if (!get_name(BADADDR, ea, info.name, SIZESTR(info.name))) // msg(EAFORMAT" ** vftable::getTableInfo(): failed to get raw name!\n", ea); // Determine the vft's method count ea_t start = info.start = ea; while (TRUE) { // Should be an ea_t offset to a function here (could be unknown if dirty IDB) // Ideal flags for 32bit: FF_DWRD, FF_0OFF, FF_REF, FF_NAME, FF_DATA, FF_IVL //dumpFlags(ea); flags_t indexFlags = get_flags_novalue(ea); if (!(isEa(indexFlags) || isUnknown(indexFlags))) { //msg(" ******* 1\n"); break; } // Look at what this (assumed vftable index) points too ea_t memberPtr = getEa(ea); if (!(memberPtr && (memberPtr != BADADDR))) { // vft's often have a zero ea_t (NULL pointer?) following, fix it if (memberPtr == 0) fixEa(ea); //msg(" ******* 2\n"); break; } // Should see code for a good vft method here, but it could be dirty flags_t flags = get_flags_novalue(memberPtr); if (!(isCode(flags) || isUnknown(flags))) { //msg(" ******* 3\n"); break; } if (ea != start) { // If we see a ref after first index it's probably the beginning of the next vft or something else if (hasRef(indexFlags)) { //msg(" ******* 4\n"); break; } // If we see a COL here it must be the start of another vftable if (RTTI::_RTTICompleteObjectLocator::isValid(memberPtr)) { //msg(" ******* 5\n"); break; } } // As needed fix ea_t pointer, and, or, missing code and function def here fixEa(ea); fixFunction(memberPtr); ea += sizeof(ea_t); }; // Reached the presumed end of it if ((info.methodCount = ((ea - start) / sizeof(ea_t))) > 0) { info.end = ea; //msg(" vftable: "EAFORMAT"-"EAFORMAT", methods: %d\n", rtInfo.eaStart, rtInfo.eaEnd, rtInfo.uMethods); return(TRUE); } } //dumpFlags(ea); return(FALSE); }
static void op_emu(op_t& x, int fIsLoad) { char szLabel[128]; cref_t ftype; ea_t ea; switch (x.type) { case o_reg: case o_phrase: return; case o_imm: if (!fIsLoad) break; op_imm(cmd.ea); return; case o_displ: case o_mem: switch (cmd.itype) { case M8B_IORD: case M8B_IOWR: case M8B_IOWX: case M8B_IPRET: ea = toIOP(x.addr); if (ea != BADADDR) { ua_dodata2(x.offb, ea, x.dtyp); if (!fIsLoad) doVar(ea); ua_add_dref(x.offb, ea, cmd.itype == M8B_IORD ? dr_R : dr_W); } break; default: ea = toRAM(x.addr); if (ea != BADADDR) { if (!has_any_name(get_flags_novalue(ea))) { qsnprintf(szLabel, sizeof(szLabel), "ram_%0.2X", x.addr); set_name(ea, szLabel, SN_NOWARN); } ua_dodata2(x.offb, ea, x.dtyp); if (!fIsLoad) doVar(ea); ua_add_dref(x.offb, ea, cmd.itype == M8B_IORD ? dr_R : dr_W); } } return; case o_near: ea = toROM(x.addr); if (ea != BADADDR) { switch (cmd.itype) { case M8B_INDEX: if (!has_any_name(get_flags_novalue(ea))) { qsnprintf(szLabel, sizeof(szLabel), "tbl_%0.4X", x.addr); set_name(ea, szLabel, SN_NOWARN); } ua_add_dref(x.offb, ea, dr_R); break; default: ftype = fl_JN; if (InstrIsSet(cmd.itype, CF_CALL)) { if (!func_does_return(ea)) fFlow = false; ftype = fl_CN; } ua_add_cref(x.offb, ea, ftype); } } return; } warning("%a: %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), x.n, x.type); }
int idaapi emu() { char szLabel[MAXSTR]; insn_t saved; segment_t* pSegment; ea_t ea, length, offset; flags_t flags; uint32 dwFeature, i; dwFeature = cmd.get_canon_feature(); fFlow = !(dwFeature & CF_STOP); if (dwFeature & CF_USE1) op_emu(cmd.Op1, 1); if (dwFeature & CF_USE2) op_emu(cmd.Op2, 1); if (dwFeature & CF_CHG1) op_emu(cmd.Op1, 0); if (dwFeature & CF_CHG2) op_emu(cmd.Op2, 0); saved = cmd; switch (cmd.itype) { case M8B_MOV: if (!cmd.Op1.is_reg(rPSP)) break; case M8B_SWAP: if (cmd.itype == M8B_SWAP && !cmd.Op2.is_reg(rDSP)) break; for (i = 0; i < 5; ++i) { ea = decode_prev_insn(cmd.ea); if (ea == BADADDR) break; if (cmd.itype == M8B_MOV && cmd.Op1.is_reg(rA) && cmd.Op2.type == o_imm) { ea = toRAM(cmd.Op2.value); if (ea != BADADDR) { qsnprintf(szLabel, sizeof(szLabel), "%s_%0.2X", cmd.itype == M8B_MOV ? "psp" : "dsp", cmd.Op2.value); ua_add_dref(cmd.Op2.offb, ea, dr_O); set_name(ea, szLabel, SN_NOWARN); } break; } } break; case M8B_JACC: pSegment = getseg(cmd.ea); if (!pSegment) break; length = pSegment->endEA - cmd.ea; if (length > 256) length = 256; for (offset = 2; offset < length; offset += 2) { ea = toROM(saved.Op1.addr + offset); if (ea == BADADDR) break; flags = getFlags(ea); if (!hasValue(flags) || (has_any_name(flags) || hasRef(flags)) || !create_insn(ea)) break; switch (cmd.itype) { case M8B_JMP: case M8B_RET: case M8B_RETI: case M8B_IPRET: add_cref(saved.ea, ea, fl_JN); break; default: offset = length; } } break; case M8B_IORD: case M8B_IOWR: case M8B_IOWX: for (i = 0; i < 5; ++i) { ea = (saved.itype == M8B_IORD) ? decode_insn(cmd.ea + cmd.size) : decode_prev_insn(cmd.ea); if (ea == BADADDR) break; if (cmd.Op1.is_reg(rA) && cmd.Op2.type == o_imm) { qsnprintf(szLabel, sizeof(szLabel), "[A=%0.2Xh] ", cmd.Op2.value); if (get_portbits_sym(szLabel + qstrlen(szLabel), saved.Op1.addr, cmd.Op2.value)) set_cmt(saved.ea, szLabel, false); break; } } } cmd = saved; if ((cmd.ea & 0xFF) == 0xFF) { switch (cmd.itype) { case M8B_RET: case M8B_RETI: case M8B_XPAGE: break; default: QueueMark(Q_noValid, cmd.ea); } } if (fFlow) ua_add_cref(0, cmd.ea + cmd.size, fl_F); return 1; }