Lyxica

Untitled

Apr 2nd, 2021
780
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.84 KB | None | 0 0
  1. from binaryninja.architecture import Architecture, ArchitectureHook
  2. from dataclasses import dataclass
  3. import struct
  4.  
  5.  
  6. @dataclass
  7. class ExceptionStruct:
  8.     rva: int
  9.     case: int
  10.     loc1: int
  11.     loc2: int
  12.  
  13. # Build breakpoint EIP adjustment table
  14. #######################################
  15. def get_struct_data(addr) -> ExceptionStruct:
  16.     rva, case, loc1, loc2 = struct.unpack('<LBll', bv.read(addr, 0xd))
  17.     return ExceptionStruct(rva, case, loc1, loc2)
  18.  
  19. def create_breakpoint_lut():
  20.     breakpoint_lut = {}
  21.     STRUCT_RVA = 0x1280a0
  22.     BASE_ADDRESS = 0x60000
  23.     offset = 0
  24.     while True:
  25.         x = get_struct_data(BASE_ADDRESS + STRUCT_RVA + offset)
  26.         if x.rva == 0:  # Continue scanning for structs until we encounter null data
  27.             break
  28.         breakpoint_lut[BASE_ADDRESS + x.rva] = x
  29.         offset += 0xd
  30.     return breakpoint_lut
  31.  
  32.  
  33. # Helper functions for our case functions.
  34. ##########################################
  35. def get_label(il, address):
  36.     label = il.get_label_for_address(Architecture['x86'], address)
  37.     if label == None:
  38.         il.add_label_for_address(Architecture['x86'], address)
  39.         label = il.get_label_for_address(Architecture['x86'], address)
  40.         assert label != None
  41.     return label
  42.  
  43. def create_branch(il, condition, t_addr, f_addr):
  44.     t = get_label(il, t_addr)
  45.     f = get_label(il, f_addr)
  46.     il.append(il.if_expr(condition, t, f))
  47.  
  48.  
  49. # Code responsible for creating the appropriate branch type for each int3
  50. #########################################################################
  51. def case0(il, t_addr, f_addr):
  52.     flag = il.flag_group('ne')
  53.     create_branch(il, flag, t_addr, f_addr)
  54.  
  55. def case1(il, t_addr, f_addr):
  56.     flag = il.flag_group('e')  
  57.     create_branch(il, flag, t_addr, f_addr)
  58.  
  59. def case2(il, t_addr, f_addr):
  60.     flag = il.flag_group('ge')  
  61.     create_branch(il, flag, t_addr, f_addr)
  62.  
  63. def case3(il, t_addr, f_addr):
  64.     flag = il.flag_group('lt')  
  65.     create_branch(il, flag, t_addr, f_addr)
  66.  
  67. def case4(il, t_addr, f_addr):
  68.     flag = il.flag_group('gt')  
  69.     create_branch(il, flag, t_addr, f_addr)
  70.  
  71. def case5(il, t_addr, f_addr):
  72.     flag = il.flag_group('le')  
  73.     create_branch(il, flag, t_addr, f_addr)
  74.  
  75. def case6(il, t_addr, f_addr):
  76.     flag = il.flag_condition(LowLevelILFlagCondition.LLFC_SGE)  
  77.     create_branch(il, flag, t_addr, f_addr)
  78.  
  79. def case7(il, t_addr, f_addr):
  80.     flag = il.flag_condition(LowLevelILFlagCondition.LLFC_SLE)  
  81.     create_branch(il, flag, f_addr, t_addr) # Reserved order of branch addresses
  82.  
  83. def case8(il, t_addr, f_addr):
  84.     flag = il.flag_condition(LowLevelILFlagCondition.LLFC_SGT)  
  85.     create_branch(il, flag, t_addr, f_addr)
  86.  
  87. def case9(il, t_addr, f_addr):
  88.     flag = il.flag_condition(LowLevelILFlagCondition.LLFC_SLE)  
  89.     create_branch(il, flag, t_addr, f_addr)
  90.  
  91. def casea(il, t_addr, f_addr):
  92.     flag = il.flag_group('pe')  
  93.     create_branch(il, flag, t_addr, f_addr)
  94.  
  95. def caseb(il, t_addr, f_addr):
  96.     flag = il.flag_group('po')  
  97.     create_branch(il, flag, t_addr, f_addr)
  98.  
  99. def cased(il, t_addr, f_addr):
  100.     flag = il.flag_condition(LowLevelILFlagCondition.LLFC_POS)  
  101.     create_branch(il, flag, t_addr, f_addr)
  102.  
  103. def casee(il, t_addr, f_addr):
  104.     flag = il.flag_condition(LowLevelILFlagCondition.LLFC_NEG)  
  105.     create_branch(il, flag, t_addr, f_addr)
  106.  
  107. def case11(il, t_addr, f_addr):
  108.     target = get_label(il, f_addr)
  109.     il.append(il.goto(target))
  110.  
  111. exception_handler_lut = {
  112.     0x0: case0,
  113.     0x1: case1,
  114.     0x2: case2,
  115.     0x3: case3,
  116.     0x4: case4,
  117.     0x5: case5,
  118.     0x6: case6,
  119.     0x7: case7,
  120.     0x8: case8,
  121.     0x9: case9,
  122.     0xa: casea,
  123.     0xb: caseb,
  124.     0xd: cased,
  125.     0xe: casee,
  126.     0x11: case11
  127. }
  128.  
  129. # Create and insert our IL hook
  130. ###############################
  131. class ILLifterHook(ArchitectureHook):
  132.     lut: dict[int, ExceptionStruct]
  133.    
  134.     def __init__(self, base_arch, lut):
  135.         super(ILLifterHook, self).__init__(base_arch)
  136.         self.lut = lut
  137.    
  138.     def get_instruction_info(self, data, addr):
  139.         # This callback is responsible for informing BN on what branches an instruction has.
  140.         # We need to hook this so that we can inform BN that some int3s have a true/false branch.
  141.         # If we don't hook this, binary ninja will not include the branch locations within the functions' address space.
  142.         # If the address isn't within the function, we wont be able to acquire address labels for if_expr IL's.
  143.         if addr in self.lut and bv.read(addr, 1) == b'\xcc':
  144.             cf_data = self.lut[addr]
  145.             info = InstructionInfo()
  146.             info.length = 1
  147.             if cf_data.case == 0x11:
  148.                 info.add_branch(enums.BranchType.UnconditionalBranch, addr + cf_data.loc2)
  149.             else:
  150.                 info.add_branch(enums.BranchType.TrueBranch, addr + cf_data.loc1)
  151.                 info.add_branch(enums.BranchType.FalseBranch, addr + cf_data.loc2)
  152.             return info
  153.         else:
  154.             return super(ILLifterHook, self).get_instruction_info(data, addr)
  155.    
  156.     def get_instruction_low_level_il(self, data, addr, il):
  157.         # This callback is responsible for inserting LLIL into the IL tree/graph.
  158.         # We'll process the int3s as if_expr's.
  159.         if data[0] == 0xCC and addr in self.lut:
  160.             control_flow = self.lut[addr]
  161.             if control_flow.case in exception_handler_lut:
  162.                 exception_handler_lut[control_flow.case](il, addr + control_flow.loc1, addr + control_flow.loc2)
  163.             else:
  164.                 print(f'Unhandled @ {hex(addr)} for case: {control_flow.case}')
  165.                 il.append(il.unimplemented())
  166.             return 1
  167.         else:
  168.             return super(ILLifterHook, self).get_instruction_low_level_il(data, addr, il)
  169.  
  170. hook = ILLifterHook(Architecture['x86'], create_breakpoint_lut())
  171. hook.register()
Advertisement
Add Comment
Please, Sign In to add comment