├── lib52pojie.so ├── module ├── __pycache__ │ ├── utils.cpython-310.pyc │ └── my_symbexec.cpython-310.pyc ├── utils.py └── my_symbexec.py ├── xflower.iml ├── README.md ├── my_patch.py └── xflower.py /lib52pojie.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xjacklove/xflower/HEAD/lib52pojie.so -------------------------------------------------------------------------------- /module/__pycache__/utils.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xjacklove/xflower/HEAD/module/__pycache__/utils.cpython-310.pyc -------------------------------------------------------------------------------- /module/__pycache__/my_symbexec.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xjacklove/xflower/HEAD/module/__pycache__/my_symbexec.cpython-310.pyc -------------------------------------------------------------------------------- /xflower.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 使用指南 2 | ======== 3 | 4 | untils.py的MAGIC记得修改 5 | 如果为下面这种,MAGIC = "CSET" 6 | ``` 7 | CSET W8, EQ 8 | ADD X9, X9, #1234@PAGEOFF 9 | LDR X8, [X9,W8,UXTW#3] 10 | BR X8 11 | ``` 12 | 如果为这种,MAGIC = "CSEL" 13 | ``` 14 | MOV W12, #0xA8 15 | MOV W13, #0x48 ; 'H' 16 | CSEL X12, X13, X12, EQ 17 | LDR X11, [X11,X12] 18 | ADD X11, X11, X15 19 | BR X11 20 | ``` 21 | -------------------------------------------------------------------------------- /module/utils.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | 3 | from miasm.expression.expression import ExprCond, ExprCompose, ExprOp, ExprMem, ExprId 4 | 5 | MAGIC = "CSEL" 6 | def replace_exprcond(expr): 7 | if isinstance(expr, ExprCond): 8 | # 对条件表达式的每个分支进行递归替换 9 | src1 = replace_exprcond(expr.src1) 10 | src2 = replace_exprcond(expr.src2) 11 | # 生成两个新的表达式,分别代表条件成立或不成立的情况 12 | return [src1, src2] 13 | elif isinstance(expr, ExprCompose): 14 | # 对ExprCompose中的每个部分进行递归替换,并处理返回的元组 15 | parts = [replace_exprcond(arg) for arg in expr.args] 16 | # 检查是否有任何部分返回了一个列表(多个替换结果) 17 | if any(isinstance(part, list) for part in parts): 18 | # 确保每个部分都是列表,单个结果转换为列表 19 | parts = [(part if isinstance(part, list) else [part]) for part in parts] 20 | # 生成所有可能的ExprCompose对象 21 | ret = [ExprCompose(*combination) for combination in product(*parts)] 22 | else: 23 | # 如果没有列表,说明没有多个替换结果,直接返回原始ExprCompose 24 | ret = [ExprCompose(*parts)] 25 | return ret 26 | elif isinstance(expr, ExprOp): 27 | # 对ExprOp的每个参数进行递归替换 28 | parts = [replace_exprcond(arg) for arg in expr.args] 29 | # 检查是否有任何部分返回了一个列表(多个替换结果) 30 | if any(isinstance(part, list) for part in parts): 31 | # 确保每个部分都是列表,单个结果转换为列表 32 | parts = [(part if isinstance(part, list) else [part]) for part in parts] 33 | # 生成所有可能的ExprOp对象 34 | ret = [ExprOp(expr.op, *combination) for combination in product(*parts)] 35 | else: 36 | # 如果没有列表,说明没有多个替换结果,直接返回原始ExprOp 37 | ret = [ExprOp(expr.op, *parts)] 38 | return ret 39 | 40 | elif isinstance(expr, ExprMem): 41 | # 对ExprMem的参数进行递归替换 42 | if type(expr.arg) != int: 43 | addr = replace_exprcond(expr.arg) 44 | # 如果递归替换的结果是一个列表(即存在多个可能的地址),则生成多个ExprMem对象 45 | if isinstance(addr, list): 46 | ret = [ExprMem(a, expr.size) for a in addr] 47 | else: 48 | # 如果没有列表,说明没有多个替换结果,直接返回原始ExprMem 49 | ret = [ExprMem(addr, expr.size)] 50 | return ret 51 | else: 52 | return expr 53 | else: 54 | # 对于其他类型的表达式(如ExprId, ExprInt等),直接返回 55 | return expr 56 | 57 | def replace_exprcond2(expr): 58 | if isinstance(expr, ExprCond): 59 | # 对条件表达式的每个分支进行递归替换 60 | src1 = replace_exprcond2(expr.src1) 61 | src2 = replace_exprcond2(expr.src2) 62 | # 生成两个新的表达式,分别代表条件成立或不成立的情况 63 | return ExprCond(ExprId("SuperMan", 64), src1, src2) 64 | 65 | elif isinstance(expr, ExprOp): 66 | # 对ExprOp的每个参数进行递归替换 67 | parts = [replace_exprcond2(arg) for arg in expr.args] 68 | ret = ExprOp(expr.op, *parts) 69 | return ret 70 | 71 | else: 72 | # 对于其他类型的表达式(如ExprId, ExprInt等),直接返回 73 | return expr -------------------------------------------------------------------------------- /my_patch.py: -------------------------------------------------------------------------------- 1 | import keystone 2 | import capstone 3 | import ida_bytes 4 | import idc 5 | from module.utils import MAGIC 6 | 7 | KS = keystone.Ks(keystone.KS_ARCH_ARM64, keystone.KS_MODE_LITTLE_ENDIAN) 8 | CS = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB) 9 | 10 | NOP_BYTES = b'\x1f\x20\x03\xd5' 11 | def handle_txt(path): 12 | addr_dict = {} 13 | f = open(path) 14 | line = f.readline().replace("\n", "") 15 | while line: 16 | info = line.split(",") 17 | if len(info) == 2: 18 | patch_addr = info[0] 19 | b_addr = info[1] 20 | if patch_addr not in addr_dict.keys(): 21 | addr_dict[patch_addr] = [b_addr] 22 | else: 23 | addr_list = addr_dict[patch_addr] 24 | if b_addr not in addr_list: 25 | addr_dict[patch_addr].append(b_addr) 26 | elif len(info) == 3: 27 | patch_addr = info[0] 28 | b_addr1 = info[1] 29 | b_addr2 = info[2] 30 | if patch_addr not in addr_dict.keys(): 31 | addr_dict[patch_addr] = [b_addr1, b_addr2] 32 | else: 33 | addr_list = addr_dict[patch_addr] 34 | if b_addr1 not in addr_list: 35 | addr_dict[patch_addr].append(b_addr1) 36 | if b_addr2 not in addr_list: 37 | addr_dict[patch_addr].append(b_addr1) 38 | else: 39 | raise Exception("check your code") 40 | line = f.readline().replace("\n", "") 41 | f.close() 42 | return addr_dict 43 | 44 | 45 | def get_b_const_bytes(ea, const): 46 | ''' 47 | 返回例如 ea: b 0x12334的指令 48 | :param ea: 49 | :param const: 50 | :return: 51 | ''' 52 | ea = int(ea, 16) 53 | CODE = f"b {const[0]}" 54 | encoding, count = KS.asm(CODE, ea) 55 | return ea, bytes(encoding) 56 | 57 | def find_magic(ea): 58 | for i in range(10): 59 | asm = idc.GetDisasm(ea) 60 | if asm.startswith(MAGIC): 61 | info = asm.split(",") 62 | cond = info[-1].replace(" ","").lower() 63 | return ea, cond 64 | ea = idc.prev_head(ea) 65 | raise Exception("check your code:" + hex(ea)) 66 | 67 | 68 | def get_bxx_const_bytes(ea, const_list): 69 | ea = int(ea, 16) 70 | patch_ea, cond = find_magic(ea) 71 | code = f"b{cond} {const_list[0]}" 72 | encoding, count = KS.asm(code, patch_ea) 73 | ret = bytes(encoding) 74 | code = f"b {const_list[1]}" 75 | encoding, count = KS.asm(code, patch_ea + 4) 76 | ret += bytes(encoding) 77 | return patch_ea, ret 78 | 79 | 80 | addr_dict = handle_txt("./addr.txt") 81 | 82 | for key in addr_dict.keys(): 83 | value = addr_dict[key] 84 | if len(value) == 1: 85 | ea, patch_bytes = get_b_const_bytes(key, value) 86 | ida_bytes.patch_bytes(ea, patch_bytes) 87 | else: 88 | ea, patch_bytes = get_bxx_const_bytes(key, value) 89 | ida_bytes.patch_bytes(ea, patch_bytes) -------------------------------------------------------------------------------- /module/my_symbexec.py: -------------------------------------------------------------------------------- 1 | from miasm.expression.expression import ExprId, ExprInt, ExprCompose, ExprCond 2 | from miasm.expression.simplifications import expr_simp_explicit 3 | from miasm.ir.symbexec import SymbolicExecutionEngine 4 | 5 | from module.utils import replace_exprcond, replace_exprcond2 6 | 7 | 8 | class MySymbolicExecutionEngine(SymbolicExecutionEngine): 9 | def __init__(self, lifter, condition_pc=[], jmp_dict={}, state=None, sb_expr_simp=expr_simp_explicit, 10 | show_mem=False, path=None): 11 | super().__init__(lifter, state, sb_expr_simp) 12 | self.show_mem = show_mem 13 | self.condition_pc = condition_pc 14 | self.pc = None 15 | self.instr = None 16 | self.path = path 17 | self.jmp_dict = jmp_dict 18 | 19 | def write(self, content): 20 | with open(self.path, "a+") as f: 21 | f.write(content) 22 | 23 | def eval_updt_irblock(self, irb, step=False): 24 | """ 25 | Symbolic execution of the @irb on the current state 26 | @irb: irbloc instance 27 | @step: display intermediate steps 28 | """ 29 | for assignblk in irb: 30 | self.pc = assignblk.instr.offset 31 | self.instr = assignblk.instr 32 | if step: 33 | print(hex(assignblk.instr.offset) + ":", assignblk.instr) 34 | print('Assignblk:') 35 | print(assignblk) 36 | print('_' * 80) 37 | 38 | if assignblk.instr.offset in self.condition_pc: 39 | # handle cesl 40 | assigns_key = next(iter(assignblk._assigns.keys())) 41 | assigns_value = assignblk._assigns[assigns_key] 42 | assignblk._assigns[assigns_key] = replace_exprcond2(assigns_value) 43 | 44 | self.eval_updt_assignblk(assignblk) 45 | 46 | if assignblk.instr.offset in self.jmp_dict.keys(): 47 | self.symbols.symbols_id[ExprId("PC", 64)] = self.eval_expr(self.jmp_dict[assignblk.instr.offset]) 48 | self.symbols.symbols_id[ExprId("IRDst", 64)] = self.eval_expr(self.jmp_dict[assignblk.instr.offset]) 49 | 50 | if step: 51 | self.dump(mems=False) 52 | ''' 53 | 内存打印太多了 54 | ''' 55 | # if assignblk.instr.offset == 0xca768: 56 | # self.dump(ids=False) 57 | print('_' * 80) 58 | 59 | if assignblk.instr.name == "BR": 60 | symbolic_pc = self.symbols.symbols_id[assignblk.instr.args[0]] 61 | if not symbolic_pc.is_cond(): 62 | pc = self.pc 63 | if type(symbolic_pc.arg) == int: 64 | next_pc = symbolic_pc.arg 65 | self.write(f"{hex(pc)},{hex(next_pc)}\n") 66 | else: 67 | expr_list = replace_exprcond(symbolic_pc) 68 | next_pc_list = [] 69 | for expr in expr_list: 70 | simp_expr = self.eval_expr(self.expr_simp(expr)) 71 | if simp_expr not in next_pc_list: 72 | next_pc_list.append(simp_expr) 73 | 74 | if len(next_pc_list) == 2: 75 | src1 = next_pc_list[0].arg 76 | src2 = next_pc_list[1].arg 77 | self.write(f"{hex(pc)},{hex(src1)},{hex(src2)}\n") 78 | elif len(next_pc_list) == 1: 79 | next_pc = next_pc_list[0].arg 80 | self.write(f"{hex(pc)},{hex(next_pc)}\n") 81 | else: 82 | raise Exception("you need check your code") 83 | else: 84 | pc = self.pc 85 | src1 = int(str(self.eval_expr(symbolic_pc.src1)), 16) 86 | src2 = int(str(self.eval_expr(symbolic_pc.src2)), 16) 87 | self.write(f"{hex(pc)},{hex(src1)},{hex(src2)}\n") 88 | 89 | dst = self.eval_expr(self.lifter.IRDst) 90 | 91 | return dst 92 | 93 | def run_at(self, ircfg, addr, lbl_stop=None, step=False): 94 | """ 95 | Symbolic execution starting at @addr 96 | @addr: address to execute (int or ExprInt or label) 97 | @lbl_stop: LocKey to stop execution on 98 | @step: display intermediate steps 99 | """ 100 | i = 0 101 | while True: 102 | irblock = ircfg.get_block(addr) 103 | if irblock is None: 104 | break 105 | if irblock.loc_key == lbl_stop: 106 | break 107 | addr = self.eval_updt_irblock(irblock, step=step) 108 | i += 1 109 | # 死循环跳出 110 | if i > 10000: 111 | print("[*] meet loop") 112 | return None 113 | return addr 114 | -------------------------------------------------------------------------------- /xflower.py: -------------------------------------------------------------------------------- 1 | #! -*- coding=utf-8 -*- 2 | import capstone 3 | from miasm.analysis.binary import Container 4 | from miasm.analysis.machine import Machine 5 | from miasm.core.utils import * 6 | from miasm.core.locationdb import LocationDB 7 | from miasm.expression.expression import ExprMem, ExprId, ExprInt, ExprAssign, ExprAff, ExprCompose, ExprOp, ExprCond 8 | from elftools.elf.elffile import ELFFile 9 | 10 | from module.utils import replace_exprcond, MAGIC 11 | from module.my_symbexec import MySymbolicExecutionEngine 12 | 13 | CS = capstone.Cs(capstone.CS_ARCH_ARM64, capstone.CS_MODE_LITTLE_ENDIAN) 14 | 15 | 16 | def read_data_section(elf_path, seg_name): 17 | with open(elf_path, 'rb') as file: 18 | elffile = ELFFile(file) 19 | 20 | # 获取.data段 21 | data_section = elffile.get_section_by_name(seg_name) 22 | 23 | # 检查是否存在.data段 24 | if not data_section: 25 | print("The file does not have a .data section.") 26 | return None 27 | 28 | # 读取.data段数据 29 | data = data_section.data() 30 | return data, data_section.header.sh_addr 31 | 32 | 33 | def get_bin(path): 34 | fp = open(path, 'rb') 35 | buffer = fp.read() 36 | fp.close() 37 | return buffer 38 | 39 | 40 | def fill_data(sb, offset, data): 41 | data = list(data) 42 | for i in range(len(data)): 43 | sb.symbols[ExprMem(ExprInt(offset + i, 64), 8)] = ExprInt(data[i], 8) 44 | 45 | 46 | def add_block(asmcfg, offset): 47 | block, next1 = mdis._dis_block(offset) 48 | asmcfg.add_block(block) 49 | 50 | 51 | def print_blocks(asmcfg): 52 | for block in asmcfg.blocks: 53 | print(block) 54 | 55 | 56 | def get_code_disam(addr, code): 57 | codes = [] 58 | for i in CS.disasm(code, addr): 59 | codes.append(i) 60 | return codes 61 | 62 | 63 | def get_all_condition_addr(asm, magic="csel"): 64 | condition_pc = [] 65 | for i in range(len(asm)): 66 | ins = asm[i] 67 | if ins.mnemonic == "br": 68 | # 开始向上寻找 69 | for j in range(i, 0, -1): 70 | magic_ins = asm[j] 71 | if magic_ins.mnemonic == magic.lower(): 72 | condition_pc.append(magic_ins.address) 73 | break 74 | if i - j > 10: 75 | raise Exception("check this br" + str(ins)) 76 | return condition_pc 77 | 78 | 79 | def init_machine(extra_blocks, condition, jmp_dict={}): 80 | lifter = machine.lifter_model_call(loc_db) 81 | asmcfg = mdis.dis_multiblock(start_addr) 82 | for block in extra_blocks: 83 | add_block(asmcfg, block) 84 | print_blocks(asmcfg) 85 | ircfg = lifter.new_ircfg_from_asmcfg(asmcfg) 86 | sb = MySymbolicExecutionEngine(lifter, condition_pc=condition, jmp_dict=jmp_dict, path=addr_path) 87 | 88 | fill_data(sb, data_offset, data) 89 | fill_data(sb, got_data_offset, got_data) 90 | # fill_data(sb, bss_data_offset, bss_data) 91 | 92 | for i in range(8): 93 | sb.symbols[ExprMem(ExprInt(0 + i, 64), 8)] = ExprInt(0, 8) 94 | return sb, ircfg 95 | 96 | 97 | def handle(blocks, condition, jmp_dict): 98 | print("[*]*****************************************************************") 99 | sb, ircfg = init_machine(blocks, condition, jmp_dict) 100 | try: 101 | symbolic_pc = sb.run_at(ircfg, start_addr, step=True) 102 | except Exception as e: 103 | print("--------Exception---------") 104 | print(e) 105 | return 106 | if symbolic_pc is not None and str(symbolic_pc) != "LR": 107 | if not symbolic_pc.is_cond(): 108 | pc = sb.pc 109 | if type(symbolic_pc.arg) == int: 110 | next_pc = symbolic_pc.arg 111 | # fp.write(f"{hex(pc)},{hex(next_pc)}\n") 112 | if next_pc not in blocks and next_pc < end_addr: 113 | blocks.append(next_pc) 114 | handle(blocks, condition, jmp_dict) 115 | else: 116 | expr_list = replace_exprcond(symbolic_pc) 117 | next_pc_list = [] 118 | for expr in expr_list: 119 | simp_expr = sb.eval_expr(sb.expr_simp(expr)) 120 | if simp_expr not in next_pc_list: 121 | next_pc_list.append(simp_expr) 122 | 123 | if len(next_pc_list) == 2: 124 | src1 = next_pc_list[0].arg 125 | src2 = next_pc_list[1].arg 126 | if src1 not in blocks and src1 < end_addr: 127 | blocks.append(src1) 128 | jmp_dict[pc] = next_pc_list[0] 129 | handle(blocks, condition, jmp_dict) 130 | if src2 not in blocks and src2 < end_addr: 131 | blocks.append(src2) 132 | jmp_dict[pc] = next_pc_list[1] 133 | handle(blocks, condition, jmp_dict) 134 | elif len(next_pc_list) == 1: 135 | next_pc = next_pc_list[0].arg 136 | if next_pc not in blocks and next_pc < end_addr: 137 | blocks.append(next_pc) 138 | handle(blocks, condition, jmp_dict) 139 | else: 140 | raise Exception("you need check your code") 141 | else: 142 | pc = sb.pc 143 | src1 = sb.eval_expr(symbolic_pc.src1).arg 144 | src2 = sb.eval_expr(symbolic_pc.src2).arg 145 | # fp.write(f"{hex(pc)},{hex(src1)},{hex(src2)}\n") 146 | if src1 not in blocks and src1 < end_addr: 147 | blocks.append(src1) 148 | jmp_dict[pc] = symbolic_pc.src1 149 | handle(blocks, condition, jmp_dict) 150 | if src2 not in blocks and src2 < end_addr: 151 | blocks.append(src2) 152 | jmp_dict[pc] = symbolic_pc.src2 153 | handle(blocks, condition, jmp_dict) 154 | 155 | 156 | path = "./lib52pojie.so" 157 | addr_path = "./addr.txt" 158 | f = open(addr_path, "w") 159 | f.close() 160 | # 使用函数读取ELF文件的.data段 161 | data, data_offset = read_data_section(path, '.data') 162 | got_data, got_data_offset = read_data_section(path, '.got') 163 | # bss_data, bss_data_offset = read_data_section(path, '.bss') 164 | code_buffer = get_bin(path) 165 | machine = Machine('aarch64l') 166 | loc_db = LocationDB() 167 | c = Container.from_string(code_buffer, loc_db) 168 | mdis = machine.dis_engine(c.bin_stream, loc_db=loc_db) 169 | 170 | start_addr = 0x1A864 171 | end_addr = 0x1AE20 172 | func_code = code_buffer[start_addr:end_addr] 173 | asm = get_code_disam(start_addr, func_code) 174 | condition = get_all_condition_addr(asm, MAGIC) 175 | handle([], condition, {}) 176 | --------------------------------------------------------------------------------