Replace HexRaysCodeXplorer and HexraysInvertIf with HexRaysPyTools
This commit is contained in:
120
plugins/HexRaysPyTools/Core/SpaghettiCode.py
Normal file
120
plugins/HexRaysPyTools/Core/SpaghettiCode.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import idaapi
|
||||
import idc
|
||||
|
||||
|
||||
def inverse_if_condition(cif):
|
||||
# cexpr_t has become broken but fortunately still exist `assing` method which copies one expr into another
|
||||
cit_if_condition = cif.expr
|
||||
tmp_cexpr = idaapi.cexpr_t()
|
||||
tmp_cexpr.assign(cit_if_condition)
|
||||
new_if_condition = idaapi.lnot(tmp_cexpr)
|
||||
cif.expr.swap(new_if_condition)
|
||||
del cit_if_condition
|
||||
|
||||
|
||||
def inverse_if(cif):
|
||||
inverse_if_condition(cif)
|
||||
idaapi.qswap(cif.ithen, cif.ielse)
|
||||
|
||||
|
||||
class InversionInfo(object):
|
||||
ARRAY_NAME = "$HexRaysPyTools:IfThenElse:"
|
||||
|
||||
def __init__(self, func_ea):
|
||||
self.__name = InversionInfo.ARRAY_NAME + hex(int(func_ea))
|
||||
self.__id = idc.GetArrayId(self.__name)
|
||||
|
||||
def get_inverted(self):
|
||||
if self.__id != -1:
|
||||
array = idc.GetArrayElement(idc.AR_STR, self.__id, 0)
|
||||
return set(map(int, array.split()))
|
||||
return set()
|
||||
|
||||
def switch_inverted(self, address):
|
||||
if self.__id == -1:
|
||||
self.__id = idc.CreateArray(self.__name)
|
||||
idc.SetArrayString(self.__id, 0, str(address))
|
||||
else:
|
||||
inverted = self.get_inverted()
|
||||
try:
|
||||
inverted.remove(address)
|
||||
if not inverted:
|
||||
idc.DeleteArray(self.__id)
|
||||
|
||||
except KeyError:
|
||||
inverted.add(address)
|
||||
|
||||
idc.SetArrayString(self.__id, 0, " ".join(map(str, inverted)))
|
||||
|
||||
|
||||
class SpaghettiVisitor(idaapi.ctree_parentee_t):
|
||||
def __init__(self):
|
||||
super(SpaghettiVisitor, self).__init__()
|
||||
|
||||
def visit_insn(self, instruction):
|
||||
if instruction.op != idaapi.cit_block:
|
||||
return 0
|
||||
|
||||
while True:
|
||||
cblock = instruction.cblock
|
||||
size = cblock.size()
|
||||
# Find block that has "If" and "return" as last 2 statements
|
||||
if size < 2:
|
||||
break
|
||||
|
||||
if cblock.at(size - 2).op != idaapi.cit_if:
|
||||
break
|
||||
|
||||
cif = cblock.at(size - 2).cif
|
||||
if cblock.back().op != idaapi.cit_return or cif.ielse:
|
||||
break
|
||||
|
||||
cit_then = cif.ithen
|
||||
|
||||
# Skip if only one (not "if") statement in "then" branch
|
||||
if cit_then.cblock.size() == 1 and cit_then.cblock.front().op != idaapi.cit_if:
|
||||
return 0
|
||||
|
||||
inverse_if_condition(cif)
|
||||
|
||||
# Take return from list of statements and later put it back
|
||||
cit_return = idaapi.cinsn_t()
|
||||
cit_return.assign(instruction.cblock.back())
|
||||
cit_return.thisown = False
|
||||
instruction.cblock.pop_back()
|
||||
|
||||
# Fill main block with statements from "Then" branch
|
||||
while cit_then.cblock:
|
||||
instruction.cblock.push_back(cit_then.cblock.front())
|
||||
cit_then.cblock.pop_front()
|
||||
|
||||
# Put back main return if there's no another return or "GOTO" already
|
||||
if instruction.cblock.back().op not in (idaapi.cit_return, idaapi.cit_goto):
|
||||
new_return = idaapi.cinsn_t()
|
||||
new_return.thisown = False
|
||||
new_return.assign(cit_return)
|
||||
instruction.cblock.push_back(new_return)
|
||||
|
||||
# Put return into "Then" branch
|
||||
cit_then.cblock.push_back(cit_return)
|
||||
return 0
|
||||
|
||||
|
||||
class SwapThenElseVisitor(idaapi.ctree_parentee_t):
|
||||
def __init__(self, func_ea):
|
||||
super(SwapThenElseVisitor, self).__init__()
|
||||
self.__inversion_info = InversionInfo(func_ea)
|
||||
self.__inverted = self.__inversion_info.get_inverted()
|
||||
|
||||
def visit_insn(self, insn):
|
||||
if insn.op != idaapi.cit_if or insn.cif.ielse is None:
|
||||
return 0
|
||||
|
||||
if insn.ea in self.__inverted:
|
||||
inverse_if(insn.cif)
|
||||
|
||||
return 0
|
||||
|
||||
def apply_to(self, *args):
|
||||
if self.__inverted:
|
||||
super(SwapThenElseVisitor, self).apply_to(*args)
|
||||
Reference in New Issue
Block a user