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"
ql
=
Qiling(path, rootfs)
challenge1(ql)
ql.run()
from
qiling
import
*
def
challenge1(ql: Qiling):
pass
if
__name__
=
=
'__main__'
:
path
=
[
'qilinglab-x86_64'
]
rootfs
=
"./qiling/examples/rootfs/x8664_linux"
ql
=
Qiling(path, rootfs)
challenge1(ql)
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
))
def
challenge1(ql: Qiling):
ql.mem.
map
(
0x1000
,
0x1000
, info
=
'[challenge1]'
)
ql.mem.write(
0x1337
, ql.pack16(
1337
))
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'
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'
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):
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):
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):
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):
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
);
}
NOTES
On Linux, sleep()
is
implemented via nanosleep(
2
). See the nanosleep(
2
)
man page
for
a discussion of the clock used.
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):
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):
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):
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)
ql.hook_address(search_mem_to_find_struct, base
+
0xFB5
)
def
hook_struct(ql: Qiling):
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)
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编辑
,原因: 更新代码