Lyxica icon

Untitled

Lyxica | PRO | 04/02/21 06:03:58 PM UTC | 0 ⭐ | 758 👁️ | Never ⏰ | []
Python |

5.84 KB

|

None

|

0 👍

/

0 👎

from binaryninja.architecture import Architecture, ArchitectureHook
from dataclasses import dataclass
import struct
 
 
@dataclass
class ExceptionStruct:
    rva: int
    case: int
    loc1: int
    loc2: int
 
# Build breakpoint EIP adjustment table
#######################################
def get_struct_data(addr) -> ExceptionStruct:
    rva, case, loc1, loc2 = struct.unpack('<LBll', bv.read(addr, 0xd))
    return ExceptionStruct(rva, case, loc1, loc2)
 
def create_breakpoint_lut():
    breakpoint_lut = {}
    STRUCT_RVA = 0x1280a0
    BASE_ADDRESS = 0x60000
    offset = 0
    while True:
        x = get_struct_data(BASE_ADDRESS + STRUCT_RVA + offset)
        if x.rva == 0:  # Continue scanning for structs until we encounter null data
            break
        breakpoint_lut[BASE_ADDRESS + x.rva] = x
        offset += 0xd
    return breakpoint_lut
 
 
# Helper functions for our case functions.
##########################################
def get_label(il, address):
    label = il.get_label_for_address(Architecture['x86'], address)
    if label == None:
        il.add_label_for_address(Architecture['x86'], address)
        label = il.get_label_for_address(Architecture['x86'], address)
        assert label != None
    return label
 
def create_branch(il, condition, t_addr, f_addr):
    t = get_label(il, t_addr)
    f = get_label(il, f_addr)
    il.append(il.if_expr(condition, t, f))
 
 
# Code responsible for creating the appropriate branch type for each int3
#########################################################################
def case0(il, t_addr, f_addr):
    flag = il.flag_group('ne')
    create_branch(il, flag, t_addr, f_addr)
 
def case1(il, t_addr, f_addr):
    flag = il.flag_group('e')   
    create_branch(il, flag, t_addr, f_addr)
 
def case2(il, t_addr, f_addr):
    flag = il.flag_group('ge')   
    create_branch(il, flag, t_addr, f_addr)
 
def case3(il, t_addr, f_addr):
    flag = il.flag_group('lt')   
    create_branch(il, flag, t_addr, f_addr)
 
def case4(il, t_addr, f_addr):
    flag = il.flag_group('gt')   
    create_branch(il, flag, t_addr, f_addr)
 
def case5(il, t_addr, f_addr):
    flag = il.flag_group('le')   
    create_branch(il, flag, t_addr, f_addr)
 
def case6(il, t_addr, f_addr):
    flag = il.flag_condition(LowLevelILFlagCondition.LLFC_SGE)  
    create_branch(il, flag, t_addr, f_addr)
 
def case7(il, t_addr, f_addr):
    flag = il.flag_condition(LowLevelILFlagCondition.LLFC_SLE)  
    create_branch(il, flag, f_addr, t_addr) # Reserved order of branch addresses
 
def case8(il, t_addr, f_addr):
    flag = il.flag_condition(LowLevelILFlagCondition.LLFC_SGT)  
    create_branch(il, flag, t_addr, f_addr)
 
def case9(il, t_addr, f_addr):
    flag = il.flag_condition(LowLevelILFlagCondition.LLFC_SLE)  
    create_branch(il, flag, t_addr, f_addr)
 
def casea(il, t_addr, f_addr):
    flag = il.flag_group('pe')   
    create_branch(il, flag, t_addr, f_addr)
 
def caseb(il, t_addr, f_addr):
    flag = il.flag_group('po')   
    create_branch(il, flag, t_addr, f_addr)
 
def cased(il, t_addr, f_addr):
    flag = il.flag_condition(LowLevelILFlagCondition.LLFC_POS)  
    create_branch(il, flag, t_addr, f_addr)
 
def casee(il, t_addr, f_addr):
    flag = il.flag_condition(LowLevelILFlagCondition.LLFC_NEG)  
    create_branch(il, flag, t_addr, f_addr)
 
def case11(il, t_addr, f_addr):
    target = get_label(il, f_addr)
    il.append(il.goto(target))
 
exception_handler_lut = {
    0x0: case0,
    0x1: case1,
    0x2: case2,
    0x3: case3,
    0x4: case4,
    0x5: case5,
    0x6: case6,
    0x7: case7,
    0x8: case8,
    0x9: case9,
    0xa: casea,
    0xb: caseb,
    0xd: cased,
    0xe: casee,
    0x11: case11
}
 
# Create and insert our IL hook
###############################
class ILLifterHook(ArchitectureHook):
    lut: dict[int, ExceptionStruct]
    
    def __init__(self, base_arch, lut):
        super(ILLifterHook, self).__init__(base_arch)
        self.lut = lut
    
    def get_instruction_info(self, data, addr):
        # This callback is responsible for informing BN on what branches an instruction has.
        # We need to hook this so that we can inform BN that some int3s have a true/false branch.
        # If we don't hook this, binary ninja will not include the branch locations within the functions' address space.
        # If the address isn't within the function, we wont be able to acquire address labels for if_expr IL's.
        if addr in self.lut and bv.read(addr, 1) == b'\xcc':
            cf_data = self.lut[addr]
            info = InstructionInfo()
            info.length = 1
            if cf_data.case == 0x11:
                info.add_branch(enums.BranchType.UnconditionalBranch, addr + cf_data.loc2)
            else:
                info.add_branch(enums.BranchType.TrueBranch, addr + cf_data.loc1)
                info.add_branch(enums.BranchType.FalseBranch, addr + cf_data.loc2)
            return info
        else:
            return super(ILLifterHook, self).get_instruction_info(data, addr)
    
    def get_instruction_low_level_il(self, data, addr, il):
        # This callback is responsible for inserting LLIL into the IL tree/graph.
        # We'll process the int3s as if_expr's.
        if data[0] == 0xCC and addr in self.lut:
            control_flow = self.lut[addr]
            if control_flow.case in exception_handler_lut:
                exception_handler_lut[control_flow.case](il, addr + control_flow.loc1, addr + control_flow.loc2)
            else:
                print(f'Unhandled @ {hex(addr)} for case: {control_flow.case}')
                il.append(il.unimplemented())
            return 1
        else:
            return super(ILLifterHook, self).get_instruction_low_level_il(data, addr, il)
 
hook = ILLifterHook(Architecture['x86'], create_breakpoint_lut())
hook.register()

Comments