首页
社区
课程
招聘
[原创]利用Triton 污点分析识别垃圾指令
发表于: 2023-6-19 23:46 25298

[原创]利用Triton 污点分析识别垃圾指令

2023-6-19 23:46
25298

此样本主要使用间接跳转
图片描述
可以利用unicorn模拟执行来确定x13的值,然后修改成直接跳转或者条件跳转,
本文的重点不在这里,不在多叙。本文的重点是如何识别这些垃圾指令,
因为光恢复它的跳转,ida还是不能反编译,它指令膨胀的非常严重,将max_func_size设置成4096也不行,所以对于BR x13这种指令,需要识别x13是由哪些指令生成的,将这些指令全部nop掉,才能减少方法的size。

如上图,代码中的所有跳转全部为BR指令,包括条件跳转和直接跳转,其中还包括不透明谓词

一种是自下而上进行活跃变量分析,将BR x8 patch成b 0x1000后,将x8认为是不活跃变量,然后就可以进行活跃变量分析,然后根据ud链,找到定义x8的地方,将这个定义也删除掉。这个定义语句也会使用到变量,此时它使用到的变量也属于不活跃变量,所以可以继续向上分析,这种方式只是我理论想出来的,并没有实践

第二种是我用到的方法,污点分析,将mov x8,0x234234,这种指令的x8定义为污染源,然后向下分析,将污染过得指令全部nop掉。我觉得这种方式处理起来比较简单,对于br,bl这种跳转语句不执行,还有return块也不执行,这样就可以把整个方法当做一个巨大的代码块,由上而下的执行,将特征指令会赋值的寄存器设置成污染源,这样也可以处理这种特殊情况,在方法序言处将一个常数写入栈,在后面的代码块中从栈里面读取这个值,再使用计算,这个可以避免自己再做上下文的分析,污点分析能直接定位到。

github地址https://github.com/JonathanSalwan/Triton.git
这个工具很强大,有污点分析和符号执行两个功能,我这次只使用到了它的污点分析功能
安装 pip install tritondse

还是利用上面的那段代码,执行完1E7D00后,将w8寄存器设置为污染源

其中的大部分代码都是模板代码,主要有用的是这两句代码,将w8设置为污染源

看下效果
图片描述
在1e7d68处使用到了w8,并且将cpsr污染了,所以下一句cset指令也是污染的,
继续向下分析,可以看到间接引用w8寄存器的指令都识别出来了。
注意1e7d94处,虽然x13寄存器是被污染的,但是这条指令并没有被污染。
Triton将这种问题留给我们自己来处理,就是如果寄存器是被污染的,那么需要我们根据实际情况,来决定是否将寄存器指向的内存污染掉,上代码

这个脚本多了这几句代码

作用也很简单,执行完这句代码后,将x13指向的内存也污染掉
看下效果
图片描述
可以看到又多识别出来一些垃圾指令
那我们继续分别将代码块开始的几个寄存器,w8,w9,w10,w11,w12都给污染掉,上代码

看下效果
图片描述
可以看到又多识别了一些垃圾指令。
还有一种特殊的栈变量,比如1E7D34处的指令,这种如何识别呢,其实在最开始已经谈到过这种情况的处理方式,这种栈变量的赋值方式一般是在方法序言处
图片描述
在这里给x4赋值
图片描述
在这里写到栈上
所以我们可以在0x1E4DB8处,将x4寄存器也给污染掉,上代码

这个脚本相比之前多了这几句代码,目的是跳过所有的跳转指令,将整个方法当成一个方法块来处理,这样会简单很多,此处我没有处理ret代码块,实际使用中,还需要跳过ret代码块,不然运行过程中pc会跑飞

在这里将x4寄存器和它指向的内存污染掉

看下效果
图片描述
可以看到将对栈变量的处理也识别到了。
其实讲到这里已经差不多了,剩下的就是全局扫描识别mov adrp 这种指令,当然需要过滤掉其中的正常指令,然后适配上面的代码,就可以将大部分的垃圾指令识别到,然后nop掉。对于强迫症患者来说,也是一个福音。
代码就不上传了,文章中的代码运行应该都没问题

Triton.setArchitecture(ARCH.AARCH64)设置架构
Triton.setConcreteMemoryAreaValue(0, bin1) 写入具体内存
Triton.taintRegister()  设置寄存器为污染源
Triton.taintMemory()设置内存地址为污染源
Triton.getConcreteRegisterValue()获取寄存器的值
Triton.untaintRegister()对寄存器进行去污染处理
Triton.untaintMemory()对内存进行去污染处理
Instruction.setOpcode()设置字节码
Instruction.setAddress()设置指令地址
Triton.processing() 执行一条语句
Triton.setArchitecture(ARCH.AARCH64)设置架构
Triton.setConcreteMemoryAreaValue(0, bin1) 写入具体内存
Triton.taintRegister()  设置寄存器为污染源
Triton.taintMemory()设置内存地址为污染源
Triton.getConcreteRegisterValue()获取寄存器的值
Triton.untaintRegister()对寄存器进行去污染处理
Triton.untaintMemory()对内存进行去污染处理
Instruction.setOpcode()设置字节码
Instruction.setAddress()设置指令地址
Triton.processing() 执行一条语句
from triton import *
import idc
import ida_bytes
from capstone import *
from capstone.arm64 import *
 
cs = Cs(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN)
cs.detail = True
 
def get_insn2(opcode0, addr):
    insns = cs.disasm(opcode0, addr)
    for i in insns:
        return i
 
def taint_analysis2(start, end):
    Triton = TritonContext()
    with open('C:\\Users\\lj\\Desktop\\junks\\test1\\CoreBook2', 'rb') as f:
        bin1 = f.read()
    Triton.setArchitecture(ARCH.AARCH64)
    Triton.setConcreteMemoryAreaValue(0, bin1)
    sp = 0x100000000
    Triton.setConcreteRegisterValue(Triton.registers.x29, sp)
    Triton.setConcreteRegisterValue(Triton.registers.sp, sp)
    pc = start
    nop_addrs = []
    while pc:
        inst = Instruction()
        opcode0 = ida_bytes.get_bytes(pc, 4)
        cs_insn: CsInsn = get_insn2(opcode0, pc)
 
 
        inst.setOpcode(opcode0)
        inst.setAddress(pc)
        Triton.processing(inst)
        print(str(inst))
        if pc == 0x1E7D00:
            Triton.taintRegister(Triton.registers.w8)
 
        if inst.isTainted():
            idc.set_color(pc, idc.CIC_ITEM, 0xffe699)
            nop_addrs.append(pc)
 
        if pc >= end:
            break
        pc = pc + 4
if __name__ == '__main__':
    taint_analysis2(0x1E7D00, 0x1E7D98)
from triton import *
import idc
import ida_bytes
from capstone import *
from capstone.arm64 import *
 
cs = Cs(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN)
cs.detail = True
 
def get_insn2(opcode0, addr):
    insns = cs.disasm(opcode0, addr)
    for i in insns:
        return i
 
def taint_analysis2(start, end):
    Triton = TritonContext()
    with open('C:\\Users\\lj\\Desktop\\junks\\test1\\CoreBook2', 'rb') as f:
        bin1 = f.read()
    Triton.setArchitecture(ARCH.AARCH64)
    Triton.setConcreteMemoryAreaValue(0, bin1)
    sp = 0x100000000
    Triton.setConcreteRegisterValue(Triton.registers.x29, sp)
    Triton.setConcreteRegisterValue(Triton.registers.sp, sp)
    pc = start
    nop_addrs = []
    while pc:
        inst = Instruction()
        opcode0 = ida_bytes.get_bytes(pc, 4)
        cs_insn: CsInsn = get_insn2(opcode0, pc)
 
 
        inst.setOpcode(opcode0)
        inst.setAddress(pc)
        Triton.processing(inst)
        print(str(inst))
        if pc == 0x1E7D00:
            Triton.taintRegister(Triton.registers.w8)
 
        if inst.isTainted():
            idc.set_color(pc, idc.CIC_ITEM, 0xffe699)
            nop_addrs.append(pc)
 
        if pc >= end:
            break
        pc = pc + 4
if __name__ == '__main__':
    taint_analysis2(0x1E7D00, 0x1E7D98)
if pc == 0x1E7D00:
    Triton.taintRegister(Triton.registers.w8)
if pc == 0x1E7D00:
    Triton.taintRegister(Triton.registers.w8)
from triton import *
import idc
import ida_bytes
from capstone import *
from capstone.arm64 import *
 
cs = Cs(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN)
cs.detail = True
 
def get_insn2(opcode0, addr):
    insns = cs.disasm(opcode0, addr)
    for i in insns:
        return i
 
def taint_analysis2(start, end):
    Triton = TritonContext()
    with open('C:\\Users\\lj\\Desktop\\junks\\test1\\CoreBook2', 'rb') as f:
        bin1 = f.read()
    Triton.setArchitecture(ARCH.AARCH64)
    Triton.setConcreteMemoryAreaValue(0, bin1)
    sp = 0x100000000
    Triton.setConcreteRegisterValue(Triton.registers.x29, sp)
    Triton.setConcreteRegisterValue(Triton.registers.sp, sp)
    pc = start
    nop_addrs = []
    while pc:
        inst = Instruction()
        opcode0 = ida_bytes.get_bytes(pc, 4)
 
 
        inst.setOpcode(opcode0)
        inst.setAddress(pc)
        Triton.processing(inst)
        print(str(inst))
        if pc == 0x1E7D00:
            Triton.taintRegister(Triton.registers.w8)
        if pc == 0x1e7d90:
            Triton.taintMemory(Triton.getConcreteRegisterValue(Triton.registers.x13))
 
        if inst.isTainted():
            idc.set_color(pc, idc.CIC_ITEM, 0xffe699)
            nop_addrs.append(pc)
 
        if pc >= end:
            break
        pc = pc + 4
if __name__ == '__main__':
    taint_analysis2(0x1E7D00, 0x1E7D9c)
from triton import *
import idc
import ida_bytes
from capstone import *
from capstone.arm64 import *
 
cs = Cs(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN)
cs.detail = True
 
def get_insn2(opcode0, addr):
    insns = cs.disasm(opcode0, addr)
    for i in insns:
        return i
 
def taint_analysis2(start, end):
    Triton = TritonContext()
    with open('C:\\Users\\lj\\Desktop\\junks\\test1\\CoreBook2', 'rb') as f:
        bin1 = f.read()
    Triton.setArchitecture(ARCH.AARCH64)
    Triton.setConcreteMemoryAreaValue(0, bin1)
    sp = 0x100000000
    Triton.setConcreteRegisterValue(Triton.registers.x29, sp)
    Triton.setConcreteRegisterValue(Triton.registers.sp, sp)
    pc = start
    nop_addrs = []
    while pc:
        inst = Instruction()
        opcode0 = ida_bytes.get_bytes(pc, 4)
 
 
        inst.setOpcode(opcode0)
        inst.setAddress(pc)
        Triton.processing(inst)
        print(str(inst))
        if pc == 0x1E7D00:
            Triton.taintRegister(Triton.registers.w8)
        if pc == 0x1e7d90:
            Triton.taintMemory(Triton.getConcreteRegisterValue(Triton.registers.x13))
 
        if inst.isTainted():
            idc.set_color(pc, idc.CIC_ITEM, 0xffe699)
            nop_addrs.append(pc)
 
        if pc >= end:
            break
        pc = pc + 4
if __name__ == '__main__':
    taint_analysis2(0x1E7D00, 0x1E7D9c)
if pc == 0x1e7d90:
    Triton.taintMemory(Triton.getConcreteRegisterValue(Triton.registers.x13))
if pc == 0x1e7d90:
    Triton.taintMemory(Triton.getConcreteRegisterValue(Triton.registers.x13))
from triton import *
import idc
import ida_bytes
from capstone import *
from capstone.arm64 import *
 
cs = Cs(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN)
cs.detail = True
 
def get_insn2(opcode0, addr):
    insns = cs.disasm(opcode0, addr)
    for i in insns:
        return i
 
def taint_analysis2(start, end):
    Triton = TritonContext()
    with open('C:\\Users\\lj\\Desktop\\junks\\test1\\CoreBook2', 'rb') as f:
        bin1 = f.read()
    Triton.setArchitecture(ARCH.AARCH64)
    Triton.setConcreteMemoryAreaValue(0, bin1)
    sp = 0x100000000
    Triton.setConcreteRegisterValue(Triton.registers.x29, sp)
    Triton.setConcreteRegisterValue(Triton.registers.sp, sp)
    pc = start
    nop_addrs = []
    while pc:
        inst = Instruction()
        opcode0 = ida_bytes.get_bytes(pc, 4)
        cs_insn: CsInsn = get_insn2(opcode0, pc)
         
 
        inst.setOpcode(opcode0)
        inst.setAddress(pc)
        Triton.processing(inst)
        print(str(inst))
        if pc == 0x1E7D00:
            Triton.taintRegister(Triton.registers.w8)
        if pc == 0x1E7D08:
            Triton.taintRegister(Triton.registers.w9)
        if pc == 0x1E7D10:
            Triton.taintRegister(Triton.registers.w10)
        if pc == 0x1E7D18:
            Triton.taintRegister(Triton.registers.w11)
        if pc == 0x1E7D20:
            Triton.taintRegister(Triton.registers.w12)
 
 
        if pc == 0x1e7d90:
            Triton.taintMemory(Triton.getConcreteRegisterValue(Triton.registers.x13))
 
        if inst.isTainted():
            idc.set_color(pc, idc.CIC_ITEM, 0xffe699)
            nop_addrs.append(pc)
 
        if pc >= end:
            break
        pc = pc + 4
if __name__ == '__main__':
    taint_analysis2(0x1E7D00, 0x1E7D98)
from triton import *
import idc
import ida_bytes
from capstone import *
from capstone.arm64 import *

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-6-20 22:43 被普通人张三编辑 ,原因:
上传的附件:
收藏
免费 11
支持
分享
最新回复 (12)
雪    币: 129
活跃值: (4485)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
666,躺下刷篇好文再睡
2023-6-20 00:04
0
雪    币: 4870
活跃值: (18870)
能力值: ( LV13,RANK:317 )
在线值:
发帖
回帖
粉丝
3
感谢分享~
2023-6-20 08:42
0
雪    币: 1229
活跃值: (1760)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
爽文,让我彻夜不眠,瞬间蹦起来要完美修正我的问题
2023-6-20 11:03
0
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
感谢分享
2023-6-20 13:54
1
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2023-9-17 11:58
0
雪    币: 7
活跃值: (389)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
很棒,感谢分享
2024-2-22 11:01
0
雪    币: 1802
活跃值: (4000)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢分享
2024-2-22 12:14
0
雪    币: 249
活跃值: (508)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
另一种方式:frida stalker采集区间指令(0x1E4D28, 0x1E7D98),然后通过IDC来修复
2024-2-26 09:27
0
雪    币: 14
活跃值: (285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
你这样反混淆 人都累死了
2024-3-11 10:36
0
雪    币: 20
活跃值: (534)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
chenxia0 另一种方式:frida stalker采集区间指令(0x1E4D28, 0x1E7D98),然后通过IDC来修复
这个方式主要是识别垃圾指令,因为垃圾指令太多,导致方法size非常大,所以即便是恢复了间接跳转,ida f5也会失败
2024-3-13 11:04
0
雪    币: 20
活跃值: (534)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
有啥更好的方式识别垃圾指令,还请赐教,开始写规则去识别垃圾指令,但是发现根本写不完,后来才想到污点分析这种方式,因为污点分析是别人写好的,框架很好用,所以也不累
2024-3-13 11:05
0
雪    币: 14
活跃值: (285)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
普通人张三 有啥更好的方式识别垃圾指令,还请赐教,开始写规则去识别垃圾指令,但是发现根本写不完,后来才想到污点分析这种方式,因为污点分析是别人写好的,框架很好用,所以也不累[em_13]
你感觉不累可能还是因为你要分析的文件混淆函数还不够多不够大 要达成完成反混淆去除block跳转相关垃圾代码 必须要做到stack analyze, instrcution pathing,stack reg protected, branch nop 还有一些细节的处理 你去找几个文件超过100M 并且 单个函数超过1M的文件多分析一下就明白了
2024-4-3 13:24
0
游客
登录 | 注册 方可回帖
返回
//