-
-
Save korniltsev/dc361d7f51bcda2e7cc2033bc2d93b16 to your computer and use it in GitHub Desktop.
Unicorn实战(一):去掉libcms.so的花指令
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from elftools.elf.constants import P_FLAGS | |
from elftools.elf.elffile import ELFFile | |
from unicorn import Uc, UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN, UC_HOOK_CODE, UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC | |
from unicorn.arm_const import * | |
from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB, CsInsn | |
from keystone import Ks, KS_MODE_THUMB, KS_ARCH_ARM | |
# 找到.text节 | |
filename = "./libcms.so" | |
fd = open(filename, 'rb') | |
elf = ELFFile(fd) | |
sh_offset = elf.get_section_by_name(".text").header['sh_offset'] | |
sh_size = elf.get_section_by_name(".text").header['sh_size'] | |
fd.seek(sh_offset) | |
text_data = fd.read(sh_size) | |
# 找到 [PUSH{...}; MOV RX,PC; MOV RX,PC -> 只找thumb | |
cs = Cs(CS_ARCH_ARM, CS_MODE_THUMB) | |
# (address, push_regs) | |
entries = [] | |
step = 1000 | |
for i in range(0, len(text_data), step): | |
_i = max(0, i - 10) | |
g = cs.disasm(text_data[_i:_i + step], 0) | |
while True: | |
try: | |
ins = next(g) | |
assert isinstance(ins, CsInsn) | |
# push {rx, rx} | |
if ins.mnemonic != 'push': | |
continue | |
ins2 = next(g) | |
assert isinstance(ins2, CsInsn) | |
# mov rx, pc | |
if not ins2.mnemonic.startswith('mov') or not ins2.op_str.endswith('pc'): | |
continue | |
ins3 = next(g) | |
assert isinstance(ins3, CsInsn) | |
# mov rx, pc | |
if not ins3.mnemonic.startswith('mov') or not ins3.op_str.endswith('pc'): | |
continue | |
entries.append((_i + sh_offset + ins.address, ins.op_str)) | |
except StopIteration: | |
break | |
print(entries) | |
# 加载 so 到内存中 | |
def align(addr, size, align): | |
fr_addr = addr // align * align | |
to_addr = (addr + size + align - 1) // align * align | |
return fr_addr, to_addr - fr_addr | |
def pflags2prot(p_flags): | |
ret = 0 | |
if p_flags & P_FLAGS.PF_R != 0: | |
ret |= UC_PROT_READ | |
if p_flags & P_FLAGS.PF_W != 0: | |
ret |= UC_PROT_WRITE | |
if p_flags & P_FLAGS.PF_X != 0: | |
ret |= UC_PROT_EXEC | |
return ret | |
load_base = 0 | |
emu = Uc(UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN) | |
load_segments = [x for x in elf.iter_segments() if x.header.p_type == 'PT_LOAD'] | |
for segment in load_segments: | |
fr_addr, size = align(load_base + segment.header.p_vaddr, segment.header.p_memsz, segment.header.p_align) | |
emu.mem_map(fr_addr, size, pflags2prot(segment.header.p_flags)) | |
emu.mem_write(load_base + segment.header.p_vaddr, segment.data()) | |
# 依次进入所有的entry,执行到栈平衡时退出 | |
STACK_ADDR = 0x7F000000 | |
STACK_SIZE = 1024 * 1024 | |
start_addr = None | |
def hook_code(mu: Uc, address, size, user_data): | |
if mu.reg_read(UC_ARM_REG_PC) != start_addr and mu.reg_read(UC_ARM_REG_SP) == STACK_ADDR + STACK_SIZE: | |
emu.emu_stop() | |
emu.mem_map(STACK_ADDR, STACK_SIZE) | |
emu.hook_add(UC_HOOK_CODE, hook_code) | |
_to_reg_id = { | |
"r0": UC_ARM_REG_R0, "r1": UC_ARM_REG_R1, "r2": UC_ARM_REG_R2, "r3": UC_ARM_REG_R3, | |
"r4": UC_ARM_REG_R4, "r5": UC_ARM_REG_R5, "r6": UC_ARM_REG_R6, "r7": UC_ARM_REG_R7, | |
"r8": UC_ARM_REG_R8, "r9": UC_ARM_REG_R9, "r10": UC_ARM_REG_R10, "r11": UC_ARM_REG_R11, | |
"r12": UC_ARM_REG_R12, "r13": UC_ARM_REG_R13, "r14": UC_ARM_REG_R14, "r15": UC_ARM_REG_R15, | |
"lr": UC_ARM_REG_LR, "pc": UC_ARM_REG_PC, "sp": UC_ARM_REG_SP, | |
"sb": UC_ARM_REG_SB, "sl": UC_ARM_REG_SL, "fp": UC_ARM_REG_FP, "ip": UC_ARM_REG_IP, | |
} | |
ret = [] | |
MAGIC32 = 0x12345678 | |
for push_entry, push_regs in entries: | |
emu.reg_write(UC_ARM_REG_SP, STACK_ADDR + STACK_SIZE) | |
print("Emulate arm code start", hex(push_entry)) | |
start_addr = push_entry | |
for r in push_regs.strip('{}').replace(' ', '').split(','): | |
emu.reg_write(_to_reg_id[r], MAGIC32) | |
emu.emu_start(push_entry + 1, 0, 0, 100) | |
print("Emulation arm code done") | |
changed = False | |
for r in push_regs.strip('{}').replace(' ', '').split(','): | |
if emu.reg_read(_to_reg_id[r]) != MAGIC32: | |
changed = True | |
break | |
stop_addr = emu.reg_read(UC_ARM_REG_PC) | |
if not changed: | |
print("Match:", start_addr, stop_addr) | |
ret.append((start_addr, stop_addr)) | |
else: | |
print("Cannot handle:", start_addr) | |
fd.close() | |
print(ret) | |
# [(55302, 55386), (55390, 55474), (55538, 55624), (55916, 56002), (56006, 56090), (56114, 56200), (60314, 60398), (60780, 60866), (61258, 61342), (61346, 61432), (96392, 96476), (107254, 107338), (107412, 107498), (130468, 130552), (131490, 131574), (131578, 131664), (132818, 132902), (135238, 135324), (135456, 135542), (136624, 136710), (144270, 144354), (144434, 144520), (144856, 144940), (145070, 145156), (147232, 147316), (151298, 151382), (151512, 151598), (151662, 151748), (152022, 152106), (152110, 152196), (157910, 157996), (158170, 158256), (159260, 159346), (159348, 159434), (161294, 161380), (161476, 161562), (161574, 161660), (161806, 161890), (161930, 162016), (165348, 165434), (165504, 165588), (165600, 165686), (165756, 165840), (165852, 165938), (166008, 166092), (166104, 166190), (166260, 166344), (166356, 166442), (166512, 166596), (166608, 166694), (166764, 166848), (166860, 166946), (167016, 167100), (167112, 167198), (167268, 167352), (167364, 167450), (169646, 169732), (169744, 169830), (170418, 170504), (170518, 170604), (172880, 172964), (173540, 173626), (173638, 173724), (173732, 173816), (173820, 173906), (185340, 185424), (185568, 185652), (185830, 185914), (186568, 186654), (211188, 211272), (211418, 211504), (211550, 211634), (211680, 211766), (211790, 211874), (211880, 211968), (211974, 212058), (212068, 212154), (212162, 212246), (214604, 214690), (217610, 217694), (222522, 222608), (224688, 224772), (225110, 225194), (225280, 225366), (226396, 226482), (226680, 226766), (226874, 226960), (227020, 227104), (227172, 227258), (484228, 484314), (486500, 486586), (487556, 487642), (487696, 487782), (487828, 487914), (487916, 488000), (490978, 491064), (492458, 492544), (494114, 494200), (494444, 494528), (494568, 494654), (505414, 505498), (506140, 506226), (507860, 507944), (509882, 509968), (510050, 510136), (510540, 510624), (512724, 512810), (512858, 512942), (513104, 513188), (513282, 513366), (513406, 513490), (516024, 516108), (516152, 516238), (516476, 516562)] | |
# in idapython | |
# for start, stop in ret: | |
# ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB) | |
# a = ks.asm("B.W $+" + str(stop - start)) | |
# PatchByte(start, a[0][0]) | |
# PatchByte(start + 1, a[0][1]) | |
# PatchByte(start + 2, a[0][2]) | |
# PatchByte(start + 3, a[0][3]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment