├── Beautify.py ├── README.md └── img ├── b0.gif └── hide.gif /Beautify.py: -------------------------------------------------------------------------------- 1 | import idaapi 2 | import ida_idp 3 | import ida_hexrays 4 | import idautils 5 | import netnode 6 | import ida_kernwin 7 | 8 | DEBUG_MODE = True 9 | 10 | def parse_reg(reg_name): 11 | reg_info = ida_idp.reg_info_t() 12 | if not ida_idp.parse_reg_name(reg_info, reg_name): 13 | print("Bad reg name:", reg_name) 14 | return None, None 15 | mreg = ida_hexrays.reg2mreg(reg_info.reg) 16 | if mreg == -1: 17 | print("Faild to covert %s to microregister", reg_name) 18 | return None, None 19 | return mreg, reg_info.size 20 | 21 | def create_move(ea, mreg, size, value): 22 | m = ida_hexrays.minsn_t(ea) 23 | m.opcode = ida_hexrays.m_mov 24 | m.l.make_number(value, size, ea) 25 | m.d.make_reg(mreg, size) 26 | m.iprops |= ida_hexrays.IPROP_ASSERT 27 | return m 28 | 29 | def refresh_pseudocode(): 30 | w = ida_kernwin.get_current_widget() 31 | if ida_kernwin.get_widget_type(w) == ida_kernwin.BWN_PSEUDOCODE: 32 | vu = ida_hexrays.get_widget_vdui(w) 33 | vu.refresh_ctext() 34 | 35 | 36 | class SpecifyRegValueManager(object): 37 | def __init__(self) -> None: 38 | self.isInitialized = False 39 | self.reg_val_list = {} # {ea: {reg_name: value}} 40 | 41 | def initialize(self): 42 | if not self.isInitialized: 43 | self.node = netnode.Netnode("Beautify.SpecifyRegValueManager") 44 | self.load_node() 45 | self.isInitialized = True 46 | 47 | def load_node(self): 48 | if "data" in self.node: 49 | self.reg_val_list = {} 50 | for key, item in self.node["data"].items(): 51 | self.reg_val_list[int(key)] = item 52 | 53 | def store_node(self): 54 | self.node["data"] = self.reg_val_list 55 | 56 | def add(self, ea, reg_name, value): 57 | ea -= idaapi.get_imagebase() 58 | if ea not in self.reg_val_list: 59 | self.reg_val_list[ea] = {} 60 | self.reg_val_list[ea][reg_name] = value 61 | self.store_node() 62 | 63 | def remove(self, ea, reg_name): 64 | ea -= idaapi.get_imagebase() 65 | if ea not in self.reg_val_list: 66 | return 67 | if reg_name not in self.reg_val_list[ea]: 68 | return 69 | del(self.reg_val_list[ea][reg_name]) 70 | 71 | if len(self.reg_val_list[ea].keys()) == 0: 72 | del(self.reg_val_list[ea]) 73 | self.store_node() 74 | 75 | def get_reg_list(self, ea): 76 | ea -= idaapi.get_imagebase() 77 | if ea not in self.reg_val_list: 78 | return None 79 | return self.reg_val_list[ea] 80 | 81 | def show_list(self): 82 | print("================= specify reg value list =================") 83 | for ea, item in self.reg_val_list.items(): 84 | print("ea: %x" % (ea + idaapi.get_imagebase())) 85 | for reg_name, value in item.items(): 86 | print("\t%s = %x" % (reg_name, value)) 87 | print("") 88 | print("==========================================================") 89 | 90 | class RemoverAddressManager(object): 91 | def __init__(self) -> None: 92 | self.isInitialized = False 93 | 94 | def initialize(self): 95 | if not self.isInitialized: 96 | self.node = netnode.Netnode("Beautify.RemoverAddressManager") 97 | self.load_netnode() 98 | self.isInitialized = True 99 | 100 | def load_netnode(self): 101 | if "data" in self.node: 102 | self.remove_list = self.node["data"] 103 | else: 104 | self.remove_list = [] 105 | 106 | def store_netnode(self): 107 | self.node["data"] = self.remove_list 108 | 109 | def add(self, addr): 110 | addr -= idaapi.get_imagebase() 111 | if addr not in self.remove_list: 112 | self.remove_list.append(addr) 113 | self.store_netnode() 114 | 115 | def remove(self, addr): 116 | addr -= idaapi.get_imagebase() 117 | if addr in self.remove_list: 118 | self.remove_list.remove(addr) 119 | self.store_netnode() 120 | 121 | def check(self, addr): 122 | addr -= idaapi.get_imagebase() 123 | return addr in self.remove_list 124 | 125 | remover_address_manager = RemoverAddressManager() 126 | specify_manager = SpecifyRegValueManager() 127 | 128 | 129 | class InsnVisitor(ida_hexrays.minsn_visitor_t): 130 | def __init__(self, *args): 131 | super().__init__(*args) 132 | def visit_minsn(self, *args) -> "int": 133 | insn_addr = self.topins.ea 134 | if remover_address_manager.check(insn_addr): 135 | self.blk.make_nop(self.topins) 136 | specify = specify_manager.get_reg_list(insn_addr) 137 | if specify != None and len(specify) > 0: 138 | for reg_name, value in specify.items(): 139 | mreg, size = parse_reg(reg_name) 140 | if mreg != None: 141 | m = create_move(insn_addr, mreg, size, value) 142 | self.blk.insert_into_block(m, self.curins.prev) 143 | return 0 # continue 144 | 145 | 146 | class MicrocodeCallback(ida_hexrays.Hexrays_Hooks): 147 | def __init__(self, *args): 148 | super().__init__(*args) 149 | 150 | def microcode(self, mba: ida_hexrays.mba_t) -> "int": 151 | # must in function. 152 | func = mba.get_curfunc() 153 | if func == None: 154 | print("not in function") 155 | return 0 156 | mba.for_all_topinsns(InsnVisitor()) 157 | return 0 158 | 159 | 160 | ####################### menu ########################################## 161 | # from: https://github.com/igogo-x86/HexRaysPyTools 162 | class ActionManager(object): 163 | def __init__(self): 164 | self.__actions = [] 165 | 166 | def register(self, action): 167 | self.__actions.append(action) 168 | idaapi.register_action( 169 | idaapi.action_desc_t(action.name, action.description, action, action.hotkey) 170 | ) 171 | 172 | 173 | def initialize(self): 174 | pass 175 | 176 | def finalize(self): 177 | for action in self.__actions: 178 | idaapi.unregister_action(action.name) 179 | 180 | action_manager = ActionManager() 181 | 182 | class Action(idaapi.action_handler_t): 183 | """ 184 | Convenience wrapper with name property allowing to be registered in IDA using ActionManager 185 | """ 186 | description = None 187 | hotkey = None 188 | 189 | def __init__(self): 190 | super(Action, self).__init__() 191 | 192 | @property 193 | def name(self): 194 | return "Beautify:" + type(self).__name__ 195 | 196 | def activate(self, ctx): 197 | # type: (idaapi.action_activation_ctx_t) -> None 198 | raise NotImplementedError 199 | 200 | def update(self, ctx): 201 | # type: (idaapi.action_activation_ctx_t) -> None 202 | raise NotImplementedError 203 | 204 | ############################################################################ 205 | 206 | 207 | class BeautifyHideMenuAction(Action): 208 | TopDescription = "Beautify" 209 | description = "Hide All References" 210 | def __init__(self): 211 | super(BeautifyHideMenuAction, self).__init__() 212 | 213 | def activate(self, ctx) -> None: 214 | target = ctx.cur_extracted_ea 215 | print("active target:", hex(target)) 216 | for xref in idautils.XrefsTo(target): 217 | if xref.frm != target: 218 | remover_address_manager.add(xref.frm) 219 | refresh_pseudocode() 220 | 221 | def update(self, ctx) -> None: 222 | if ctx.widget_type in [idaapi.BWN_PSEUDOCODE, idaapi.BWN_DISASM]: 223 | idaapi.attach_action_to_popup(ctx.widget, None, self.name, self.TopDescription + "/") 224 | return idaapi.AST_ENABLE_FOR_WIDGET 225 | return idaapi.AST_DISABLE_FOR_WIDGET 226 | 227 | class BeautifyShowMenuAction(Action): 228 | TopDescription = "Beautify" 229 | description = "Show All References" 230 | def __init__(self): 231 | super(BeautifyShowMenuAction, self).__init__() 232 | 233 | def activate(self, ctx) -> None: 234 | target = ctx.cur_extracted_ea 235 | print("active target:", hex(target)) 236 | for xref in idautils.XrefsTo(target): 237 | if xref.frm != target: 238 | remover_address_manager.remove(xref.frm) 239 | refresh_pseudocode() 240 | 241 | def update(self, ctx) -> None: 242 | if ctx.form_type in [idaapi.BWN_PSEUDOCODE, idaapi.BWN_DISASM]: 243 | idaapi.attach_action_to_popup(ctx.widget, None, self.name, self.TopDescription + "/") 244 | return idaapi.AST_ENABLE_FOR_WIDGET 245 | return idaapi.AST_DISABLE_FOR_WIDGET 246 | 247 | 248 | 249 | class SpecifyMenuAction(Action): 250 | TopDescription = "Beautify" 251 | description = "Specify Value" 252 | def __init__(self): 253 | super(SpecifyMenuAction, self).__init__() 254 | 255 | def activate(self, ctx) -> None: 256 | ea = ctx.cur_ea 257 | highlight = idaapi.get_highlight(idaapi.get_current_viewer()) 258 | if highlight != None: 259 | reg_name = highlight[0] 260 | mreg, size = parse_reg(reg_name) 261 | if mreg != None: 262 | reg_list = specify_manager.get_reg_list(ea) 263 | value = 0 264 | if reg_list != None and reg_name in reg_list: 265 | value = reg_list[reg_name] 266 | ask_form = "Input value for register:%s" 267 | value = idaapi.ask_long(value, ask_form % reg_name) 268 | if value != None: 269 | specify_manager.add(ea, reg_name, value) 270 | refresh_pseudocode() 271 | 272 | def update(self, ctx) -> None: 273 | if ctx.form_type in [idaapi.BWN_DISASM]: 274 | idaapi.attach_action_to_popup(ctx.widget, None, self.name, self.TopDescription + "/") 275 | return idaapi.AST_ENABLE_FOR_WIDGET 276 | return idaapi.AST_DISABLE_FOR_WIDGET 277 | 278 | 279 | class UnSpecifyMenuAction(Action): 280 | TopDescription = "Beautify" 281 | description = "Unspecify Value" 282 | def __init__(self): 283 | super(UnSpecifyMenuAction, self).__init__() 284 | 285 | def activate(self, ctx) -> None: 286 | ea = ctx.cur_ea 287 | highlight = idaapi.get_highlight(idaapi.get_current_viewer()) 288 | if highlight != None: 289 | reg_name = highlight[0] 290 | mreg, size = parse_reg(reg_name) 291 | if mreg != None: 292 | specify_manager.remove(ea, reg_name) 293 | refresh_pseudocode() 294 | 295 | def update(self, ctx) -> None: 296 | if ctx.form_type in [idaapi.BWN_DISASM]: 297 | idaapi.attach_action_to_popup(ctx.widget, None, self.name, self.TopDescription + "/") 298 | return idaapi.AST_ENABLE_FOR_WIDGET 299 | return idaapi.AST_DISABLE_FOR_WIDGET 300 | 301 | class ShowMenuAction(Action): 302 | TopDescription = "Beautify" 303 | description = "Show Specified Reg List" 304 | def __init__(self): 305 | super(ShowMenuAction, self).__init__() 306 | 307 | def activate(self, ctx) -> None: 308 | specify_manager.show_list() 309 | 310 | def update(self, ctx) -> None: 311 | if ctx.form_type in [idaapi.BWN_DISASM]: 312 | idaapi.attach_action_to_popup(ctx.widget, None, self.name, self.TopDescription + "/") 313 | return idaapi.AST_ENABLE_FOR_WIDGET 314 | return idaapi.AST_DISABLE_FOR_WIDGET 315 | 316 | action_manager.register(BeautifyHideMenuAction()) 317 | action_manager.register(BeautifyShowMenuAction()) 318 | action_manager.register(SpecifyMenuAction()) 319 | action_manager.register(UnSpecifyMenuAction()) 320 | action_manager.register(ShowMenuAction()) 321 | 322 | if ida_hexrays.init_hexrays_plugin(): 323 | remover_address_manager.initialize() 324 | specify_manager.initialize() 325 | 326 | r = MicrocodeCallback() 327 | r.hook() 328 | 329 | # r.unhook() 330 | # action_manager.finalize() 331 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Beautify 2 | An IDA plugin for making pseudocode better. 3 | 4 | It was only tested on IDA 7.7, other versions are not guaranteed. 5 | 6 | # Features 7 | 8 | - Hide specific references 9 | ![hide](img/hide.gif) 10 | 11 | - Specify register value in a specific address 12 | ![b0](img/b0.gif) 13 | It helps ida internal optimizer to work better. 14 | 15 | All changes stored in idb database! 16 | 17 | # Requirements 18 | ``` 19 | pip3 install ida-netnode 20 | ``` 21 | -------------------------------------------------------------------------------- /img/b0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P4nda0s/IDABeautify/d969aa77d65613a8c8c98a8502576a5941993fb7/img/b0.gif -------------------------------------------------------------------------------- /img/hide.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/P4nda0s/IDABeautify/d969aa77d65613a8c8c98a8502576a5941993fb7/img/hide.gif --------------------------------------------------------------------------------