|
| 1 | +""" Invert the then and else blocks of a cif_t. |
| 2 | +
|
| 3 | +Author: EiNSTeiN_ <einstein@g3nius.org> |
| 4 | +
|
| 5 | +This is a rewrite in Python of the vds3 example that comes with hexrays sdk. |
| 6 | +
|
| 7 | +
|
| 8 | +The main difference with the original C code is that when we create the inverted |
| 9 | +condition object, the newly created cexpr_t instance is given to the hexrays and |
| 10 | +must not be freed by swig. To achieve this, we have to change the 'thisown' flag |
| 11 | +when appropriate. See http://www.swig.org/Doc1.3/Python.html#Python_nn35 |
| 12 | +
|
| 13 | +""" |
| 14 | + |
| 15 | +import idautils |
| 16 | +import idaapi |
| 17 | +import idc |
| 18 | + |
| 19 | +import traceback |
| 20 | + |
| 21 | +NETNODE_NAME = '$ hexrays-inverted-if' |
| 22 | + |
| 23 | +class hexrays_callback_info(object): |
| 24 | + |
| 25 | + def __init__(self): |
| 26 | + self.vu = None |
| 27 | + |
| 28 | + self.node = idaapi.netnode() |
| 29 | + if not self.node.create(NETNODE_NAME): |
| 30 | + # node exists |
| 31 | + self.load() |
| 32 | + else: |
| 33 | + self.stored = [] |
| 34 | + |
| 35 | + return |
| 36 | + |
| 37 | + def load(self): |
| 38 | + |
| 39 | + self.stored = [] |
| 40 | + |
| 41 | + try: |
| 42 | + data = self.node.getblob(0, 'I') |
| 43 | + if data: |
| 44 | + self.stored = eval(data) |
| 45 | + print 'Invert-if: Loaded %s' % (repr(self.stored), ) |
| 46 | + except: |
| 47 | + print 'Failed to load invert-if locations' |
| 48 | + traceback.print_exc() |
| 49 | + return |
| 50 | + |
| 51 | + return |
| 52 | + |
| 53 | + def save(self): |
| 54 | + |
| 55 | + try: |
| 56 | + self.node.setblob(repr(self.stored), 0, 'I') |
| 57 | + except: |
| 58 | + print 'Failed to save invert-if locations' |
| 59 | + traceback.print_exc() |
| 60 | + return |
| 61 | + |
| 62 | + return |
| 63 | + |
| 64 | + def invert_if(self, cfunc, insn): |
| 65 | + |
| 66 | + if insn.opname != 'if': |
| 67 | + return False |
| 68 | + |
| 69 | + cif = insn.details |
| 70 | + |
| 71 | + if not cif.ithen or not cif.ielse: |
| 72 | + return False |
| 73 | + |
| 74 | + idaapi.qswap(cif.ithen, cif.ielse) |
| 75 | + cond = idaapi.cexpr_t(cif.expr) |
| 76 | + notcond = idaapi.lnot(cond) |
| 77 | + cond.thisown = 0 # the new wrapper 'notcond' now holds the reference to the cexpr_t |
| 78 | + |
| 79 | + cif.expr.swap(notcond) |
| 80 | + |
| 81 | + return True |
| 82 | + |
| 83 | + def add_location(self, ea): |
| 84 | + if ea in self.stored: |
| 85 | + self.stored.remove(ea) |
| 86 | + else: |
| 87 | + self.stored.append(ea) |
| 88 | + self.save() |
| 89 | + return |
| 90 | + |
| 91 | + def invert_if_event(self, vu): |
| 92 | + |
| 93 | + vu.get_current_item(idaapi.USE_KEYBOARD) |
| 94 | + item = vu.item |
| 95 | + |
| 96 | + cfunc = vu.cfunc.__deref__() |
| 97 | + |
| 98 | + if item.citype != idaapi.VDI_EXPR: |
| 99 | + return False |
| 100 | + |
| 101 | + if self.invert_if(cfunc, item.it.to_specific_type): |
| 102 | + vu.refresh_ctext() |
| 103 | + |
| 104 | + self.add_location(item.it.ea) |
| 105 | + |
| 106 | + return True |
| 107 | + |
| 108 | + def restore(self, cfunc): |
| 109 | + |
| 110 | + #~ print 'restoring invert-if for %x' % (cfunc.entry_ea, ) |
| 111 | + |
| 112 | + str(cfunc) # generate treeitems. |
| 113 | + |
| 114 | + restored = False |
| 115 | + |
| 116 | + for item in cfunc.treeitems: |
| 117 | + item = item.to_specific_type |
| 118 | + if item.opname == 'if' and item.ea in self.stored: |
| 119 | + if self.invert_if(cfunc, item): |
| 120 | + restored = True |
| 121 | + #~ print 'restore invert-if location %x' % (item.ea, ) |
| 122 | + else: |
| 123 | + print 'invert-if location %x: NOT RESTORED' % (item.ea, ) |
| 124 | + |
| 125 | + return restored |
| 126 | + |
| 127 | + def menu_callback(self): |
| 128 | + try: |
| 129 | + self.invert_if_event(self.vu) |
| 130 | + except: |
| 131 | + traceback.print_exc() |
| 132 | + return 0 |
| 133 | + |
| 134 | + def event_callback(self, event, *args): |
| 135 | + |
| 136 | + try: |
| 137 | + if event == idaapi.hxe_keyboard: |
| 138 | + vu, keycode, shift = args |
| 139 | + |
| 140 | + if idaapi.lookup_key_code(keycode, shift, True) == idaapi.get_key_code("I") and shift == 0: |
| 141 | + if self.invert_if_event(vu): |
| 142 | + return 1 |
| 143 | + |
| 144 | + elif event == idaapi.hxe_right_click: |
| 145 | + self.vu = args[0] |
| 146 | + idaapi.add_custom_viewer_popup_item(self.vu.ct, "Invert then/else", "I", self.menu_callback) |
| 147 | + |
| 148 | + elif event == idaapi.hxe_maturity: |
| 149 | + cfunc, maturity = args |
| 150 | + |
| 151 | + if maturity == idaapi.CMAT_FINAL: |
| 152 | + self.restore(cfunc) |
| 153 | + except: |
| 154 | + traceback.print_exc() |
| 155 | + |
| 156 | + return 0 |
| 157 | + |
| 158 | +if idaapi.init_hexrays_plugin(): |
| 159 | + i = hexrays_callback_info() |
| 160 | + idaapi.install_hexrays_callback(i.event_callback) |
| 161 | +else: |
| 162 | + print 'invert-if: hexrays is not available.' |
0 commit comments