def generate(self): idaapi.visit_patched_bytes(0, idaapi.BADADDR, self.get_patch_byte) if len(self.patched_bytes) == 0: msg = 'Cannot generate patch because there is no patch applied.' print('genpatch: %s' % msg) ida_kernwin.warning(msg) return False template_path = '' for path in sys.path: if 'plugins' in path: template_path = os.path.join(path, 'patch_template.txt') patch_path = idc.get_input_file_path() + '_patch.py' template_data = None with open(template_path, "r") as f: template_data = f.readlines() lines = 13 with open(patch_path, "w") as f: for data in self.patched_bytes: template_data.insert(lines, "# address: 0x%x\n" % data['begin_addr']) lines += 1 template_data.insert(lines, "# function name: %s\n" % data['name']) lines += 1 template_data.insert( lines, "# comment: %s\n" % data['comment'].replace('\n', ' ')) lines += 1 template_data.insert( lines, "matches = re.findall('%s', target_data)\n" % data['original']) lines += 1 template_data.insert(lines, "if len(matches) == 1:\n") lines += 1 template_data.insert( lines, " target_data = target_data.replace('%s', '%s')\n" % (data['original'], data['patched'])) lines += 1 template_data.insert(lines, "else:\n") lines += 1 template_data.insert( lines, ' print("Patch pattern isn\'t unique")\n') lines += 1 template_data.insert(lines, " sys.exit()\n") lines += 1 f.writelines(template_data) msg = 'Successfully generated patch to %s from Patched Bytes' % patch_path print('genpatch: %s' % msg) ida_kernwin.info(msg) return True
def get_patched_bytes(start=None, end=None): start, end = fix_addresses(start, end) patched_bytes = dict() def collector(ea, fpos, original, patched): patched_bytes[ea] = PatchedByte(ea, fpos, original, patched) return 0 idaapi.visit_patched_bytes(start, end, collector) return patched_bytes
def get_patched_bytes(self, start=None, end=None): if start is None: start = idaapi.cvar.inf.minEA if end is None: end = idaapi.cvar.inf.maxEA patched_bytes = dict() def collector(ea, fpos, original, patched): patched_bytes[ea] = PatchData(ea, fpos, original, patched) return 0 idaapi.visit_patched_bytes(start, end, collector) return patched_bytes
def formbook_patch_encrypted_bytecode(): text_segm = ida_segment.get_segm_by_name('.text') if not text_segm: return idaapi.BADADDR seg_start = text_segm.startEA seg_end = text_segm.endEA fb_decrypt = FormBookDecryption() rc4_key = "faddefad156c45629c95d5f429363b0653ad5c1d".decode('hex') # same as rc4_final from formbook_decrypt_hashes_and_strings() for i in [(0x40, 0x48), (0x41, 0x49), (0x42, 0x4a), (0x43, 0x4b), (0x44, 0x4c)]: egg_pattern = ''.join('{:02x} '.format(x) for x in [i[0], 0x90, 0x90, 0x90, i[1]]) encrypted_start = idaapi.find_binary(seg_start, seg_end, egg_pattern, 16, idaapi.SEARCH_DOWN) if encrypted_start != idaapi.BADADDR: encrypted_end = idaapi.find_binary(encrypted_start + 5, seg_end, "90 90 90 90", 16, idaapi.SEARCH_DOWN) if encrypted_end != idaapi.BADADDR: encrypted_start += 5 patch_length = encrypted_end - encrypted_start if idaapi.visit_patched_bytes(encrypted_start, encrypted_end, callback_on_patched_bytes) == 0: encrypted_buff = idaapi.get_bytes(encrypted_start, patch_length) decrypted_buff = fb_decrypt.decrypt_func2(encrypted_buff, rc4_key) print('Patching encrypted bytecode at 0x{:x} ({:d} bytes)'.format(encrypted_start, patch_length)) idaapi.patch_many_bytes(encrypted_start, decrypted_buff) else: print('Encrypted bytecode at 0x{:x} ({:d} bytes) is already patched'.format(encrypted_start, patch_length))
def main(): print("Visiting all patched bytes:") v = patched_bytes_visitor() r = idaapi.visit_patched_bytes(0, idaapi.BADADDR, v) if r != 0: print("visit_patched_bytes() returned %d" % r) else: print("Patched: %d Skipped: %d" % (v.patch, v.skip))
def OnCommand(self, n, cmd_id): # Apply patches to a file if cmd_id == self.cmd_apply_patches: # Set initial start/end EA values start_ea = 0x0 end_ea = idaapi.cvar.inf.maxEA # Set initial output file values org_file = GetInputFilePath() bkp_file = "%s.bak" % org_file # Create the form f = PatchApplyForm(start_ea, end_ea, org_file, bkp_file) # Execute the form ok = f.Execute() if ok == 1: # Get restore checkbox self.restore = f.rRestore.checked # Get updated ea max/min start_ea = f.intStartEA.value end_ea = f.intEndEA.value # Get updated file path new_org_file = f.orgFile.value # Backup the file before replacing if f.rBackup.checked: bkp_file = f.bkpFile.value shutil.copyfile(org_file, bkp_file) # Apply patches try: self.patch_file = open(new_org_file, 'rb+') except Exception, e: idaapi.warning("Cannot update file '%s'" % new_org_file) else: r = idaapi.visit_patched_bytes(start_ea, end_ea, self.apply_patch_byte) self.patch_file.close() self.restore = False # Update db input file, so we are working # with a patched version. #if not org_file == new_org_file: # idaapi.set_root_filename(new_org_file) # org_file = new_org_file # Dispose the form f.Free()
def OnCommand(self, n, cmd_id): # Apply patches to a file if cmd_id == self.cmd_apply_patches: # Set initial start/end EA values start_ea = 0x0 end_ea = idaapi.cvar.inf.maxEA # Set initial output file values org_file = GetInputFilePath() bkp_file = "%s.bak" % org_file # Create the form f = PatchApplyForm(start_ea, end_ea, org_file, bkp_file) # Execute the form ok = f.Execute() if ok == 1: # Get restore checkbox self.restore = f.rRestore.checked # Get updated ea max/min start_ea = f.intStartEA.value end_ea = f.intEndEA.value # Get updated file path new_org_file = f.orgFile.value # Backup the file before replacing if f.rBackup.checked: bkp_file = f.bkpFile.value shutil.copyfile(org_file, bkp_file) # Apply patches try: self.patch_file = open(new_org_file,'rb+') except Exception, e: idaapi.warning("Cannot update file '%s'" % new_org_file) else: r = idaapi.visit_patched_bytes(start_ea, end_ea, self.apply_patch_byte) self.patch_file.close() self.restore = False # Update db input file, so we are working # with a patched version. #if not org_file == new_org_file: # idaapi.set_root_filename(new_org_file) # org_file = new_org_file # Dispose the form f.Free()
def visit_patched_bytes(self): """Iterates through patched bytes and stores them in a buffer.""" try: visitor = self.PatchVisitor() result = idaapi.visit_patched_bytes(0, idaapi.BADADDR, visitor) if result != 0: dap_err("visit_patched_bytes() returned unexpected result", "error code ({})".format(result)) return [] return visitor.patched_bytes except Exception as e: dap_err("Exception encountered while visiting patched bytes", str(e)) except: dap_err("Unknown")
def _unpatch(self, from_ea, to_ea): if self.disalePatchedBytes: self.unp_from_ea = from_ea idaapi.visit_patched_bytes(from_ea, to_ea, self._bytes_unpatcher)
def refreshitems(self): self.items_data = [] self.items = [] idaapi.visit_patched_bytes(0, idaapi.BADADDR, self.get_patch_byte)
def OnCommand(self, n, cmd_id): # Apply patches to a file if cmd_id == self.cmd_apply_patches: # Set initial start/end EA values start_ea = 0x0 end_ea = idaapi.cvar.inf.maxEA # Set initial output file values org_file = GetInputFilePath() bkp_file = "%s.bak" % org_file # Create the form f = PatchApplyForm(start_ea, end_ea, org_file, bkp_file) # Execute the form ok = f.Execute() if ok == 1: # Get restore checkbox self.restore = f.rRestore.checked # Get updated ea max/min start_ea = f.intStartEA.value end_ea = f.intEndEA.value # Get updated file path new_org_file = f.orgFile.value # Backup the file before replacing if f.rBackup.checked: bkp_file = f.bkpFile.value shutil.copyfile(org_file, bkp_file) # Apply patches try: self.patch_file = open(new_org_file,'rb+') except Exception as e: idaapi.warning("Cannot update file '%s'" % new_org_file) else: r = idaapi.visit_patched_bytes(start_ea, end_ea, self.apply_patch_byte) self.patch_file.close() self.restore = False # Update db input file, so we are working # with a patched version. #if not org_file == new_org_file: # idaapi.set_root_filename(new_org_file) # org_file = new_org_file # Dispose the form f.Free() # Restore selected byte(s) elif cmd_id == self.cmd_restore_bytes: # List start/end if n == -2 or n ==-3: return 1 elif not len(self.items) > 0: idaapi.warning("There are no patches to restore.") return 1 # Nothing selected elif n == -1: idaapi.warning("Please select bytes to restore.") return 1 ea = self.items_data[n][0] fpos = self.items_data[n][1] buf = self.items_data[n][4] addr_str = "%#x" % ea fpos_str = "%#x" % fpos if fpos != -1 else "N/A" patch_str = self.items[n][3] org_str = self.items[n][4] # Create the form f = PatchRestoreForm(addr_str, fpos_str, patch_str, org_str) # Execute the form ok = f.Execute() if ok == 1: # Restore original bytes idaapi.put_many_bytes(ea, struct.pack("B"*len(buf), *buf)) # Refresh all IDA views self.refreshitems() # Dispose the form f.Free() return 1