控制流平坦化的去除
不过没考虑走遍所有分支的情况
第一步的python代码,第一步主要是识别主分发器之类的东西
import idaapi import idc fun_start = 0x000000000001E3C fun_end = 0x00000000002F04 # 存在 bug,fun.end_ea得到的不一定是函数的尾地址。已修复,使用了一种比较笨的方法 def get_block_of_fun(ea,ed): block_all = [] fun = idaapi.get_func(ea) fc = idaapi.FlowChart(fun) for block in fc: block_all.append( (block.start_ea,block.end_ea)) block_all_order = sorted(block_all, key=lambda item: item[0]) # for i in block_all_order: # print(hex(i[0]),hex(i[1])) return block_all_order def Get_Asm(begin,end): Asm_data = [] ea = begin while ea < end: ttt = str(hex(ea)) + ": " + idc.generate_disasm_line(ea, 0) Asm_data.append(ttt) ea = idc.next_head(ea) return Asm_data # 对某函数的所有基本快进行染色 def dye_blocks(block_all): blocks_dye = [None] * len(block_all) # 对所有的基本块进行染色,0代表序言,1代表主分发器,2代表预处理器,3代表子分发器,4代表真实块,5代表retn块 blocks_asm = [None] * len(block_all) # 存放所有基本块的汇编 # 先遍历一遍,找出序言、主分发器、预处理器 for i in range(len(block_all)): block_start = block_all[i][0] block_end = block_all[i][1] asm_codes = Get_Asm(block_start,block_end) blocks_asm[i] = asm_codes[:] blocks_dye[0] = 0 # 第一个基本块代表序言,第二个基本块代表主分发器。 blocks_dye[1] = 1 jmp_table = [None] * len(block_all) preprocessor_addr = -1 for i in range(len(blocks_asm)): asm_codes= blocks_asm[i] fin_code:str = asm_codes[len(asm_codes)-1] if "B " in fin_code: B_addr = int(fin_code.split("loc_")[1].strip(),16) block_start = block_all[i][0] if block_start not in jmp_table: jmp_table[i] = B_addr if B_addr == block_all[1][0] and i!=0: # 如果目的地址是序言,且不是主分发器,那么一定就是预处理器了 blocks_dye[i] = 2 preprocessor_addr = block_all[i][0] elif "RET" in fin_code: # 找到ret块 blocks_dye[i] = 5 if preprocessor_addr == -1: print("can't find preprocessor") assert 0 for i in range(len(jmp_table)): # 目的地址是预处理器的,都是真实块 block_jmp = jmp_table[i] if block_jmp == None: continue if block_jmp == preprocessor_addr and i != 0: blocks_dye[i] = 4 # 剩下的就都是子分发器喽 for i in range(len(blocks_dye)): if blocks_dye[i] == None: blocks_dye[i] = 3 return blocks_dye blocks_all = get_block_of_fun(fun_start,fun_end) blocks_dye = dye_blocks(blocks_all) for i in range(len(blocks_all)): print(f"{{{hex(blocks_all[i][0])},{hex(blocks_all[i][1])},{blocks_dye[i]}}}",end =",")
第二步的unidbg代码,第二步主要是模拟执行找真实块之间的关系
package com.deobf; import capstone.api.Instruction; import com.Tencent_game.tracer_fin_2023; import com.github.unidbg.AndroidEmulator; import com.github.unidbg.Emulator; import com.github.unidbg.Module; import com.github.unidbg.arm.backend.Backend; import com.github.unidbg.arm.backend.ReadHook; import com.github.unidbg.arm.backend.UnHook; import com.github.unidbg.debugger.BreakPointCallback; import com.github.unidbg.debugger.DebuggerType; import com.github.unidbg.linux.android.AndroidEmulatorBuilder; import com.github.unidbg.linux.android.AndroidResolver; import com.github.unidbg.linux.android.dvm.DalvikModule; import com.github.unidbg.linux.android.dvm.DvmClass; import com.github.unidbg.linux.android.dvm.VM; import com.github.unidbg.listener.TraceCodeListener; import com.github.unidbg.memory.Memory; import com.github.unidbg.virtualmodule.android.AndroidModule; import java.util.HashMap; import capstone.Capstone; import capstone.Capstone.OpInfo; import capstone.api.Instruction; import keystone.Keystone; import keystone.KeystoneArchitecture; import keystone.KeystoneMode; import keystone.KeystoneEncoded; import com.github.unidbg.arm.context.RegisterContext; import unicorn.Arm64Const; import com.github.unidbg.arm.backend.CodeHook; import java.io.File; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.HashSet; import java.util.Set; import java.util.Arrays; import com.github.unidbg.pointer.UnidbgPointer; import java.io.*; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.ArrayList; import java.util.List; public class deollvm { public final AndroidEmulator emulator; public final VM vm; public final Memory memory; public final Module module; public deollvm(){ emulator = AndroidEmulatorBuilder.for64Bit().build(); memory = emulator.getMemory(); memory.setLibraryResolver(new AndroidResolver(23)); emulator.getSyscallHandler().setEnableThreadDispatcher(true); vm = emulator.createDalvikVM(); new AndroidModule(emulator,vm).register(memory); DalvikModule dalvikModule = vm.loadLibrary(new File("C:\\Users\\27236\\Desktop\\Anti_ollvm\\tea_fla_split"), true); module = dalvikModule.getModule(); vm.callJNI_OnLoad(emulator,module); } public static void main(String[] args) { deollvm mainActivity = new deollvm(); mainActivity.deollvm(); } Instruction[][] blocks_asm; long [][]blocks_dye_mess = { {0x1e3c,0x1e64,0},{0x1e64,0x1e7c,1},{0x1e7c,0x1e80,3},{0x1e80,0x1e94,3},{0x1e94,0x1e98,3},{0x1e98,0x1eac,3},{0x1eac,0x1eb0,3},{0x1eb0,0x1ec4,3},{0x1ec4,0x1ec8,3},{0x1ec8,0x1edc,3},{0x1edc,0x1ee0,3},{0x1ee0,0x1ef4,3},{0x1ef4,0x1ef8,3},{0x1ef8,0x1f0c,3},{0x1f0c,0x1f10,3},{0x1f10,0x1f24,3},{0x1f24,0x1f28,3},{0x1f28,0x1f3c,3},{0x1f3c,0x1f40,3},{0x1f40,0x1f54,3},{0x1f54,0x1f58,3},{0x1f58,0x1f6c,3},{0x1f6c,0x1f70,3},{0x1f70,0x1f84,3},{0x1f84,0x1f88,3},{0x1f88,0x1f9c,3},{0x1f9c,0x1fa0,3},{0x1fa0,0x1fb4,3},{0x1fb4,0x1fb8,3},{0x1fb8,0x1fcc,3},{0x1fcc,0x1fd0,3},{0x1fd0,0x1fe4,3},{0x1fe4,0x1fe8,3},{0x1fe8,0x1ffc,3},{0x1ffc,0x2000,3},{0x2000,0x2014,3},{0x2014,0x2018,3},{0x2018,0x202c,3},{0x202c,0x2030,3},{0x2030,0x2044,3},{0x2044,0x2048,3},{0x2048,0x205c,3},{0x205c,0x2060,3},{0x2060,0x2074,3},{0x2074,0x2078,3},{0x2078,0x208c,3},{0x208c,0x2090,3},{0x2090,0x20a4,3},{0x20a4,0x20a8,3},{0x20a8,0x20bc,3},{0x20bc,0x20c0,3},{0x20c0,0x20d4,3},{0x20d4,0x20d8,3},{0x20d8,0x20ec,3},{0x20ec,0x20f0,3},{0x20f0,0x2104,3},{0x2104,0x2108,3},{0x2108,0x211c,3},{0x211c,0x2120,3},{0x2120,0x2134,3},{0x2134,0x2138,3},{0x2138,0x214c,3},{0x214c,0x2150,3},{0x2150,0x2164,3},{0x2164,0x2168,3},{0x2168,0x217c,3},{0x217c,0x2180,3},{0x2180,0x2194,3},{0x2194,0x2198,3},{0x2198,0x21ac,3},{0x21ac,0x21b0,3},{0x21b0,0x21c4,3},{0x21c4,0x21c8,3},{0x21c8,0x21dc,3},{0x21dc,0x21e0,3},{0x21e0,0x21f4,3},{0x21f4,0x21f8,3},{0x21f8,0x220c,3},{0x220c,0x2210,3},{0x2210,0x2224,3},{0x2224,0x2228,3},{0x2228,0x223c,3},{0x223c,0x2240,3},{0x2240,0x2254,3},{0x2254,0x2258,3},{0x2258,0x226c,3},{0x226c,0x2270,3},{0x2270,0x2284,3},{0x2284,0x2288,3},{0x2288,0x229c,3},{0x229c,0x22a0,3},{0x22a0,0x22b4,3},{0x22b4,0x22b8,3},{0x22b8,0x22cc,3},{0x22cc,0x22d0,3},{0x22d0,0x22e4,3},{0x22e4,0x22e8,3},{0x22e8,0x22fc,3},{0x22fc,0x2300,3},{0x2300,0x2314,3},{0x2314,0x2318,3},{0x2318,0x232c,3},{0x232c,0x2330,3},{0x2330,0x2344,3},{0x2344,0x2348,3},{0x2348,0x235c,3},{0x235c,0x2360,3},{0x2360,0x2374,3},{0x2374,0x2378,3},{0x2378,0x238c,3},{0x238c,0x2390,3},{0x2390,0x23a4,3},{0x23a4,0x23a8,3},{0x23a8,0x23bc,3},{0x23bc,0x23c0,3},{0x23c0,0x23d4,3},{0x23d4,0x23d8,3},{0x23d8,0x23ec,3},{0x23ec,0x23f0,3},{0x23f0,0x2404,3},{0x2404,0x2408,3},{0x2408,0x241c,3},{0x241c,0x2420,3},{0x2420,0x2434,3},{0x2434,0x2438,3},{0x2438,0x244c,3},{0x244c,0x2450,3},{0x2450,0x2464,3},{0x2464,0x2468,3},{0x2468,0x247c,3},{0x247c,0x2480,3},{0x2480,0x2484,3},{0x2484,0x24a4,4},{0x24a4,0x24b4,4},{0x24b4,0x24d8,4},{0x24d8,0x24f0,4},{0x24f0,0x2528,4},{0x2528,0x254c,4},{0x254c,0x2578,4},{0x2578,0x259c,4},{0x259c,0x25b4,4},{0x25b4,0x25cc,4},{0x25cc,0x25f4,4},{0x25f4,0x260c,4},{0x260c,0x2628,4},{0x2628,0x2654,4},{0x2654,0x2678,4},{0x2678,0x2690,4},{0x2690,0x26a8,4},{0x26a8,0x274c,4},{0x274c,0x27b4,4},{0x27b4,0x27cc,4},{0x27cc,0x27e8,4},{0x27e8,0x2800,4},{0x2800,0x2810,4},{0x2810,0x2844,4},{0x2844,0x28f4,4},{0x28f4,0x290c,4},{0x290c,0x291c,4},{0x291c,0x2934,4},{0x2934,0x2954,4},{0x2954,0x2984,4},{0x2984,0x29a8,4},{0x29a8,0x29b8,4},{0x29b8,0x29d0,4},{0x29d0,0x29fc,4},{0x29fc,0x2a20,4},{0x2a20,0x2a40,4},{0x2a40,0x2a60,4},{0x2a60,0x2aa4,4},{0x2aa4,0x2ab4,4},{0x2ab4,0x2ad8,4},{0x2ad8,0x2af0,4},{0x2af0,0x2b0c,4},{0x2b0c,0x2b24,4},{0x2b24,0x2b3c,4},{0x2b3c,0x2b64,4},{0x2b64,0x2b88,4},{0x2b88,0x2bf8,4},{0x2bf8,0x2c34,4},{0x2c34,0x2cb0,4},{0x2cb0,0x2cd8,4},{0x2cd8,0x2cf0,4},{0x2cf0,0x2d10,4},{0x2d10,0x2d28,4},{0x2d28,0x2d38,4},{0x2d38,0x2d70,4},{0x2d70,0x2dd0,4},{0x2dd0,0x2e3c,4},{0x2e3c,0x2e60,4},{0x2e60,0x2e78,4},{0x2e78,0x2e98,4},{0x2e98,0x2eb0,4},{0x2eb0,0x2ed4,4},{0x2ed4,0x2ee4,4},{0x2ee4,0x2ef4,4},{0x2ef4,0x2f00,5},{0x2f00,0x2f04,2}, }; public void get_blocks_asm(int block_idx,long begin,long end){ Capstone capstone = new Capstone(Capstone.CS_ARCH_ARM64,Capstone.CS_MODE_LITTLE_ENDIAN); byte[] bytes = emulator.getBackend().mem_read(begin + module.base, end - begin); blocks_asm[block_idx] = capstone.disasm(bytes, begin); } public void init_blocks_asm(){ blocks_asm = new Instruction[blocks_dye_mess.length][]; for(int i=0;i<blocks_dye_mess.length;i++){ long begin = blocks_dye_mess[i][0]; long end = blocks_dye_mess[i][1]; get_blocks_asm(i,begin,end); } } public long last_true_block = -1; public long last_condition_true_block = -1; public long last_condition_false_block = -1; public String con_op; class select_ins{ long ins_addr; long taraddr; long other_taraddr=-1; long block_idx; String condition; String true_or_false; } public ArrayList<select_ins> global_select_list= new ArrayList<>(); public void set_ins_hook(long begin_addr,long end_addr){ emulator.getBackend().hook_add_new(new CodeHook() { private UnHook unHook; @Override public void hook(Backend backend, long address, int size, Object user) { try{ long offset = address-module.base; int idx = (int)addr2block_idx[(int)offset]; Instruction block_asm[] = blocks_asm[idx]; long begin_offset = blocks_dye_mess[idx][0]; int block_off = (int)(offset-begin_offset)/4; if( block_off > 0 && block_asm[ block_off -1].getMnemonic().contains("csel")){ String[] ops = block_asm[block_off-1].getOpStr().split(","); String tarreg = ops[0].replace("w","x").trim(); String op1_reg = ops[1].replace("w","x").trim(); String op2_reg = ops[2].replace("w","x").trim(); String conditon = ops[3].trim(); long tarreg_val = read_reg_by_str(backend,tarreg); long op1_reg_val = read_reg_by_str(backend,op1_reg); long op2_reg_val = read_reg_by_str(backend,op2_reg); if(tarreg_val == op1_reg_val){ last_condition_true_block = offset-4; }else{ last_condition_false_block = offset-4; } con_op = new String(conditon); } if(block_end_addr_table.containsKey(offset)){ // 1、判断是不是真实块 int block_idx = end_to_block_idx.get(offset); long dye = blocks_dye_mess[block_idx][2]; if(dye == 4){ // CSET、CSEL代表出现了条件分支,这里我们以csel作为条件分支,因为ollvm主要以csel作为分割 if(last_condition_true_block != -1){ if(addr2block_idx[(int)offset] != addr2block_idx[(int)last_condition_true_block]){ select_ins ins = new select_ins(); ins.ins_addr = last_condition_true_block; ins.condition = new String(con_op); ins.taraddr = blocks_dye_mess[block_idx][0]; ins.block_idx = block_idx; ins.true_or_false = "true"; global_select_list.add(ins); last_condition_true_block = -1; } }else if(last_condition_false_block != -1){ if(addr2block_idx[(int)offset] != addr2block_idx[(int)last_condition_false_block]){ select_ins ins = new select_ins(); ins.ins_addr = last_condition_false_block; ins.condition = new String(con_op); ins.taraddr = blocks_dye_mess[block_idx][0]; ins.block_idx = block_idx; ins.true_or_false = "false"; global_select_list.add(ins); last_condition_false_block = -1; } } if (last_true_block != -1){ true_block_jmp_table.put(last_true_block,blocks_dye_mess[block_idx][0]); last_true_block = offset; }else{ last_true_block = offset; } } // 2、判断是不是ret块 if(dye == 5){ true_block_jmp_table.put(last_true_block,blocks_dye_mess[block_idx][0]); last_true_block = -1; unHook.unhook(); // detach hook } // 3、判断是不是主分发器 if(dye == 0){ last_true_block = offset; } } }catch (Exception e){ System.out.println(e); } } @Override public void onAttach(UnHook unHook) { this.unHook = unHook; } @Override public void detach() { } },begin_addr+module.base,end_addr+module.base,null); } public HashMap<Long,Boolean> block_end_addr_table = new HashMap<>(); public HashMap<Long,Integer> end_to_block_idx = new HashMap<>(); public HashMap<Long,Long> true_block_jmp_table = new HashMap<>(); // 这个表是为了记录真实块之间的跳转的 public int ins_long = 4; public long[] addr2block_idx; public void init_block_end_jmp_table(){ for(int i=0;i<blocks_dye_mess.length;i++){ long end =blocks_dye_mess[i][1]; block_end_addr_table.put(end-ins_long,true); } } public void init_end_to_block_idx(){ for(int i=0;i<blocks_dye_mess.length;i++){ long end =blocks_dye_mess[i][1]; end_to_block_idx.put(end-ins_long,i); } } public void init_addr2block_idx(long begin,long end){ addr2block_idx = new long[(int)end + 0x10]; for(int i=0;i<blocks_dye_mess.length;i++){ long be = blocks_dye_mess[i][0]; long ed = blocks_dye_mess[i][1]; for(int j=(int)be;j<ed;j++){ addr2block_idx[j] = i; } } } public void patcher(long begin,long end){ System.out.printf("patch = ["); for (Map.Entry<Long, Long> entry : true_block_jmp_table.entrySet()) { Long src_address = entry.getKey(); Long tar_address = entry.getValue(); System.out.printf("(0x%x,0x%x),",src_address,tar_address); } System.out.printf("]\n"); HashMap<Long,select_ins> part_select_list= new HashMap<>(); long []set_ins = new long[(int)end + 0x10]; for(select_ins ins: global_select_list){ long ins_addr = ins.ins_addr; if(set_ins[(int)ins_addr]!=0){ if (set_ins[(int)ins_addr] != ins.taraddr){ part_select_list.get(ins_addr).other_taraddr = ins.taraddr; } }else{ set_ins[(int)ins_addr] = ins.taraddr; part_select_list.put(ins_addr,ins); } } System.out.printf("patch_sel = ["); for (Map.Entry<Long, select_ins> entry : part_select_list.entrySet()) { long ins_addr = entry.getKey(); select_ins ins_mess = entry.getValue(); System.out.printf("(0x%x , '%s' , 0x%x , 0x%x, '%s') ,",ins_addr,ins_mess.true_or_false,ins_mess.taraddr,ins_mess.other_taraddr,ins_mess.condition); } System.out.printf("]\n"); } public HashMap<String, Integer> reg2val = new HashMap<>(); public void padding_reg2val() { reg2val.put("x0",Arm64Const.UC_ARM64_REG_X0); reg2val.put("x1",Arm64Const.UC_ARM64_REG_X1); reg2val.put("x2",Arm64Const.UC_ARM64_REG_X2); reg2val.put("x3",Arm64Const.UC_ARM64_REG_X3); reg2val.put("x4",Arm64Const.UC_ARM64_REG_X4); reg2val.put("x5",Arm64Const.UC_ARM64_REG_X5); reg2val.put("x6",Arm64Const.UC_ARM64_REG_X6); reg2val.put("x7",Arm64Const.UC_ARM64_REG_X7); reg2val.put("x8",Arm64Const.UC_ARM64_REG_X8); reg2val.put("x9",Arm64Const.UC_ARM64_REG_X9); reg2val.put("x10",Arm64Const.UC_ARM64_REG_X10); reg2val.put("x11",Arm64Const.UC_ARM64_REG_X11); reg2val.put("x12",Arm64Const.UC_ARM64_REG_X12); reg2val.put("x13",Arm64Const.UC_ARM64_REG_X13); reg2val.put("x14",Arm64Const.UC_ARM64_REG_X14); reg2val.put("x15",Arm64Const.UC_ARM64_REG_X15); reg2val.put("x16",Arm64Const.UC_ARM64_REG_X16); reg2val.put("x17",Arm64Const.UC_ARM64_REG_X17); reg2val.put("x18",Arm64Const.UC_ARM64_REG_X18); reg2val.put("x19",Arm64Const.UC_ARM64_REG_X19); reg2val.put("x20",Arm64Const.UC_ARM64_REG_X20); reg2val.put("x21",Arm64Const.UC_ARM64_REG_X21); reg2val.put("x22",Arm64Const.UC_ARM64_REG_X22); reg2val.put("x23",Arm64Const.UC_ARM64_REG_X23); reg2val.put("x24",Arm64Const.UC_ARM64_REG_X24); reg2val.put("x25",Arm64Const.UC_ARM64_REG_X25); reg2val.put("x26",Arm64Const.UC_ARM64_REG_X26); reg2val.put("x27",Arm64Const.UC_ARM64_REG_X27); reg2val.put("x28",Arm64Const.UC_ARM64_REG_X28); reg2val.put("x29",Arm64Const.UC_ARM64_REG_FP); reg2val.put("x30",Arm64Const.UC_ARM64_REG_LR); reg2val.put("sp",Arm64Const.UC_ARM64_REG_SP); reg2val.put("pc",Arm64Const.UC_ARM64_REG_PC); } public long read_reg_by_str(Backend backend,String reg){ long true_reg_val = -1; if(reg2val.containsKey(reg)){ true_reg_val = backend.reg_read(reg2val.get(reg)).longValue(); }else if(reg.equals("xzr")){ true_reg_val = 0; }else{ assert false; } return true_reg_val; } public void deollvm() { long begin_addr = 0x000000000001E3C; long end_addr = 0x00000000002F04; // 1、获取各基本块的汇编信息 init_blocks_asm(); // 2、指令级hook set_ins_hook(begin_addr,end_addr); // 3、初始化 block_end_jmp_table ,这个表是为了set_ins_hook做准备,每次只处理尾地址,优化unidbg执行效率 init_block_end_jmp_table(); // 4、初始化 end_to_block_idx , 这个是为了方便末尾地址对bloc序列的转化 init_end_to_block_idx(); // 5、初始化 addr2block_idx 。这个是为了方便任意地址找block序列 init_addr2block_idx(begin_addr,end_addr); // 6、padding_reg2val padding_reg2val(); // 7、模拟执行 module.callFunction(emulator,0x00000000000325C); // 8、patcher patcher(begin_addr,end_addr); } }
第三步的patch脚本
import idc from keystone import * def patcher(patch): Kstone = Ks(KS_ARCH_ARM64,KS_MODE_LITTLE_ENDIAN) for i in range(len(patch)): block_patch = patch[i] asm_code = f"b {hex(block_patch[1])}" asm_addr = block_patch[0] encode,count =Kstone.asm(asm_code,asm_addr) for j in range(4): idc.patch_byte(asm_addr+j,encode[j]) def patcher_sel(patch): Kstone = Ks(KS_ARCH_ARM64,KS_MODE_LITTLE_ENDIAN) for i in range(len(patch)): block_patch = patch[i] condition = block_patch[4] true_or_false = block_patch[1] taraddr = block_patch[2] other_addr = block_patch[3] ins_addr = block_patch[0] if other_addr == 0xffffffffffffffff: other_addr = taraddr if "true" in true_or_false: asm_code = f"b{condition} {hex(taraddr)}\n" + f"b {hex(other_addr)}" else: asm_code = f"b{condition} {hex(other_addr)}\n" + f"b {hex(taraddr)}" encode,count =Kstone.asm(asm_code,ins_addr) for j in range(len(encode)): idc.patch_byte(ins_addr+j,encode[j]) def upc(begin,end): for i in range(begin,end): idc.del_items(i) for i in range(begin,end): idc.create_insn(i) idaapi.add_func(begin,end) print("Finish!!!") patch = [(0x2840,0x2844),(0x2980,0x2984),(0x2548,0x254c),(0x25c8,0x25cc),(0x2608,0x260c),(0x2748,0x274c),(0x27c8,0x27cc),(0x2908,0x290c),(0x268c,0x2690),(0x280c,0x25f4),(0x2650,0x2654),(0x2950,0x2954),(0x24d4,0x24d8),(0x2598,0x259c),(0x2918,0x291c),(0x1e60,0x2484),(0x24a0,0x24a4),(0x2524,0x2528),(0x2624,0x2628),(0x26a4,0x26a8),(0x27e4,0x27e8),(0x29a4,0x29a8),(0x24ec,0x24f0),(0x24b0,0x24b4),(0x25b0,0x25b4),(0x25f0,0x25f4),(0x27b0,0x27b4),(0x28f0,0x28f4),(0x2930,0x2934),(0x2574,0x2578),(0x2674,0x2810),(0x29b4,0x2ef4),(0x27fc,0x2800),] patch_sel = [(0x24cc , 'true' , 0x24d8 , 0xffffffffffffffff, 'gt') ,(0x266c , 'true' , 0x2678 , 0x2810, 'ne') ,(0x299c , 'true' , 0x2578 , 0x29a8, 'ne') ,] patcher(patch) patcher_sel(patch_sel) fun_start = 0x000000000001E3C fun_end = 0x00000000002F04 upc(fun_start,fun_end)