其他分享
首页 > 其他分享> > 利用unicron去除ollvm混淆

利用unicron去除ollvm混淆

作者:互联网

测试程序是2022 TX的一道安卓赛题,主函数以及所有的子函数都被混淆了。

去混淆思路

去混淆具体过程

main函数去混淆前的流程图如下

利用反汇编引擎找到左右的控制流基本块

控制流基本块的划分是通过b,bge,bgt,ble,blt,bne,beq,beq.w等指令分割的,同时注意ret块比较特殊是以pop popeq等指令划分的。

for i in md.disasm(bin1[offset:end],offset):
    insStr += "0x%x:\t%s\t%s\n" %(i.address, i.mnemonic, i.op_str) 
    if isNew:
        isNew = False
        block_item = {}
        block_item["saddress"] = i.address
        

    if  (i.mnemonic == 'b'       or \
        i.mnemonic == 'beq.w'    or \
        i.mnemonic == 'beq'      or \
        i.mnemonic == 'bne'      or \
        i.mnemonic == 'bgt'      or \
        i.mnemonic == 'bge'      or \
        i.mnemonic == 'ble'      or \
        i.mnemonic == 'blt'      or \
        i.mnemonic == 'popeq'    or \
        i.mnemonic == 'pop'):              #所有的跳转指令作为基本块区分

        
        isNew = True
        block_item["eaddress"] = i.address
        block_item['ins'] = insStr
        print(insStr)
        insStr = ''
        for op in i.operands:               
            if op.type == ARM_OP_IMM:                           #如果是立即数
                block_item["naddress"] = op.value.imm    
                if op.value.imm not in  processors:             #计算后继块的引用计数
                    processors[op.value.imm] = 1
                else:
                    processors[op.value.imm] += 1
        if "naddress" not in block_item:                        #如果操作数中不含有立即数(ret块)     
            block_item['naddress'] = None
        list_blocks[block_item["saddress"]] = block_item        #保存所有的块的信息

找到所有基本块中的真实块

我们寻找此混淆代码中真实块的特点发现,凡是有内存操作的都是真实块,没有内存操作的都是虚假块。(其他混淆中不一定,重要的是寻找真实块的特点)

#真实块中需要过滤的块
fake_blocks = []
for i in real_blocks:
    insns = list_blocks[i]['ins'].split('\n') 
    flag = 0
    for ins in insns:
        if ins.find('[') != -1:                   #包含内存操作,则一定是真实块
            flag = 1
            break            
    if flag == 0:
        fake_blocks.append(i)
            
for x in fake_blocks:                             #去除虚假块(去除后其中也可能包含虚假控制流的块,永远不会执行的)
    real_blocks.remove(x)

利用unicorn寻找真实块的路径

在利用unicorn寻找路径的时候只关心控制块能够寻找到的路径,其他非我们预留堆栈内存操作的指令都直接pass。

#指令如果是一些非堆栈的内存操作直接pass不执行
if ins.op_str.find('[') != -1:
  if ins.op_str.find('[sp') == -1:    
    flag_pass = True  #如果是非栈内存访问pass              
    for op in ins.operands:
      if op.type == ARM_OP_MEM:       #如果是内存操作数
        addr = 0
        if op.value.mem.base != 0:
          addr += mu.reg_read(reg_ctou(ins.reg_name(op.value.mem.base)))
        elif op.value.index != 0:
          addr += mu.reg_read(reg_ctou(ins.reg_name(op.value.mem.index)))
        elif op.value.disp != 0:
          addr += op.value.disp
        if addr >= 0x80000000 and addr < 0x80000000 +  0x10000 * 8:
          flag_pass = False       #如果是我们自己的栈内存操作就no pass

此混淆代码中真实块中的状态变量条件控制指令如下,。状态变量为R0,我们通过unicron模拟执行的时候主动控制状态变量值的修改,进而寻找不同路径下对应的真实块。

通过判断当前指令是否为cmp,然后判断紧接着的指令是否为movwne和movtne。branch_control = 0 时执行第一条路径,否则走第二条路径。


#cpm指令
        if ins.mnemonic == 'cmp':
            #人工更改流程的走向#ollvm branch
            #解析movwne
            for ins1 in md.disasm(bin1[address+size:address+size+4],address+size):            
                if ins1.mnemonic != 'movwne':
                    return
                else:
                    regs = [reg_ctou(x) for x in ins1.op_str.split(', ')]                     #获取movne操作的寄存器
                    for op1 in ins1.operands:
                        if op1.type == ARM_OP_IMM:                 #获取立即数(操作数)
                            v1 = op1.value.imm
                            print("v1:%x" % v1)
            #解析movtne
            for ins1 in md.disasm(bin1[address+size+4:address+size+4+4],address+size+4):
                if ins1.mnemonic != 'movtne':
                    return
                else:
                    regs = [reg_ctou(x) for x in ins1.op_str.split(', ')]                     #获取movne操作的寄存器
                    for op2 in ins1.operands:
                        if op2.type == ARM_OP_IMM:                 #获取立即数(操作数)
                            v1 = (op2.value.imm << 16) + v1
                            print("v1:%x" % v1)
            #第一条路径
            if branch_control == 0:              
                print("first")
            #第二条路径
            else:
                uc.reg_write(regs[0],v1)                               #修改寄存器的值,人为控制状态变量的值
            uc.reg_write(UC_ARM_REG_PC, address + size + size + size)  #掠过三条指令
                                                                       #cmp
                                                                       #movwne
                                                                       #movtne

patch程序重建控制流

for k, v in flow.items():
    node = None
    if(flow[k] == [None]): continue

    for i in list_blocks:
        if list_blocks[i]['saddress'] == k:         
            node = list_blocks[i]
            #分割代码块中的每一条指令
            insns = node['ins'].split('\n')         
            
            if len(flow[k]) == 2:                   #如果此代码块有分支

                if insns[-5].find('cmp') != -1:
                    branch1 = flow[k][0]        #第一个路径(==跳转
                    branch2 = flow[k][1]        #第二个路径(!=跳转
                    print("ins: %s" % node['ins'])

                    if insns[-4].find('ne') != -1:    
                        #patch地址
                        patch_offset = int(insns[-4][:6], 16)   
                        bytes(_ks_assemble(("bne #0x%x" % branch),patch_offset))
                        bin1 = bin1[:patch_offset] + bytes(_ks_assemble(("bne #0x%x" % branch2),patch_offset)) + bytes(_ks_assemble(("b #0x%x" % branch1),patch_offset+ 4)) + bin1[patch_offset+8:] 
                        
                       
            if len(flow[k]) == 1:                   #如果代码无分支
                branch = flow[k][0]
                patch_offset = int(insns[-2][:6], 16)
                print ("patch_offset: %x" % patch_offset)  
                bin1 = bin1[:patch_offset] + bytes(_ks_assemble(("b #0x%x" % branch),patch_offset)) + bin1[patch_offset+4:]

修复后的控制流程图

参考链接:https://bbs.pediy.com/thread-252321.htm

标签:mnemonic,混淆,value,patch,offset,ollvm,ins,unicron,op
来源: https://www.cnblogs.com/revercc/p/16339476.html