首页
社区
课程
招聘
[原创] Qiling框架分析实战:从 QilingLab 详解到 Qiling 源码分析
发表于: 2023-5-29 21:42 23142

[原创] Qiling框架分析实战:从 QilingLab 详解到 Qiling 源码分析

2023-5-29 21:42
23142

最近在学习 IoT 相关漏洞利用,打算先学习一下 Qiling 框架,为后续的漏洞利用文章做铺垫。 Qiling 框架是基于 unicorn 的多架构平台模拟执行框架,提供的仿真环境很全面,能够在模拟执行的基础上提供统一的分析 API,这个A PI 包括插桩分析、快照、系统调用和API劫持等操作。在2021年JOANSIVION提供了两个QilingLab能够针对Qiling框架各种操作进行学习的程序,并提供了相应的writeup。他提供的 writeup 是 arm 架构的,因此本文以 x86_64 架构为基础,在他的文章上进行相应补充。程序下载地址放在了文末参考链接中。

时隔两年,Qiling 框架进行了很多更新与改动,我在完成 QilingLab 的过程中发现高版本的 Qiling 存在问题,因此从代码审计的角度入手,分析并提出解决方案,如果曾经分析过 QilingLab 的朋友可以直接跳到 Challenge 10 部分。本文将以最为基础的视角来陪着大家从 0 到 1 学习 Qiling 框架,希望大家看完能有所收获。

首先下载Qiling:

使用版本为最新版:

可以看到 QilingLab 提供的11个挑战如下:

运行一下程序,可以看到输出了挑战的所有题目:

先调用Qiling仿真环境运行一下:

发现报错:

接下来进行分析无法运行的原因,按照出题人所说需要解决第一个挑战才能正常进入。首先查看一下文件信息,可以看到程序使用小端顺序,符号表未裁剪:

拖到IDA里看一下函数流程,main函数:

可以看到跳转到start,查看一下start伪代码:

查看调用的checker函数伪代码,可以知道当检查到问题已解决时返回1:

我们梳理一下函数逻辑:循环初始化数组v13所有元素为0,如果完成对应挑战就会改变v13对应数组的值,再用checker进行一次检查v13数组元素是否为0.再将checker返回值传递给变量,再加到下一次的检查结果上。这个过程不断重复,最后将累加起来的值输出到"\nYou solved %d/%d of the challenges\n"

拖到IDA里看一下 challenge 1 汇编代码:

可以看出我们需要让内存地址1337h处的值为1337才能让cmp判断相等,rdi传入的是数组地址对应数组首个元素地址,相等后调整rdi地址处的值为1,这也符合后续被checker函数检查数组后进行的一系列操作。

challenge 1 对应的伪代码如下:

在Qiling中编写字节序列常用有以下方式,我选用的是pack16。

根据前面的分析可以得到 challenge 1 writeup:

运行上面的脚本,可以看到 challenge 1 已经解决:

如果我们想使用Qiling进行远程调试的话,应该怎么做?

我们在使用qemu配合IDA进行远程调试时,需要使用下面的qemu-arm-static:

查了一下qiling文档,调试qiling的仿真程序需要在脚本中添加下面的代码:

接着设置一下IDA的gdb debugger,断点在入口函数处,

运行添加dbg后的脚本:

运行后报错:

Qiling对于报错的提示都挺好的,这里需要将qilinglab-x86_64放置到指定的rootfs目录(我这里是使用的rootfs/x8664_linux作为rootfs目录)下运行,复制后更改一下程序运行的路径,更改后的代码如下:

可以看到程序已经可以远程调试了:

Challenge 2: Make the 'uname' syscall return the correct values.

查看challenges 2 汇编代码:

正确的运行逻辑: challenge2 -> loc_555555554BFC -> loc_555555554C6D -> loc_555555554CB8 -> loc_555555554D13 -> loc_555555554D27

对应伪代码:

第一个if判断:

uname(&name) 是一个系统调用函数,它的作用是获取当前系统的名称和版本信息,并将这些信息存储到 struct utsname 类型的结构体变量 name 中,name 使用struct utsname name;声明 ,如果成功获取的话函数返回值为0,就可以进入else了。else中我们最后需要执行*a1 = 1,这里面有两个循环进行字符串逐个判断,如果相同就能在最后的if判断中让*a1 = 1。此处我们需要了解uname的结构体,uname的结构为:

我们需要让name.sysname等于"QilingOS",name.version等于"ChallengeStart"。

出题人提供了源码,可以看到源码的逻辑跟分析的一致:

根据上述分析,我们需要hook系统调用uname。在Qiling中有四种hook方式,这四个方式都是常量:

为了使用上面的hook方式,需要使用 from qiling.const import * 导入Qiling模拟器中的常量。
系统调用返回结构体型数据时,会将结构体的地址存放在寄存器rdi中,因此我们需要使用 ql.arch.regs.rdi得到rdi中存储的uname地址。

writeup:

用IDA看一下运行脚本后rdi指向的sysname和version,可以看到已经按照我们的脚本进行了修改:

运行脚本,challenge2已解决:

Challenge 3: Make '/dev/urandom' and 'getrandom' "collide".

IDA 看一下 Challenge 3:

Challenge 3 伪代码:

分析程序逻辑,主要关注点在buf,v5与v7三者之间的关系:

read(fd, buf, 0x20uLL):从文件描述符fd读取32(0x20)字节的数据,并将其存储在字符数组buf中。原函数:ssize_t read(int fd, void *buf, size_t count);
read(fd, &v5, 1uLL):从文件描述符fd读取1字节的数据,并将其存储在字符变量v5中。
getrandom(v7, 32LL, 1LL):系统调用,从系统提供的随机数源获取随机数据。代码含义是从系统熵池中获取32字节的随机数据,并将其存储在字符数组v7中。

我们需要在i循环中让buf[i]v7[i]相等,且buf[i]不等于v5。getrandom是利用系统调用获取随机数,urandom是利用文件读写操作获取随机数,要解决这道题需要让两者一样。关于 /dev/urandomgetrandom 的相关知识:

/dev/urandom 是一个 Unix/Linux 系统中的特殊文件,它是一个伪随机数发生器设备文件,用于生成随机数。
在Qiling中使用 ql.add_fs_mapper("/dev/urandom", "/dev/urandom") 将宿主机中的 /dev/urandom (后面的) 设备文件映射到 Qiling 虚拟机中的 /dev/urandom (前面的) 文件上,以便为虚拟机中的程序提供随机数服务。

getrandom使用方法:

我们可以使用QlFsMappedObject自定义文件对象,实现"/dev/urandom":

我们可以通过hook系统调用自定义一个"getrandom",例如:

运行后,可以看到challenge 3已解决:

Challenge 4: Enter inside the "forbidden" loop.

IDA 查看伪代码发现什么都看不到:

根据汇编逻辑,我们最终需要实现 mov byte ptr [rax], 1 ,但是在 loc_555555554E40 中 :

实际上就是 0比0,我们需要让[rbp+var_4]小于[rbp+var_8],jl指令才会跳转到loc_555555554E35函数中,执行*a=1,然后再通过 add [rbp+var_4], 1 跳出循环。

我们根据逻辑patch汇编使得 [rbp+var_8], 1 ,就可以得到正确的伪代码:

可以看到我们的分析是正确的,接着就来编写 Qiling challenge 4 writeup:

运行后,可以看到 challenge 4 已经被解决:

Challenge 5: Guess every call to rand().

challenge 5 伪代码如下:

分析代码逻辑,我们想要最后得到*a1 = 1的话,需要绕过第二个for循环。让rand()得到的值都为0就可以了。hook方法在官方手册 Hijacking OS API (POSIX)

运行后没有显示第五个挑战是否被解决,因为被第六题的死循环卡住了。

Challenge 6: Avoid the infinite loop.

查看伪代码,可以看到跟第四题一样:

我们需要执行loc_555555554F0B函数,然后再退出循环。我们需要让ZF=0,jnz才能跳转loc_555555554F0B函数。
主要关注点在test al, al上,这条指令的含义是将EAX的低8位(al)与自身与运算,主要是用于修改ZF标志位。

因此我们需要将eax设置为0,对mov [rbp+var_5], 1 进行patch,改为 mov [rbp+var_5], 0,就可以正确生成伪代码了,得到的和我们预期的一致。

运行后可以看到第五个挑战已经解决,但是第六个还没显示,应该是需要解出第七题:

Challenge 7: Don't waste time waiting for 'sleep'.

伪代码如下:

我们可以利用之前学的方法hook sleep函数,还是比较简单的。

运行后,可以看到1-7题已解决:

Challenge 8: Unpack the struct and write at the target address.

伪代码如下:

v2是一个指针,指向malloc分配的内存块,相当于结构体的头指针,结构体整理后的内容如下:

我们需要修改*a1为1,我使用的是以下方法对程序运行时存在的魔数进行搜索来判断结构体头指针位置,进而根据对应地址进行修改:

运行后可以看到第八题已解出:

Challenge 9: Fix some string operation to make the iMpOsSiBlE come true.

伪代码为:

根据代码,我们需要让 strcmp(src, dest) == 0 ,strcmp(str1,str2) 如果str1 == str2,则返回 0。
tolower函数是将给定的字符转换为小写形式。我们可以通过hook tolower让tolower失效,strcmp自然能够顺利对比一致。

运行后顺利通过:

Challenge 10: Fake the 'cmdline' line file to return the right content.

对应伪代码为:

根据代码,我们需要让 buf 等于 "qilinglab"。
fd:open失败为-1,open成功为0。
/proc/self/cmdline是一个在Linux系统中的特殊文件,它提供了当前进程(即访问/proc/self/cmdline的进程)的命令行参数信息。

假如我们使用命令./my_program arg1 arg2 arg3启动一个程序时,读取/proc/self/cmdline的过程在 ./my_program 中,/proc/self/cmdline文件的内容将是:

按照第三个挑战的方法,我们可以使用自定义文件对象来更改读取文件时的返回值:

在运行后并没有解题成功,好像是在hook /proc/self/cmdline 这里存在问题,我写了个脚本单独调试以下cmdline读取程序:

c 程序:用来读取cmdline,文件名:test_cmdline

python程序:用来hook test_cmdline 中的文件操作

运行结果如下,可以看到确实在读取操作的过程中存在问题。

切换到 Qilinglab当时使用的版本看一下是否存在这个问题,Qilinglab的文章是21年7月发的,对应Qiling版本应该是1.2.4,使用pip指定版本安装方法:

运行后存在版本不兼容问题,因此我将从这个版本开始直到最新版的每个版本都进行了测试。结果如下:

1.4.3 可以正确进行文件映射:

1.4.4 无法正确进行文件映射:

我们使用的最新版是 1.4.5,也就是说在1.4.3到1.4.4这个版本更新中可能存在问题,因此接下来进行代码审计。文件映射在源码对应的 qiling/os/mapper.py 中,我们对比一下文件改动:

改动如下:

第1点:
在之前,Qiling只支持字符串和对象做为文件系统映射。而QlFsMappedCallable允许用户传入一个类对象real_dest,然后在调用时实例化这个类对象。
用于 add_fs_mapping(self, ql_path: Union[os.PathLike, str], real_dest: Union[str, QlFsMappedObject, QlFsMappedCallable])

第2点:

第3点:

第4点:

我们替换1.4.4的mapper.py为1.4.3版本,

更改后依然没变化,报错。接着分析是否是针对 /proc/self/cmdline 有新的处理方式,加载1.4.4的源码到vscode中,发现在 linux.py 文件中新增以下代码:

看一下更新对比:

1.4.4版本的linux.py文件与1.4.3版本的linux.py文件相比,有以下主要改动:

之前在1.4.3版本中模拟/proc目录的方式有两个:

这两种方式存在一定缺点:

所以总的来说1.4.4版本对/proc处理做了封装,使得它更模块化、易用。但是在新增的几个模块中对 '/proc/self/auxv' 等文件做出了额外的限制,我们在映射这几个文件时可能存在问题。因此我怀疑 cmdline 的问题就是在这个地方。

接着看run(self)函数:

这段代码的含义是:
只有在加载ELF文件或可执行程序的时候,才设置/proc文件系统。

因此将此处判断代码注释后,就应该可以成功运行了。注释后运行:

运行成功!

这个问题应该在1.4.4和1.4.5中都存在,我们可以通过新增一个选项 ql = Qiling(path, rootfs, enable_procfs=False) 来控制是否设置/proc文件系统,当enable_procfs=False 时关闭,默认值为True。我们需要修改 core.py 文件:

修改 linux.py 中的代码新增对参数enable_procfs的判断:

这样我们只需要将ql改成下面的代码即可:

然后修改我们的challenge10测试一下,运行成功!

Challenge 11: Bypass CPUID/MIDR_EL1 checks.

伪代码如下:

关键部分汇编代码如下:

我们需要让*a=1,就要让if的判断顺利通过,if ( __PAIR64__(_RBX, _RCX) == 0x696C6951614C676ELL && (_DWORD)_RDX == 538976354 ) 的含义为:

最后可以看到全部题目均已解决:

最后完整的代码为:

跟着上面的文章思路走一遍,我相信大家已经了解了 Qiling 框架的使用方法。通过攥写本文时分析 Qiling 的源码,也加强了我对 Qiling框架的理解。
如果在文中发现问题,欢迎大家在下面留言。

Qiling 官方文档
Qiling lab
Qiling Framework入门,11个挑战快速上手@PJXRocks
浅尝qiling框架-qilinglab writeup@badmonkey
11个小挑战,Qiling Framework 入门上手跟练@Cr0ssx2

 
 
git clone --recurse-submodules https://github.com/qilingframework/qiling.git # 使用 --recurse-submodules 递归下载模块,rootfs是单独更新的项目
git clone --recurse-submodules https://github.com/qilingframework/qiling.git # 使用 --recurse-submodules 递归下载模块,rootfs是单独更新的项目
> pip show qiling
Name: qiling
Version: 1.4.5
Summary: Qiling is an advanced binary emulation framework that cross-platform-architecture
> pip show qiling
Name: qiling
Version: 1.4.5
Summary: Qiling is an advanced binary emulation framework that cross-platform-architecture
Welcome to QilingLab.
Here is the list of challenges:
Challenge 1: Store 1337 at pointer 0x1337.
Challenge 2: Make the 'uname' syscall return the correct values.
Challenge 3: Make '/dev/urandom' and 'getrandom' "collide".
Challenge 4: Enter inside the "forbidden" loop.
Challenge 5: Guess every call to rand().
Challenge 6: Avoid the infinite loop.
Challenge 7: Don't waste time waiting for 'sleep'.
Challenge 8: Unpack the struct and write at the target address.
Challenge 9: Fix some string operation to make the iMpOsSiBlE come true.
Challenge 10: Fake the 'cmdline' line file to return the right content.
Challenge 11: Bypass CPUID/MIDR_EL1 checks.
Welcome to QilingLab.
Here is the list of challenges:
Challenge 1: Store 1337 at pointer 0x1337.
Challenge 2: Make the 'uname' syscall return the correct values.
Challenge 3: Make '/dev/urandom' and 'getrandom' "collide".
Challenge 4: Enter inside the "forbidden" loop.
Challenge 5: Guess every call to rand().
Challenge 6: Avoid the infinite loop.
Challenge 7: Don't waste time waiting for 'sleep'.
Challenge 8: Unpack the struct and write at the target address.
Challenge 9: Fix some string operation to make the iMpOsSiBlE come true.
Challenge 10: Fake the 'cmdline' line file to return the right content.
Challenge 11: Bypass CPUID/MIDR_EL1 checks.
> ./qilinglab-x86_64
Welcome to QilingLab.
Here is the list of challenges:
Challenge 1: Store 1337 at pointer 0x1337.
Challenge 2: Make the 'uname' syscall return the correct values.
Challenge 3: Make '/dev/urandom' and 'getrandom' "collide".
Challenge 4: Enter inside the "forbidden" loop.
Challenge 5: Guess every call to rand().
Challenge 6: Avoid the infinite loop.
Challenge 7: Don't waste time waiting for 'sleep'.
Challenge 8: Unpack the struct and write at the target address.
Challenge 9: Fix some string operation to make the iMpOsSiBlE come true.
Challenge 10: Fake the 'cmdline' line file to return the right content.
Challenge 11: Bypass CPUID/MIDR_EL1 checks.
 
Checking which challenge are solved...
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[1]    8036 segmentation fault (core dumped)  ./qilinglab-x86_64
> ./qilinglab-x86_64
Welcome to QilingLab.
Here is the list of challenges:
Challenge 1: Store 1337 at pointer 0x1337.
Challenge 2: Make the 'uname' syscall return the correct values.
Challenge 3: Make '/dev/urandom' and 'getrandom' "collide".
Challenge 4: Enter inside the "forbidden" loop.
Challenge 5: Guess every call to rand().
Challenge 6: Avoid the infinite loop.
Challenge 7: Don't waste time waiting for 'sleep'.
Challenge 8: Unpack the struct and write at the target address.
Challenge 9: Fix some string operation to make the iMpOsSiBlE come true.
Challenge 10: Fake the 'cmdline' line file to return the right content.
Challenge 11: Bypass CPUID/MIDR_EL1 checks.
 
Checking which challenge are solved...
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[1]    8036 segmentation fault (core dumped)  ./qilinglab-x86_64
from qiling import *
 
if __name__ == '__main__':
    path = ["qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    ql.run()
from qiling import *
 
if __name__ == '__main__':
    path = ["qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    ql.run()
unicorn.unicorn.UcError: Invalid memory read (UC_ERR_READ_UNMAPPED)
unicorn.unicorn.UcError: Invalid memory read (UC_ERR_READ_UNMAPPED)
> readelf -h qilinglab-x86_64
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0xa80
  Start of program headers:          64 (bytes into file)
  Start of section headers:          15840 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28
> readelf -h qilinglab-x86_64
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0xa80
  Start of program headers:          64 (bytes into file)
  Start of section headers:          15840 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28
> file -L qilinglab-x86_64
qilinglab-x86_64: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=76164e6b494c1af9d9f746e2dc7d3663cc23525c, not stripped
> file -L qilinglab-x86_64
qilinglab-x86_64: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=76164e6b494c1af9d9f746e2dc7d3663cc23525c, not stripped
; Attributes: bp-based frame
 
; int __cdecl main(int argc, const char **argv, const char **envp)
public main
main proc near
 
var_10= qword ptr -10h
var_4= dword ptr -4
 
; __unwind {
push    rbp
mov     rbp, rsp
sub     rsp, 10h
mov     [rbp+var_4], edi
mov     [rbp+var_10], rsi
mov     eax, 0
call    start
mov     eax, 0
leave
retn
; } // starts at 15CA
main endp
; Attributes: bp-based frame
 
; int __cdecl main(int argc, const char **argv, const char **envp)
public main
main proc near
 
var_10= qword ptr -10h
var_4= dword ptr -4
 
; __unwind {
push    rbp
mov     rbp, rsp
sub     rsp, 10h
mov     [rbp+var_4], edi
mov     [rbp+var_10], rsi
mov     eax, 0
call    start
mov     eax, 0
leave
retn
; } // starts at 15CA
main endp
unsigned __int64 start()
{
  int v0; // eax
  int i; // [rsp+0h] [rbp-20h]
  int v3; // [rsp+4h] [rbp-1Ch]
  int v4; // [rsp+4h] [rbp-1Ch]
  int v5; // [rsp+4h] [rbp-1Ch]
  int v6; // [rsp+4h] [rbp-1Ch]
  int v7; // [rsp+4h] [rbp-1Ch]
  int v8; // [rsp+4h] [rbp-1Ch]
  int v9; // [rsp+4h] [rbp-1Ch]
  int v10; // [rsp+4h] [rbp-1Ch]
  int v11; // [rsp+4h] [rbp-1Ch]
  int v12; // [rsp+4h] [rbp-1Ch]
  char v13[11]; // [rsp+Dh] [rbp-13h] BYREF
  char v14[11]; // [rsp+Eh] [rbp-12h] BYREF
  char v15[11]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v16; // [rsp+18h] [rbp-8h]
 
  v16 = __readfsqword(0x28u);  // __readfsqword指令的参数是一个偏移量,0x28u是一个无符号整数常量,值为0x28,即40,表示从FS寄存器中的偏移量为40的地址开始读取64位数据。
  for ( i = 0; i < 11; ++i )
    v13[i] = 0;
  printf("Welcome to QilingLab.\nHere is the list of challenges:");
  printf("\nChallenge 1: Store 1337 at pointer 0x1337.");
  printf("\nChallenge 2: Make the 'uname' syscall return the correct values.");
  printf("\nChallenge 3: Make '/dev/urandom' and 'getrandom' \"collide\".");
  printf("\nChallenge 4: Enter inside the \"forbidden\" loop.");
  printf("\nChallenge 5: Guess every call to rand().");
  printf("\nChallenge 6: Avoid the infinite loop.");
  printf("\nChallenge 7: Don't waste time waiting for 'sleep'.");
  printf("\nChallenge 8: Unpack the struct and write at the target address.");
  printf("\nChallenge 9: Fix some string operation to make the iMpOsSiBlE come true.");
  printf("\nChallenge 10: Fake the 'cmdline' line file to return the right content.");
  printf("\nChallenge 11: Bypass CPUID/MIDR_EL1 checks.");
  puts(
    "\n"
    "\n"
    "Checking which challenge are solved...\n"
    "Note: Some challenges will results in segfaults and infinite loops if they aren't solved.");
  challenge1(v13);
  v3 = checker(v13, 0LL);
  challenge2(v14);
  v4 = checker(v13, 1LL) + v3;
  challenge3(&v14[1]);
  v5 = checker(v13, 2LL) + v4;
  challenge4(v15);
  v6 = checker(v13, 3LL) + v5;
  challenge5(&v15[1]);
  v7 = checker(v13, 4LL) + v6;
  challenge6(&v15[2]);
  v8 = checker(v13, 5LL) + v7;
  challenge7(&v15[3]);
  v9 = checker(v13, 6LL) + v8;
  challenge8(&v15[4]);
  v10 = checker(v13, 7LL) + v9;
  challenge9(&v15[5]);
  v11 = checker(v13, 8LL) + v10;
  challenge10(&v15[6]);
  v12 = checker(v13, 9LL) + v11;
  challenge11(&v15[7]);
  v0 = checker(v13, 10LL);
  printf("\nYou solved %d/%d of the challenges\n", (unsigned int)(v0 + v12), 11LL);
  return __readfsqword(0x28u) ^ v16;
}
unsigned __int64 start()
{
  int v0; // eax
  int i; // [rsp+0h] [rbp-20h]
  int v3; // [rsp+4h] [rbp-1Ch]
  int v4; // [rsp+4h] [rbp-1Ch]
  int v5; // [rsp+4h] [rbp-1Ch]
  int v6; // [rsp+4h] [rbp-1Ch]
  int v7; // [rsp+4h] [rbp-1Ch]
  int v8; // [rsp+4h] [rbp-1Ch]
  int v9; // [rsp+4h] [rbp-1Ch]
  int v10; // [rsp+4h] [rbp-1Ch]
  int v11; // [rsp+4h] [rbp-1Ch]
  int v12; // [rsp+4h] [rbp-1Ch]
  char v13[11]; // [rsp+Dh] [rbp-13h] BYREF
  char v14[11]; // [rsp+Eh] [rbp-12h] BYREF
  char v15[11]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v16; // [rsp+18h] [rbp-8h]
 
  v16 = __readfsqword(0x28u);  // __readfsqword指令的参数是一个偏移量,0x28u是一个无符号整数常量,值为0x28,即40,表示从FS寄存器中的偏移量为40的地址开始读取64位数据。
  for ( i = 0; i < 11; ++i )
    v13[i] = 0;
  printf("Welcome to QilingLab.\nHere is the list of challenges:");
  printf("\nChallenge 1: Store 1337 at pointer 0x1337.");
  printf("\nChallenge 2: Make the 'uname' syscall return the correct values.");
  printf("\nChallenge 3: Make '/dev/urandom' and 'getrandom' \"collide\".");
  printf("\nChallenge 4: Enter inside the \"forbidden\" loop.");
  printf("\nChallenge 5: Guess every call to rand().");
  printf("\nChallenge 6: Avoid the infinite loop.");
  printf("\nChallenge 7: Don't waste time waiting for 'sleep'.");
  printf("\nChallenge 8: Unpack the struct and write at the target address.");
  printf("\nChallenge 9: Fix some string operation to make the iMpOsSiBlE come true.");
  printf("\nChallenge 10: Fake the 'cmdline' line file to return the right content.");
  printf("\nChallenge 11: Bypass CPUID/MIDR_EL1 checks.");
  puts(
    "\n"
    "\n"
    "Checking which challenge are solved...\n"
    "Note: Some challenges will results in segfaults and infinite loops if they aren't solved.");
  challenge1(v13);
  v3 = checker(v13, 0LL);
  challenge2(v14);
  v4 = checker(v13, 1LL) + v3;
  challenge3(&v14[1]);
  v5 = checker(v13, 2LL) + v4;
  challenge4(v15);
  v6 = checker(v13, 3LL) + v5;
  challenge5(&v15[1]);
  v7 = checker(v13, 4LL) + v6;
  challenge6(&v15[2]);
  v8 = checker(v13, 5LL) + v7;
  challenge7(&v15[3]);
  v9 = checker(v13, 6LL) + v8;
  challenge8(&v15[4]);
  v10 = checker(v13, 7LL) + v9;
  challenge9(&v15[5]);
  v11 = checker(v13, 8LL) + v10;
  challenge10(&v15[6]);
  v12 = checker(v13, 9LL) + v11;
  challenge11(&v15[7]);
  v0 = checker(v13, 10LL);
  printf("\nYou solved %d/%d of the challenges\n", (unsigned int)(v0 + v12), 11LL);
  return __readfsqword(0x28u) ^ v16;
}
__int64 __fastcall checker(__int64 a1, int a2)
{
  __int64 result; // rax
 
  if ( *(_BYTE *)(a2 + a1) ) ; 检查数组a1中下标为a2的元素是否为0,非0返回1
  {
    printf("\nChallenge %d: SOLVED", (unsigned int)(a2 + 1));
    result = 1LL;
  }
  else
  {
    printf("\nChallenge %d: NOT SOLVED", (unsigned int)(a2 + 1));
    result = 0LL;
  }
  return result;
}
__int64 __fastcall checker(__int64 a1, int a2)
{
  __int64 result; // rax
 
  if ( *(_BYTE *)(a2 + a1) ) ; 检查数组a1中下标为a2的元素是否为0,非0返回1
  {
    printf("\nChallenge %d: SOLVED", (unsigned int)(a2 + 1));
    result = 1LL;
  }
  else
  {
    printf("\nChallenge %d: NOT SOLVED", (unsigned int)(a2 + 1));
    result = 0LL;
  }
  return result;
}
.text:0000000000000B8A                 public challenge1
.text:0000000000000B8A challenge1      proc near               ; CODE XREF: start+123↓p
.text:0000000000000B8A
.text:0000000000000B8A var_18          = qword ptr -18h        ; 分配quadword类型的局部变量var_18位于[rbp-18h]的位置
.text:0000000000000B8A var_C           = dword ptr -0Ch        ; qword 8字节,dword 4字节
.text:0000000000000B8A var_8           = qword ptr -8
.text:0000000000000B8A
.text:0000000000000B8A ; __unwind {
.text:0000000000000B8A                 push    rbp
.text:0000000000000B8B                 mov     rbp, rsp
.text:0000000000000B8E                 mov     [rbp+var_18], rdi  ; [rbp-18h], rdi 此处rdi值为指向v13的指针
.text:0000000000000B92                 mov     [rbp+var_8], 1337h
.text:0000000000000B9A                 mov     rax, [rbp+var_8]
.text:0000000000000B9E                 mov     eax, [rax]         ; 将内存地址1337h的值传递给eax
.text:0000000000000BA0                 mov     [rbp+var_C], eax
.text:0000000000000BA3                 cmp     [rbp+var_C], 539h  ; cmp jnz: 不相等就跳转loc_BB3进行retn (539h = 1337)
.text:0000000000000BAA                 jnz     short loc_BB3
.text:0000000000000BAC                 mov     rax, [rbp+var_18]
.text:0000000000000BB0                 mov     byte ptr [rax], 1  ; 将值为1的字节写入存储在rax所指向的内存地址中
.text:0000000000000BB3
.text:0000000000000BB3 loc_BB3:                                ; CODE XREF: challenge1+20↑j
.text:0000000000000BB3                 nop
.text:0000000000000BB4                 pop     rbp
.text:0000000000000BB5                 retn
.text:0000000000000BB5 ; } // starts at B8A
.text:0000000000000B8A                 public challenge1
.text:0000000000000B8A challenge1      proc near               ; CODE XREF: start+123↓p
.text:0000000000000B8A
.text:0000000000000B8A var_18          = qword ptr -18h        ; 分配quadword类型的局部变量var_18位于[rbp-18h]的位置
.text:0000000000000B8A var_C           = dword ptr -0Ch        ; qword 8字节,dword 4字节
.text:0000000000000B8A var_8           = qword ptr -8
.text:0000000000000B8A
.text:0000000000000B8A ; __unwind {
.text:0000000000000B8A                 push    rbp
.text:0000000000000B8B                 mov     rbp, rsp
.text:0000000000000B8E                 mov     [rbp+var_18], rdi  ; [rbp-18h], rdi 此处rdi值为指向v13的指针
.text:0000000000000B92                 mov     [rbp+var_8], 1337h
.text:0000000000000B9A                 mov     rax, [rbp+var_8]
.text:0000000000000B9E                 mov     eax, [rax]         ; 将内存地址1337h的值传递给eax
.text:0000000000000BA0                 mov     [rbp+var_C], eax
.text:0000000000000BA3                 cmp     [rbp+var_C], 539h  ; cmp jnz: 不相等就跳转loc_BB3进行retn (539h = 1337)
.text:0000000000000BAA                 jnz     short loc_BB3
.text:0000000000000BAC                 mov     rax, [rbp+var_18]
.text:0000000000000BB0                 mov     byte ptr [rax], 1  ; 将值为1的字节写入存储在rax所指向的内存地址中
.text:0000000000000BB3
.text:0000000000000BB3 loc_BB3:                                ; CODE XREF: challenge1+20↑j
.text:0000000000000BB3                 nop
.text:0000000000000BB4                 pop     rbp
.text:0000000000000BB5                 retn
.text:0000000000000BB5 ; } // starts at B8A
.text:0000000000000B8E                 mov     [rbp+var_18], rdi
 
...
 
.text:0000000000000BAC                 mov     rax, [rbp+var_18]
.text:0000000000000BB0                 mov     byte ptr [rax], 1
.text:0000000000000B8E                 mov     [rbp+var_18], rdi
 
...
 
.text:0000000000000BAC                 mov     rax, [rbp+var_18]
.text:0000000000000BB0                 mov     byte ptr [rax], 1
_BYTE *__fastcall challenge1(_BYTE *a1)
{
  _BYTE *result; // rax
 
  result = (_BYTE *)*(unsigned int *)((char *)&loc_1335 + 2); // 标识符loc_xxxx通常用于表示一个内存地址或常量值
  if ( *(_DWORD *)((char *)&loc_1335 + 2) == 1337 )
  {
    result = a1;
    *a1 = 1;
  }
  return result;
}
_BYTE *__fastcall challenge1(_BYTE *a1)
{
  _BYTE *result; // rax
 
  result = (_BYTE *)*(unsigned int *)((char *)&loc_1335 + 2); // 标识符loc_xxxx通常用于表示一个内存地址或常量值
  if ( *(_DWORD *)((char *)&loc_1335 + 2) == 1337 )
  {
    result = a1;
    *a1 = 1;
  }
  return result;
}
ql.mem.write(0x1000, b'\x41\x42\x43') # 手动输入
 
ql.pack(">I", 0x12345678) # 函数调用将返回一个4字节的大端序字节序列,其中包含整数值 0x12345678 的二进制表示。
                          # ">I"参数指定了这个字节序列的格式,其中">"表示大端序,"<"表示小端序,"I"表示一个32位无符号整数。
 
ql.pack16(0x1234)         # 这个函数专门用于16位整数
ql.mem.write(0x1000, b'\x41\x42\x43') # 手动输入
 
ql.pack(">I", 0x12345678) # 函数调用将返回一个4字节的大端序字节序列,其中包含整数值 0x12345678 的二进制表示。
                          # ">I"参数指定了这个字节序列的格式,其中">"表示大端序,"<"表示小端序,"I"表示一个32位无符号整数。
 
ql.pack16(0x1234)         # 这个函数专门用于16位整数
from qiling import *
 
def challenge1(ql):
    ql.mem.map(0x1000, 0x1000, info='[challenge1]')
    # 为地址范围 [0x1000, 0x2000) 映射了一块内存,第一个参数0x1000是映射的起始地址,第二个参数0x1000是映射的大小,映射的大小必须是页大小的倍数,这里的页大小是 Qiling模拟器的默认页大小,4096字节。info是对这部分内存做的一个标记,后续Qiling如果想接着使用的话就可以用这个标记来定位。
    ql.mem.write(0x1337, ql.pack16(1337))
    # 将整数值 1337 转换为一个16位字节序列写入内存地址 0x1337 所指定的内存位置,小端输入
 
if __name__ == '__main__':
    path = ["qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    challenge1(ql)
    ql.run()
from qiling import *
 
def challenge1(ql):
    ql.mem.map(0x1000, 0x1000, info='[challenge1]')
    # 为地址范围 [0x1000, 0x2000) 映射了一块内存,第一个参数0x1000是映射的起始地址,第二个参数0x1000是映射的大小,映射的大小必须是页大小的倍数,这里的页大小是 Qiling模拟器的默认页大小,4096字节。info是对这部分内存做的一个标记,后续Qiling如果想接着使用的话就可以用这个标记来定位。
    ql.mem.write(0x1337, ql.pack16(1337))
    # 将整数值 1337 转换为一个16位字节序列写入内存地址 0x1337 所指定的内存位置,小端输入
 
if __name__ == '__main__':
    path = ["qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    challenge1(ql)
    ql.run()
Challenge 11: Bypass CPUID/MIDR_EL1 checks.
 
Checking which challenge are solved...
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x54) = 0x54
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x5a) = 0x5a
 
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x1) = 0x1
[=]     uname(buf = 0x80000000db70) = 0x0
Challenge 1: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     openat(fd = 0xffffff9c, path = 0x555555555698, flags = 0x0, mode = 0x0) = -0x2 (ENOENT)
[=]     read(fd = 0xffffffff, buf = 0x80000000dce0, length = 0x20) = -0x9 (EBADF)
[=]     read(fd = 0xffffffff, buf = 0x80000000dcdf, length = 0x1) = -0x9 (EBADF)
[=]     close(fd = 0xffffffff) = -0x1 (EPERM)
[=]     getrandom(buf = 0x80000000dd00, buflen = 0x20, flags = 0x1) = 0x20
Challenge 2: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
Challenge 3: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
[=]     time() = 0x64704df9
Challenge 4: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
Challenge 11: Bypass CPUID/MIDR_EL1 checks.
 
Checking which challenge are solved...
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x54) = 0x54
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x5a) = 0x5a
 
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x1) = 0x1
[=]     uname(buf = 0x80000000db70) = 0x0
Challenge 1: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     openat(fd = 0xffffff9c, path = 0x555555555698, flags = 0x0, mode = 0x0) = -0x2 (ENOENT)
[=]     read(fd = 0xffffffff, buf = 0x80000000dce0, length = 0x20) = -0x9 (EBADF)
[=]     read(fd = 0xffffffff, buf = 0x80000000dcdf, length = 0x1) = -0x9 (EBADF)
[=]     close(fd = 0xffffffff) = -0x1 (EPERM)
[=]     getrandom(buf = 0x80000000dd00, buflen = 0x20, flags = 0x1) = 0x20
Challenge 2: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
Challenge 3: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
[=]     time() = 0x64704df9
Challenge 4: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
 
sudo chroot ./ ./qemu-arm-static -g 12345 ./bin/httpd
sudo chroot ./ ./qemu-arm-static -g 12345 ./bin/httpd
ql.debugger = 'gdb:0.0.0.0:12345'
ql.debugger = 'gdb:0.0.0.0:12345'
 
 
 
 
 
ValueError: '/home/ubuntu/Desktop/qilinglab/qilinglab-x86_64' does not start with '/home/ubuntu/Desktop/qilinglab/rootfs/x8664_linux'
ValueError: '/home/ubuntu/Desktop/qilinglab/qilinglab-x86_64' does not start with '/home/ubuntu/Desktop/qilinglab/rootfs/x8664_linux'
from qiling import *
 
def challenge1(ql):
    ql.mem.map(0x1000, 0x1000, info='[challenge1]')
    ql.mem.write(0x1337, ql.pack16(1337))
 
if __name__ == '__main__':
    path = ["rootfs/x8664_linux/qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    challenge1(ql)
    ql.debugger = 'gdb:0.0.0.0:12345'
    ql.run()
from qiling import *
 
def challenge1(ql):
    ql.mem.map(0x1000, 0x1000, info='[challenge1]')
    ql.mem.write(0x1337, ql.pack16(1337))
 
if __name__ == '__main__':
    path = ["rootfs/x8664_linux/qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    challenge1(ql)
    ql.debugger = 'gdb:0.0.0.0:12345'
    ql.run()
 
 
.text:0000555555554BB6                 public challenge2
.text:0000555555554BB6 challenge2      proc near               ; CODE XREF: start+147↓p
.text:0000555555554BB6
.text:0000555555554BB6 var_1D8         = qword ptr -1D8h
.text:0000555555554BB6 var_1D0         = dword ptr -1D0h
.text:0000555555554BB6 var_1CC         = dword ptr -1CCh
.text:0000555555554BB6 var_1C8         = dword ptr -1C8h
.text:0000555555554BB6 var_1C4         = dword ptr -1C4h
.text:0000555555554BB6 name            = utsname ptr -1C0h
.text:0000555555554BB6 s               = byte ptr -3Ah
.text:0000555555554BB6 var_32          = word ptr -32h
.text:0000555555554BB6 var_30          = byte ptr -30h
.text:0000555555554BB6 var_18          = qword ptr -18h
.text:0000555555554BB6
.text:0000555555554BB6                 push    rbp
.text:0000555555554BB7                 mov     rbp, rsp
.text:0000555555554BBA                 push    rbx
.text:0000555555554BBB                 sub     rsp, 1D8h
.text:0000555555554BC2                 mov     [rbp+var_1D8], rdi
.text:0000555555554BC9                 mov     rax, fs:28h     ; 从Segment fs(用于TLS)对应的内存段,偏移量40h处取一个值,把这个值加载到rax寄存器
.text:0000555555554BD2                 mov     [rbp+var_18], rax
.text:0000555555554BD6                 xor     eax, eax        ; 清零eax寄存器,更新零标志位ZF = 1(表示eax为0)
.text:0000555555554BD8                 lea     rax, [rbp+name] ; 将[rbp+name]的地址传给rax
.text:0000555555554BDF                 mov     rdi, rax        ; name
.text:0000555555554BE2                 call    _uname
.text:0000555555554BE7                 test    eax, eax        ; 不修改eax的内容,只更新标志位
.text:0000555555554BE9                 jz      short loc_555555554BFC ; ZF=1,则转移到目的地址
.text:0000555555554BEB                 lea     rdi, s          ; "uname"
.text:0000555555554BF2                 call    _perror         ; _perror() 用于打印错误信息
.text:0000555555554BF7                 jmp     loc_555555554D13
.text:0000555555554BFC ; ---------------------------------------------------------------------------
.text:0000555555554BFC
.text:0000555555554BFC loc_555555554BFC:                       ; CODE XREF: challenge2+33↑j
.text:0000555555554BFC                 mov     rax, cs:qword_55555555567E
.text:0000555555554C03                 mov     qword ptr [rbp+s], rax
.text:0000555555554C07                 movzx   eax, cs:word_555555555686
.text:0000555555554C0E                 mov     [rbp+var_32], ax
.text:0000555555554C12                 mov     rax, cs:qword_555555555688
.text:0000555555554C19                 mov     rdx, cs:qword_555555555690
.text:0000555555554C20                 mov     qword ptr [rbp+var_30], rax
.text:0000555555554C24                 mov     qword ptr [rbp+var_30+8], rdx
.text:0000555555554C28                 mov     [rbp+var_1D0], 0
.text:0000555555554C32                 mov     [rbp+var_1CC], 0
.text:0000555555554C3C                 jmp     short loc_555555554C6D
.text:0000555555554C3E ; ---------------------------------------------------------------------------
.text:0000555555554C3E
.text:0000555555554C3E loc_555555554C3E:                       ; CODE XREF: challenge2+CF↓j
.text:0000555555554C3E                 mov     eax, [rbp+var_1C8]
.text:0000555555554C44                 cdqe
.text:0000555555554C46                 movzx   edx, [rbp+rax+name.sysname]
.text:0000555555554C4E                 mov     eax, [rbp+var_1C8]
.text:0000555555554C54                 cdqe
.text:0000555555554C56                 movzx   eax, [rbp+rax+s]
.text:0000555555554C5B                 cmp     dl, al
.text:0000555555554C5D                 jnz     short loc_555555554C66
.text:0000555555554C5F                 add     [rbp+var_1D0], 1
.text:0000555555554C66
.text:0000555555554C66 loc_555555554C66:                       ; CODE XREF: challenge2+A7↑j
.text:0000555555554C66                 add     [rbp+var_1C8], 1
.text:0000555555554C6D
.text:0000555555554C6D loc_555555554C6D:                       ; CODE XREF: challenge2+86↑j
.text:0000555555554C6D                 mov     eax, [rbp+var_1C8]
.text:0000555555554C73                 movsxd  rbx, eax
.text:0000555555554C76                 lea     rax, [rbp+s]
.text:0000555555554C7A                 mov     rdi, rax        ; s
.text:0000555555554C7D                 call    _strlen
.text:0000555555554C82                 cmp     rbx, rax        ; 相等,则ZF=1, CF=0, OF=0
                                                               ; 小于,则ZF=0, CF=1, OF=0
                                                               ; 大于,则ZF=0, CF=0, OF=0
.text:0000555555554C85                 jb      short loc_555555554C3E ; 前一条指令执行的结果为小于则跳转
.text:0000555555554C87                 jmp     short loc_555555554CB8 ; 此处跳出循环
.text:0000555555554C89 ; ---------------------------------------------------------------------------
.text:0000555555554C89
.text:0000555555554C89 loc_555555554C89:                       ; CODE XREF: challenge2+11A↓j
.text:0000555555554C89                 mov     eax, [rbp+var_1C4]
.text:0000555555554C8F                 cdqe
.text:0000555555554C91                 movzx   edx, [rbp+rax+name.version]
.text:0000555555554C99                 mov     eax, [rbp+var_1C4]
.text:0000555555554C9F                 cdqe
.text:0000555555554CA1                 movzx   eax, [rbp+rax+var_30]
.text:0000555555554CA6                 cmp     dl, al
.text:0000555555554CA8                 jnz     short loc_555555554CB1
.text:0000555555554CAA                 add     [rbp+var_1CC], 1
.text:0000555555554CB1
.text:0000555555554CB1 loc_555555554CB1:                       ; CODE XREF: challenge2+F2↑j
.text:0000555555554CB1                 add     [rbp+var_1C4], 1
.text:0000555555554CB8
.text:0000555555554CB8 loc_555555554CB8:                       ; CODE XREF: challenge2+D1↑j
.text:0000555555554CB8                 mov     eax, [rbp+var_1C4]
.text:0000555555554CBE                 movsxd  rbx, eax        ; 将eax寄存器中的32位符号扩展为64位,并将结果存储到rbx寄存器中
.text:0000555555554CC1                 lea     rax, [rbp+var_30]
.text:0000555555554CC5                 mov     rdi, rax        ; s
.text:0000555555554CC8                 call    _strlen
.text:0000555555554CCD                 cmp     rbx, rax
.text:0000555555554CD0                 jb      short loc_555555554C89
.text:0000555555554CD2                 mov     ebx, [rbp+var_1D0]
.text:0000555555554CD8                 lea     rax, [rbp+s]
.text:0000555555554CDC                 mov     rdi, rax        ; s
.text:0000555555554CDF                 call    _strlen
.text:0000555555554CE4                 cmp     rbx, rax
.text:0000555555554CE7                 jnz     short loc_555555554D13
.text:0000555555554CE9                 mov     ebx, [rbp+var_1CC]
.text:0000555555554CEF                 lea     rax, [rbp+var_30]
.text:0000555555554CF3                 mov     rdi, rax        ; s
.text:0000555555554CF6                 call    _strlen
.text:0000555555554CFB                 cmp     rbx, rax
.text:0000555555554CFE                 jnz     short loc_555555554D13
.text:0000555555554D00                 cmp     [rbp+var_1D0], 5
.text:0000555555554D07                 jbe     short loc_555555554D13
.text:0000555555554D09                 mov     rax, [rbp+var_1D8]
.text:0000555555554D10                 mov     byte ptr [rax], 1
.text:0000555555554D13
.text:0000555555554D13 loc_555555554D13:                       ; CODE XREF: challenge2+41↑j
.text:0000555555554D13                                         ; challenge2+131↑j ...
.text:0000555555554D13                 mov     rax, [rbp+var_18]
.text:0000555555554D17                 xor     rax, fs:28h
.text:0000555555554D20                 jz      short loc_555555554D27
.text:0000555555554D22                 call    ___stack_chk_fail
.text:0000555555554D27 ; ---------------------------------------------------------------------------
.text:0000555555554D27
.text:0000555555554D27 loc_555555554D27:                       ; CODE XREF: challenge2+16A↑j
.text:0000555555554D27                 add     rsp, 1D8h
.text:0000555555554D2E                 pop     rbx
.text:0000555555554D2F                 pop     rbp
.text:0000555555554D30                 retn
.text:0000555555554D30 challenge2      endp
.text:0000555555554BB6                 public challenge2
.text:0000555555554BB6 challenge2      proc near               ; CODE XREF: start+147↓p
.text:0000555555554BB6
.text:0000555555554BB6 var_1D8         = qword ptr -1D8h
.text:0000555555554BB6 var_1D0         = dword ptr -1D0h
.text:0000555555554BB6 var_1CC         = dword ptr -1CCh
.text:0000555555554BB6 var_1C8         = dword ptr -1C8h
.text:0000555555554BB6 var_1C4         = dword ptr -1C4h
.text:0000555555554BB6 name            = utsname ptr -1C0h
.text:0000555555554BB6 s               = byte ptr -3Ah
.text:0000555555554BB6 var_32          = word ptr -32h
.text:0000555555554BB6 var_30          = byte ptr -30h
.text:0000555555554BB6 var_18          = qword ptr -18h
.text:0000555555554BB6
.text:0000555555554BB6                 push    rbp
.text:0000555555554BB7                 mov     rbp, rsp
.text:0000555555554BBA                 push    rbx
.text:0000555555554BBB                 sub     rsp, 1D8h
.text:0000555555554BC2                 mov     [rbp+var_1D8], rdi
.text:0000555555554BC9                 mov     rax, fs:28h     ; 从Segment fs(用于TLS)对应的内存段,偏移量40h处取一个值,把这个值加载到rax寄存器
.text:0000555555554BD2                 mov     [rbp+var_18], rax
.text:0000555555554BD6                 xor     eax, eax        ; 清零eax寄存器,更新零标志位ZF = 1(表示eax为0)
.text:0000555555554BD8                 lea     rax, [rbp+name] ; 将[rbp+name]的地址传给rax
.text:0000555555554BDF                 mov     rdi, rax        ; name
.text:0000555555554BE2                 call    _uname
.text:0000555555554BE7                 test    eax, eax        ; 不修改eax的内容,只更新标志位
.text:0000555555554BE9                 jz      short loc_555555554BFC ; ZF=1,则转移到目的地址
.text:0000555555554BEB                 lea     rdi, s          ; "uname"
.text:0000555555554BF2                 call    _perror         ; _perror() 用于打印错误信息
.text:0000555555554BF7                 jmp     loc_555555554D13
.text:0000555555554BFC ; ---------------------------------------------------------------------------
.text:0000555555554BFC
.text:0000555555554BFC loc_555555554BFC:                       ; CODE XREF: challenge2+33↑j
.text:0000555555554BFC                 mov     rax, cs:qword_55555555567E
.text:0000555555554C03                 mov     qword ptr [rbp+s], rax
.text:0000555555554C07                 movzx   eax, cs:word_555555555686
.text:0000555555554C0E                 mov     [rbp+var_32], ax
.text:0000555555554C12                 mov     rax, cs:qword_555555555688
.text:0000555555554C19                 mov     rdx, cs:qword_555555555690
.text:0000555555554C20                 mov     qword ptr [rbp+var_30], rax
.text:0000555555554C24                 mov     qword ptr [rbp+var_30+8], rdx
.text:0000555555554C28                 mov     [rbp+var_1D0], 0
.text:0000555555554C32                 mov     [rbp+var_1CC], 0
.text:0000555555554C3C                 jmp     short loc_555555554C6D
.text:0000555555554C3E ; ---------------------------------------------------------------------------
.text:0000555555554C3E
.text:0000555555554C3E loc_555555554C3E:                       ; CODE XREF: challenge2+CF↓j
.text:0000555555554C3E                 mov     eax, [rbp+var_1C8]
.text:0000555555554C44                 cdqe
.text:0000555555554C46                 movzx   edx, [rbp+rax+name.sysname]
.text:0000555555554C4E                 mov     eax, [rbp+var_1C8]
.text:0000555555554C54                 cdqe
.text:0000555555554C56                 movzx   eax, [rbp+rax+s]
.text:0000555555554C5B                 cmp     dl, al
.text:0000555555554C5D                 jnz     short loc_555555554C66
.text:0000555555554C5F                 add     [rbp+var_1D0], 1
.text:0000555555554C66
.text:0000555555554C66 loc_555555554C66:                       ; CODE XREF: challenge2+A7↑j
.text:0000555555554C66                 add     [rbp+var_1C8], 1
.text:0000555555554C6D
.text:0000555555554C6D loc_555555554C6D:                       ; CODE XREF: challenge2+86↑j
.text:0000555555554C6D                 mov     eax, [rbp+var_1C8]
.text:0000555555554C73                 movsxd  rbx, eax
.text:0000555555554C76                 lea     rax, [rbp+s]
.text:0000555555554C7A                 mov     rdi, rax        ; s
.text:0000555555554C7D                 call    _strlen
.text:0000555555554C82                 cmp     rbx, rax        ; 相等,则ZF=1, CF=0, OF=0
                                                               ; 小于,则ZF=0, CF=1, OF=0
                                                               ; 大于,则ZF=0, CF=0, OF=0
.text:0000555555554C85                 jb      short loc_555555554C3E ; 前一条指令执行的结果为小于则跳转
.text:0000555555554C87                 jmp     short loc_555555554CB8 ; 此处跳出循环
.text:0000555555554C89 ; ---------------------------------------------------------------------------
.text:0000555555554C89
.text:0000555555554C89 loc_555555554C89:                       ; CODE XREF: challenge2+11A↓j
.text:0000555555554C89                 mov     eax, [rbp+var_1C4]
.text:0000555555554C8F                 cdqe
.text:0000555555554C91                 movzx   edx, [rbp+rax+name.version]
.text:0000555555554C99                 mov     eax, [rbp+var_1C4]
.text:0000555555554C9F                 cdqe
.text:0000555555554CA1                 movzx   eax, [rbp+rax+var_30]
.text:0000555555554CA6                 cmp     dl, al
.text:0000555555554CA8                 jnz     short loc_555555554CB1
.text:0000555555554CAA                 add     [rbp+var_1CC], 1
.text:0000555555554CB1
.text:0000555555554CB1 loc_555555554CB1:                       ; CODE XREF: challenge2+F2↑j
.text:0000555555554CB1                 add     [rbp+var_1C4], 1
.text:0000555555554CB8
.text:0000555555554CB8 loc_555555554CB8:                       ; CODE XREF: challenge2+D1↑j
.text:0000555555554CB8                 mov     eax, [rbp+var_1C4]
.text:0000555555554CBE                 movsxd  rbx, eax        ; 将eax寄存器中的32位符号扩展为64位,并将结果存储到rbx寄存器中
.text:0000555555554CC1                 lea     rax, [rbp+var_30]
.text:0000555555554CC5                 mov     rdi, rax        ; s
.text:0000555555554CC8                 call    _strlen
.text:0000555555554CCD                 cmp     rbx, rax
.text:0000555555554CD0                 jb      short loc_555555554C89
.text:0000555555554CD2                 mov     ebx, [rbp+var_1D0]
.text:0000555555554CD8                 lea     rax, [rbp+s]
.text:0000555555554CDC                 mov     rdi, rax        ; s
.text:0000555555554CDF                 call    _strlen
.text:0000555555554CE4                 cmp     rbx, rax
.text:0000555555554CE7                 jnz     short loc_555555554D13
.text:0000555555554CE9                 mov     ebx, [rbp+var_1CC]
.text:0000555555554CEF                 lea     rax, [rbp+var_30]
.text:0000555555554CF3                 mov     rdi, rax        ; s
.text:0000555555554CF6                 call    _strlen
.text:0000555555554CFB                 cmp     rbx, rax
.text:0000555555554CFE                 jnz     short loc_555555554D13
.text:0000555555554D00                 cmp     [rbp+var_1D0], 5
.text:0000555555554D07                 jbe     short loc_555555554D13
.text:0000555555554D09                 mov     rax, [rbp+var_1D8]
.text:0000555555554D10                 mov     byte ptr [rax], 1
.text:0000555555554D13
.text:0000555555554D13 loc_555555554D13:                       ; CODE XREF: challenge2+41↑j
.text:0000555555554D13                                         ; challenge2+131↑j ...
.text:0000555555554D13                 mov     rax, [rbp+var_18]
.text:0000555555554D17                 xor     rax, fs:28h
.text:0000555555554D20                 jz      short loc_555555554D27
.text:0000555555554D22                 call    ___stack_chk_fail
.text:0000555555554D27 ; ---------------------------------------------------------------------------
.text:0000555555554D27
.text:0000555555554D27 loc_555555554D27:                       ; CODE XREF: challenge2+16A↑j
.text:0000555555554D27                 add     rsp, 1D8h
.text:0000555555554D2E                 pop     rbx
.text:0000555555554D2F                 pop     rbp
.text:0000555555554D30                 retn
.text:0000555555554D30 challenge2      endp
 
unsigned __int64 __fastcall challenge2(_BYTE *a1)
{
  unsigned int v2; // [rsp+10h] [rbp-1D0h]
  int v3; // [rsp+14h] [rbp-1CCh]
  int v4; // [rsp+18h] [rbp-1C8h]
  int v5; // [rsp+1Ch] [rbp-1C4h]
  struct utsname name; // [rsp+20h] [rbp-1C0h] BYREF
  char s[10]; // [rsp+1A6h] [rbp-3Ah] BYREF
  char v8[24]; // [rsp+1B0h] [rbp-30h] BYREF
  unsigned __int64 v9; // [rsp+1C8h] [rbp-18h]
 
  v9 = __readfsqword(0x28u);
  if ( uname(&name) )
  {
    perror("uname");
  }
  else
  {
    strcpy(s, "QilingOS");
    strcpy(v8, "ChallengeStart");
    v2 = 0;
    v3 = 0;
    while ( v4 < strlen(s) )
    {
      if ( name.sysname[v4] == s[v4] )
        ++v2;
      ++v4;
    }
    while ( v5 < strlen(v8) )
    {
      if ( name.version[v5] == v8[v5] )
        ++v3;
      ++v5;
    }
    if ( v2 == strlen(s) && v3 == strlen(v8) && v2 > 5 )
      *a1 = 1;
  }
  return __readfsqword(0x28u) ^ v9;
}
unsigned __int64 __fastcall challenge2(_BYTE *a1)
{
  unsigned int v2; // [rsp+10h] [rbp-1D0h]
  int v3; // [rsp+14h] [rbp-1CCh]
  int v4; // [rsp+18h] [rbp-1C8h]
  int v5; // [rsp+1Ch] [rbp-1C4h]
  struct utsname name; // [rsp+20h] [rbp-1C0h] BYREF
  char s[10]; // [rsp+1A6h] [rbp-3Ah] BYREF
  char v8[24]; // [rsp+1B0h] [rbp-30h] BYREF
  unsigned __int64 v9; // [rsp+1C8h] [rbp-18h]
 
  v9 = __readfsqword(0x28u);
  if ( uname(&name) )
  {
    perror("uname");
  }
  else
  {
    strcpy(s, "QilingOS");
    strcpy(v8, "ChallengeStart");
    v2 = 0;
    v3 = 0;
    while ( v4 < strlen(s) )
    {
      if ( name.sysname[v4] == s[v4] )
        ++v2;
      ++v4;
    }
    while ( v5 < strlen(v8) )
    {
      if ( name.version[v5] == v8[v5] )
        ++v3;
      ++v5;
    }
    if ( v2 == strlen(s) && v3 == strlen(v8) && v2 > 5 )
      *a1 = 1;
  }
  return __readfsqword(0x28u) ^ v9;
}
if ( uname(&name) )
{
  perror("uname");
}
if ( uname(&name) )
{
  perror("uname");
}
struct utsname {
    char sysname[65];
    char nodename[65];
    char release[65];  
    char version[65];
    char machine[65];
    char domainname[65];
};
struct utsname {
    char sysname[65];
    char nodename[65];
    char release[65];  
    char version[65];
    char machine[65];
    char domainname[65];
};
 
void  challenge2(char *check) {
    unsigned int i, j, k, l;
    struct utsname name;
    char qiling_OS[10];
    char chall_start[24];
 
    if ( uname(&name) ) {
        perror("uname");
    }
    else {
        strcpy(qiling_OS, "QilingOS");
        strcpy(chall_start, "ChallengeStart");
        i = 0;
        j = 0;
        while ( k < strlen(qiling_OS) ) {
            if ( name.sysname[k] == qiling_OS[k] )
                ++i;
            ++k;
        }
        while ( l < strlen(chall_start) ) {
            if ( name.version[l] == chall_start[l] )
                ++j;
            ++l;
        }
        if ( i == strlen(qiling_OS) && j == strlen(chall_start) && i > 5 )
            *check = 1;
    }
}
void  challenge2(char *check) {
    unsigned int i, j, k, l;
    struct utsname name;
    char qiling_OS[10];
    char chall_start[24];
 
    if ( uname(&name) ) {
        perror("uname");
    }
    else {
        strcpy(qiling_OS, "QilingOS");
        strcpy(chall_start, "ChallengeStart");
        i = 0;
        j = 0;
        while ( k < strlen(qiling_OS) ) {
            if ( name.sysname[k] == qiling_OS[k] )
                ++i;
            ++k;
        }
        while ( l < strlen(chall_start) ) {
            if ( name.version[l] == chall_start[l] )
                ++j;
            ++l;
        }
        if ( i == strlen(qiling_OS) && j == strlen(chall_start) && i > 5 )
            *check = 1;
    }
}
from qiling import *
from qiling.const import * # 导入Qiling模拟器中的常量
 
def my_uname_on_exit_hook(ql, *args):
    rdi = ql.arch.regs.rdi
    print(f"utsname address: {hex(rdi)}") # utsname address: 0x80000000db50
    ql.mem.write(rdi, b'QilingOS\x00')
    ql.mem.write(rdi + 65 * 3, b'ChallengeStart\x00') # 000080000000DC13
 
def challenge2(ql):
    # 使用QL_INTERCEPT.EXIT在系统调用执行完成之后立即执行hook函数,ql.os.set_syscall 使用方法在官方文档 Hijack 部分
    ql.os.set_syscall("uname", my_uname_on_exit_hook, QL_INTERCEPT.EXIT)
 
if __name__ == '__main__':
    path = ["rootfs/x8664_linux/qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    # 记得加上challenge1
    challenge2(ql)
    ql.run()
from qiling import *
from qiling.const import * # 导入Qiling模拟器中的常量
 
def my_uname_on_exit_hook(ql, *args):
    rdi = ql.arch.regs.rdi
    print(f"utsname address: {hex(rdi)}") # utsname address: 0x80000000db50
    ql.mem.write(rdi, b'QilingOS\x00')
    ql.mem.write(rdi + 65 * 3, b'ChallengeStart\x00') # 000080000000DC13
 
def challenge2(ql):
    # 使用QL_INTERCEPT.EXIT在系统调用执行完成之后立即执行hook函数,ql.os.set_syscall 使用方法在官方文档 Hijack 部分
    ql.os.set_syscall("uname", my_uname_on_exit_hook, QL_INTERCEPT.EXIT)
 
if __name__ == '__main__':
    path = ["rootfs/x8664_linux/qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    # 记得加上challenge1
    challenge2(ql)
    ql.run()
 
 
 
 
Checking which challenge are solved...
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x54) = 0x54
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x5a) = 0x5a
 
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x1) = 0x1
[=]     uname(buf = 0x80000000db50) = 0x0
Challenge 1: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     openat(fd = 0xffffff9c, path = 0x555555555698, flags = 0x0, mode = 0x0) = -0x2 (ENOENT)
[=]     read(fd = 0xffffffff, buf = 0x80000000dcc0, length = 0x20) = -0x9 (EBADF)
[=]     read(fd = 0xffffffff, buf = 0x80000000dcbf, length = 0x1) = -0x9 (EBADF)
[=]     close(fd = 0xffffffff) = -0x1 (EPERM)
[=]     getrandom(buf = 0x80000000dce0, buflen = 0x20, flags = 0x1) = 0x20
Challenge 2: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
Challenge 3: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
[=]     time() = 0x6471f7b0
Challenge 4: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
Checking which challenge are solved...
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x54) = 0x54
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x5a) = 0x5a
 
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x1) = 0x1
[=]     uname(buf = 0x80000000db50) = 0x0
Challenge 1: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     openat(fd = 0xffffff9c, path = 0x555555555698, flags = 0x0, mode = 0x0) = -0x2 (ENOENT)
[=]     read(fd = 0xffffffff, buf = 0x80000000dcc0, length = 0x20) = -0x9 (EBADF)
[=]     read(fd = 0xffffffff, buf = 0x80000000dcbf, length = 0x1) = -0x9 (EBADF)
[=]     close(fd = 0xffffffff) = -0x1 (EPERM)
[=]     getrandom(buf = 0x80000000dce0, buflen = 0x20, flags = 0x1) = 0x20
Challenge 2: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
Challenge 3: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
[=]     time() = 0x6471f7b0
Challenge 4: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
 
.text:0000555555554D31                 public challenge3
.text:0000555555554D31 challenge3      proc near               ; CODE XREF: start+16B↓p
.text:0000555555554D31
.text:0000555555554D31 var_68          = qword ptr -68h
.text:0000555555554D31 var_60          = dword ptr -60h
.text:0000555555554D31 var_5C          = dword ptr -5Ch
.text:0000555555554D31 fd              = dword ptr -58h
.text:0000555555554D31 var_51          = byte ptr -51h
.text:0000555555554D31 buf             = byte ptr -50h
.text:0000555555554D31 var_30          = byte ptr -30h
.text:0000555555554D31 var_8           = qword ptr -8
.text:0000555555554D31
.text:0000555555554D31                 push    rbp
.text:0000555555554D32                 mov     rbp, rsp
.text:0000555555554D35                 sub     rsp, 70h
.text:0000555555554D39                 mov     [rbp+var_68], rdi
.text:0000555555554D3D                 mov     rax, fs:28h
.text:0000555555554D46                 mov     [rbp+var_8], rax
.text:0000555555554D4A                 xor     eax, eax
.text:0000555555554D4C                 mov     esi, 0          ; oflag
.text:0000555555554D51                 lea     rdi, file       ; "/dev/urandom"
.text:0000555555554D58                 mov     eax, 0
.text:0000555555554D5D                 call    _open
.text:0000555555554D62                 mov     [rbp+fd], eax
.text:0000555555554D65                 lea     rcx, [rbp+buf]
.text:0000555555554D69                 mov     eax, [rbp+fd]
.text:0000555555554D6C                 mov     edx, 20h ; ' '  ; nbytes
.text:0000555555554D71                 mov     rsi, rcx        ; buf
.text:0000555555554D74                 mov     edi, eax        ; fd
.text:0000555555554D76                 call    _read
.text:0000555555554D7B                 lea     rcx, [rbp+var_51]
.text:0000555555554D7F                 mov     eax, [rbp+fd]
.text:0000555555554D82                 mov     edx, 1          ; nbytes
.text:0000555555554D87                 mov     rsi, rcx        ; buf
.text:0000555555554D8A                 mov     edi, eax        ; fd
.text:0000555555554D8C                 call    _read
.text:0000555555554D91                 mov     eax, [rbp+fd]
.text:0000555555554D94                 mov     edi, eax        ; fd
.text:0000555555554D96                 call    _close
.text:0000555555554D9B                 lea     rax, [rbp+var_30]
.text:0000555555554D9F                 mov     edx, 1
.text:0000555555554DA4                 mov     esi, 20h ;
.text:0000555555554DA9                 mov     rdi, rax
.text:0000555555554DAC                 call    _getrandom
.text:0000555555554DB1                 mov     [rbp+var_60], 0
.text:0000555555554DB8                 mov     [rbp+var_5C], 0
.text:0000555555554DBF                 jmp     short loc_555555554DF3
.text:0000555555554DC1 ; ---------------------------------------------------------------------------
.text:0000555555554DC1
.text:0000555555554DC1 loc_555555554DC1:                       ; CODE XREF: challenge3+C6↓j
.text:0000555555554DC1                 mov     eax, [rbp+var_5C]
.text:0000555555554DC4                 cdqe
.text:0000555555554DC6                 movzx   edx, [rbp+rax+buf] ; edx清零,读取 rbp+rax+buf 地址处的一个字节,并将其扩充到64位移入edx寄存器低8
.text:0000555555554DCB                 mov     eax, [rbp+var_5C]
.text:0000555555554DCE                 cdqe                       ; 将32位eax值扩展为64位rax值
.text:0000555555554DD0                 movzx   eax, [rbp+rax+var_30]
.text:0000555555554DD5                 cmp     dl, al
.text:0000555555554DD7                 jnz     short loc_555555554DEF
.text:0000555555554DD9                 mov     eax, [rbp+var_5C]
.text:0000555555554DDC                 cdqe
.text:0000555555554DDE                 movzx   edx, [rbp+rax+buf]
.text:0000555555554DE3                 movzx   eax, [rbp+var_51]
.text:0000555555554DE7                 cmp     dl, al             ; di:edx低8位,al:eax低8
.text:0000555555554DE9                 jz      short loc_555555554DEF
.text:0000555555554DEB                 add     [rbp+var_60], 1
.text:0000555555554DEF
.text:0000555555554DEF loc_555555554DEF:                       ; CODE XREF: challenge3+A6↑j
.text:0000555555554DEF                                         ; challenge3+B8↑j
.text:0000555555554DEF                 add     [rbp+var_5C], 1
.text:0000555555554DF3
.text:0000555555554DF3 loc_555555554DF3:                       ; CODE XREF: challenge3+8E↑j
.text:0000555555554DF3                 cmp     [rbp+var_5C], 1Fh
.text:0000555555554DF7                 jle     short loc_555555554DC1 ; 小于或等于则跳转
.text:0000555555554DF9                 cmp     [rbp+var_60], 20h ;
.text:0000555555554DFD                 jnz     short loc_555555554E06
.text:0000555555554DFF                 mov     rax, [rbp+var_68]
.text:0000555555554E03                 mov     byte ptr [rax], 1 ; byte ptr是指定操作数的大小,这里是一个byte
                                                                 ; 将字节值1存储在rax寄存器指向的内存地址中
.text:0000555555554E06
.text:0000555555554E06 loc_555555554E06:                       ; CODE XREF: challenge3+CC↑j
.text:0000555555554E06                 nop
.text:0000555555554E07                 mov     rax, [rbp+var_8]
.text:0000555555554E0B                 xor     rax, fs:28h
.text:0000555555554E14                 jz      short locret_555555554E1B
.text:0000555555554E16                 call    ___stack_chk_fail
.text:0000555555554E1B ; ---------------------------------------------------------------------------
.text:0000555555554E1B
.text:0000555555554E1B locret_555555554E1B:                    ; CODE XREF: challenge3+E3↑j
.text:0000555555554E1B                 leave
.text:0000555555554E1C                 retn
.text:0000555555554E1C challenge3      endp
.text:0000555555554D31                 public challenge3
.text:0000555555554D31 challenge3      proc near               ; CODE XREF: start+16B↓p
.text:0000555555554D31
.text:0000555555554D31 var_68          = qword ptr -68h
.text:0000555555554D31 var_60          = dword ptr -60h
.text:0000555555554D31 var_5C          = dword ptr -5Ch
.text:0000555555554D31 fd              = dword ptr -58h
.text:0000555555554D31 var_51          = byte ptr -51h
.text:0000555555554D31 buf             = byte ptr -50h
.text:0000555555554D31 var_30          = byte ptr -30h
.text:0000555555554D31 var_8           = qword ptr -8
.text:0000555555554D31
.text:0000555555554D31                 push    rbp
.text:0000555555554D32                 mov     rbp, rsp
.text:0000555555554D35                 sub     rsp, 70h
.text:0000555555554D39                 mov     [rbp+var_68], rdi
.text:0000555555554D3D                 mov     rax, fs:28h
.text:0000555555554D46                 mov     [rbp+var_8], rax
.text:0000555555554D4A                 xor     eax, eax
.text:0000555555554D4C                 mov     esi, 0          ; oflag
.text:0000555555554D51                 lea     rdi, file       ; "/dev/urandom"
.text:0000555555554D58                 mov     eax, 0
.text:0000555555554D5D                 call    _open
.text:0000555555554D62                 mov     [rbp+fd], eax
.text:0000555555554D65                 lea     rcx, [rbp+buf]
.text:0000555555554D69                 mov     eax, [rbp+fd]
.text:0000555555554D6C                 mov     edx, 20h ; ' '  ; nbytes
.text:0000555555554D71                 mov     rsi, rcx        ; buf
.text:0000555555554D74                 mov     edi, eax        ; fd
.text:0000555555554D76                 call    _read
.text:0000555555554D7B                 lea     rcx, [rbp+var_51]
.text:0000555555554D7F                 mov     eax, [rbp+fd]
.text:0000555555554D82                 mov     edx, 1          ; nbytes
.text:0000555555554D87                 mov     rsi, rcx        ; buf
.text:0000555555554D8A                 mov     edi, eax        ; fd
.text:0000555555554D8C                 call    _read
.text:0000555555554D91                 mov     eax, [rbp+fd]
.text:0000555555554D94                 mov     edi, eax        ; fd
.text:0000555555554D96                 call    _close
.text:0000555555554D9B                 lea     rax, [rbp+var_30]
.text:0000555555554D9F                 mov     edx, 1
.text:0000555555554DA4                 mov     esi, 20h ;
.text:0000555555554DA9                 mov     rdi, rax
.text:0000555555554DAC                 call    _getrandom
.text:0000555555554DB1                 mov     [rbp+var_60], 0
.text:0000555555554DB8                 mov     [rbp+var_5C], 0
.text:0000555555554DBF                 jmp     short loc_555555554DF3
.text:0000555555554DC1 ; ---------------------------------------------------------------------------
.text:0000555555554DC1
.text:0000555555554DC1 loc_555555554DC1:                       ; CODE XREF: challenge3+C6↓j
.text:0000555555554DC1                 mov     eax, [rbp+var_5C]
.text:0000555555554DC4                 cdqe
.text:0000555555554DC6                 movzx   edx, [rbp+rax+buf] ; edx清零,读取 rbp+rax+buf 地址处的一个字节,并将其扩充到64位移入edx寄存器低8
.text:0000555555554DCB                 mov     eax, [rbp+var_5C]
.text:0000555555554DCE                 cdqe                       ; 将32位eax值扩展为64位rax值
.text:0000555555554DD0                 movzx   eax, [rbp+rax+var_30]
.text:0000555555554DD5                 cmp     dl, al
.text:0000555555554DD7                 jnz     short loc_555555554DEF
.text:0000555555554DD9                 mov     eax, [rbp+var_5C]
.text:0000555555554DDC                 cdqe
.text:0000555555554DDE                 movzx   edx, [rbp+rax+buf]
.text:0000555555554DE3                 movzx   eax, [rbp+var_51]
.text:0000555555554DE7                 cmp     dl, al             ; di:edx低8位,al:eax低8
.text:0000555555554DE9                 jz      short loc_555555554DEF
.text:0000555555554DEB                 add     [rbp+var_60], 1
.text:0000555555554DEF
.text:0000555555554DEF loc_555555554DEF:                       ; CODE XREF: challenge3+A6↑j
.text:0000555555554DEF                                         ; challenge3+B8↑j
.text:0000555555554DEF                 add     [rbp+var_5C], 1
.text:0000555555554DF3
.text:0000555555554DF3 loc_555555554DF3:                       ; CODE XREF: challenge3+8E↑j
.text:0000555555554DF3                 cmp     [rbp+var_5C], 1Fh
.text:0000555555554DF7                 jle     short loc_555555554DC1 ; 小于或等于则跳转
.text:0000555555554DF9                 cmp     [rbp+var_60], 20h ;
.text:0000555555554DFD                 jnz     short loc_555555554E06
.text:0000555555554DFF                 mov     rax, [rbp+var_68]
.text:0000555555554E03                 mov     byte ptr [rax], 1 ; byte ptr是指定操作数的大小,这里是一个byte
                                                                 ; 将字节值1存储在rax寄存器指向的内存地址中
.text:0000555555554E06
.text:0000555555554E06 loc_555555554E06:                       ; CODE XREF: challenge3+CC↑j
.text:0000555555554E06                 nop
.text:0000555555554E07                 mov     rax, [rbp+var_8]
.text:0000555555554E0B                 xor     rax, fs:28h
.text:0000555555554E14                 jz      short locret_555555554E1B
.text:0000555555554E16                 call    ___stack_chk_fail
.text:0000555555554E1B ; ---------------------------------------------------------------------------
.text:0000555555554E1B
.text:0000555555554E1B locret_555555554E1B:                    ; CODE XREF: challenge3+E3↑j
.text:0000555555554E1B                 leave
.text:0000555555554E1C                 retn
.text:0000555555554E1C challenge3      endp
unsigned __int64 __fastcall challenge3(_BYTE *a1)
{
  int v2; // [rsp+10h] [rbp-60h]
  int i; // [rsp+14h] [rbp-5Ch]
  int fd; // [rsp+18h] [rbp-58h]
  char v5; // [rsp+1Fh] [rbp-51h] BYREF
  char buf[32]; // [rsp+20h] [rbp-50h] BYREF
  char v7[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+68h] [rbp-8h]
 
  v8 = __readfsqword(0x28u); // 从fs段读取地址0x28处的8个字节,并将其存储在v8变量中。地址0x28处的数据通常被用来存储函数的返回地址
  fd = open("/dev/urandom", 0);
  read(fd, buf, 0x20uLL);
  read(fd, &v5, 1uLL);
  close(fd);
  getrandom(v7, 32LL, 1LL);
  v2 = 0;
  for ( i = 0; i <= 31; ++i )
  {
    if ( buf[i] == v7[i] && buf[i] != v5 )
      ++v2;
  }
  if ( v2 == 32 )
    *a1 = 1; // 修改指针所指向的内存中的值
  return __readfsqword(0x28u) ^ v8;
}
unsigned __int64 __fastcall challenge3(_BYTE *a1)
{
  int v2; // [rsp+10h] [rbp-60h]
  int i; // [rsp+14h] [rbp-5Ch]
  int fd; // [rsp+18h] [rbp-58h]
  char v5; // [rsp+1Fh] [rbp-51h] BYREF
  char buf[32]; // [rsp+20h] [rbp-50h] BYREF
  char v7[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+68h] [rbp-8h]
 
  v8 = __readfsqword(0x28u); // 从fs段读取地址0x28处的8个字节,并将其存储在v8变量中。地址0x28处的数据通常被用来存储函数的返回地址
  fd = open("/dev/urandom", 0);
  read(fd, buf, 0x20uLL);
  read(fd, &v5, 1uLL);
  close(fd);
  getrandom(v7, 32LL, 1LL);
  v2 = 0;
  for ( i = 0; i <= 31; ++i )
  {
    if ( buf[i] == v7[i] && buf[i] != v5 )
      ++v2;
  }
  if ( v2 == 32 )
    *a1 = 1; // 修改指针所指向的内存中的值
  return __readfsqword(0x28u) ^ v8;
}
  read(fd, buf, 0x20uLL);
  read(fd, &v5, 1uLL);
···
  getrandom(v7, 32LL, 1LL);
  read(fd, buf, 0x20uLL);
  read(fd, &v5, 1uLL);
···
  getrandom(v7, 32LL, 1LL);
 
 
 
getrandom(ql, buf, buflen, flags)
 
buf:指向缓冲区的指针,用于存储读取到的随机数据。
buflen:要从系统熵池读取的字节数。
flags:指定 getrandom 函数的行为。常见的 flags 值包括:
    0:如果系统熵池中没有足够的熵,getrandom 会阻塞直到有足够的熵可用。
    GRND_NONBLOCK(通常为 1):getrandom 在系统熵池中没有足够的熵时,会立即返回错误而不是阻塞。
    GRND_RANDOM(通常为 2):尝试从 /dev/random 获取随机数据,而不是从 /dev/urandom 获取。这个选项会导致 getrandom 的行为更加谨慎,可能会在熵不足时阻塞。
 
返回值:
如果成功获取随机数据,getrandom 返回实际读取的字节数。
如果出错,返回 -1 并设置 errno。常见的错误包括 EAGAIN(系统熵池中没有足够的熵,且 flags 设置为非阻塞模式)和 EFAULT(buf 指针无效或指向不可访问的内存区域)。
getrandom(ql, buf, buflen, flags)
 
buf:指向缓冲区的指针,用于存储读取到的随机数据。
buflen:要从系统熵池读取的字节数。
flags:指定 getrandom 函数的行为。常见的 flags 值包括:
    0:如果系统熵池中没有足够的熵,getrandom 会阻塞直到有足够的熵可用。
    GRND_NONBLOCK(通常为 1):getrandom 在系统熵池中没有足够的熵时,会立即返回错误而不是阻塞。
    GRND_RANDOM(通常为 2):尝试从 /dev/random 获取随机数据,而不是从 /dev/urandom 获取。这个选项会导致 getrandom 的行为更加谨慎,可能会在熵不足时阻塞。
 
返回值:
如果成功获取随机数据,getrandom 返回实际读取的字节数。
如果出错,返回 -1 并设置 errno。常见的错误包括 EAGAIN(系统熵池中没有足够的熵,且 flags 设置为非阻塞模式)和 EFAULT(buf 指针无效或指向不可访问的内存区域)。
from qiling import Qiling
from qiling.os.mapper import QlFsMappedObject
 
class FakeUrandom(QlFsMappedObject):
 
    def read(self, size: int) -> bytes:
        if size == 1:
         return b"\x42" # v5的长度为1
        # return a constant value upon reading
        else:
         return b"\x41"
 
    def fstat(self) -> int: # fstat() 是Linux/Unix系统调用之一,用来获取文件的状态信息
        # return -1 to let syscall fstat ignore it
        return -1
 
    def close(self) -> int:
        return 0
 
if __name__ == "__main__":
    ql = Qiling([r'rootfs/x86_linux/bin/x86_fetch_urandom'], r'rootfs/x86_linux')
 
    ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    ql.run()
from qiling import Qiling
from qiling.os.mapper import QlFsMappedObject
 
class FakeUrandom(QlFsMappedObject):
 
    def read(self, size: int) -> bytes:
        if size == 1:
         return b"\x42" # v5的长度为1
        # return a constant value upon reading
        else:
         return b"\x41"
 
    def fstat(self) -> int: # fstat() 是Linux/Unix系统调用之一,用来获取文件的状态信息
        # return -1 to let syscall fstat ignore it
        return -1
 
    def close(self) -> int:
        return 0
 
if __name__ == "__main__":
    ql = Qiling([r'rootfs/x86_linux/bin/x86_fetch_urandom'], r'rootfs/x86_linux')
 
    ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    ql.run()
def hook_getrandom(ql, buf, buflen, flags):
    # 自定义 getrandom 函数实现
    if buflen == 32:
        data = b'\x41' * buflen  # b'\x41' = A
        ql.mem.write(buf, data)
        ql.os.set_syscall_return(buflen)
    else:
        ql.os.set_syscall_return(-1)
 
···
# 调用自定义系统调用
ql.os.set_syscall("getrandom", hook_getrandom)
def hook_getrandom(ql, buf, buflen, flags):
    # 自定义 getrandom 函数实现
    if buflen == 32:
        data = b'\x41' * buflen  # b'\x41' = A
        ql.mem.write(buf, data)
        ql.os.set_syscall_return(buflen)
    else:
        ql.os.set_syscall_return(-1)
 
···
# 调用自定义系统调用
ql.os.set_syscall("getrandom", hook_getrandom)
from qiling import *
from qiling.const import * # 导入Qiling模拟器中的常量
from qiling.os.mapper import QlFsMappedObject
 
class FakeUrandom(QlFsMappedObject): 
 
    def read(self, size: int) -> bytes: 
        if size == 1:
            return b"\x42"
        else:
            return b"\x41" * size
 
    def close(self) -> int:
        return 0
 
def hook_getrandom(ql, buf, buflen, flags):
    # 自定义 getrandom 函数实现
    if buflen == 32:
        data = b'\x41' * buflen  # b'\x41' = A
        ql.mem.write(buf, data)
        ql.os.set_syscall_return(buflen)
    else:
        ql.os.set_syscall_return(-1)
 
def challenge3(ql):
    ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    ql.os.set_syscall("getrandom", hook_getrandom)
 
if __name__ == '__main__':
    path = ["rootfs/x8664_linux/qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    # 记得加上challenge1
    challenge2(ql)
    ql.run()
from qiling import *
from qiling.const import * # 导入Qiling模拟器中的常量
from qiling.os.mapper import QlFsMappedObject
 
class FakeUrandom(QlFsMappedObject): 
 
    def read(self, size: int) -> bytes: 
        if size == 1:
            return b"\x42"
        else:
            return b"\x41" * size
 
    def close(self) -> int:
        return 0
 
def hook_getrandom(ql, buf, buflen, flags):
    # 自定义 getrandom 函数实现
    if buflen == 32:
        data = b'\x41' * buflen  # b'\x41' = A
        ql.mem.write(buf, data)
        ql.os.set_syscall_return(buflen)
    else:
        ql.os.set_syscall_return(-1)
 
def challenge3(ql):
    ql.add_fs_mapper(r'/dev/urandom', FakeUrandom())
    ql.os.set_syscall("getrandom", hook_getrandom)
 
if __name__ == '__main__':
    path = ["rootfs/x8664_linux/qilinglab-x86_64"]
    rootfs = "rootfs/x8664_linux"
    ql = Qiling(path, rootfs)
    # 记得加上challenge1
    challenge2(ql)
    ql.run()
Checking which challenge are solved...
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x54) = 0x54
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x5a) = 0x5a
 
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x1) = 0x1
utsname address: 0x80000000db50
[=]     uname(buf = 0x80000000db50) = 0x0
Challenge 1: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     openat(fd = 0xffffff9c, path = 0x555555555698, flags = 0x0, mode = 0x0) = 0x3
[=]     read(fd = 0x3, buf = 0x80000000dcc0, length = 0x20) = 0x20
[=]     read(fd = 0x3, buf = 0x80000000dcbf, length = 0x1) = 0x1
[=]     close(fd = 0x3) = 0x0
[=]     getrandom(buf = 0x80000000dce0, buflen = 0x20, flags = 0x1) = ?
Challenge 2: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
Challenge 3: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     time() = 0x6472521d
Challenge 4: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
Checking which challenge are solved...
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x54) = 0x54
Note: Some challenges will results in segfaults and infinite loops if they aren't solved.
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x5a) = 0x5a
 
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x1) = 0x1
utsname address: 0x80000000db50
[=]     uname(buf = 0x80000000db50) = 0x0
Challenge 1: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     openat(fd = 0xffffff9c, path = 0x555555555698, flags = 0x0, mode = 0x0) = 0x3
[=]     read(fd = 0x3, buf = 0x80000000dcc0, length = 0x20) = 0x20
[=]     read(fd = 0x3, buf = 0x80000000dcbf, length = 0x1) = 0x1
[=]     close(fd = 0x3) = 0x0
[=]     getrandom(buf = 0x80000000dce0, buflen = 0x20, flags = 0x1) = ?
Challenge 2: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
Challenge 3: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     time() = 0x6472521d
Challenge 4: NOT SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x18) = 0x18
.text:0000555555554E1D                 public challenge4
.text:0000555555554E1D challenge4      proc near               ; CODE XREF: start+18F↓p
.text:0000555555554E1D
.text:0000555555554E1D var_18          = qword ptr -18h
.text:0000555555554E1D var_8           = dword ptr -8
.text:0000555555554E1D var_4           = dword ptr -4
.text:0000555555554E1D
.text:0000555555554E1D                 push    rbp
.text:0000555555554E1E                 mov     rbp, rsp
.text:0000555555554E21                 mov     [rbp+var_18], rdi
.text:0000555555554E25                 mov     [rbp+var_8], 0
.text:0000555555554E2C                 mov     [rbp+var_4], 0
.text:0000555555554E33                 jmp     short loc_555555554E40
.text:0000555555554E35 ; ---------------------------------------------------------------------------
.text:0000555555554E35
.text:0000555555554E35 loc_555555554E35:                       ; CODE XREF: challenge4+29↓j
.text:0000555555554E35                 mov     rax, [rbp+var_18]
.text:0000555555554E39                 mov     byte ptr [rax], 1
.text:0000555555554E3C                 add     [rbp+var_4], 1
.text:0000555555554E40
.text:0000555555554E40 loc_555555554E40:                       ; CODE XREF: challenge4+16↑j
.text:0000555555554E40                 mov     eax, [rbp+var_8]
.text:0000555555554E43                 cmp     [rbp+var_4], eax
.text:0000555555554E46                 jl      short loc_555555554E35 ; 小于则跳转
.text:0000555555554E48                 nop
.text:0000555555554E49                 pop     rbp
.text:0000555555554E4A                 retn
.text:0000555555554E4A challenge4      endp
.text:0000555555554E1D                 public challenge4
.text:0000555555554E1D challenge4      proc near               ; CODE XREF: start+18F↓p
.text:0000555555554E1D
.text:0000555555554E1D var_18          = qword ptr -18h
.text:0000555555554E1D var_8           = dword ptr -8
.text:0000555555554E1D var_4           = dword ptr -4
.text:0000555555554E1D
.text:0000555555554E1D                 push    rbp
.text:0000555555554E1E                 mov     rbp, rsp
.text:0000555555554E21                 mov     [rbp+var_18], rdi
.text:0000555555554E25                 mov     [rbp+var_8], 0
.text:0000555555554E2C                 mov     [rbp+var_4], 0
.text:0000555555554E33                 jmp     short loc_555555554E40
.text:0000555555554E35 ; ---------------------------------------------------------------------------
.text:0000555555554E35
.text:0000555555554E35 loc_555555554E35:                       ; CODE XREF: challenge4+29↓j
.text:0000555555554E35                 mov     rax, [rbp+var_18]
.text:0000555555554E39                 mov     byte ptr [rax], 1
.text:0000555555554E3C                 add     [rbp+var_4], 1
.text:0000555555554E40
.text:0000555555554E40 loc_555555554E40:                       ; CODE XREF: challenge4+16↑j
.text:0000555555554E40                 mov     eax, [rbp+var_8]
.text:0000555555554E43                 cmp     [rbp+var_4], eax
.text:0000555555554E46                 jl      short loc_555555554E35 ; 小于则跳转
.text:0000555555554E48                 nop
.text:0000555555554E49                 pop     rbp
.text:0000555555554E4A                 retn
.text:0000555555554E4A challenge4      endp
__int64 challenge4()
{
  return 0LL;
}
__int64 challenge4()
{
  return 0LL;
}
mov     [rbp+var_8], 0
mov     [rbp+var_4], 0
 
···
 
mov     eax, [rbp+var_8]
cmp     [rbp+var_4], eax
add     [rbp+var_4], 1
mov     [rbp+var_8], 0
mov     [rbp+var_4], 0
 
···
 
mov     eax, [rbp+var_8]
cmp     [rbp+var_4], eax
add     [rbp+var_4], 1
 
 
 
__int64 __fastcall challenge4(_BYTE *a1)
{
  __int64 result; // rax
  int i; // [rsp+14h] [rbp-4h]
 
  for ( i = 0; ; ++i ) // for 循环运行一次后让*a1 = 1,接着break
  {
    result = 1LL;
    if ( i >= 1 )
      break;
    *a1 = 1;
  }
  return result;
}
__int64 __fastcall challenge4(_BYTE *a1)
{
  __int64 result; // rax
  int i; // [rsp+14h] [rbp-4h]
 
  for ( i = 0; ; ++i ) // for 循环运行一次后让*a1 = 1,接着break
  {
    result = 1LL;
    if ( i >= 1 )
      break;
    *a1 = 1;
  }
  return result;
}
def enter_forbidden_loop_hook(ql):
    ql.arch.regs.eax = 1
def challenge4(ql):
    """
    .text:0000555555554E40                 mov     eax, [rbp+var_8]
    .text:0000555555554E43                 cmp     [rbp+var_4], eax <-- 在运行此命令前hook eax,使得eax = 1
    .text:0000555555554E46                 jl      short loc_555555554E35
    """
    base = ql.mem.get_lib_base(os.path.split(ql.path)[-1])  # 根据文件路径查找已经加载的文件,获取对应文件的基地址
    # os.path.split(ql.path):os.path.split 函数将 ql.path 分成两部分:目录名和基本文件名。这个函数返回一个包含这两部分的元组。
    # os.path.split(ql.path)[-1]:这将返回元组中的最后一个元素,即基本文件名。在 Python 中,-1 索引表示列表或元组的最后一个元素。
    # base = ql.mem.get_lib_base(os.path.split(ql.path)[-1]):ql.mem.get_lib_base 函数使用提取的文件名作为参数,以获取已加载库的基地址。将返回的基地址赋值给变量 base
    hook_addr = base + 0xE43
    ql.hook_address(enter_forbidden_loop_hook, hook_addr) # 当执行流程到达hook_addr时,该函数将被调用。此时hook_addr处的代码还未被执行。
def enter_forbidden_loop_hook(ql):
    ql.arch.regs.eax = 1
def challenge4(ql):
    """
    .text:0000555555554E40                 mov     eax, [rbp+var_8]
    .text:0000555555554E43                 cmp     [rbp+var_4], eax <-- 在运行此命令前hook eax,使得eax = 1
    .text:0000555555554E46                 jl      short loc_555555554E35
    """
    base = ql.mem.get_lib_base(os.path.split(ql.path)[-1])  # 根据文件路径查找已经加载的文件,获取对应文件的基地址
    # os.path.split(ql.path):os.path.split 函数将 ql.path 分成两部分:目录名和基本文件名。这个函数返回一个包含这两部分的元组。
    # os.path.split(ql.path)[-1]:这将返回元组中的最后一个元素,即基本文件名。在 Python 中,-1 索引表示列表或元组的最后一个元素。
    # base = ql.mem.get_lib_base(os.path.split(ql.path)[-1]):ql.mem.get_lib_base 函数使用提取的文件名作为参数,以获取已加载库的基地址。将返回的基地址赋值给变量 base
    hook_addr = base + 0xE43
    ql.hook_address(enter_forbidden_loop_hook, hook_addr) # 当执行流程到达hook_addr时,该函数将被调用。此时hook_addr处的代码还未被执行。
Challenge 1: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     openat(fd = 0xffffff9c, path = 0x555555555698, flags = 0x0, mode = 0x0) = 0x3
[=]     read(fd = 0x3, buf = 0x80000000dcc0, length = 0x20) = 0x20
[=]     read(fd = 0x3, buf = 0x80000000dcbf, length = 0x1) = 0x1
[=]     close(fd = 0x3) = 0x0
[=]     getrandom(buf = 0x80000000dce0, buflen = 0x20, flags = 0x1) = ?
Challenge 2: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
Challenge 3: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     time() = 0x64730987
Challenge 4: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
Challenge 1: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     openat(fd = 0xffffff9c, path = 0x555555555698, flags = 0x0, mode = 0x0) = 0x3
[=]     read(fd = 0x3, buf = 0x80000000dcc0, length = 0x20) = 0x20
[=]     read(fd = 0x3, buf = 0x80000000dcbf, length = 0x1) = 0x1
[=]     close(fd = 0x3) = 0x0
[=]     getrandom(buf = 0x80000000dce0, buflen = 0x20, flags = 0x1) = ?
Challenge 2: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
Challenge 3: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
[=]     time() = 0x64730987
Challenge 4: SOLVED
[=]     write(fd = 0x1, buf = 0x55555575a260, count = 0x14) = 0x14
.text:0000555555554E4B                 public challenge5
.text:0000555555554E4B challenge5      proc near               ; CODE XREF: start+1B3↓p
.text:0000555555554E4B
.text:0000555555554E4B var_58          = qword ptr -58h
.text:0000555555554E4B var_48          = dword ptr -48h
.text:0000555555554E4B var_44          = dword ptr -44h
.text:0000555555554E4B var_40          = dword ptr -40h
.text:0000555555554E4B var_20          = dword ptr -20h
.text:0000555555554E4B var_8           = qword ptr -8
.text:0000555555554E4B
.text:0000555555554E4B                 push    rbp
.text:0000555555554E4C                 mov     rbp, rsp
.text:0000555555554E4F                 sub     rsp, 60h
.text:0000555555554E53                 mov     [rbp+var_58], rdi
.text:0000555555554E57                 mov     rax, fs:28h
.text:0000555555554E60                 mov     [rbp+var_8], rax
.text:0000555555554E64                 xor     eax, eax
.text:0000555555554E66                 mov     edi, 0          ; timer
.text:0000555555554E6B                 call    _time
.text:0000555555554E70                 mov     edi, eax        ; seed
.text:0000555555554E72                 call    _srand
.text:0000555555554E77                 mov     [rbp+var_48], 0
.text:0000555555554E7E                 jmp     short loc_555555554EA1
.text:0000555555554E80 ; ---------------------------------------------------------------------------
.text:0000555555554E80
.text:0000555555554E80 loc_555555554E80:                       ; CODE XREF: challenge5+5A↓j
.text:0000555555554E80                 mov     eax, [rbp+var_48]
.text:0000555555554E83                 cdqe
.text:0000555555554E85                 mov     [rbp+rax*4+var_40], 0
.text:0000555555554E8D                 call    _rand
.text:0000555555554E92                 mov     edx, eax
.text:0000555555554E94                 mov     eax, [rbp+var_48]
.text:0000555555554E97                 cdqe
.text:0000555555554E99                 mov     [rbp+rax*4+var_20], edx
.text:0000555555554E9D                 add     [rbp+var_48], 1
.text:0000555555554EA1
.text:0000555555554EA1 loc_555555554EA1:                       ; CODE XREF: challenge5+33↑j
.text:0000555555554EA1                 cmp     [rbp+var_48], 4
.text:0000555555554EA5                 jle     short loc_555555554E80
.text:0000555555554EA7                 mov     [rbp+var_44], 0
.text:0000555555554EAE                 jmp     short loc_555555554ED3
.text:0000555555554EB0 ; ---------------------------------------------------------------------------
.text:0000555555554EB0
.text:0000555555554EB0 loc_555555554EB0:                       ; CODE XREF: challenge5+8C↓j
.text:0000555555554EB0                 mov     eax, [rbp+var_44]
.text:0000555555554EB3                 cdqe
.text:0000555555554EB5                 mov     edx, [rbp+rax*4+var_40]
.text:0000555555554EB9                 mov     eax, [rbp+var_44]
.text:0000555555554EBC                 cdqe
.text:0000555555554EBE                 mov     eax, [rbp+rax*4+var_20]
.text:0000555555554EC2                 cmp     edx, eax
.text:0000555555554EC4                 jz      short loc_555555554ECF
.text:0000555555554EC6                 mov     rax, [rbp+var_58]
.text:0000555555554ECA                 mov     byte ptr [rax], 0
.text:0000555555554ECD                 jmp     short loc_555555554EE0
.text:0000555555554ECF ; ---------------------------------------------------------------------------
.text:0000555555554ECF
.text:0000555555554ECF loc_555555554ECF:                       ; CODE XREF: challenge5+79↑j
.text:0000555555554ECF                 add     [rbp+var_44], 1
.text:0000555555554ED3
.text:0000555555554ED3 loc_555555554ED3:                       ; CODE XREF: challenge5+63↑j
.text:0000555555554ED3                 cmp     [rbp+var_44], 4
.text:0000555555554ED7                 jle     short loc_555555554EB0
.text:0000555555554ED9                 mov     rax, [rbp+var_58]
.text:0000555555554EDD                 mov     byte ptr [rax], 1
.text:0000555555554EE0
.text:0000555555554EE0 loc_555555554EE0:                       ; CODE XREF: challenge5+82↑j
.text:0000555555554EE0                 mov     rax, [rbp+var_8]
.text:0000555555554EE4                 xor     rax, fs:28h
.text:0000555555554EED                 jz      short locret_555555554EF4
.text:0000555555554EEF                 call    ___stack_chk_fail
.text:0000555555554EF4 ; ---------------------------------------------------------------------------
.text:0000555555554EF4
.text:0000555555554EF4 locret_555555554EF4:                    ; CODE XREF: challenge5+A2↑j
.text:0000555555554EF4                 leave
.text:0000555555554EF5                 retn
.text:0000555555554EF5 challenge5      endp
.text:0000555555554E4B                 public challenge5
.text:0000555555554E4B challenge5      proc near               ; CODE XREF: start+1B3↓p
.text:0000555555554E4B
.text:0000555555554E4B var_58          = qword ptr -58h
.text:0000555555554E4B var_48          = dword ptr -48h
.text:0000555555554E4B var_44          = dword ptr -44h
.text:0000555555554E4B var_40          = dword ptr -40h
.text:0000555555554E4B var_20          = dword ptr -20h
.text:0000555555554E4B var_8           = qword ptr -8
.text:0000555555554E4B
.text:0000555555554E4B                 push    rbp
.text:0000555555554E4C                 mov     rbp, rsp
.text:0000555555554E4F                 sub     rsp, 60h
.text:0000555555554E53                 mov     [rbp+var_58], rdi
.text:0000555555554E57                 mov     rax, fs:28h
.text:0000555555554E60                 mov     [rbp+var_8], rax
.text:0000555555554E64                 xor     eax, eax
.text:0000555555554E66                 mov     edi, 0          ; timer
.text:0000555555554E6B                 call    _time
.text:0000555555554E70                 mov     edi, eax        ; seed
.text:0000555555554E72                 call    _srand
.text:0000555555554E77                 mov     [rbp+var_48], 0
.text:0000555555554E7E                 jmp     short loc_555555554EA1

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-5-29 22:27 被bwner编辑 ,原因: 补全图片
收藏
免费 13
支持
分享
打赏 + 5.00雪花
打赏次数 1 雪花 + 5.00
 
赞赏  orz1ruo   +5.00 2023/06/03 助人为乐~
最新回复 (5)
雪    币: 22174
活跃值: (6541)
能力值: (RANK:445 )
在线值:
发帖
回帖
粉丝
2
有一个图挂了,补下。
2023-5-29 22:17
0
雪    币: 2445
活跃值: (5519)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
3
胡一米 有一个图挂了,补下。
好的,已检查全文补齐图片
2023-5-29 22:28
1
雪    币: 3573
活跃值: (31026)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2023-5-30 09:03
1
雪    币: 1935
活跃值: (4180)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
写得好,感谢分享
2023-5-30 11:13
1
雪    币: 70
活跃值: (2113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
很有耐心~
2023-6-7 16:46
0
游客
登录 | 注册 方可回帖
返回
//