qiling框架能够做到
麒麟框架不仅仅是一个仿真平台或逆向工程工具。它还将“二进制插桩”和“二进制仿真”结合一起。并解决了应用程序不能在隔离环境里运行并且高度依赖于操作系统的问题。由于大量的操作系统支持,麒麟框架为二进制分析提供了无限的可能性和潜力。使用麒麟框架,你可以:
- 跨平台:Windows、MacOS、Linux、BSD、UEFI、DOS
- 跨体系结构:X86、X86 64位、ARM、ARM 64位、MIPS、8086
- 多种文件格式:PE、MachO、ELF、COM
- 在隔离环境中模拟沙盒机器代码
- 支持跨体系结构和平台调试功能
- 提供高级API来设置和配置沙盒
- 细化检测:允许不同级别的钩子(指令/基本块/内存访问/异常/系统调用/IO等)
- 允许动态热补丁运行代码,包括加载的库
麒麟框架能够模拟:
- Windows x86 32/64位
- Linux x86 32/64位,ARM,AARCH64,MIPS
- MacOS x86 32/64位
- FreeBSD x86 32/64位
- UEFI
- DOS
- MBR
麒麟框架能够在Linux/MacOS/FreeBSD/Windows(WSL2)等操作系统上运行,且不受CPU架构所限制
感觉是个挺有用挺好玩的框架,上手学一下
0x1.运行不同架构的程序
来个最简单的helloworld程序,mips小端序架构
#include <stdio.h>
int main(int argc,char *argv[])
{
printf("Hello world");
return 0;
}
用qemu运行使用以下命令
qemu-mipsel -L /usr/mipsel-linux-gnu/ ./hello
用qiling运行使用如下脚本
#!/usr/bin/python3
from qiling import *
def mysandbox(path,rootfs):
ql=Qiling(path,rootfs,output='default')
ql.run()
if __name__=="__main__":
mysandbox(['hello'],'/usr/mipsel-linux-gnu')
我们先运行一下,看看效果
root@IOT:~# /usr/bin/python3 "/root/demo.py"
brk(0x0)
mmap2(0x0, 0x2000, 0x3, 0x802, -1, 0) = 0x774bf000
uname(0x7ff3c728) = 0
access(/etc/ld.so.nohwcap, 0x0) = -1
access(/etc/ld.so.preload, 0x4) = -1
openat(-100, /etc/ld.so.cache, 0x0, 0o0) = -1
openat(-100, /lib/mipsel-linux-gnu/tls/i686/libc.so.6, 0x0, 0o0) = -1
stat64(/lib/mipsel-linux-gnu/tls/i686, 0x7ff3c360) = -1
openat(-100, /lib/mipsel-linux-gnu/tls/libc.so.6, 0x0, 0o0) = -1
stat64(/lib/mipsel-linux-gnu/tls, 0x7ff3c360) = -1
openat(-100, /lib/mipsel-linux-gnu/i686/libc.so.6, 0x0, 0o0) = -1
stat64(/lib/mipsel-linux-gnu/i686, 0x7ff3c360) = -1
openat(-100, /lib/mipsel-linux-gnu/libc.so.6, 0x0, 0o0) = -1
stat64(/lib/mipsel-linux-gnu, 0x7ff3c360) = -1
openat(-100, /usr/lib/mipsel-linux-gnu/tls/i686/libc.so.6, 0x0, 0o0) = -1
stat64(/usr/lib/mipsel-linux-gnu/tls/i686, 0x7ff3c360) = -1
openat(-100, /usr/lib/mipsel-linux-gnu/tls/libc.so.6, 0x0, 0o0) = -1
stat64(/usr/lib/mipsel-linux-gnu/tls, 0x7ff3c360) = -1
openat(-100, /usr/lib/mipsel-linux-gnu/i686/libc.so.6, 0x0, 0o0) = -1
stat64(/usr/lib/mipsel-linux-gnu/i686, 0x7ff3c360) = -1
openat(-100, /usr/lib/mipsel-linux-gnu/libc.so.6, 0x0, 0o0) = -1
stat64(/usr/lib/mipsel-linux-gnu, 0x7ff3c360) = -1
openat(-100, /lib/tls/i686/libc.so.6, 0x0, 0o0) = -1
stat64(/lib/tls/i686, 0x7ff3c360) = -1
openat(-100, /lib/tls/libc.so.6, 0x0, 0o0) = -1
stat64(/lib/tls, 0x7ff3c360) = -1
openat(-100, /lib/i686/libc.so.6, 0x0, 0o0) = -1
stat64(/lib/i686, 0x7ff3c360) = -1
openat(-100, /lib/libc.so.6, 0x0, 0o0) = 3
read(3, 0x7ff3c4ac, 0x200) = 512
prctl() = 0
_llseek(3, 0x0, 0x208, 0x7ff3c238) = 0
_llseek(3, 0x0, 0x208, 0x7ff3c238) = -1
read(3, 0x7ff3c278, 0x24) = 36
_llseek(3, 0x0, 0x33c, 0x7ff3c210) = 0
_llseek(3, 0x0, 0x33c, 0x7ff3c210) = -1
read(3, 0x7ff3c250, 0x20) = 32
fstat64(3, 0x7ff3c368) = 0
mmap2(0x0, 0x191030, 0x5, 0x2002, 3, 0) = 0x774c1000
mprotect(0x7763a000, 0xf000, 0x0) = 0
mmap2(0x77649000, 0x7000, 0x3, 0x2012, 3, 1540096) = 0x77649000
mmap2(0x77650000, 0x2030, 0x3, 0x812, -1, 0) = 0x77650000
close(3) = 0
set_thread_area(0x774c7230)
mprotect(0x77649000, 0x4000, 0x1) = 0
mprotect(0x410000, 0x1000, 0x1) = 0
mprotect(0x47ed000, 0x1000, 0x1) = 0
fstat64(1, 0x7ff3c7b0) = 0
brk(0x0)
brk(0x435000)
write(1,414150,11) = 0
Hello worldexit_group(0)
非常详细的系统调用
接下来我们跟进到Qiling
这个类里面
class Qiling(QlCoreStructs, QlCoreHooks, QlCoreUtils):
def __init__(
self,
filename=None,
rootfs=None,
env=None,
shellcoder=None,
ostype=None,
archtype=None,
bigendian=False,
output=None,
verbose=1,
profile=None,
console=True,
log_dir=None,
log_split=None,
append=None,
libcache = False,
stdin=0,
stdout=0,
stderr=0,
):
可选的参数有很多,不过大部分情况下我们需要操作的只有filename
、rootfs
、output
以及在模拟路由器中我们需要设置的env
在这个脚本里我们的文件是当前目录下的hello,库文件目录为/usr/mipsel-linux-gnu
接下来我们开启qiling的远程调试,使用gdb调试这个小程序
要开启调试功能,只需要在ql.run()
前加一个ql.debugger=True
,这样默认绑定9999端口,或者使用ql.debugger=‘:9999’
,这样绑定会0.0.0.0:9999
这里贴上官方的文档
#!/usr/bin/python3
from qiling import *
def mysandbox(path,rootfs):
ql=Qiling(path,rootfs,output='default')
ql.debugger = True
# You can also customize address & port or type of debugging server
# ql.debugger= ":9999" # GDB server listens to 0.0.0.0:9999
# ql.debugger = "127.0.0.1:9999" # GDB server listens to 127.0.0.1:9999
# ql.debugger = "gdb:127.0.0.1:9999" # GDB server listens to 127.0.0.1:9999
# ql.debugger = "idapro:127.0.0.1:9999" # IDA pro server listens to 127.0.0.1:9999
ql.run()
if __name__=="__main__":
mysandbox(['hello'],'/usr/mipsel-linux-gnu')
不过个人感觉qiling的调试很慢,ni一下要等好几秒,也可能是我的操作不当,所以我一般调试还是用qemu