首页
社区
课程
招聘
[原创]11个小挑战,Qiling Framework 入门上手跟练
发表于: 2021-8-19 22:47 16860

[原创]11个小挑战,Qiling Framework 入门上手跟练

2021-8-19 22:47
16860

QilingLab来源: Shielder - QilingLab – Release,是一个包含十几个小挑战的程序,用于快速上手Qiling框架的主要功能。Qiling框架就不多做介绍了。

两个不同架构但是内容一样,任选其一做即可。aarch64版本已有Joan Sivion做的Qiling Labs - JoanSivion Security Blog,我这里用x86-64做了一遍,当作对Joan Sivion的补充和中文翻译。

样本见附件

qiling framework开发到现在,一些api有所改动,2022.8.24我回顾了一下本篇文章,发现原来的脚本在最新的qiling上已经跑不通了。
更新后的代码我会放在文章最后面,以最后给出的代码为准

qilinglab出发点只是训练qiling框架的使用,所以没有啥逆向强度,符号也没有去,我们直接用IDA打开看即可。

运行看到题目列表:

IDA打开,可以看到main() → start()里就是一大堆调用challangeX(a)并对结果进行校验,我们的目的就是让传入的指针指向的位置能被正确赋值1。没有逆向难度所以不多做解释。

直接运行的话,并不会输出每个Challenge的结果(SOLVED/UNSOLVED),甚至还会出现segment fault,这些都是正常现象,请放心食用,当你完成某些挑战后,自然就能看到更多的结果了。

我们需要用到rootfs里的东西,所以把qiling的GitHub仓库clone下来,里面rootfs是个submodule所以干脆整个用

克隆下来

需要我们让内存0x1337上存放一个值为1337,我们其实并不能保证程序加载基地址,这里我们需要用

映射一块内存,需要注意的是,qiling底层就是用的Unicorn Engine,内存映射时,要4k对齐。

综上,还是挺容易得出第一处解法。

ql.run()前加一句ql.verbose = 0方便看输出内容

让我们修改uname系统调用,让它返回正确的值。IDA看下“正确的值”指的是什么

uname系统调用用来获取系统的一些信息,传入一个utsname结构体buffer让它填充。可以在<sys/utsname.h>看到utsname的定义(经过整理):

而Qiling提供了在系统调用返回时进行hook的功能。

可以看到需要我们解决两个问题:

直接读取/dev/urandom得到的随机数,和通过getrandom()得到的随机数要完全一样

还要有一个字节的随机数,和剩下的都不一样。

Qiling提供了QlFsMappedObject让我们能很方便地自定义文件系统,最少要实现close,剩下的可以看源码,根据需要自行去实现:read, write, fileno, lseek, fstat, ioctl, tell, dup, readline

在我的IDA上,F5看不到完整流程。

所以看汇编:

可以看到有个不成立的循环,正常执行不会进入。相当于是:

所以在比较前将终止条件改为1,这样可以执行一次,让函数参数赋值为1。

hook_address里注册的回调在执行被hook地址处之前执行,然后才执行这个地址上的指令。所以我们hook在cmp这句。这样while里就是比较 i < 1了。

来看看我们的目标:

显然,只要让rand()每次都返回0是最简单的修改方法了。所以代码比较简单:

看不到输出challenge5: SOLVED是正常的,因为卡在了challenge6,没有输出来信息。

流程很清晰,只要我们修改死循环部分,参数就会乖乖被赋值1

同理,要抢在比较之前修改al的值

可以很轻易想到n种办法:

修改sleep参数值,减少睡眠时间

自己实现apisleep(),直接返回

修改系统调用nanosleep(),直接返回,因为sleep()底层调用的nanosleep()

    可以看一下

这里直接借用Joan Sivion整理的代码:

方法有两种:

    然后结构体偏移+0x16的地方就是保存了参数的位置。

要么让tolower()失效,要么让strcmp()失效。

让我们能从/proc/self/cmdline读到"qilinglab",故技重施即可,hook文件系统。

可以直接替换指定文件成我们的文件,先创建我们需要的文件:

然后代码就可以这样写了:

还一种方法,代码也不用写了,直接往qiling的rootfs里面写:

这里指的是用qiling的指令hook_code()而不是ql.hook_insn(),先看下目标

看下汇编:

目标就很明确了。cpuid指令会填充几个寄存器,具体可以参考intel手册。

说明:

ql.mem.map_info也就是ql.mem.show_mapinfo()的内容,5表示的是r-x属性,加这个判断也是为了缩小hook的范围,提高性能。

好耶!

到此位置这个练习就全部结束了!感觉也没啥太多坑的点,有的话根据报错信息来解决就好。

更新后的脚本:

Qiling Framework Documentation

 
 
 
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.
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.
 
git clone https://github.com/qilingframework/qiling.git --recursiv
git clone https://github.com/qilingframework/qiling.git --recursiv
from qiling import *
 
def challenge1(ql: Qiling):
    pass
 
if __name__  == '__main__':
    path = ['qilinglab-x86_64'] # 我们的目标
    rootfs = "./qiling/examples/rootfs/x8664_linux" # 在你clone下来的仓库里
    ql = Qiling(path, rootfs)
    challenge1(ql) # 在ql.run()之前,做好我们的hook工作
    ql.run()
from qiling import *
 
def challenge1(ql: Qiling):
    pass
 
if __name__  == '__main__':
    path = ['qilinglab-x86_64'] # 我们的目标
    rootfs = "./qiling/examples/rootfs/x8664_linux" # 在你clone下来的仓库里
    ql = Qiling(path, rootfs)
    challenge1(ql) # 在ql.run()之前,做好我们的hook工作
    ql.run()
_BYTE *__fastcall challenge1(_BYTE *a1)
{
  _BYTE *result; // rax
 
  result = (_BYTE *)MEMORY[0x1337];
  if ( MEMORY[0x1337] == 1337 )
  {
    result = a1;
    *a1 = 1;
  }
  return result;
}
_BYTE *__fastcall challenge1(_BYTE *a1)
{
  _BYTE *result; // rax
 
  result = (_BYTE *)MEMORY[0x1337];
  if ( MEMORY[0x1337] == 1337 )
  {
    result = a1;
    *a1 = 1;
  }
  return result;
}
ql.mem.map(0x1000, 0x1000, info='[challenge]')
ql.mem.map(0x1000, 0x1000, info='[challenge]')
 
def challenge1(ql: Qiling):
    ql.mem.map(0x1000, 0x1000, info='[challenge1]')
    ql.mem.write(0x1337, ql.pack16(1337)) # pack16(value) == struct.pack('H', value)
def challenge1(ql: Qiling):
    ql.mem.map(0x1000, 0x1000, info='[challenge1]')
    ql.mem.write(0x1337, ql.pack16(1337)) # pack16(value) == struct.pack('H', value)
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[16]; // [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[16]; // [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;
}
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];
};
def hook_uname_on_exit(ql: Qiling, *args):
    rdi = ql.reg.rdi
    ql.mem.write(rdi, b'QilingOS\x00')
    ql.mem.write(rdi + 65 * 3, b'ChallengeStart\x00')
 
def challenge2(ql: Qiling):
    ql.set_syscall('uname', hook_uname_on_exit, QL_INTERCEPT.EXIT)
def hook_uname_on_exit(ql: Qiling, *args):
    rdi = ql.reg.rdi
    ql.mem.write(rdi, b'QilingOS\x00')
    ql.mem.write(rdi + 65 * 3, b'ChallengeStart\x00')
 
def challenge2(ql: Qiling):
    ql.set_syscall('uname', hook_uname_on_exit, QL_INTERCEPT.EXIT)
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 buf2[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+68h] [rbp-8h]
 
  v8 = __readfsqword(0x28u);
  fd = open("/dev/urandom", 0);
  read(fd, buf, 0x20uLL);
  read(fd, &v5, 1uLL);
  close(fd);
  getrandom((__int64)buf2, 32LL, 1LL);
  v2 = 0;
  for ( i = 0; i <= 31; ++i )
  {
    if ( buf[i] == buf2[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 buf2[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+68h] [rbp-8h]
 
  v8 = __readfsqword(0x28u);
  fd = open("/dev/urandom", 0);
  read(fd, buf, 0x20uLL);
  read(fd, &v5, 1uLL);
  close(fd);
  getrandom((__int64)buf2, 32LL, 1LL);
  v2 = 0;
  for ( i = 0; i <= 31; ++i )
  {
    if ( buf[i] == buf2[i] && buf[i] != v5 )
      ++v2;
  }
  if ( v2 == 32 )
    *a1 = 1;
  return __readfsqword(0x28u) ^ v8;
}
class Fake_urandom(QlFsMappedObject):
    def read(self, expected_len):
        if expected_len == 1:
            return b'\x23'  # casual single byte here
        else:
            return b'\x00' * expected_len
 
    def close(self):
        return 0
 
 
def hook_getrandom(ql: Qiling, buf, buflen, flags, *args):
    ql.mem.write(buf, b'\x00' * buflen)
    ql.os.set_syscall_return(0)
 
 
def challenge3(ql: Qiling):
    ql.add_fs_mapper('/dev/urandom', Fake_urandom())
    ql.set_syscall('getrandom', hook_getrandom)
class Fake_urandom(QlFsMappedObject):
    def read(self, expected_len):
        if expected_len == 1:
            return b'\x23'  # casual single byte here
        else:
            return b'\x00' * expected_len
 
    def close(self):
        return 0
 
 
def hook_getrandom(ql: Qiling, buf, buflen, flags, *args):
    ql.mem.write(buf, b'\x00' * buflen)
    ql.os.set_syscall_return(0)
 
 
def challenge3(ql: Qiling):
    ql.add_fs_mapper('/dev/urandom', Fake_urandom())
    ql.set_syscall('getrandom', hook_getrandom)
__int64 challenge4()
{
  return 0LL;
}
__int64 challenge4()
{
  return 0LL;
}
 
 
while (i < 0) {
    *a1 = 1;
    i++;
}
return;
while (i < 0) {
    *a1 = 1;
    i++;
}
return;
def enter_forbidden_loop_hook(ql: Qiling):
    ql.reg.eax = 1
 
def challenge4(ql: Qiling):
    """
    000055A3E4800E40 8B 45 F8   mov     eax, [rbp+var_8]
    000055A3E4800E43 39 45 FC   cmp     [rbp+var_4], eax        <<< hook here
    000055A3E4800E46 7C ED      jl      short loc_55A3E4800E35
    """
    base = ql.mem.get_lib_base(ql.path)
    hook_addr = base + 0xE43
    ql.hook_address(enter_forbidden_loop_hook, hook_addr)
def enter_forbidden_loop_hook(ql: Qiling):
    ql.reg.eax = 1
 
def challenge4(ql: Qiling):
    """
    000055A3E4800E40 8B 45 F8   mov     eax, [rbp+var_8]
    000055A3E4800E43 39 45 FC   cmp     [rbp+var_4], eax        <<< hook here
    000055A3E4800E46 7C ED      jl      short loc_55A3E4800E35
    """
    base = ql.mem.get_lib_base(ql.path)
    hook_addr = base + 0xE43
    ql.hook_address(enter_forbidden_loop_hook, hook_addr)
unsigned __int64 __fastcall challenge5(_BYTE *a1)
{
  unsigned int v1; // eax
  int i; // [rsp+18h] [rbp-48h]
  int j; // [rsp+1Ch] [rbp-44h]
  int v5[14]; // [rsp+20h] [rbp-40h]
  unsigned __int64 v6; // [rsp+58h] [rbp-8h]
 
  v6 = __readfsqword(0x28u);
  v1 = time(0LL);
  srand(v1);
  for ( i = 0; i <= 4; ++i )
  {
    v5[i] = 0;
    v5[i + 8] = rand();
  }
  for ( j = 0; j <= 4; ++j )
  {
    if ( v5[j] != v5[j + 8] )
    {
      *a1 = 0;
      return __readfsqword(0x28u) ^ v6;
    }
  }
  *a1 = 1;
  return __readfsqword(0x28u) ^ v6;
}
unsigned __int64 __fastcall challenge5(_BYTE *a1)
{
  unsigned int v1; // eax
  int i; // [rsp+18h] [rbp-48h]
  int j; // [rsp+1Ch] [rbp-44h]
  int v5[14]; // [rsp+20h] [rbp-40h]
  unsigned __int64 v6; // [rsp+58h] [rbp-8h]
 
  v6 = __readfsqword(0x28u);
  v1 = time(0LL);
  srand(v1);
  for ( i = 0; i <= 4; ++i )
  {
    v5[i] = 0;
    v5[i + 8] = rand();
  }
  for ( j = 0; j <= 4; ++j )
  {
    if ( v5[j] != v5[j + 8] )
    {
      *a1 = 0;
      return __readfsqword(0x28u) ^ v6;
    }
  }
  *a1 = 1;
  return __readfsqword(0x28u) ^ v6;
}
def hook_rand(ql: Qiling):
    ql.reg.rax = 0
 
def challenge5(ql: Qiling):
    ql.set_api('rand', hook_rand)
def hook_rand(ql: Qiling):
    ql.reg.rax = 0
 
def challenge5(ql: Qiling):
    ql.set_api('rand', hook_rand)
 
def hook_while_true(ql: Qiling):
    """
    0000564846E00F12 0F B6 45 FB    movzx   eax, [rbp+var_5]
    0000564846E00F16 84 C0          test    al, al          <<< hook here
    0000564846E00F18 75 F1          jnz     short loc_564846E00F0B
    """
    ql.reg.rax = 0
 
def challenge6(ql: Qiling):
    base = ql.mem.get_lib_base(ql.path)
    ql.hook_address(hook_while_true, base + 0xF16)
def hook_while_true(ql: Qiling):
    """
    0000564846E00F12 0F B6 45 FB    movzx   eax, [rbp+var_5]
    0000564846E00F16 84 C0          test    al, al          <<< hook here
    0000564846E00F18 75 F1          jnz     short loc_564846E00F0B
    """
    ql.reg.rax = 0
 
def challenge6(ql: Qiling):
    base = ql.mem.get_lib_base(ql.path)
    ql.hook_address(hook_while_true, base + 0xF16)
unsigned int __fastcall challenge7(_BYTE *a1)
{
  *a1 = 1;
  return sleep(0xFFFFFFFF);
}
unsigned int __fastcall challenge7(_BYTE *a1)
{
  *a1 = 1;
  return sleep(0xFFFFFFFF);
}
# man 3 sleep
NOTES
       On Linux, sleep() is implemented via nanosleep(2).   See  the  nanosleep(2)
       man page for a discussion of the clock used.
# man 3 sleep
NOTES
       On Linux, sleep() is implemented via nanosleep(2).   See  the  nanosleep(2)
       man page for a discussion of the clock used.
def modify_arg(ql: Qiling):
    ql.reg.edi = 0
 
def i_slept_i_faked_it(ql: Qiling):
    # 我睡了,我装的
    return
 
def hook_nanosleep(ql: Qiling, *args, **kwargs):
    # 注意参数列表
    return
 
def challenge7(ql: Qiling):
    # method 1
    # ql.set_api('sleep', modify_arg, QL_INTERCEPT.ENTER)
    # method 2
    # ql.set_api('sleep', i_slept_i_faked_it)
    # method 3
    ql.set_syscall('nanosleep', hook_nanosleep)
def modify_arg(ql: Qiling):
    ql.reg.edi = 0
 
def i_slept_i_faked_it(ql: Qiling):
    # 我睡了,我装的
    return
 
def hook_nanosleep(ql: Qiling, *args, **kwargs):
    # 注意参数列表
    return
 
def challenge7(ql: Qiling):
    # method 1
    # ql.set_api('sleep', modify_arg, QL_INTERCEPT.ENTER)
    # method 2
    # ql.set_api('sleep', i_slept_i_faked_it)
    # method 3
    ql.set_syscall('nanosleep', hook_nanosleep)
void challenge8(char *check) {
    random_struct *s;
 
    s = (random_struct *)malloc(24);
    s->some_string = (char *)malloc(0x1E);
    s->magic = 0x3DFCD6EA00000539;
    strcpy(s->field_0, "Random data");
    s->check_addr = check;
}
 
struct random_struct {
  char *some_string;
  __int64 magic;
  char *check_addr;
};
void challenge8(char *check) {
    random_struct *s;
 
    s = (random_struct *)malloc(24);
    s->some_string = (char *)malloc(0x1E);
    s->magic = 0x3DFCD6EA00000539;
    strcpy(s->field_0, "Random data");
    s->check_addr = check;
}
 
struct random_struct {
  char *some_string;
  __int64 magic;
  char *check_addr;
};
.text:0000564846E00FA9 48 8B 45 F8      mov     rax, [rbp+stru] ; stru == -8
.text:0000564846E00FAD 48 8B 55 E8      mov     rdx, [rbp+var_18]
.text:0000564846E00FB1 48 89 50 10      mov     [rax+10h], rdx
.text:0000564846E00FB5 90               nop
.text:0000564846E00FB6 C9               leave
.text:0000564846E00FB7 C3               retn
.text:0000564846E00FA9 48 8B 45 F8      mov     rax, [rbp+stru] ; stru == -8
.text:0000564846E00FAD 48 8B 55 E8      mov     rdx, [rbp+var_18]
.text:0000564846E00FB1 48 89 50 10      mov     [rax+10h], rdx
.text:0000564846E00FB5 90               nop
.text:0000564846E00FB6 C9               leave
.text:0000564846E00FB7 C3               retn
def hook_struct(ql: Qiling):
    """
    0000564846E00FA9 48 8B 45 F8      mov     rax, [rbp+str]    ; rbp - 8
    0000564846E00FAD 48 8B 55 E8      mov     rdx, [rbp+var_18]
    0000564846E00FB1 48 89 50 10      mov     [rax+10h], rdx
    0000564846E00FB5 90               nop       <<< hook here
    0000564846E00FB6 C9               leave
    0000564846E00FB7 C3               retn
    """
    heap_struct_addr = ql.unpack64(ql.mem.read(ql.reg.rbp - 8, 8))
    heap_struct = ql.mem.read(heap_struct_addr, 24)
    printHex(heap_struct)
    _, _, check_addr = struct.unpack('QQQ', heap_struct)
    ql.mem.write(check_addr, b'\x01')
 
def search_mem_to_find_struct(ql: Qiling):
    MAGIC = ql.pack64(0x3DFCD6EA00000539)
    candidate_addrs = ql.mem.search(MAGIC)
 
    for addr in candidate_addrs:
        # 有可能有多个地址,所以通过其他特征进一步确认
        stru_addr = addr - 8
        stru = ql.mem.read(stru_addr, 24)
        string_addr, _, check_addr = struct.unpack('QQQ', stru)
        if ql.mem.string(string_addr) == 'Random data':
            ql.mem.write(check_addr, b'\x01')
            break
 
def challenge8(ql: Qiling):
    base = ql.mem.get_lib_base(ql.path)
    # method 1
    # ql.hook_address(hook_struct, base + 0xFB5)
    # method 2
    ql.hook_address(search_mem_to_find_struct, base + 0xFB5)
def hook_struct(ql: Qiling):
    """
    0000564846E00FA9 48 8B 45 F8      mov     rax, [rbp+str]    ; rbp - 8
    0000564846E00FAD 48 8B 55 E8      mov     rdx, [rbp+var_18]
    0000564846E00FB1 48 89 50 10      mov     [rax+10h], rdx
    0000564846E00FB5 90               nop       <<< hook here
    0000564846E00FB6 C9               leave
    0000564846E00FB7 C3               retn
    """
    heap_struct_addr = ql.unpack64(ql.mem.read(ql.reg.rbp - 8, 8))
    heap_struct = ql.mem.read(heap_struct_addr, 24)
    printHex(heap_struct)
    _, _, check_addr = struct.unpack('QQQ', heap_struct)
    ql.mem.write(check_addr, b'\x01')
 
def search_mem_to_find_struct(ql: Qiling):
    MAGIC = ql.pack64(0x3DFCD6EA00000539)
    candidate_addrs = ql.mem.search(MAGIC)
 
    for addr in candidate_addrs:
        # 有可能有多个地址,所以通过其他特征进一步确认
        stru_addr = addr - 8
        stru = ql.mem.read(stru_addr, 24)
        string_addr, _, check_addr = struct.unpack('QQQ', stru)
        if ql.mem.string(string_addr) == 'Random data':
            ql.mem.write(check_addr, b'\x01')
            break
 
def challenge8(ql: Qiling):
    base = ql.mem.get_lib_base(ql.path)
    # method 1
    # ql.hook_address(hook_struct, base + 0xFB5)
    # method 2
    ql.hook_address(search_mem_to_find_struct, base + 0xFB5)
unsigned __int64 __fastcall challenge9(bool *a1)
{
  char *i; // [rsp+18h] [rbp-58h]
  char dest[32]; // [rsp+20h] [rbp-50h] BYREF
  char src[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v5; // [rsp+68h] [rbp-8h]
 
  v5 = __readfsqword(0x28u);
  strcpy(src, "aBcdeFghiJKlMnopqRstuVWxYz");
  strcpy(dest, src);
  for ( i = dest; *i; ++i )
    *i = tolower(*i);
  *a1 = strcmp(src, dest) == 0;
  return __readfsqword(0x28u) ^ v5;
}
unsigned __int64 __fastcall challenge9(bool *a1)
{
  char *i; // [rsp+18h] [rbp-58h]
  char dest[32]; // [rsp+20h] [rbp-50h] BYREF
  char src[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v5; // [rsp+68h] [rbp-8h]
 
  v5 = __readfsqword(0x28u);
  strcpy(src, "aBcdeFghiJKlMnopqRstuVWxYz");
  strcpy(dest, src);
  for ( i = dest; *i; ++i )
    *i = tolower(*i);
  *a1 = strcmp(src, dest) == 0;
  return __readfsqword(0x28u) ^ v5;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-8-24 00:27 被Cr0ssx2编辑 ,原因: 更新代码
上传的附件:
收藏
免费 3
支持
分享
最新回复 (3)
雪    币: 8
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2

[em_63]作者您好!请问为什么 challenge 11 不能使用 hook_address 的方法实现呢?我用下面的代码确实不能通过

def hook_cpuid(ql: Qiling):
    ql.reg.ebx = 0x696C6951
    ql.reg.ecx = 0x614C676E
    ql.reg.edx = 0x20202062
    # ql.reg.rip += 2

base = ql.mem.get_lib_base(os.path.split(ql.path)[-1])
ql.hook_address(hook_cpuid, base + 0x1193)


最后于 2021-11-30 20:11 被cloud0606_f编辑 ,原因: 删除多余代码
2021-11-30 20:10
0
雪    币: 1193
活跃值: (1297)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
cloud0606_f [em_63]作者您好!请问为什么 challenge 11 不能使用 hook_address 的方法实现呢?我用下面的代码确实不能通过def&nbsp;hook_cpuid(ql:& ...

你可以看下这附近的指令,base + 0x1193处对edx的修改,并没有影响到后面的

+0x119B    mov     [rbp+var_2C], eax


修改如下后能通过

def hook_cpuid(ql: Qiling):
    ql.reg.ebx = 0x696C6951
    ql.reg.ecx = 0x614C676E
    ql.reg.eax = 0x20202062 # modified
    # ql.reg.rip += 2


2022-2-15 01:31
0
雪    币: 1795
活跃值: (3995)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
好框架
2022-4-17 15:47
0
游客
登录 | 注册 方可回帖
返回
//