0%

qira源码分析

0x00 前言

之前很早用过 qira 这款工具,由于种种原因(安装太难了、界面ui。。。),做一些二进制分析,还是gdb好用,在和18、19级培训完之后,老师说ppt应该多加图片,但是之后培训动态调试程序的时候,因为学弟、学妹们都比较萌新用gdb调试,肯定都会看蒙掉,需要一些可复现而且操作简单的gui工具,所以,我想到了qira,但是qira的界面太乱了,我准备优化一下,要改就要知道运行原理,所以,我准备先分析一下源代码(还好qira是开源的,真好

0x01 安装

尽人事,听天命,如果,不行就换个虚拟机吧。。。。

1
2
3
git clone https://github.com/geohot/qira.git
cd qira
sudo ./install.sh

还是安装最新版的吧

0x02 安装过程分析

首先分析一下 install.sh 脚本,执行了以下几个步骤:

  • 安装一些工具

    1
    sudo apt-get -y install git curl python python-virtualenv python-dev build-essential pkg-config zlib1g-dev libglib2.0-dev libpixman-1-dev
  • 构建qemu(见源码tracers/qemu_build.sh)

  • 构建python虚拟环境

    1
    2
    3
    4
    virtualenv venv
    source venv/bin/activate
    pip install --upgrade pip
    pip install --upgrade -r requirements.txt
  • 运行测试脚本

  • 建立软连接到 /usr/local/bin
    1
    sudo ln -sf $(pwd)/qira /usr/local/bin/qira

这样就完成了安装,那么我们运行qira程序的时候,其实,是运行qira源码文件夹下qira这个脚本

0x03 qira脚本分析

  • 先是做一些判断
  • 清除PYTHONPATH环境变量
  • 导入新的环境变量

    1
    source $DIR/venv/bin/activate
  • 运行/middleware/qira.py文件

    1
    exec /usr/bin/env python $DIR/middleware/qira.py $*

那么继续跟进

0x04 /middleware/qira.py脚本分析

  • 首先设置设置参数,解析参数(就不粘贴了)
  • 然后执行
    1
    program = qira_program.Program(args.binary, args.args, qemu_args)

0x00 调用了qira_program.py下Program类

看一下该类的 init 函数

  • 首先创建log文件

    1
    os.mkdir(qira_config.TRACE_FILE_BASE)

    再看一下,qira_config.py的trace_file_base全局变量

    1
    2
    3
    4
    if os.name == "nt":
    TRACE_FILE_BASE = "c:/qiratmp"
    else:
    TRACE_FILE_BASE = "/tmp/qira_logs/"

    判断一下系统类型,根据不同的系统类型,定制不同的路径

  • 之后调用 which 函数

    1
    self.program = which(prog)

    看一下 which 函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def which(prog):
    try:
    cmd = ["which", prog]
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    res = p.stdout.readlines()
    if len(res) == 0:
    raise Exception("binary not found")
    return os.path.realpath(res[0].strip())
    except:
    # fallback mode, look for the binary straight up
    if os.path.isfile(prog):
    return os.path.realpath(prog)
    else:
    raise Exception("binary not found")

    这个函数主要是用找程序的真实路径,现在 PATH 中找,然后判断 prog 是否为一个文件,如果是的话,就找到真实的路径

  • 之后,就是参数复制
  • 初始化static成员变量

    1
    self.static = static2.Static(self.program)

    再来看一下static2.py的static类的 init 函数

    1
    loader.load_binary(self)

    调用loader.py文件的 load_binary() 函数

    • 再看一下load_binary()函数,这个函数是获得文件的架构,程序入口地址,以及plt表之类的信息
  • 之后就判断 program 的位置是否和”/tmp/qira_binary”路径一致,如果不一致,建立新的软连接(我寻思着,如果是nt的话,这软连接恐怕建立不了吧,看不懂了,可能默认是linux吧

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if self.program != "/tmp/qira_binary":
    try:
    os.unlink("/tmp/qira_binary")
    except:
    pass
    try:
    os.symlink(os.path.realpath(self.program), "/tmp/qira_binary")
    except:
    pass
  • 最后读取文件的架构,设置qemu的路径

    0x05 调用qira_socat.start_bindserver()函数

    1
    qira_socat.start_bindserver(program, qira_config.SOCAT_PORT, -1, 1, True)

0x06 启动http服务

1
qira_webserver.run_server(args, program)