7

[原创]使用unicorn对ollvm字符串进行解密

 3 years ago
source link: https://bbs.pediy.com/thread-268108.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

使用unicorn对字符串进行解密

偷懒使用unicorn直接将整个so文件load进memory,读取data的数据全是00,修复后也是错误的,我按照leadroyal大佬的脚本修改后是正确的

有时候使用unicorn map后,代码看着没有问题,但是跑起来就报错,可能你需要看看你分配的内存是不是不是1024的倍数

脚本如下:

import binascii
import math
import ida_bytes
import idaapi
from capstone import *
from elftools.elf.elffile import ELFFile
from elftools.elf.sections import SymbolTableSection
from keystone import *
from unicorn import *
from unicorn.arm_const import *
class FILFINIT(object):
def __init__(self, file, mode):
self.file = file
self.fd = self.file_init(mode)
self.elf = ELFFile(self.fd)
self.file_size = self.file_size()
self.data_divs = self.get_data_div()
def file_init(self, mode='rb+'):
fd = open(self.file, mode=mode)
return fd
def file_close(self):
self.fd.close()
def file_seek_to(self, seekto):
self.fd.seek(seekto, 0)
def file_read(self, size=-1):
binary = self.fd.read(size)
return binary
def file_write(self, data):
self.fd.write(data)
def file_size(self):
import os
return os.path.getsize(self.file)
def get_data_div(self):
data_divs = []
if self.elf:
symtab = self.elf.get_section_by_name('.dynsym')
assert isinstance(symtab, SymbolTableSection)
for sym in symtab.iter_symbols():  # sym.name:str
if sym.name.startswith('.datadiv'):
data_divs.append(sym.entry.st_value)
return data_divs
class UCINIT(object):
def __init__(self, file, mode, offset=0x10000, stack_size=0x10000, data_size=0x10000):
self.cs = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
self.fileinfo = FILFINIT(file, mode)
self.data_divs = self.uc_filter()
self.func_start_and_end = self.get_func_start_and_end()
self.uc = unicorn.Uc(UC_ARCH_ARM, UC_MODE_THUMB)
self.image_base = 0x10000
self.offset = offset
self.stack_size = stack_size
self.data_size = data_size
self.image_size = (math.ceil(self.fileinfo.file_size / self.offset) + 1) * self.offset
self.uc.mem_map(self.image_base, self.image_size)
self.init_seg()
# self.uc.mem_write(self.image_base, self.fileinfo.file_read()) # 全文件导入是错误的,不知道为什么
self.stack_base = self.image_base + self.image_size + self.offset
self.stack_top = self.stack_base + self.stack_size - 0x1000
self.uc.mem_map(self.stack_base, self.stack_size)
self.uc.reg_write(UC_ARM_REG_SP, self.stack_top)
self.data_base = self.stack_base + self.stack_size + self.offset
self.uc.mem_map(self.data_base, self.data_size)
def init_seg(self):
segs = [seg for seg in self.fileinfo.elf.iter_segments() if seg.header.p_type == 'PT_LOAD']
for seg in segs:
self.uc.mem_write(self.image_base + seg.header.p_vaddr, seg.data())
def init_reg(self, regs):
index = 0
for reg in regs:
reg_num = 66 + index
self.uc.reg_write(reg_num, reg)
def uc_run(self, target, end):
targ = target + self.image_base
util = self.image_base + end
self.uc.emu_start(targ, util)
def uc_stop(self):
self.uc.emu_stop()
self.fileinfo.file_close()
def register_hook_code(self, htype, callback):
self.uc.hook_add(htype, callback)
def uc_filter(self, size=0x2):
data_divs = []
for data_div in self.fileinfo.data_divs:
self.fileinfo.file_seek_to(data_div - 1)
data = self.fileinfo.file_read(size)
for inis in self.cs.disasm(data, 0):
if inis.mnemonic == 'bx' and inis.op_str == 'lr':
continue
else:
data_divs.append(data_div)
self.fileinfo.file_seek_to(0)
return data_divs
def get_func_start_and_end(self):
data_divs = []
for data_div in self.data_divs:
func = idaapi.get_func(data_div)
func_start_and_end = (data_div, func.end_ea - 0x2)
data_divs.append(func_start_and_end)
return data_divs
def get_elf_data(self):
data_section_header = self.fileinfo.elf.get_section_by_name('.data').header
print('[+] .data addr {}-{}'.format(hex(data_section_header.sh_addr), hex(data_section_header.sh_size)))
new_data = self.uc.mem_read(self.image_base + data_section_header.sh_addr, data_section_header.sh_size)
print('[+] .data binary {}'.format(binascii.hexlify(new_data)))
return new_data
def patch_so_data(self):
data_section_header = self.fileinfo.elf.get_section_by_name('.data').header
data_addr = data_section_header.sh_addr
# self.fileinfo.file_seek_to(data_addr)
# self.fileinfo.file_write(self.get_elf_data())
new_data = self.get_elf_data()  # new_data: bytearray
print('[+] patch so data addr {}\n {}'.format(hex(data_addr), bytes(new_data)))
ida_bytes.patch_bytes(data_addr, bytes(new_data))
def patch_data_div(self):
ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB)
for data_div in self.data_divs:
binary = ks.asm('bx lr')
print(bytes(binary[0]))
# print(struct.pack('B', binary[0]))
print('[+] patch so text .datadiv {}\n {}'.format(hex(data_div - 1), bytes(binary[0])))
ida_bytes.patch_bytes(data_div - 1, bytes(binary[0]))
def hook_code(uc: unicorn.Uc, address, size, user_data):
cs = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
me = uc.mem_read(address, size)
for code in cs.disasm(me, size):
print("[+] Tracing instructions at 0x%x, instructions size = ix%x, inst: %s %s" % (
address, size, code.mnemonic, code.op_str))
def hook_mem_access(uc, access, address, size, value, user_data):
if access == UC_MEM_WRITE:
print('[+] Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x' % (address, size, value))
else# READ
me = uc.mem_read(address, size)
print('[+] Memory is being READ at 0x%x, data size = %u, data value = 0x%s' % (
address, size, binascii.hexlify(me)))
if __name__ == '__main__':
print('[+] So file parse starting!')
so = UCINIT('libcrack.so', 'rb')
# so.get_elf_data()
for start, end in so.func_start_and_end:
print('[+] Data div addr {}-{}'.format(hex(start), hex(end)))
so.init_reg((0, 0, 0))
# so.register_hook_code(UC_HOOK_CODE, hook_code)
# so.register_hook_code(UC_HOOK_MEM_READ, hook_mem_access)
# so.register_hook_code(UC_HOOK_MEM_WRITE, hook_mem_access)
so.uc_run(start, end)
so.patch_data_div()
# so.patch_so_data()
# so.get_elf_data()
so.uc_stop()
print('[+] So file run finished!')

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK