• 网络靶场实战-物联网安全qiling框架初探


    背景

    Qiling Framework是一个基于Python的二进制分析、模拟和虚拟化框架。它可以用于动态分析和仿真运行不同操作系统、处理器和体系结构下的二进制文件。除此之外,Qiling框架还提供了易于使用的API和插件系统,方便使用者进行二进制分析和漏洞挖掘等工作。其创始人是一名IoT Hacker,创建qiling的初衷便是解决在研究IoT时遇到的种种问题,这也是为什么上一小节说qiling框架比unicorn框架更加适合IoT研究初学者。

    qiling使用基础

    qiling框架和AFLplusplus安装

    1. sudo apt-get update
    2. sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev
    3. sudo apt-get install -y lld-14 llvm-14 llvm-14-dev clang-14
    4. sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev
    5. pip3 install qiling
    6. git clone https://github.com/AFLplusplus/AFLplusplus
    7. make -C AFLplusplus
    8. cd AFLplusplus/unicorn_mode
    9. ./build_unicorn_support.sh

    程序仿真

        首先我们需要克隆qiling仓库,仓库中一些实例脚本可供我们学习。

    git clone --recurse-submodules https://github.com/qilingframework/qiling.git

        一个简单的示例:

    1. #include 
    2. #include 
    3. # gcc test.c -o test
    4. # 注意:编译程序的主机libc需要与rootfs glibc版本(libc-2.7.so)相对应,其他架构同理
    5. int main(){
    6.    printf("hello world!");
    7.    return 0;
    8. }

        使用qiling编写一个简单的仿真脚本。

    1. from qiling import *
    2. from qiling.const import QL_VERBOSE
    3. # 导入qiling模块和qiling.const模块中的QL_VERBOSE常量
    4. if __name__ == "__main__":
    5.    #创建Qiling对象,实例中三个参数分别为:path(仿真程序路径)、rootfs(仿真程序文件系统目录)和verbose(输出信息参数),除此外还可以设置env和log_plain参数。
    6.   ql = Qiling(["./x8664_linux_symlink/test"], "./x8664_linux_symlink",verbose=QL_VERBOSE.DEBUG)
    7.    #运行Qiling对象的run()方法,开始执行仿真程序
    8.   ql.run()

        这里的verbose(输出信息参数)有如下级别及其作用:

    图片

    图片

    VFS劫持

        x86_fetch_urandom程序的作用为打开/dev/urandom文件,生成随机数。当qiling仿真x86_fetch_urandom程序时,环境需要用到仿真文件系统,我们就需要用到VFS劫持,这样就可以模拟修改文件系统。下面的代码中为仿真虚拟路径 "/dev/urandom" 会被映射到宿主系统上的现有"/dev/urandom"文件。当模拟程序将访问 /dev/random 时,将改为访问映射文件。

    1. from qiling import Qiling
    2. if __name__ == "__main__":
    3.   ql = Qiling(["x86_linux/bin/x86_fetch_urandom"], "x86_linux")
    4.   ql.add_fs_mapper(r'/dev/urandom'r'/dev/urandom')
    5.   ql.verbose=0
    6.   ql.run()

    图片

        如果我们想要控制虚拟文件'/dev/urandom'的交互结果,可以继承QlFsMappedObject类,并可自定义read、write、fstat、ioctl、readline等方法。

    1. from qiling import Qiling
    2. from qiling.os.mapper import QlFsMappedObject
    3. class FakeUrandom(QlFsMappedObject):
    4.   def read(self, size: int) -> bytes:
    5.       return b"\x01" #可以修改读取返回结果
    6.   def fstat(self) -> int:
    7.       return -1
    8.   def close(self) -> int:
    9.       return 0
    10. if __name__ == "__main__":
    11.   ql = Qiling(["x86_linux/bin/x86_fetch_urandom"], "x86_linux")
    12.   ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    13.   ql.run()

    图片

    函数hook

        下面示例中,我们给str1和str2俩个变量内存中分别复制"abcdef"和"ABCDEF"字符串。正常执行完毕后会打印出"str1 大于 str2"。我们可以使用qiling框架劫持strcmp实现为hook strcmp函数的效果,使其执行到不同分支的结果。

    1. #include <stdio.h>
    2. #include <string.h>
    3. //cd ./x8664_linux/
    4. //gcc demo.c -o test
    5. int main ()
    6. {
    7.   char str1[15];
    8.   char str2[15];
    9.   int ret;
    10.   strcpy(str1"abcdef");
    11.   strcpy(str2"ABCDEF");
    12.   ret = strcmp(str1, str2);
    13.   if(ret < 0)
    14.   {
    15.      printf("str1 小于 str2");
    16.   }
    17.   else if(ret > 0)
    18.   {
    19.      printf("str1 大于 str2");
    20.   }
    21.   else
    22.   {
    23.      printf("str1 等于 str2");
    24.   }
    25.   return(0);
    26. }

        以下代码为hook strcmp函数,并通过修改rax寄存器改变执行流程。

    1. from qiling import *
    2. from qiling.const import *
    3. # 自定义strcmp hook函数。当程序执行strcmp函数退出时,会调用此函数,并且在比较完毕后,将 rax 寄存器的值修改为 0,表示相等。
    4. def hook_strcmp(ql,*args):
    5. # qiling框架的寄存器取值为ql.arch.reg.xxx
    6.   rax = ql.arch.regs.rax
    7.   print("hook_addr_rax:",hex(rax))
    8.   ql.arch.regs.eax = 0 # 0:等于; -1:小于 ;1:大于
    9. # 使用 ql.os.set_api 函数为 strcmp 设置hook函数,第一个参数为要hook的函数名,第二个参数为自定义hook函数,第三个参数为hook类型,这里为退出时触发hook函数。
    10. def hook_func(ql):
    11.   ql.os.set_api('strcmp',hook_strcmp,QL_INTERCEPT.EXIT) # 也可以使用ql.hook_address()函数进行hook,使用方法为ql.hook_address(hook_strcmp,0xXXXXXXXX)
    12. if __name__ == "__main__":
    13.   ql = Qiling(["./x8664_linux/test"],"./x8664_linux",verbose=QL_VERBOSE.DEBUG)
    14.   hook_func(ql)
    15.   #ql.debugger = "gdb:0.0.0.0:12345"
    16.   ql.run()

    图片

        定义hook函数时hook类型参数有以下三种:

    图片

    qiling使用实例

    使用qiling解密CTF赛题

        当我们掌握了最基础的三个用法后,我们可以测试一个简单的例子来加深对qiling框架的理解。以上一小节中unicorn解密ctf题目为例,我们先简单写一个运行脚本。这里的ql.debugger="gdb:0.0.0.0:12345"为开启gdbserver服务,我们可以使用ida或者gdb进行调试。

    图片

        简单运行后发现程序和上一小节中unicorn的运行状况类似。由于这里我设置了multithead为True,所以这里会比上一小节中unicorn的解密速度快不少。但是还是在有限时间内只输出4个字符。

    图片

        当我们将verbose设置为QL_VERBOSE.DISASM便可观察模拟执行的汇编指令,根据汇编指令我们明显看到程序在call 0x400670处进行了递归调用(或使用调试器调试查看),导致解密时间非常长。所以我们需要进行代码优化,思路为使用栈空间来保存一个不同输入参数以及对应计算结果的字典来避免重复计算。

    图片

       这里qiling由于是由unicorn开发而来,所以很多用法和unicorn相似。

    1. from qiling import *
    2. from qiling.const import *
    3. from pwn import *
    4. def hook_start(ql):
    5.     arg0 = ql.arch.regs.rdi
    6.     r_rsi = ql.arch.regs.rsi
    7.     arg1 = u32(ql.mem.read(r_rsi,4))
    8.     if (arg0,arg1in direct:
    9.         (ret_rax,ret_ref) = direct[(arg0,arg1)]
    10.         ql.arch.regs.rax = ret_rax
    11.         ql.mem.write(r_rsi,p32(ret_ref))
    12.         ql.arch.regs.rip = 0x400582
    13.     else:
    14.         ql.arch.stack_push(r_rsi)
    15.         ql.arch.stack_push(arg1)
    16.         ql.arch.stack_push(arg0)
    17. def hook_end(ql):
    18.     arg0 = ql.arch.stack_pop()
    19.     arg1 = ql.arch.stack_pop()
    20.     r_rsi = ql.arch.stack_pop()
    21.     ret_rax = ql.arch.regs.rax
    22.     ret_ref = u32(ql.mem.read(r_rsi,4))
    23.     direct[(arg0,arg1)] = (ret_rax,ret_ref)
    24. def solve(ql):
    25.     start_address = 0x400670
    26.     end_address = 0x4006f1
    27.     end_address2 = 0x400709
    28.     ql.hook_address(hook_start,start_address)
    29.     ql.hook_address(hook_end,end_address)
    30.     ql.hook_address(hook_end,end_address2)
    31. if __name__ == '__main__':
    32.     path = ["./x8664_linux_symlink/test"]
    33.     rootfs = "./x8664_linux_symlink"
    34.     direct = {}
    35.     ql = Qiling(path, rootfs,verbose=QL_VERBOSE.DEFAULT)
    36.     solve(ql)
    37.     ql.run()

    运行后便会打印出解密结果。

    图片

        除了上一小节中的ctf题目掌握qiling的使用外,我们还可通过qilinglab来加深对qiling框架的使用。qilingLab是由11个小挑战组成的二进制程序,用来帮助新手快速熟悉和掌握 Qiling 框架的基本用法。官方提供了aarch64程序的解题方法,我们根据这个作为参考解密一下x86_64架构的练习程序。

        x86_64程序下载(https://www.shielder.com/attachments/qilinglab-x86_64)

        首先运行程序,给我们提示,challenges会造成程序崩溃,只有当我们解出相应challenge后才会显示信息。

    图片

        我们可以通过ida逆向以及编写qiling脚本进行动态调试来完成这些challenge。

    图片

        最终的解密脚本如下:

    1. from qiling import *
    2. from pwn import *
    3. from qiling.const import *
    4. from qiling.os.mapper import QlFsMappedObject
    5. import os
    6. import struct
    7. def hook_cpuid(ql, address, size):
    8.     if ql.mem.read(address, size) == b'\x0F\xA2':
    9.         regs = ql.arch.regs
    10.         regs.ebx = 0x696C6951
    11.         regs.ecx = 0x614C676E
    12.         regs.edx = 0x20202062
    13.         regs.rip += 2
    14. def challenge11(ql):
    15.     begin, end = 00
    16.     for info in ql.mem.map_info:
    17.         #print("=====")
    18.         #print(info)
    19.         #print("=====")
    20.         if info[2] == 5 and 'qilinglab-x86_64' in info[3]:
    21.             begin, end = info[:2]
    22.             #print("begin_addr",begin)
    23.             #print("end_addr",end)
    24.     ql.hook_code(hook_cpuid, begin=begin, end=end)
    25. class cmdline(QlFsMappedObject):
    26.     def read(self, expected_len):
    27.         return b'qilinglab'
    28.     def close(self):
    29.         return 0
    30. def challenge10(ql):
    31.     ql.add_fs_mapper('/proc/self/cmdline', cmdline())
    32. def hook_tolower(ql):
    33.     return 0
    34. def challenge9(ql):
    35.     ql.os.set_api('tolower', hook_tolower)
    36. def find_and_patch(ql, *args, **kw):
    37.     MAGIC = 0x3DFCD6EA00000539
    38.     magic_addrs = ql.mem.search(p64(MAGIC))
    39.     #print("magic_address:",hex(magic_addrs))
    40.     for magic_addr in magic_addrs:
    41.         malloc1_addr = magic_addr - 8
    42.         malloc1_data = ql.mem.read(malloc1_addr, 24)
    43.         string_addr, _ , check_addr = struct.unpack("QQQ",malloc1_data)
    44.         if ql.mem.string(string_addr) == "Random data":
    45.             ql.mem.write(check_addr, b"\x01")
    46.             break
    47. def challenge8(ql):
    48.     base_addr = ql.mem.get_lib_base(os.path.split(ql.path)[-1])
    49.     #print("base_addr",hex(base_addr))
    50.     ql.hook_address(find_and_patch, base_addr+0xFB5)
    51. def hook_sleep(ql):
    52.     return 0
    53. def challenge7(ql):
    54.     ql.os.set_api('sleep',hook_sleep)
    55. def hook_rax(ql):
    56.     ql.arch.regs.rax = 0
    57. def challenge6(ql):
    58.     base_addr = ql.mem.get_lib_base(os.path.split(ql.path)[-1])
    59.     #print("base_addr",hex(base_addr))
    60.     hook_addr = base_addr + 0xF16
    61.     ql.hook_address(hook_rax, hook_addr)
    62. def hook_rand(ql):
    63.     ql.arch.regs.rax = 0
    64. def challenge5(ql):
    65.     ql.os.set_api('rand',hook_rand)
    66. def enter_forbidden_loop_hook(ql):
    67.     ql.arch.regs.eax = 1
    68. def challenge4(ql):
    69.     base = ql.mem.get_lib_base(os.path.split(ql.path)[-1])
    70.     hook_addr = base + 0xE43
    71.     print("qiling binary hookaddr:",hex(hook_addr))
    72.     ql.hook_address(enter_forbidden_loop_hook, hook_addr)
    73. class FakeUrandom(QlFsMappedObject):
    74.     def read(self, size: int) -> bytes:
    75.         if size == 1:
    76.             return b"\x42"
    77.         else:
    78.             return b"\x41" * size
    79.     def close(self) -> int:
    80.         return 0
    81. def hook_getrandom(ql, buf, buflen, flags):
    82.     if buflen == 32:
    83.         data = b'\x41' * buflen # b'\x41' = A
    84.         ql.mem.write(buf, data)
    85.         ql.os.set_syscall_return(buflen)
    86.     else:
    87.         ql.os.set_syscall_return(-1)
    88. def challenge3(ql):
    89.     ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    90.     ql.os.set_syscall("getrandom", hook_getrandom)
    91. def my_uname_on_exit_hook(ql, *args):
    92.     rdi = ql.arch.regs.rdi
    93.     print(f"utsname address: {hex(rdi)}")
    94.     ql.mem.write(rdi, b'QilingOS\x00')
    95.     ql.mem.write(rdi + 65 * 3, b'ChallengeStart\x00')
    96. def challenge2(ql):
    97.     ql.os.set_api("uname", my_uname_on_exit_hook, QL_INTERCEPT.EXIT)
    98. def challenge1(ql):
    99.     ql.mem.map(0x10000x1000, info='challenge1')
    100.     ql.mem.write(0x1337, p16(1337))
    101.  
    102. if __name__ == '__main__':
    103.     path = ["./x8664_linux/qilinglab-x86_64"]
    104.     rootfs = "./x8664_linux"
    105.     ql = Qiling(path, rootfs,verbose=QL_VERBOSE.OFF)
    106.     challenge1(ql)
    107.     challenge2(ql)
    108.     challenge3(ql)
    109.     challenge4(ql)
    110.     challenge5(ql)
    111.     challenge6(ql)
    112.     challenge7(ql)
    113.     challenge8(ql)
    114.     challenge9(ql)
    115.     challenge10(ql)
    116.     challenge11(ql)
    117.     #ql.debugger = "gdb:0.0.0.0:12345"
    118.     ql.run()

        运行后,所有的challenge都会显示SOLVED。

    图片

    qiling设备仿真

        qiling提供了路由器仿真案例,该脚本路径为qiling/example路径下

    1. #!/usr/bin/env python3
    2. # 1. Download AC15 Firmware from https://down.tenda.com.cn/uploadfile/AC15/US_AC15V1.0BR_V15.03.05.19_multi_TD01.zip
    3. # 2. unzip
    4. # 3. binwalk -e US_AC15V1.0BR_V15.03.05.19_multi_TD01.bin
    5. # 4. locate squashfs-root
    6. # 5. rm -rf webroot && mv webroot_ro webroot
    7. #
    8. # notes: we are using rootfs in this example, so rootfs = squashfs-root
    9. #
    10. import os, socket, threading
    11. import sys
    12. sys.path.append("../../../")
    13. from qiling import Qiling
    14. # 从qiling.const中导入QL_VERBOSE,指定qiling的日志输出级别
    15. from qiling.const import QL_VERBOSE
    16. # 定义patcher函数,用于跳过网卡信息检测。在前面小节我们仿真tenda路由器时,路由器httpd程序在初始化网络时会检查网卡名称是否为br0。这里脚本直接将代码执行前内存中的br0字符串替换成了lo,从而跳过检查。
    17. def patcher(ql: Qiling):
    18.     br0_addr = ql.mem.search("br0".encode() + b'\x00')
    19.     for addr in br0_addr:
    20.         ql.mem.write(addr, b'lo\x00')
    21. # 定义nvram_listener函数,使用该函数监听Unix套接字,并在收到消息时返回数据。
    22. def nvram_listener():
    23.     server_address = 'rootfs/var/cfm_socket'
    24.     data = ""
    25.     try:
    26.         os.unlink(server_address)
    27.     except OSError:
    28.         if os.path.exists(server_address):
    29.             raise
    30.     sock = socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
    31.     sock.bind(server_address)
    32.     sock.listen(1)
    33.     while True:
    34.         connection, _ = sock.accept()
    35.         try:
    36.             while True:
    37.                 data += str(connection.recv(1024))
    38.                 if "lan.webiplansslen" in data:
    39.                     connection.send('192.168.170.169'.encode())
    40.                 else:
    41.                     break
    42.                 data = ""
    43.         finally:
    44.             connection.close()
    45. # 定义myvfork函数,仿真程序在执行系统调用vfork时被调用,返回值0
    46. def myvfork(ql: Qiling):
    47.     regreturn = 0
    48.     ql.log.info("vfork() = %d" % regreturn)
    49.     return regreturn
    50. # 仿真主函数,生成qiling实例和添加VFS映射。
    51. def my_sandbox(path, rootfs):
    52.     print("path:",path)
    53.     print("rootfs",rootfs)
    54.     ql = Qiling(path, rootfs, verbose=QL_VERBOSE.DEBUG)
    55.     print("ql:",ql)
    56.     ql.add_fs_mapper("/dev/urandom","/dev/urandom")
    57.     ql.hook_address(patcher, ql.loader.elf_entry)
    58.     ql.debugger = False
    59.     if ql.debugger == True:
    60.         ql.os.set_syscall("vfork", myvfork) # vfork函数返回0时,debugger可正常调试。
    61.     ql.run()
    62. if __name__ == "__main__":
    63.   # 创建后台运行的线程并执行,以便收到Unix套接字的消息时进行响应。
    64.     nvram_listener_therad = threading.Thread(target=nvram_listener, daemon=True)
    65.     nvram_listener_therad.start()
    66.   # 运行仿真实例
    67.     my_sandbox(["rootfs/bin/httpd"], "rootfs")

        当我们运行脚本后,会显示路由器的ip和端口,当我们发现本地的8080正在监听时,说明设备已经仿真成功。

    图片

        仿真成功后可访问http://localhost:8080查看效果:

    图片

        在后面的小节中,我们会学习对仿真路由器设备进行fuzz。其中最为重要的一步便是编写仿真脚本,后续在我们分析好固件程序中要fuzz地址范围后,只有仿真设备可以顺利触发保存快照的功能,才可保证fuzz的正确性。

    qiling fuzz

        qiling框架可以使用AFLplusplus对arm架构程序进行fuzz测试,测试代码如下:

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. // Program that will crash easily.
    5. #define SIZE (10)
    6. int fun(int i)
    7. {
    8.     char *buf = malloc(SIZE);
    9.     char buf2[SIZE];
    10.     
    11.     while ((*buf = getc(stdin)) == 'A')
    12.     {
    13.         buf[i++] = *buf;
    14.     }
    15.     strncpy(buf2, buf, i);
    16.     puts(buf2);
    17.     return 0;
    18. }
    19. int main(int argc, char **argv)
    20. {
    21.     return fun(argc);
    22. }

        qiling提供的fuzz脚本如下:

    1. #!/usr/bin/env python3
    2. """
    3. Simple example of how to use Qiling together with AFLplusplus.
    4. This is tested with the recent Qiling framework (the one you cloned),
    5. afl++ from https://github.com/AFLplusplus/AFLplusplus
    6. After building afl++, make sure you install `unicorn_mode/setup_unicorn.sh`
    7. Then, run this file using afl++ unicorn mode with
    8. afl-fuzz -i ./afl_inputs -o ./afl_outputs -m none -U -- python3 ./fuzz_x8664_linux.py @@
    9. """
    10.                                                                                                                                                                                               
    11. # No more need for importing unicornafl, try ql.afl_fuzz instead!
    12. import sys, os
    13. from binascii import hexlify
    14. sys.path.append("../../..")
    15. from qiling import *
    16. from qiling.extensions import pipe
    17. from qiling.extensions.afl import ql_afl_fuzz
    18. def main(input_file, enable_trace=False):
    19.     ql = Qiling(["./arm_fuzz"], "../../rootfs/arm_qnx", console=enable_trace)
    20.     # 设置ql的标准输入为进程的标准输入
    21.     ql.os.stdin = pipe.SimpleInStream(sys.stdin.fileno())
    22.   # 如果没有启用控制台追踪,则将标准输出和标准错误流设置为Null
    23.     if not enable_trace:
    24.         ql.os.stdout = pipe.NullOutStream(sys.stdout.fileno())
    25.         ql.os.stderr = pipe.NullOutStream(sys.stderr.fileno())
    26.     def place_input_callback(ql: Qiling, input: bytes, _: int):
    27.       # 设置fuzz输入点
    28.         ql.os.stdin.write(input)
    29.         return True
    30.     def start_afl(_ql: Qiling):
    31.       # 设置fuzz实例
    32.         ql_afl_fuzz(_ql, input_file=input_file, place_input_callback=place_input_callback, exits=[ql.os.exit_point])
    33.   # 获取libc的基地址
    34.     LIBC_BASE = int(ql.profile.get("OS32""interp_address"), 16)
    35.     # 设置hook函数,用于处理SignalKill信号
    36.     ql.hook_address(callback=lambda x: os.abort(), address=LIBC_BASE + 0x38170)
    37.     # main函数地址
    38.     main_addr = 0x08048aa0
    39.     # 设置hook函数,在main函数运行时调用start_afl函数
    40.     ql.hook_address(callback=start_afl, address=main_addr)
    41.   
    42.   # 若启用控制台追踪,则将设置相关信息输出
    43.     if enable_trace:
    44.         # The following lines are only for `-t` debug output
    45.         md = ql.arch.disassembler
    46.         count = [0]
    47.         def spaced_hex(data):
    48.             return b' '.join(hexlify(data)[i:i+2for i in range(0, len(hexlify(data)), 2)).decode('utf-8')
    49.         def disasm(count, ql, address, size):
    50.             buf = ql.mem.read(address, size)
    51.             try:
    52.                 for i in md.disasm(buf, address):
    53.                     return "{:08X}\t{:08X}: {:24s} {:10s} {:16s}".format(count[0], i.address, spaced_hex(buf), i.mnemonic,
    54.                                                                         i.op_str)
    55.             except:
    56.                 import traceback
    57.                 print(traceback.format_exc())
    58.         def trace_cb(ql, address, size, count):
    59.             rtn = '{:100s}'.format(disasm(count, ql, address, size))
    60.             print(rtn)
    61.             count[0] += 1
    62.         ql.hook_code(trace_cb, count)
    63.     # okay, ready to roll.
    64.     # try:
    65.     ql.run()
    66.     # except Exception as ex:
    67.     # # Probable unicorn memory error. Treat as crash.
    68.     # print(ex)
    69.     # os.abort()
    70.     os._exit(0) # that's a looot faster than tidying up.
    71.                                                                                                                                                                                               
    72. if __name__ == "__main__":
    73.     if len(sys.argv) == 1:
    74.         raise ValueError("No input file provided.")
    75.     if len(sys.argv) > 2 and sys.argv[1] == "-t":
    76.         main(sys.argv[2], enable_trace=True)
    77.     else:
    78.         main(sys.argv[1])

        AFLplusplus执行脚本如下:

    1. #!/usr/bin/sh
    2. AFL_AUTORESUME=1 AFL_PATH="$(realpath ../../../AFLplusplus)" PATH="$AFL_PATH:$PATH" afl-fuzz -i afl_inputs -o afl_outputs -U -- python3 ./fuzz_arm_qnx.py @@

        运行后fuzz.sh后,便会出现afl++ 运行界面,等待几秒后便出现crash。

    图片

        crash的变异数据存放在afl_outputs目录下,我们可以使用xxd id:000000,xxxxxx命令查看变异数据。

    1. #xxd id:000000,sig:06,src:000000,time:4112,execs:1077,op:havoc,rep:8 
    2. 00000000: 4141 4141 4141 4141 4141 4141 ff74241 AAAAAAAAAAAA..BA
    3. 00000010: 4141 4145 4141 be41 4dff 0000 0041 4141 AAAEAA.AM....AAA
    4. 00000020: 41

    总结

    在这一小节中,我们简单学习了qiling框架,我们使用ctf例题以及qilinglab的11个闯关题目进行练习,熟练掌握了qiling框架的基础使用。后面的小节中,我们将使用qiling框架对仿真设备进行实例fuzz测试。

  • 相关阅读:
    红菜苔炒腊肉
    阿里10年架构师:由Java多线程+MySQL+JVM出发怎样做好职业规划?
    嵌入式Linux入门-代码重定位和清除bss段讲解
    点云从入门到精通技术详解100篇-基于点云的刺梨果实三维建模 及其生物力学特性研究(中)
    重学JavaSE 第14章 : 泛型、自定义泛型、泛型通配符
    Java8中Optional解决空指针异常
    从智能门锁,看3D视觉的安全性突围
    Docker--容器挂载
    鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:尺寸设置)
    2022/7/30
  • 原文地址:https://blog.csdn.net/We8__/article/details/138185518