概述
qiling是一个开源的二进制分析框架
https://github.com/qilingframework/qiling
官方介绍:
https://docs.qiling.io/en/latest/
qiling是一个可模拟多种架构和平台的模拟执行框架,基于Unicorn
框架开发而来,可支持的平台有:Windows, MacOS, Linux, BSD, UEFI, DOS,可支持的架构有: X86,
X86_64, Arm, Arm64, MIPS,
8086,同时还提供跨架构的调试能力,多种层次的hook方法,qiling基于python开发,上手使用起来也非常方便,学习成本低
安装
pip3 install qiling
一行命令安装完就完事了,需要Python 3.5以上的版本
import一下没问题就说明安装成功了
qiling也支持docker化部署,直接pull一下就可以拿到一个独立的qiling 运行环境了
s
docker pull qilingframework/qiling:latest
运行的时候需要挂载必要的一些目录
bash hljs
docker run -dt --name qiling
-v /analysis/win/rootfs/x86_windows:/qiling/examples/rootfs/x86_windows
-v /analysis/win/rootfs/x8664_windows:/qiling/examples/rootfs/x8664_windows
qilingframework/qiling:latest
使用
qiling的git目录中有个example目录,里面包含了各种实例用法
这里直接上手跑个脚本看看效果吧,这个脚本是用来解一个windows的逆向的
python3 crackme_x86_windows.py
马上就遇到报错
这里报错卡了我很久,有点莫名其妙的, 我寻思你自己的例子还有语法错误?
后面找了很久才发现,我pip3安装的qiling是稳定版的,而git clone过来的是最新版源码,这里导致测试程序的写法会有稍许的不同产生语法报错
因此解决方案就同步安装一个最新版的qiling就好了
pip3 install --user https://github.com/qilingframework/qiling/archive/dev.zip
搞定了上面的坑,又来一个新的坑
这种情况实际上是因为Ubuntu1804上没有window的dll和注册表等组件,qiling运行exe是需要从windows系统上搞来这些东西才能模拟运行的,但是qiling因为版权问题,不能直接提供给我们,这里提供了一个脚本:在qiling/examples/scripts/dllscollector.bat,拿到自己的win上跑一下,就能得到全部所需要的依赖了
把文件夹下的内容拷贝到相应的目录下就能运行脚本
最后就跑出结果来了
这种应该是典型的CTF逆向题用法,以后搞逆向又多一个好用的工具了
来具体的看看这题是如何用qiling解出来的
以qiling/examples/rootfs/x86_linux/bin/crackme_linux为例子(题目可以去GitHub下)
简单看一下题目
就是通过scanf函数往bss段上输入一些内容,当这些内容满足check函数里面的约束时,就可以调用ok函数拿到flag
这里的约束也很简单,无非就是一些指定某某值要等于某某值,然后就是一些异或运算,手算也很快就能得到结果,这里用qiling来解题 ,具体操作可以看下面的脚本,并不难理解,我都写了注释说明
```python hljs
!/usr/bin/env python3
import sys
import os
from qiling import Qiling
def hook_each_ins(ql: Qiling, address: int, size: int, user_data):
md = ql.create_disassembler()
buf = ql.mem.read(address, size)
rip=ql.reg.arch_pc
if rip==0x080484F0:
这里是考虑到在没有完成循环爆破之前就已经遍历到flag的情况
那么就需要每次检测rip是否为0x080484F0
该地址是完成输入字符串比较后的最后一个地址
print("+++++++++++++++++ has get the flag!")
return 0
user_data[0] += 1
def run_one(pay):
每次都调用一次
用于爆破
ql = Qiling(["qiling/examples/rootfs/x86_linux/bin/crackme_linux"], "qiling/examples/rootfs/x86_linux",
console=False, # thwart qiling logger output
stdout=sys.stdout) # thwart program output
ins_count = [0]
这个变量是为了得到的执行的汇编指令数量
ql.mem.write(0x080<span class="knowKeyWords" data-id="8" ><span class="knowKeyWords" data-id="8" ><span class="knowKeyWords" data-id="8" >4A</span></span></span>020,pay)
往bss段上写入pay,模拟程序中通过scanf输入到bss的数据
# print (ql.mem.read(0x080<span class="knowKeyWords" data-id="8" ><span class="knowKeyWords" data-id="8" ><span class="knowKeyWords" data-id="8" >4A</span></span></span>020, 6))
ql.hook_code(hook_each_ins, ins_count)
hook_code是用每次执行一条汇编指令时都会触发的hook,可以用于实时监听汇编的执行情况
ql.run(begin = 0x08048451, end = 0x080484F6)
这里直接指定从check函数的开头执行,到check函数末尾
# print (ins_count)
del ql
return ins_count[0]
每次执行一次pay输入的爆破,都要返回总共执行的汇编指令数
def solve1():
pay=[0,0,0,0,0,0]
last_num=run_one(bytes(pay))
先预执行一次,此时last_num的初试值是8,也就是输入全都是错的情况下最少在check函数里面执行8条汇编指令
# input()
idx_list = (1, 4, 2,0, 3)
这里指定爆破flag的下标
这是因为爆破是基于上一次执行的指令数量来判断是否爆破到正确的值的
因此通过分析check函数的约束条件,这里选择非顺序的idx来逐一爆破单字节
for i in idx_list:
for x in '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ ':
pay[i]=ord(x)
print ("trying :",bytes(pay))
tmp=run_one(bytes(pay))
if tmp >last_num:
last_num=tmp
print("get {} char:{}".format(i,x))
break
print ("flag maybe:",end="")
for x in pay:
print(chr(x),end="")
print("")
if name == "main":
solve1()
```
这个脚本是我自己写的,官方提供的脚本有问题,无法执行成功会爆一个莫名其妙的错误,但核心的爆破思想是一样的
运行结果如下:
由此我们可以得到flag就是 L1NUX了
基于qiling的各种姿势
官方做了一个收集,里面各种使用了qiling框架的工具,姿势都会被收录其中,很多东西做的还是针不戳的
https://github.com/qilingframework/qiling/issues/134
有人基于此写了fuzz,如efi_fuzz,有的人写了使用qiling复现漏洞的过程,还有人用qiling模拟运行了路由器的固件,还有用于ctf逆向的各种骚操作
VulnHub:CROSSROADS:1 crossroads:1为3月份vulnhub和HackMyVM刚刚上架的一台靶机,模拟了一台带有漏洞的医疗网站web服务器,要攻破这台机器,我们的最终目标是拿下它的root权限,靶机涉及到的漏洞点有smb魔术脚本、本…
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论