size_t VtableScanner::getVtableMethodsCount ( ea_t curAddress ) { ea_t startTable = BADADDR; ea_t curEntry = 0; // Iterate until we find a result for (; ; curAddress += 4) { flags_t flags = IDAUtils::GetFlags (curAddress); // First iteration if (startTable == BADADDR) { startTable = curAddress; if (!(hasRef (flags) && (has_name (flags) || (flags & FF_LABL)))) { // Start of vtable should have a xref and a name (auto or manual) return 0; } } else if (hasRef (flags)) { // Might mean start of next vtable break; } if (!hasValue (flags) || !isData (flags)) { break; } if ((curEntry = get_long (curAddress))) { flags = IDAUtils::GetFlags (curEntry); if (!hasValue (flags) || !isCode (flags) || get_long (curEntry) == 0) { break; } } } if (startTable != BADADDR) { return (curAddress - startTable) / 4; } else { // No vtable at this EA return 0; } }
// 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); } }
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); }
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; }
// 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); } }