ida 插件安装_使用Qiling IDA插件解密Mirai病毒数据

介绍

Qiling Framework 基于Unicorn,能够在一个平台上模拟多个OS和架构的二进制文件,包括Linux、MacOS、Windows、FreeBSD、DOS、UEFI和MBR。它支持x86(16、32和64位)、ARM、ARM64和MIPS。因此,我们几乎不需要担心因为环境搭建困难及手头设备不足导致无法进行分析工作,尤其像基于ARM或MIPS的IoT固件,想要进行逆向分析和漏洞挖掘尤其不易。

在澪同学的文章用麒麟框架深入分析实模式二进制文件中提到了Qiling能够进行gdb远程调试,这实际上是我为Qiling所贡献的第一个功能。将调试能力赋予Qiling,我们就能够在完全可控的环境中对二进制文件进行动态分析,不必担心病毒样本对主机造成影响,能够绕过检测,甚至能够只执行其中的一部分。

但这样的调试还不够优雅,在这里我想要为大家介绍的是Qiling调试功能的全新模块:Qiling IDA插件。与当今最强大的反编译器结合,我们可以做很多很棒的事。不需要IDA remote server和虚拟机就能够轻松地在IDA上进行动态调试和反编译,实时查看寄存器,堆栈和内存,绘制代码的执行路径等。此外,结合自定义脚本,我们能够使用Qiling提供的全部功能。我们还有更高级的功能:自动分析并反ollvm控制流平坦化,这将在今后进行单独介绍。

文章同步发表于我的Blog

K's House​kabeor.cn
2c142514d0292cd6d5a4d4dd32239208.png

安装

安装Qiling

Qiling的安装方式在这里,由于Qiling更新速度较快,想要获取最新版本请

git clone https://github.com/qilingframework/qiling/tree/dev

注意 请将Qiling安装在IDA所使用的Python3环境内。

安装插件

插件的安装方式有两种

  1. 作为一个IDA插件

只需要建立一个Qiling插件与IDA plugin目录的符号链接。

# Linux    ln -s /absolute/path/to/qiling/extensions/idaplugin/qilingida.py /path/to/your/ida/plugins/
# Macos    ln -s /absolute/path/to/qiling/extensions/idaplugin/qilingida.py /Applications//ida.app/Contents/MacOS/plugins/
# Windows    mklink C:absolutepathtoIDApluginsqilingida.py D:absolutepathtoqilingextensionsidapluginqilingida.py

IDA在启动时会自动加载Qiling插件。

  1. 作为一个脚本文件

运行IDA,点击File/Script file...,定位插件所在位置(也可以在此处下载最新版本),选择qilingida.py即可。

加载脚本后可以在Edit->Plugins->Qiling Emulator和右键菜单找到按钮。

插件的具体用法请访问

IDAPro Plugin - Qiling Framework Documentation​docs.qiling.io
51b8aaf1091397f5a92fa50142fe8bad.png

支持状态

插件支持IDA7.x && Python3.6+, 当前建议使用环境macOS及Linux

插件支持环境如下:

f23528e6a361ff4d2b4635f2f4935a02.png

使用Qiling IDA插件解密Mirai

配置好插件后我们就可以开始分析本次的示例Mirai了。

视频展示

为此我录制了视频来展示整体流程:

bilibili版本​www.bilibili.com
f0cae0bc783dc2f4359f35c86daf6fe0.png
Qiling's IDAPro Plugin: Instrument and Decrypt Mirai's Secret​www.youtube.com

样本分析

本次使用的样本是ARM架构的IoT僵尸网络病毒Mirai。

通过分析我们可以在0xFC50处发现一些被加密的字符串,程序会把它们添加到一个table,而这个table事实上是病毒用来爆破ssh的字典。

143e63d996aa796d9835f3b28cd0f5cd.png

定位到0x12A20,我们会发现该函数正是用来加解密table的。

2cfbb7afcdc66a36ec058b863280a9b2.png

使用F5进行反编译,可以看到加解密算法为异或key,因此我们只需要将加密数据输入该函数即可得到解密后的明文。

348b8fca3113962f3b57bdf03374fd9a.png

分析解密循环的反汇编,我们可以得知,LR寄存器存放了待解密buffer的内存地址,因此我们只需要将加密数据写入该内存区域然后运行到循环结束就可以得到结果。

2a7fa37e986469cdc22c29843b3340a1.png

由于读写寄存器及内存的操作需要循环多次,我们手工操作会非常繁琐,因此Qiling IDA插件的自定义脚本就派上了用场。

编写插件自定义脚本

自定义脚本的基本结构如下:

class QILING_IDA():
    def __init__(self):
        pass

    def custom_prepare(self, ql):   # Qiling初始化时调用
        pass

    def custom_continue(self, ql:Qiling):  # 点击“Continue”按钮时调用
        hook = []
        return hook

    def custom_step(self, ql:Qiling):  # 点击“Step”按钮时调用
        hook = []
        return hook

对于本样例,脚本如下,脚本分析在注释中说明

import struct
from qiling import *


def show_encode_string_memory_address(ql:Qiling):
    # 显示待解密buffer所在地址
    memory_address_bytes = bytes(ql.mem.read(ql.reg.read('LR'), 0x4))
    memory_address = hex(struct.unpack('<I', memory_address_bytes)[0])
    print('encode_string_memory_address at: '+memory_address)

def hook_LR(ql:Qiling, encoded_message_ascii):
    encode_string_length=len(encoded_message_ascii)
    encode_bytes_length=encode_string_length.to_bytes(length=1, byteorder='big')

    # 在内存中覆写待解密buffer的长度
    ql.mem.write(ql.reg.read('LR')+0x4, encode_bytes_length)

    memory_address_bytes = bytes(ql.mem.read(ql.reg.read('LR'), 0x4))
    memory_address = hex(struct.unpack('<I', memory_address_bytes)[0])
    memory_address = int(memory_address, 16)

    # 将待解密buffer中的值替换为我们需要解密的数据
    new_encode=b''
    for x in encoded_message_ascii:
        new_encode += x.to_bytes(length=1, byteorder='big')
    ql.mem.write(memory_address, new_encode)
    print('Encode: ', bytes(ql.mem.read(memory_address, len(encoded_message_ascii))))

def decode_show(ql, encoded_message_ascii):
    # 读取待解密buffer中的值
    encode_string_length=len(encoded_message_ascii)
    memory_address_bytes = bytes(ql.mem.read(ql.reg.read('LR'), 0x4))
    memory_address = hex(struct.unpack('<I', memory_address_bytes)[0])
    memory_address = int(memory_address, 16)
    print('Decode: ', bytes(ql.mem.read(memory_address, encode_string_length)).replace(b'T', b' '))

class QILING_IDA():
    def __init__(self):
        pass

    def custom_prepare(self, ql):
        ql.patch(0xF58C, b'x90x90x90x90x90')  # 将该地址的clock函数nop,否则无法继续模拟

        # 读取加密数据,转换格式
        encoded_message_bytes = bytes(ql.mem.read(0x1393C, 0x1395B-0x1393C))
        encoded_message_ascii = []
        for i in encoded_message_bytes:
            encoded_message_ascii.append(i)

        # 显示待解密buffer所在地址,便于在内存中查看结果
        ql.hook_address(show_encode_string_memory_address, 0x12A68)
        # 将加密数据写入LR指向的内存地址
        ql.hook_address(hook_LR, 0x12A70, user_data=encoded_message_ascii)

    def custom_continue(self, ql:Qiling):
        # 读取加密数据,转换格式
        encoded_message = bytes(ql.mem.read(0x1393C, 0x1395B-0x1393C))
        encoded_message_ascii = []
        for i in encoded_message:
            encoded_message_ascii.append(i)

        # 显示每循环一次后当前内存的解密状态
        decode_show_hook = ql.hook_address(decode_show, 0x12AC8, user_data=encoded_message_ascii)
        # 返回该hook的handle,插件将自动处理
        hook = [decode_show_hook]
        return hook

    def custom_step(self, ql:Qiling):
        hook = []
        return hook

初始化插件

  1. 右键-Qiling Emulator-Setup
  2. 设置rootfs(即环境根目录,Qiling会加载其中的lib,一般建议使用qiling/example/rootfs下对应环境的文件夹路径作为rootfs),本次分析样本还需要将ld-uClibc.so.0放置在rootfs/lib目录下。
  3. 设置自定义脚本文件的路径。

a8a39349dbcf3ebe89a97e5c97674c46.png

如果Qiling初始化和加载自定义脚本成功,则IDA输出窗口显示如下内容

bf727d869aa0fbe9af736e061f0e82f3.png

提示 在IDA 反汇编界面的基址位置会显示该文件所依赖的lib。

b3ab222c5e19ba577608d07645371003.png

运行插件进行解密

回到加解密函数,我们在解密循环前设置断点,用于访问内存地址,并在循环结束后设置断点,因为不必继续模拟。

830c77d1937160527edc50beae4a552c.png

点击右键-Qiling Emulator-Continue,Qiling将模拟到第一个断点

840b54e40afe11c6ffcf68c933c2913c.png

我们得到了待解密buffer起始地址为0x1E258

右键-Qiling Emulator-View Memory,输入地址及要查看的内存大小,即可查看实时内存

19dee90a634e62eb7a0415e7e254c716.png

同样的,在右键-Qiling Emulator中点击 View Register和View Stack可以查看寄存器及堆栈。整理窗口位置后如下

111366a89f5d7514ca70b66fedb96768.png

可以看出当前内存中已经写入了我们要解密的数据,在寄存器R2中则存储着将要异或的key。

再次点击Continue,进行解密

3a7dfeb0448903cde316a5c55df791e1.png

内存窗口中黄色字符串即为发生变化的内存,右侧输出窗口也实时显示了解密结果(动态效果参见视频)。

总结

本次我使用了一个较为简单的例子向大家演示了Qiling IDA插件的功能,但它的潜力远不仅此。未来我们也会继续添加更多可用功能,使其更加完整。

当然,在开发过程中也不可避免会出现bug,请到这里提 issue。

qilingframework/qiling​github.com
6df038772b8c40accbf9f9c6197b858b.png

同时我们也欢迎各位参与到开发中,提出pr。

如果有更多问题和想法,欢迎到 gitter 或QQ群: 486812017 进行交流。

觉得项目不错的话就请给个star吧~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值