//---------------------------------------------------------------------- static void fixup(uint32 ea, uint32 delta, int extdef) { fixup_data_t fd; fd.type = FIXUP_OFF32; if ( extdef ) fd.type |= FIXUP_EXTDEF; segment_t *s = getseg(delta); fd.displacement = get_long(ea); if ( s == NULL ) { fd.sel = 0; fd.off = delta; } else { fd.sel = (ushort)s->sel; fd.off = delta - get_segm_base(s); } set_fixup(ea, &fd); uint32 target = get_long(ea) + delta; put_long(ea, target); set_offset(ea, 0, 0); cmd.ea = ea; ua_add_dref(0, target, dr_O); cmd.ea = BADADDR; if ( target != toc_ea && !has_name(get_flags_novalue(ea)) && has_name(get_flags_novalue(target)) ) { char buf[MAXSTR]; if ( get_true_name(BADADDR, target, &buf[3], sizeof(buf)-3) != NULL ) { buf[0] = 'T'; buf[1] = 'C'; buf[2] = '_'; do_name_anyway(ea, buf); make_name_auto(ea); } } // toc.charset(ea,XMC_TC+1,1); }
ea_t GetDelayedBranchAdr(void) // if previous instruction is delayed jump return jump adr, else -1 { int16 disp; if (! isFlow(uFlag)) return BADADDR; // Does the previous instruction exist and pass execution flow to the current byte? if (cmd.size <= 0) return BADADDR; int sub = 3; // backward offset to skip 3 previous 1-word instruction ea_t ea = cmd.ea - sub; if (isCode(get_flags_novalue(ea))) // Does flag denote start of an instruction? { int code = get_full_byte(ea); // get the instruction word if ((code & 0xff000000) == 0x61000000) // Branch unconditionally (delayed) return code & 0xffffff; if ((code & 0xffe00000) == 0x6a200000) // BranchD conditionally { disp = code & 0xffff; return cmd.ea + disp; } if ((code & 0xfe200000) == 0x6e200000) // DecrementD and branch conditionally { disp = code & 0xffff; return cmd.ea + disp; } } return BADADDR; }
//-------------------------------------------------------------------------- void idaapi cr16c_data(ea_t ea) { char obuf[256]; init_output_buffer(obuf, sizeof(obuf)); int col = 0; uint32 flags = get_flags_novalue(ea); if (isWord(flags)) { out_snprintf("%s %xh", ash.a_word ? ash.a_word : "", get_word(ea)); } else if (isDwrd(flags)) { out_snprintf("%s %xh", ash.a_dword ? ash.a_dword : "", get_long(ea)); } else { //if (isByte(flags)) { int val = get_byte(ea); char ch = ' '; if (val >= 0x20 && val <= 0x7E) { ch = val; } out_snprintf("%s %02xh ; %c", ash.a_byte ? ash.a_byte : "", val, ch); } term_output_buffer(); gl_comm = 1; MakeLine(obuf); return; }
//---------------------------------------------------------------------- static void destroy_if_unnamed_array(ea_t ea) { flags_t F = get_flags_novalue(ea); if ( isTail(F) && segtype(ea) == SEG_IMEM ) { ea_t head = prev_not_tail(ea); if ( !has_user_name(get_flags_novalue(head)) ) { do_unknown(head, DOUNK_SIMPLE); doByte(head, ea-head); ea_t end = nextthat(ea, inf.maxEA, f_isHead, NULL); if ( end == BADADDR ) end = getseg(ea)->endEA; doByte(ea+1, end-ea-1); } } }
bool idaapi create_func_frame(func_t *pfn) { if ( pfn == NULL ) return 0; ea_t ea = pfn->startEA; insn_t insn[4]; int i; for (i = 0; i < 4; i++) { decode_insn(ea); insn[i] = cmd; ea += cmd.size; } i = 0; ushort regsize = 0; // number of saved registers // first insn is not either push fp OR st fp, @-sp if ( (insn[i].itype != m32r_push || insn[i].Op1.reg != rFP ) && (insn[i].itype != m32r_st || insn[i].Op1.reg != rFP || insn[i].Op2.reg != rSP || insn[i].Op2.specflag1 != fRIAS)) { return 0; } regsize += 4; i++; // next insn is push lr OR st lr, @-sp if ( (insn[i].itype == m32r_push && insn[i].Op1.reg == rLR ) || (insn[i].itype == m32r_st && insn[i].Op1.reg == rFP && insn[i].Op2.reg == rLR && insn[i].Op2.specflag1 != fRIAS)) { regsize += 4; i++; } // next insn is not addi sp, #imm if ( insn[i].itype != m32r_addi || insn[i].Op1.reg != rSP ) return 0; sval_t offset = - (sval_t) insn[i].Op2.value; // toggle to the negative sign of the immediate operand of the addi insn if ( !is_invsign(insn[i].ea, get_flags_novalue(insn[i].ea), 2) ) toggle_sign(insn[i].ea, 2); i++; // next insn is not mv fp, sp if ( insn[i].itype != m32r_mv || insn[i].Op1.reg != rFP || insn[i].Op2.reg != rSP ) return 0; #if DEBUG msg("=> %d bytes\n", - (signed) insn[1].Op2.value); #endif pfn->flags |= (FUNC_FRAME | FUNC_BOTTOMBP); //setflag((uint32 &) pfn->flags, FUNC_FRAME | FUNC_BOTTOMBP, 1); return add_frame(pfn, offset, regsize, 0); }
//---------------------------------------------------------------------- static void TouchArg(op_t &x, int isload) { switch ( x.type ) { case o_displ: case o_imm: if ( op_adds_xrefs(uFlag, x.n) ) { int outf = x.type != o_imm ? OOF_ADDR : 0; ua_add_off_drefs2(x, dr_O, outf|OOF_SIGNED); } break; case o_mem: case o_ind_mem: case o_reg: case o_ind_reg: { ea_t dea; if ( x.type == o_mem || x.type == o_ind_mem ) { dea = map_addr(x.addr, x.n, true); } else { if ( x.reg >= rRR0 ) dea = map_addr(x.reg - rRR0, x.n, true); else dea = map_addr(x.reg - rR0, x.n, true); } ua_dodata2(x.offb, dea, x.dtyp); if ( !isload ) doVar(dea); ua_add_dref(x.offb, dea, isload ? dr_R : dr_W); if ( !has_user_name(get_flags_novalue(dea)) && dea > intmem) { char buf[10]; int num = dea - intmem; if ( num < 0x100 ) { qsnprintf(buf, sizeof(buf), "R%d", num); } else if ( num < 0x1000 ) { qsnprintf(buf, sizeof(buf), "ERF_%X_%d", num >> 8, num & 0xFF); } else { int reg_no = ((num >> 4) & 0xF0) + (num & 0xF); int subbank_no = ((num >> 4) & 0xF) + 1; qsnprintf(buf, sizeof(buf), "R%d_%X", reg_no, subbank_no); } set_name(dea, buf, SN_NOWARN); }
//---------------------------------------------------------------------- static int canFlow(void) { if ( isC2() ) return 1; if ( !isFlow(uFlag) ) return 1; // no previous instructions ea_t ea = prevInstruction(cmd.ea); if ( cmd.size == 2 ) // our instruction is long { ; // nothing to do } else { // our instruction short if ( (cmd.ea-ea) == 2 ) // prev instruction long return 1; // can flow always flags_t F = get_flags_novalue(ea); if ( !isCode(F) || !isFlow(F) ) return 1; // no prev instr... ea = prevInstruction(ea); } flags_t F = get_flags_novalue(ea); return !isCode(F) || !isDelayedStop((ushort)get_full_byte(ea)); }
//--------------------------------------------------------------------------- static void idaapi ch_enter(void *obj, uint32 n) { x86seh_ctx_t *ctx = (x86seh_ctx_t *)obj; if ( --n < ctx->handlers.size() ) { ea_t ea = ctx->handlers[n]; if ( !isCode(get_flags_novalue(ea)) ) create_insn(ea); jumpto(ea); } }
//---------------------------------------------------------------------- ea_t find_first_insn_in_packet(ea_t ea) { while ( (ea & 0x1F) != 0 ) { ea_t ea2 = prev_not_tail(ea); if ( ea2 == BADADDR || !isCode(get_flags_novalue(ea2)) || (get_long(ea2) & BIT0) == 0 ) break; ea = ea2; } return ea; }
//---------------------------------------------------------------------- static bool canFlow(void) { if ( ! isFlow(uFlag) ) return 1; // no previous instructions ea_t ea = cmd.ea - 4; flags_t F = get_flags_novalue(ea); if ( isFlow(F) && isCode(F) ) { if ( isDelayedStop(get_long(ea)) ) // now or later { ea -= 4; if ( !isCode(get_flags_novalue(ea)) || !isDual(get_long(ea)) ) return 0; return 1; } if ( isFlow(F) ) { ea -= 4; return !isCode(get_flags_novalue(ea)) || !isDelayedStop(get_long(ea)); } } return 1; }
// 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 delayed_stop(void) { if (! isFlow(uFlag)) return false; if (cmd.size <= 0 || cmd.size > 2) return false; int sub = 2 - cmd.size; // backward offset to skip the previous 1-word instruction in the case of 2 consecutive 1-word instructions // first, we analyze 1-word instructions ea_t ea = cmd.ea - sub - 1; if (isCode(get_flags_novalue(ea))) { int code = get_full_byte(ea); // get the instruction word switch (code) { case 0xF6E2: // TMS320C54_baccd, // Branch to Location Specified by Accumulator 1111 01ZS 1110 0010 BACC[D] src case 0xF7E2: case 0xF6E6: // TMS320C54_fbaccd, // Far Branch to Location Specified by Accumulator 1111 01ZS 1110 0110 FBACC[D] src case 0xF7E6: case 0xF6E4: // TMS320C54_fretd, // Far Return 1111 01Z0 1110 0100 FRET[D] case 0xF6E5: // TMS320C54_freted, // Enable Interrupts and Far Return From Interrupt 1111 01Z0 1110 0101 FRETE[D] case 0xFE00: // TMS320C54_retd, // Return 1111 11Z0 0000 0000 RET[D] case 0xF6EB: // TMS320C54_reted, // Enable Interrupts and Return From Interrupt 1111 01Z0 1110 1011 RETE[D] case 0xF69B: // TMS320C54_retfd, // Enable Interrupts and Fast Return From Interrupt 1111 01Z0 1001 1011 RETF[D] return true; } } // else, we analyze 2-word instructions ea = cmd.ea - sub - 2; if (isCode(get_flags_novalue(ea))) { int code = get_full_byte(ea); // get the first instruction word if ( code == 0xF273 // TMS320C54_bd, // Branch Unconditionally 1111 00Z0 0111 0011 16-bit constant B[D] pmad || (code & 0xFF80) == 0xFA80) // TMS320C54_fbd, // Far Branch Unconditionally 1111 10Z0 1 7bit constant=pmad(22-16) 16-bit constant=pmad(15-0) FB[D] extpmad return true; } return false; }
void run(int) { netnode n("$ vmm functions"); ea_t ea = get_screen_ea(); // get current address if ( !isCode(get_flags_novalue(ea)) ) return; // not an instruction ea_t callee = n.altval(ea)-1; // get the callee address from the database char buf[MAXSTR]; qsnprintf(buf, sizeof(buf), form, help); if ( AskUsingForm_c(buf, &callee) ) { n.altset(ea, callee+1); // save the new address noUsed(ea); // reanalyze the current instruction } }
//---------------------------------------------------------------------- int find_ar(ea_t *res) { ea_t ea = cmd.ea; for ( int i=0; i < lookback; i++ ) { ea = prevInstruction(ea); if ( !isCode(get_flags_novalue(ea)) ) break; ushort code = (ushort)get_full_byte(ea); if ( isC2() ) { switch ( code >> 11 ) { case 6: // LAR return 0; case 0x18: // LARK *res = toEA(dataSeg(),(code & 0xFF)); return 1; case 0x1A: // LRLK if ( (code & 0xF8FF) == 0xD000 ) { ushort b = (ushort)get_full_byte(ea+1); *res = toEA(dataSeg(), b); return 1; } } continue; } switch ( code >> 11 ) { case 0: // Load AR from addressed data return 0; // LAR found, unknown address case 0x16: // Load AR short immediate *res = toEA(dataSeg(), code & 0xFF); return 1; case 0x17: // Load AR long immediate if ( (code & ~7) == 0xBF08 ) { ushort b = (ushort)get_full_byte(ea+1); *res = toEA(dataSeg(),b); return 1; } } } return 0; }
//--------------------------------------------------------------------------- // Validate table attributes static bool check_table(ea_t table, uval_t elsize, uval_t tsize) { flags_t F; if ( getseg(table) == NULL || isCode((F=get_flags_novalue(table))) || isTail(F) ) { warning("AUTOHIDE NONE\nIncorrect table address %a", table); return false; } if ( elsize != 1 && elsize != 2 && elsize != 4 && elsize != 8 ) { warning("AUTOHIDE NONE\nIncorrect table element size %d", elsize); return false; } flags_t DF = get_flags_by_size((size_t)elsize); if ( !can_define_item(table, elsize*tsize, DF) ) { warning("AUTOHIDE NONE\nCan not create table at %a size %d", table, tsize); return false; } return true; }
//---------------------------------------------------------------------- static void setup_far_func(func_t *pfn) { if ( (pfn->flags & FUNC_FAR) == 0 ) { ea_t ea1 = pfn->startEA; ea_t ea2 = pfn->endEA; while ( ea1 < ea2 ) { if ( isCode(get_flags_novalue(ea1)) ) { decode_insn(ea1); if ( is_far_ending() ) { pfn->flags |= FUNC_FAR; update_func(pfn); break; } } ea1 = next_head(ea1, ea2); } } }
//---------------------------------------------------------------------- static bool may_be_skipped(void) { ea_t ea = cmd.ea - 1; if ( isCode(get_flags_novalue(ea)) ) { int code = get_full_byte(ea); switch ( code & 0xFC00 ) { // 0001 00rd dddd rrrr cpse rd, rr 4 Compare, Skip if Equal case 0x1000: // 1111 110r rrrr xbbb sbrc rr, b Skip if Bit in I/O Register Cleared // 1111 111r rrrr xbbb sbrs rr, b Skip if Bit in I/O Register Set case 0xFC00: return true; // 1001 1001 pppp pbbb sbic p, b Skip if Bit in Register Cleared // 1001 1011 pppp pbbb sbis p, b Skip if Bit in Register Set case 0x9800: return (code & 0x0100) != 0; } } return false; }
void idaapi run(int) { static const char * nname; if ( ph.id == PLFM_MIPS ) nname = "$ mips"; else if ( ph.id == PLFM_ARM ) nname = " $arm"; else nname = "$ vmm functions"; netnode n(nname); ea_t ea = get_screen_ea(); // get current address if ( !isCode(get_flags_novalue(ea)) ) return; // not an instruction ea_t callee = n.altval(ea)-1; // get the callee address from the database // remove thumb bit for arm if ( ph.id == PLFM_ARM ) callee &= ~1; char buf[MAXSTR]; qsnprintf(buf, sizeof(buf), form, help); if ( AskUsingForm_c(buf, &callee) ) { if ( callee == BADADDR ) { n.altdel(ea); } else { if ( ph.id == PLFM_ARM && (callee & 1) == 0 ) { // if we're calling a thumb function, set bit 0 sel_t tbit = getSR(callee, T); if ( tbit != 0 && tbit != BADSEL ) callee |= 1; } n.altset(ea, callee+1); // save the new address } noUsed(ea); // reanalyze the current instruction } }
bool delayed_stop(void) { if (! isFlow(uFlag)) return false; // Does the previous instruction exist and pass execution flow to the current byte? if (cmd.size <= 0) return false; int sub = 3; // backward offset to skip 3 previous 1-word instruction ea_t ea = cmd.ea - sub; if (isCode(get_flags_novalue(ea))) // Does flag denote start of an instruction? { int code = get_full_byte(ea); // get the instruction word if ((code & 0xff000000) == 0x61000000) return true; // Branch unconditionally delayed 0110 0001 xxxx xxxx xxxx xxxx xxxx xxxx if ((code & 0xfdff0000) == 0x68200000) return true; // Branch conditionally delayed (with U cond) 0110 10x0 001x xxxx xxxx xxxx xxxx xxxx //if ((code & 0xfc3f0000) == 0x6c200000) return true; // Decrement and branch conditionally (with U cond) 0110 11xx xx1x xxxx xxxx xxxx xxxx xxxx // выброшено, т.к. используется в основном для огранизации циклов // а циклы не покидают пределы процедуры } return false; }
//---------------------------------------------------------------------- bool is_basic_block_end(void) { if (delayed_stop()) return true; return ! isFlow(get_flags_novalue(cmd.ea+cmd.size)); }
//---------------------------------------------------------------------- bool jump_pattern_t::follow_tree(ea_t ea, int n) { if ( n == 0 ) return true; int rsaved[sizeof(r)]; bool ssaved[sizeof(spoiled)]; memcpy(rsaved, r, sizeof(r)); memcpy(ssaved, spoiled, sizeof(spoiled)); bool success = false; if ( n < 0 ) { success = true; n = -n; } jmsg("follow_tree(%a, %d)\n", ea, n); if ( !skip[n] ) { if ( eas[n] == BADADDR ) { cmd.ea = ea; bool found_insn = false; while ( true ) { if ( cmd.ea < minea ) break; farref = false; ea_t prev = BADADDR; if ( allow_noflows || isFlow(get_flags_novalue(cmd.ea)) ) prev = decode_prev_insn(cmd.ea); if ( prev == BADADDR ) { if ( !allow_farrefs ) break; ea_t cur_addr = cmd.ea; if ( decode_preceding_insn(cmd.ea, &farref) == BADADDR ) break; // skip branches which are used to glue blocks together if ( farref && is_branch_to(cur_addr) ) continue; } if ( handle_mov() ) continue; if ( (this->*check[n])() ) { found_insn = true; break; } if ( failed ) return false; jmsg("%a: can't be %d.", cmd.ea, n); jmsg(" rA=%d%s rB=%d%s rC=%d%s rD=%d%s rE=%d%s\n", r[1], spoiled[1] ? "*" : "", r[2], spoiled[2] ? "*" : "", r[3], spoiled[3] ? "*" : "", r[4], spoiled[4] ? "*" : "", r[5], spoiled[5] ? "*" : ""); check_spoiled(); } if ( !found_insn ) { memcpy(r, rsaved, sizeof(r)); if ( success ) goto SUCC; return false; } eas[n] = cmd.ea; } if ( eas[n] >= ea ) { jmsg("%a: depends on %a\n", ea, eas[n]); return success; } ea = eas[n]; jmsg("%a: found %d\n", cmd.ea, n); } SUCC: if ( depends[n][0] && !follow_tree(ea, depends[n][0]) ) return success; if ( depends[n][1] && !follow_tree(ea, depends[n][1]) ) return success; jmsg("follow_tree(%d) - ok\n", n); memcpy(spoiled, ssaved, sizeof(spoiled)); return true; }
//--------------------------------------------------------------------------- // The main function - called when the user selects the menu item static bool idaapi callback(void *) { // Calculate the default values to display in the form ea_t screen_ea = get_screen_ea(); segment_t *s = getseg(screen_ea); if ( s == NULL || !isCode(get_flags_novalue(screen_ea)) ) { warning("AUTOHIDE NONE\nThe cursor must be on the table jump instruction"); return false; } ea_t startea = screen_ea; while ( true ) { ea_t prev = prev_not_tail(startea); if ( !is_switch_insn(prev) ) break; startea = prev; } ea_t jumps = get_first_dref_from(screen_ea); uval_t jelsize = s->abytes(); uval_t jtsize = 0; if ( jumps != BADADDR ) { decode_insn(screen_ea); jtsize = guess_table_size(jumps); } uval_t shift = 0; uval_t elbase = 0; char input[MAXSTR]; input[0] = '\0'; ea_t defea = BADADDR; uval_t lowcase = 0; ushort jflags = 0; ushort vflags = 0; ea_t vtable = BADADDR; ea_t vtsize = 0; ea_t velsize = s->abytes(); reg_info_t ri; ri.size = 0; // If switch information is present in the database, use it for defaults switch_info_ex_t si; if ( get_switch_info_ex(screen_ea, &si, sizeof(si)) > 0 ) { jumps = si.jumps; jtsize = si.ncases; startea = si.startea; elbase = si.elbase; jelsize = si.get_jtable_element_size(); shift = si.get_shift(); defea = (si.flags & SWI_DEFAULT) ? si.defjump : BADADDR; if ( si.regnum != -1 ) get_reg_name(si.regnum, get_dtyp_size(si.regdtyp), input, sizeof(input)); if ( si.flags & SWI_SIGNED ) jflags |= 2; if ( si.flags2 & SWI2_SUBTRACT ) jflags |= 4; if ( si.flags & SWI_SPARSE ) { jflags |= 1; vtable = si.values; vtsize = jtsize; velsize = si.get_vtable_element_size(); if ( si.flags2 & SWI2_INDIRECT ) { vflags |= 1; jtsize = si.jcases; } if ( si.flags & SWI_JMP_INV ) vflags |= 2; } else { lowcase = si.lowcase; } } // Now display the form and let the user edit the attributes while ( AskUsingForm_c(main_form, &jumps, &jtsize, &jelsize, &shift, &elbase, &startea, input, &lowcase, &defea, &jflags) ) { if ( !check_table(jumps, jelsize, jtsize) ) continue; if ( shift > 3 ) { warning("AUTOHIDE NONE\nInvalid shift value (allowed values are 0..3)"); continue; } if ( !isCode(get_flags_novalue(startea)) ) { warning("AUTOHIDE NONE\nInvalid switch idiom start %a (must be an instruction", startea); continue; } ri.reg = -1; if ( input[0] != '\0' && !parse_reg_name(input, &ri) ) { warning("AUTOHIDE NONE\nUnknown input register: %s", input); continue; } if ( defea != BADADDR && !isCode(get_flags_novalue(defea)) ) { warning("AUTOHIDE NONE\nInvalid default jump %a (must be an instruction", defea); continue; } if ( jflags & 1 ) // value table is present { bool vok = false; while ( AskUsingForm_c(value_form, &vflags, &vtable, &vtsize, &velsize) ) { if ( (vflags & 1) == 0 ) vtsize = jtsize; if ( check_table(vtable, velsize, vtsize) ) { vok = true; break; } } if ( !vok ) break; } // ok, got and validated all params -- fill the structure si.flags = SWI_EXTENDED; si.flags2 = 0; if ( jflags & 2 ) si.flags |= SWI_SIGNED; if ( jflags & 4 ) si.flags2 |= SWI2_SUBTRACT; si.jumps = jumps; si.ncases = ushort(jtsize); si.startea = startea; si.elbase = elbase; if ( elbase != 0 ) si.flags |= SWI_ELBASE; si.set_jtable_element_size((int)jelsize); si.set_shift((int)shift); if ( defea != BADADDR ) { si.flags |= SWI_DEFAULT; si.defjump = defea; } if ( ri.reg != -1 ) si.set_expr(ri.reg, get_dtyp_by_size(ri.size)); if ( jflags & 1 ) // value table is present { si.flags |= SWI_SPARSE; si.values = vtable; si.set_vtable_element_size((int)velsize); if ( (vflags & 1) != 0 ) { si.flags2 |= SWI2_INDIRECT; si.jcases = (int)jtsize; si.ncases = (ushort)vtsize; } if ( (vflags & 2) != 0 ) si.flags |= SWI_JMP_INV; } else { si.lowcase = lowcase; } // ready, store it set_switch_info_ex(screen_ea, &si); create_switch_table(screen_ea, &si); setFlbits(screen_ea, FF_JUMP); create_insn(screen_ea); info("AUTOHIDE REGISTRY\nSwitch information has been stored"); break; } return true; }
bool has_meaningful_name(ea_t ea) { _ASSERTE(isEnabled(ea)); char tmp[MAXNAMESIZE]; return has_name(get_flags_novalue(ea)) && get_true_name(BADADDR, ea, CPY(tmp)) != 0 && !pcre_match("^unknown_libname_\\d+$", tmp); }
//---------------------------------------------------------------------- static void TouchArg(op_t &x,int isAlt,int isload) { switch ( x.type ) { case o_phrase: //Добавляем в список ошибок(выводим сообщение) //ошибку и адресс где это случилось //QueueMark(Q_jumps, cmd.ea); case o_void: case o_reg: break; case o_sr: case o_displ: //Установить для данного байта признак immedia doImmd(cmd.ea); //Получить флаг для указанного линейного адресса if ( !isAlt ) { uint32 offb; ushort addr = ushort(x.addr); if ( x.type == o_displ ) { addr += (ushort)cmd.ip; addr += cmd.size; //Получить линейный адресс offb = (uint32)toEA(codeSeg(addr,x.n), 0); DataSet(x, offb+addr, isload); } else if ( isOff(uFlag, x.n) ) { reref: ua_add_off_drefs2(x, dr_O, x.type == o_displ ? OOF_ADDR : 0); if ( x.type == o_displ ) //Преобразовать данные по указанному линейному адрессу в указанный тип ua_dodata2(x.offb, calc_target(cmd.ea+x.offb, cmd.ea, x.n, x.addr), x.dtyp); } else if ( x.type == o_displ && !x.reg && !isDefArg(uFlag, x.n ) && set_offset(cmd.ea, x.n, toEA(cmd.cs,0))) goto reref; } break; case o_stk: case o_imm: { //Установить для данного байта признак immedia doImmd(cmd.ea); if ( isOff(get_flags_novalue(cmd.ea), x.n) ) ua_add_off_drefs2(x, dr_O, 0); } break; case o_ab: { if ( x.TypeOper == TAB_INDIRECTED_ABS_X ) { ea_t ea = toEA(cmd.cs, x.addr); ua_dodata2(x.offb, ea, dt_word); //добавить крос референсы для текущей инструкции ua_add_dref(x.offb, ea, isload ? dr_R : dr_W); //получить данные uint32 Addr; Addr = get_word(ea); Addr = uint32( Addr | (getPG<<16)); //добавить крос референсы для текущей инструкции ua_add_cref(2, Addr, fl_JF); } else DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); } break; case o_mem: { // Конвертирование в данные(указан адресс) по указанному типу, //добавить крос референсы для текущей инструкции switch ( x.TypeOper ) { case TDIR_DIR_Y: case TDIR_DIR_X: case TDIR_DIR: case TDIR_INDIRECT_DIR: case TDIR_INDIRECT_DIR_X: case TDIR_INDIRECT_DIR_Y: case TDIR_L_INDIRECT_DIR: case TDIR_L_INDIRECT_DIR_Y: { if ( getDPReg == 1 ) { uint32 d = x.addr & 0xC; x.addr &= 0xFF3F; DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); x.addr |=d; } else DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); } break; default: DataSet(x, toEA(codeSeg(x.addr,x.n), x.addr), isload); }//end switch } break; case o_near: { //Получить линейный адресс ea_t ea = toEA(cmd.cs, x.addr); switch ( cmd.itype ) { case m7900_jsr: { //добавить крос референсы для текущей инструкции ua_add_cref(x.offb, ea, fl_CN ); if ( !func_does_return(ea) ) flow = false; } break; case m7900_jsrl: //добавить крос референсы для текущей инструкции ua_add_cref(x.offb, ea, fl_CF); if ( !func_does_return(ea) ) flow = false; break; case m7900_jmpl: //добавить крос референсы для текущей инструкции ua_add_cref(x.offb, ea, fl_JF); break; default: ua_add_cref(x.offb, ea, fl_JN); break; } } break; default: // warning("%a: %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), x.n, x.type); break; } }
// Process function void processFunction(func_t *f) { // Skip tiny functions if(f->size() >= 5) { // Don't add comments to API wrappers char name[MAXNAMELEN]; name[0] = name[SIZESTR(name)] = 0; if(!apiMap.empty()) { if(get_short_name(BADADDR, f->startEA, name, SIZESTR(name))) { if(apiMap.find(name) != apiMap.end()) return; } } // Iterate function body STRLIST importLstTmp; LPSTR commentPtr = NULL; char comment[MAXSTR]; comment[0] = comment[SIZESTR(comment)] = 0; UINT commentLen = 0; #define ADDNM(_str) { UINT l = strlen(_str); memcpy(comment + commentLen, _str, l); commentLen += l; _ASSERT(commentLen < MAXSTR); } func_item_iterator_t it(f); do { ea_t currentEA = it.current(); // Will be a "to" xref xrefblk_t xb; if(xb.first_from(currentEA, XREF_FAR)) { BOOL isImpFunc = FALSE; name[0] = 0; // If in import segment // ============================================================================================ ea_t refAdrEa = xb.to; if(isInImportSeg(refAdrEa)) { flags_t flags = get_flags_novalue(refAdrEa); if(has_name(flags) && hasRef(flags) && isDwrd(flags)) { if(get_short_name(BADADDR, refAdrEa, name, SIZESTR(name))) { // Nix the imp prefix if there is one if(strncmp(name, "__imp_", SIZESTR("__imp_")) == 0) memmove(name, name + SIZESTR("__imp_"), ((strlen(name) - SIZESTR("__imp_")) + 1)); isImpFunc = TRUE; } else msg(EAFORMAT" *** Failed to get import name! ***\n", refAdrEa); } } // Else, check for import wrapper // ============================================================================================ else if(!apiMap.empty()) { // Reference is a function entry? flags_t flags = get_flags_novalue(refAdrEa); if(isCode(flags) && has_name(flags) && hasRef(flags)) { if(func_t *refFuncPtr = get_func(refAdrEa)) { if(refFuncPtr->startEA == refAdrEa) { if(get_short_name(BADADDR, refAdrEa, name, SIZESTR(name))) { // Skip common unwanted types "sub_.." or "unknown_libname_.." if( // not "sub_.. /*"sub_"*/ (*((PUINT) name) != 0x5F627573) && // not "unknown_libname_.. /*"unknown_"*/ ((*((PUINT64) name) != 0x5F6E776F6E6B6E75) && (*((PUINT64) (name + 8)) != /*"libname_"*/ 0x5F656D616E62696C)) && // not nullsub_.. /*"nullsub_"*/ (*((PUINT64) name) != 0x5F6275736C6C756E) ) { // Nix the import prefixes if(strncmp(name, "__imp_", SIZESTR("__imp_")) == 0) memmove(name, name + SIZESTR("__imp_"), ((strlen(name) - SIZESTR("__imp_")) + 1)); // Assumed to be a wrapped import if it's in the list isImpFunc = (apiMap.find(name) != apiMap.end()); } } else msg(EAFORMAT" *** Failed to get function name! ***\n", refAdrEa); } } } } // Found import function to add list if(isImpFunc) { // Skip those large common STL names if(strncmp(name, "std::", SIZESTR("std::")) != 0) { // Skip if already seen in this function BOOL known = FALSE; for(STRLIST::iterator ji = importLstTmp.begin(); ji != importLstTmp.end(); ji++) { if(strcmp(ji->c_str(), name) == 0) { known = TRUE; break; } } // Not seen if(!known) { importLstTmp.push_front(name); // Append to existing comments w/line feed if(!commentLen && !commentPtr) { commentPtr = get_func_cmt(f, true); if(!commentPtr) get_func_cmt(f, false); if(commentPtr) { commentLen = strlen(commentPtr); // Bail out not enough comment space if(commentLen >= (MAXSTR - 20)) { qfree(commentPtr); return; } memcpy(comment, commentPtr, commentLen); ADDNM("\n"MYTAG); } } if(!commentLen) ADDNM(MYTAG); // Append a "..." (continuation) and bail out if name hits max comment length if((commentLen + strlen(name) + SIZESTR("()") + sizeof(", ")) >= (MAXSTR - sizeof("..."))) { ADDNM(" ..."); break; } // Append this function name else { if(importLstTmp.size() != 1) ADDNM(", "); ADDNM(name); ADDNM("()"); } } } else { //msg("%s\n", szName); } } } }while(it.next_addr()); if(!importLstTmp.empty() && commentLen) { // Add comment comment[commentLen] = 0; set_func_cmt(f, comment, true); commentCount++; } if(commentPtr) qfree(commentPtr); } }
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); }
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; }
//---------------------------------------------------------------------- static void TouchArg(op_t &x,int isload) { ea_t ea; switch ( x.type ) { case o_phrase: // 2 registers or indirect addressing if ( cmd.itype != TMS_mar && cmd.itype != TMS2_mar && find_ar(&ea) ) goto set_dref; case o_reg: case o_bit: case o_cond: break; case o_imm: if ( ! isload ) goto badTouch; doImmdValue(); if ( isOff(uFlag, x.n) ) ua_add_off_drefs2(x, dr_O, is_mpy() ? OOF_SIGNED : 0); break; case o_mem: ea = toEA(dataSeg_op(x.n),x.addr); set_dref: ua_dodata2(x.offb, ea, x.dtyp); if ( ! isload ) doVar(ea); ua_add_dref(x.offb,ea,isload ? dr_R : dr_W); if ( x.type == o_mem ) if ( cmd.itype == TMS_dmov || cmd.itype == TMS_ltd || cmd.itype == TMS_macd || cmd.itype == TMS_madd || cmd.itype == TMS2_dmov || cmd.itype == TMS2_macd ) ua_add_dref(x.offb,ea+1,dr_W); break; case o_near: { ea_t segbase = codeSeg(x.addr, x.n); ea = toEA(segbase, x.addr); if ( cmd.itype == TMS_blpd || cmd.itype == TMS_mac || cmd.itype == TMS_macd || cmd.itype == TMS2_blkp || cmd.itype == TMS2_mac || cmd.itype == TMS2_macd ) goto set_dref; uval_t thisseg = cmd.cs; int iscall = InstrIsSet(cmd.itype,CF_CALL); if ( cmd.itype == TMS_rptb && isTail(get_flags_novalue(ea)) ) { // small hack to display end_loop-1 instead of before_end_loop+1 ea++; } ua_add_cref(x.offb, ea, iscall ? ((segbase == thisseg) ? fl_CN : fl_CF) : ((segbase == thisseg) ? fl_JN : fl_JF)); if ( iscall ) { if ( !func_does_return(ea) ) flow = false; } } break; default: badTouch: warning("%a: %s,%d: bad optype %d", cmd.ea, cmd.get_canon_mnem(), x.n, x.type); break; } }
//---------------------------------------------------------------------- static int LoadArg(op_t &x) { dref_t xreftype; switch ( x.type ) { case o_reg: { if ( x.reg == R_sp ) goto Undefined; // AbstractRegister *in = &i5_getreg(x.reg); // if ( ! in->isDef() ) goto Undefined; // r.doInt(in->value()); return 1; } case o_imm: // r.doInt(unsigned(x.value)); xreftype = dr_O; MakeImm: doImmdValue(x.n); if ( isOff(uFlag, x.n) ) ua_add_off_drefs2(x, xreftype, 0); return 1; case o_displ: // r.undef(); xreftype = dr_R; goto MakeImm; case o_mem: { ea_t ea = toEA(dataSeg_op(x.n),x.addr); ua_add_dref(x.offb,ea,dr_R); ua_dodata2(x.offb, ea, x.dtyp); if ( !isVar(get_flags_novalue(ea)) && isLoaded(ea) ) { // r.doInt( x.dtyp != dt_byte ? get_word(ea) : char(get_byte(ea)) ); return 1; } } case o_phrase: Undefined: // r.undef(); break; case o_near: { ea_t segbase = codeSeg(x.addr,x.n); ea_t ea = toEA(segbase,x.addr); ea_t thisseg = cmd.cs; int iscall = InstrIsSet(cmd.itype,CF_CALL); ua_add_cref(x.offb, ea, iscall ? ((segbase == thisseg) ? fl_CN : fl_CF) : ((segbase == thisseg) ? fl_JN : fl_JF)); if ( iscall && !func_does_return(ea) ) flow = false; // r.doInt(unsigned(x.addr)); } return 1; default: // warning("%a: %s,%d: bad load optype %d", cmd.ea, cmd.get_canon_mnem(), x.n, x.type); break; } return 0; }
// 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); }