From c280f9939487a9eb5ebdc3b0bbc835271febf4f1 Mon Sep 17 00:00:00 2001 From: srgblv <156221391+srgblv@users.noreply.github.com> Date: Sat, 2 Nov 2024 13:59:54 +0300 Subject: [PATCH] A few small auto-renamer fixes --- src/helpers.cpp | 39 +++++++++---- src/helpers.h | 2 +- src/hrtng.cpp | 14 +++-- src/lit.cpp | 4 +- src/rename.cpp | 139 ++++++++++++++++++++++++++------------------- src/structures.cpp | 2 +- 6 files changed, 122 insertions(+), 78 deletions(-) diff --git a/src/helpers.cpp b/src/helpers.cpp index ee547e9..79815f2 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -112,8 +112,13 @@ bool is_ea(flags64_t flg) ea_t get_ea(ea_t ea) { if(is64bit()) - return (ea_t)get_qword(ea); - return (ea_t)get_dword(ea); + ea = (ea_t)get_qword(ea); + else + ea = (ea_t)get_dword(ea); + + if(isARM() && is_tail(get_flags(ea))) + ea = ea & ~1; + return ea; } void create_type_from_size(tinfo_t* t, asize_t size) @@ -144,17 +149,27 @@ void create_type_from_size(tinfo_t* t, asize_t size) void stripName(qstring* name) { - if (!strncmp(name->c_str(), "__imp_", 6)) - name->remove(0, 6); + size_t len = name->length(); + if (len > 6 && !strncmp(name->c_str(), "__imp_", 6)) { + name->remove(0, 6); + len -= 6; + } - if (!strncmp(name->c_str(), "j_", 2)) - name->remove(0, 2); + if (len > 2 && !strncmp(name->c_str(), "j_", 2)) { + name->remove(0, 2); + len -= 2; + } - size_t len = name->length(); if (len > 2) { char last = name->at(len - 1); - if(last >= '0' && last <= '9' && name->at(len - 2) == '_') - name->remove_last(2); + if(last >= '0' && last <= '9') { + last = name->at(len - 2); + if(last == '_') { + name->remove_last(2); + } else if (len > 3 && last >= '0' && last <= '9' && name->at(len - 3) == '_') { + name->remove_last(3); + } + } } } @@ -165,18 +180,18 @@ void stripNum(qstring* name) //strip "i64" suffix if(l > 3 && !qstrcmp(name->c_str() + l - 3, "i64")) { l -= 3; - name->resize(l); + name->remove_last(3); } #else //IDA_SDK_VERSION >= 830 //strip "LL" suffix if(l > 2 && !qstrcmp(name->c_str() + l - 2, "LL")) { l -= 2; - name->resize(l); + name->remove_last(2); } #endif //IDA_SDK_VERSION < 830 //strip "u" suffix if(l > 1 && name->at(l - 1) == 'u') { - name->resize(l - 1); + name->remove_last(1); } } diff --git a/src/helpers.h b/src/helpers.h index 345ac9b..b2bf719 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -125,9 +125,9 @@ size_t get_idx_of_lvar(vdui_t &vu, lvar_t *lvar); tinfo_t getType4Name(const char *name); #define is64bit() inf_is_64bit() -#define is32bit() inf_is_32bit() #define ea_size (is64bit() ? 8 : 4) #define isX86() (PH.id == PLFM_386) +#define isARM() (PH.id == PLFM_ARM) bool is_ea(flags64_t flg); ea_t get_ea(ea_t ea); diff --git a/src/hrtng.cpp b/src/hrtng.cpp index c7f5a4f..ca42e7f 100644 --- a/src/hrtng.cpp +++ b/src/hrtng.cpp @@ -2634,7 +2634,7 @@ static bool idaapi is_stack_var_assign_int(const cexpr_t * stmt, const lvars_t* if (val) *val = right; if(size) { - *size = BADADDR; + *size = BADADDR; if(left->op == cot_var) *size = (sval_t)var->tif.get_size(); else if(left->op == cot_ptr) @@ -2711,6 +2711,7 @@ struct ida_local stack_char_assign_locator_t : public ctree_visitor_t return 0; } }; + static void assign2wstr(qvector &wstr, uint64 _value, sval_t size) { wstr.push_back((wchar16_t)_value); @@ -2794,6 +2795,7 @@ static int scan_stack_string2(action_activation_ctx_t *ctx, bool bDecrypt) nVarsFound++; if(!bDecrypt && !it->second.val) //zeroterminate break; + cexpr_t* val = it->second.val; last_asgn_size = it->second.sz; @@ -2859,6 +2861,7 @@ static int scan_stack_string2(action_activation_ctx_t *ctx, bool bDecrypt) } } } + if(nVarsFound) { if(bDecrypt) { const char* inBuf; @@ -2966,6 +2969,7 @@ bool is_array_char_assign(vdui_t *vu, int* varIdx, ea_t *ea) *ea = ((cexpr_t *)expr)->x->ea; return is_array_char_assign_int(((cexpr_t *)expr)->x, varIdx, NULL, NULL); } + struct ida_local valNsize2_t { uint64 val; @@ -3800,7 +3804,7 @@ const char* FunctionsToggleSync = "FunctionsToggleSync"; #endif bool idaapi runFuncSwitchSync() - { +{ TWidget *wdg = find_widget("Functions window"); if(wdg && get_widget_type(wdg) == BWN_FUNCS) { activate_widget(wdg, true); @@ -3817,7 +3821,7 @@ bool idaapi runFuncSwitchSync() msg("[hrt] `activate_widget` does't work\n"); #endif -#if defined __LINUX__ && IDA_SDK_VERSION >= 740 && IDA_SDK_VERSION <= 750 +#if defined __LINUX__ && IDA_SDK_VERSION >= 740 && IDA_SDK_VERSION <= 750 //ida 7.7 works without crutches //on ida 7.6 this trick does not works anymore //linux IDA 7.4 & 7.5 does not activate widget immediately @@ -3851,7 +3855,7 @@ bool idaapi runFuncSwitchSync() msg("[hrt] AST_DISABLE_FOR_WIDGET\n"); //update_action_state(FunctionsToggleSync, AST_ENABLE_FOR_WIDGET); } - bool checked; +....bool checked; bool bc = get_action_checked(FunctionsToggleSync, &checked); bool visibility; bool bv = get_action_visibility(FunctionsToggleSync, &visibility); @@ -4382,7 +4386,7 @@ plugmod_t* addon.producer = "Sergey Belov and Milan Bohacek, Rolf Rolles, Takahiro Haruyama," \ " Karthik Selvaraj, Ali Rahbar, Ali Pezeshk, Elias Bachaalany, Markus Gaasedelen"; addon.url = "https://github.com/KasperskyLab/hrtng"; - addon.version = "1.1.4"; + addon.version = "1.1.5"; register_addon(&addon); return PLUGIN_KEEP; diff --git a/src/lit.cpp b/src/lit.cpp index af71634..f2e2099 100644 --- a/src/lit.cpp +++ b/src/lit.cpp @@ -284,8 +284,8 @@ static const char* importEnumFromTil(til_t *til, const char* name, uint64 val) return NULL; #endif //IDA_SDK_VERSION < 840 for(uint32 ordinal = 1; ordinal < limit; ++ordinal) { - const type_t *type; - const p_list *fields; + const type_t *type; + const p_list *fields; if(get_numbered_type(til, ordinal, &type, &fields) && type && is_type_enum(*type) && fields) { tinfo_t t; if (t.deserialize(til, &type, &fields)) { diff --git a/src/rename.cpp b/src/rename.cpp index 5d97d03..b09c1bc 100644 --- a/src/rename.cpp +++ b/src/rename.cpp @@ -94,6 +94,7 @@ static bool isNameGood1(const char* name) return false; } } + if((name[0] == 'F' || name[0] == 'B') && !qstrcmp(name + 1, "link")) return false; @@ -115,9 +116,10 @@ static bool isNameGood2(const char* name) { if (!isNameGood1(name)) return false; + for(size_t i = 0; i < qnumber(badArgNames); i++) if(!qstrcmp(name, badArgNames[i])) - return false; + return false; return true; } @@ -190,6 +192,11 @@ static bool getCallName(cfunc_t *func, cexpr_t* call, qstring* name) static bool getEaName(ea_t ea, qstring* name) { flags64_t flg = get_flags(ea); + if(is_tail(flg) && isARM()) { + ea = ea & ~1; + flg = get_flags(ea); + } + if (has_user_name(flg)) { if (name) { get_ea_name(name, ea); @@ -248,12 +255,17 @@ static bool renameEa(ea_t refea, const char* funcname, ea_t ea, const qstring* n msg("[hrt] FIXME: renameEa(%a, \"%s\")\n", refea, newName.c_str()); return false; } + if (!has_cmt(get_flags(ea)) && newName != *name) + set_cmt(ea, name->c_str(), true); + + if(!strncmp(newName.c_str(), "sub_", 4)) + newName.insert('p'); - if (set_name(ea, newName.c_str(), SN_NOCHECK | SN_AUTO | SN_NOWARN | SN_FORCE)) { - make_name_auto(ea); + if (!set_name(ea, newName.c_str(), SN_NOCHECK | SN_AUTO | SN_NOWARN | SN_FORCE)) { + msg("[hrt] %a %s: fail to rename %a to \"%s\"\n", refea, funcname, ea, newName.c_str()); + return false; } - if (!has_cmt(get_flags(ea)) && newName != *name) - set_cmt(ea, name->c_str(), true); + make_name_auto(ea); msg("[hrt] %a %s: Global at %a was renamed to \"%s\"\n", refea, funcname, ea, newName.c_str()); return true; } @@ -279,76 +291,89 @@ bool renameVar(ea_t refea, const char* funcname, cfunc_t *func, ssize_t varIdx, if (newName.size() > MAX_NAME_LEN) newName.resize(MAX_NAME_LEN); if(!validate_name(&newName, VNT_IDENT)) { - msg("[hrt] FIXME: renameVar(%a, \"%s\")\n", refea, newName.c_str()); + //msg("[hrt] FIXME: renameVar(%a, \"%s\")\n", refea, newName.c_str()); return false; } //check if proc doesnt already has such name bool acceptName = false; qstring basename = newName; - for(int i = 0; i < 20; i++) { + for(int i = 0; i < 100; i++) { lvars_t::iterator it = vars->begin(); for(; it != vars->end(); it++) { if(it->name == newName) { - if(it == var) //why it tries rename again? + if(it == var) {//why it tries rename again? + //msg("[hrt] FIXME: renameVar(%a, \"%s\") dup\n", refea, newName.c_str()); return false; - newName = basename; - newName.cat_sprnt("_%d", i + 1); + } break; } } if(it == vars->end()) { - acceptName = true; - break; + // it seems ida donsnt allow renaming local var to the name of existing proc, but OK with global var + ea_t nnea = get_name_ea(BADADDR, newName.c_str()); + if (nnea == BADADDR || !is_func(get_flags(nnea))) { + acceptName = true; + break; + } } + newName = basename; + newName.cat_sprnt("_%d", i + 1); } - if(acceptName) { - //if var is arg it will be useful to rename argument inside function prototype - if(var->is_arg_var()) { - int vIdx = (int)varIdx; - ssize_t argIdx = func->argidx.index(vIdx); - if(argIdx != -1) { - tinfo_t funcType; - if(func->get_func_type(&funcType)) { - func_type_data_t fi; - if(funcType.get_func_details(&fi) && fi.size() > (size_t)argIdx) { - //msg("[hrt] %a %s: Rename arg%d \"%s\" to \"%s\"\n", refea, funcname, argIdx + 1, fi[argIdx].name.c_str(), newName.c_str()); - fi[argIdx].name = newName; - tinfo_t newFType; - newFType.create_func(fi); - if(newFType.is_correct() && apply_tinfo(func->entry_ea, newFType, TINFO_DEFINITE)) { - qstring typeStr; - newFType.print(&typeStr); - msg("[hrt] %a %s: Function prototype was recast for change arg-name into \"%s\"\n", refea, funcname, typeStr.c_str()); - } + if(!acceptName) { + //msg("[hrt] FIXME: renameVar(%a, \"%s\") not accepted\n", refea, newName.c_str()); + return false; + } + + //if var is arg it will be useful to rename argument inside function prototype + if(var->is_arg_var()) { + int vIdx = (int)varIdx; + ssize_t argIdx = func->argidx.index(vIdx); + if(argIdx != -1) { + tinfo_t funcType; + if(func->get_func_type(&funcType)) { + func_type_data_t fi; + if(funcType.get_func_details(&fi) && fi.size() > (size_t)argIdx) { + //msg("[hrt] %a %s: Rename arg%d \"%s\" to \"%s\"\n", refea, funcname, argIdx + 1, fi[argIdx].name.c_str(), newName.c_str()); + fi[argIdx].name = newName; + stripName(&fi[argIdx].name); + tinfo_t newFType; + newFType.create_func(fi); + if(newFType.is_correct() && apply_tinfo(func->entry_ea, newFType, TINFO_DEFINITE)) { + qstring typeStr; + newFType.print(&typeStr); + msg("[hrt] %a %s: Function prototype was recasted for change arg-name into \"%s\"\n", refea, funcname, typeStr.c_str()); } } } } - msg("[hrt] %a %s: Var \"%s\" was renamed to \"%s\"\n", refea, funcname, var->name.c_str(), newName.c_str()); - if (vdui) { - vdui->rename_lvar(var, newName.c_str(), true); // vdui->rename_lvar can rebuild all internal structures/ call later!!! - } else { - //this way of renaming/retyping is not stored in databese, use: - //restore_user_lvar_settings save_user_lvar_settings modify_user_lvars - ///< use mbl_array_t::set_nice_lvar_name() and - ///< mbl_array_t::set_user_lvar_name() to modify it - // - //CHECKME! mba->set_lvar_name(lvar_t &v, const char *name, int flagbits); appeared in ida8.3 - var->name = newName; - var->set_user_name(); - - if(!var->has_user_type()) { - tinfo_t t = getType4Name(newName.c_str()); - if(!t.empty() && var->accepts_type(t)) - if(var->set_lvar_type(t, true)) - msg("[hrt] %a %s: type of var '%s' refreshed\n", refea, funcname, newName.c_str()); - } + } + bool res = true; + qstring oldname = var->name; + if (vdui) { + res = vdui->rename_lvar(var, newName.c_str(), true); // vdui->rename_lvar can rebuild all internal structures/ call later!!! + } else { + //this way of renaming/retyping is not stored in databese, use: + //restore_user_lvar_settings save_user_lvar_settings modify_user_lvars + ///< use mbl_array_t::set_nice_lvar_name() and + ///< mbl_array_t::set_user_lvar_name() to modify it + // + //CHECKME! mba->set_lvar_name(lvar_t &v, const char *name, int flagbits); appeared in ida8.3 + var->name = newName; + var->set_user_name(); + + if(!var->has_user_type()) { + tinfo_t t = getType4Name(newName.c_str()); + if(!t.empty() && var->accepts_type(t)) + if(var->set_lvar_type(t, true)) + msg("[hrt] %a %s: type of var '%s' refreshed\n", refea, funcname, newName.c_str()); } - return true; } - return false; + if(res) + msg("[hrt] %a %s: Var \"%s\" was renamed to \"%s\"\n", refea, funcname, oldname.c_str(), newName.c_str()); + //else msg("[hrt] %a %s: Var \"%s\" rename to \"%s\" falied\n", refea, funcname, oldname.c_str(), newName.c_str()); + return res; } static bool getUdtMembName(tinfo_t type, uint32 offset, qstring* name) @@ -838,13 +863,9 @@ void autorename_n_pull_comments(cfunc_t *cfunc) if(call->op != cot_call) return 0; callCnt++; - carglist_t &args = *call->a; - if(!args.size()) - return 0; ea_t dstea; tinfo_t tif = getCallInfo(call, &dstea); - bool bAllowTypeChange = false; if(dstea != BADADDR && !tif.is_from_subtil()) { func_t *f = get_func(dstea); @@ -880,6 +901,10 @@ void autorename_n_pull_comments(cfunc_t *cfunc) } } + carglist_t &args = *call->a; + if(!args.size()) + return 0; + bool bCallAssign = false; qstring anL, anR; size_t iL, iR; @@ -1052,7 +1077,7 @@ void autorename_n_pull_comments(cfunc_t *cfunc) } //rename func itself if it has dummy name and only one statement inside - if (stmtCnt == 1 && callCnt == 1 && has_dummy_name(get_flags(func->entry_ea))) { + if (stmtCnt <= 1 && callCnt == 1 && has_dummy_name(get_flags(func->entry_ea))) { if (!callProcName.empty() && strncmp(callProcName.c_str(), "psub_", 5)) { qstring newName = callProcName; if (newName.size() > MAX_NAME_LEN - 1) diff --git a/src/structures.cpp b/src/structures.cpp index 9645f1c..753a1b8 100644 --- a/src/structures.cpp +++ b/src/structures.cpp @@ -124,7 +124,7 @@ void add_vt_member(struc_t* sptr, ea_t offset, const char* name, const tinfo_t& if (!get_member_by_name(sptr, newName.c_str())) { set_member_name(sptr, offset, newName.c_str()); break; -} + } } } member_t* memb = get_member(sptr, offset);