直接拖入IDA。
整个程序的对输入的检查分为几个部分。
获取输入长度,然后计算crc32的值(略有修改,标准crc32里的无符号右移在本程序中是有符号右移)
main函数末尾对这个值有检查:
计算3n+1猜想,由于最后必定落入4->2->1->4的循环,因此 v17 = v66[198] | v66[197] | v66[196]
的值一定等于 4 | 2 | 1 = 7
动态调试发现,v72受所有输入字符的影响,导致循环中的v15可能为负数,只能落入-1 -> -2 -> -1的循环,这显然不是正确答案。
确定输入的第3-6个字符是"KCTF"。由第二部分,可以认为在正确的输入下v17是常量7。
迭代输入的第7-15位共九个数字,将其逐渐加位转换为整数,然后验证能被位数整除。由于位数不超过9,所以v23 <= 1262703685
的条件永远成立。
这个校验的Python等价代码:
容易发现在数位长度为偶数时除数也是偶数,因此偶数位必须都是偶数才有可能整除。
这里对第7-15个字符做冒泡排序,然后验证值为1-9,因此可确定第7-15个字符是'1'-'9'的全排列
对奇数位的5个数和偶数位的4个数的全排列分别遍历:
得到唯一符合要求的结果:381654729
至此,可确定正确的输入满足正则:???KCTF381654729.*
题目做到这里时先写了爆破crc的程序(见第六部分),但是没爆出结果。后来才发现是因为忘记调用init_crctable()
初始化crc table……
痛哭流涕……(此时题目一血还未出现)
(因为前一部分的失误,浪费了不少时间在这里整理sub_4010E1
的逻辑,其实这个函数完全无用)
sub_4010E1
的核心是8字节到8字节的一个线性变换,Python的等价写法为:
对于它的求解,可以用z3一把梭:(注意z3的BitVec重载的>>是算术右移)
这部分检查的是输入值从第16个字节开始的部分:
将asc_4055C0
和asc_403DC8
异或,然后以8字节为单位求解,发现无解
现在只有前三个字节未知。crc是可逆的,不过3个字节还是直接爆破更简单,直接复制IDA反编译的伪代码:
秒出结果:421KCTF381654729
,输入程序中验证通过。
...
scanf(
"%s"
, (char)inputvalue);
printf(
"\n现在,你就是韩立,韩立就是你,如遇绝境,吼:男人至死是少年!"
, v33);
inputvalue[
41
]
=
0
;
inputlen
=
strlen(inputvalue);
v5
=
0
;
inputlen2
=
inputlen;
v6
=
inputlen;
v72
=
0
;
if
( inputlen )
{
v7
=
inputvalue;
do
{
v5 ^
=
*
v7;
-
-
v6;
+
+
v7;
v8
=
8
;
do
{
v9
=
2
*
v5;
v10
=
v9 ^
7
;
if
( v9 >
=
0
)
v10
=
v9;
v5
=
v10;
-
-
v8;
}
while
( v8 );
}
while
( v6 );
inputlen
=
inputlen2;
v72
=
v10;
}
init_crctable();
v11
=
-
1
;
for
( i
=
0
; i < inputlen;
+
+
i )
v11
=
crctable[(unsigned __int8)(v11 ^ inputvalue[i])] ^ (v11 >>
8
);
v67
=
~v11;
...
...
scanf(
"%s"
, (char)inputvalue);
printf(
"\n现在,你就是韩立,韩立就是你,如遇绝境,吼:男人至死是少年!"
, v33);
inputvalue[
41
]
=
0
;
inputlen
=
strlen(inputvalue);
v5
=
0
;
inputlen2
=
inputlen;
v6
=
inputlen;
v72
=
0
;
if
( inputlen )
{
v7
=
inputvalue;
do
{
v5 ^
=
*
v7;
-
-
v6;
+
+
v7;
v8
=
8
;
do
{
v9
=
2
*
v5;
v10
=
v9 ^
7
;
if
( v9 >
=
0
)
v10
=
v9;
v5
=
v10;
-
-
v8;
}
while
( v8 );
}
while
( v6 );
inputlen
=
inputlen2;
v72
=
v10;
}
init_crctable();
v11
=
-
1
;
for
( i
=
0
; i < inputlen;
+
+
i )
v11
=
crctable[(unsigned __int8)(v11 ^ inputvalue[i])] ^ (v11 >>
8
);
v67
=
~v11;
...
...
if
( v67
=
=
0xF52E0765
)
{
printf(
"\n你一如既往的谨慎,哪怕屠龙在手........."
, v61);
printf(
"\n"
"十年后,你终于干掉了赤月恶魔,肃清了赤月邪教,获得了 赤月套装 .\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了."
,
v62);
}
...
...
if
( v67
=
=
0xF52E0765
)
{
printf(
"\n你一如既往的谨慎,哪怕屠龙在手........."
, v61);
printf(
"\n"
"十年后,你终于干掉了赤月恶魔,肃清了赤月邪教,获得了 赤月套装 .\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了\n"
"恭喜你,少年,你成功了."
,
v62);
}
...
...
hex_to_int(inputvalue, inputlen);
v13
=
v72;
v69
=
1
;
v68
=
v72
+
1
;
v14
=
v68;
do
{
v15
=
v13;
for
( j
=
1
; j <
200
;
+
+
j )
{
if
( (v15 &
1
) !
=
0
)
v15
=
3
*
v15
+
1
;
/
/
3n
+
1
else
v15 >>
=
1
;
v66[j]
=
v15;
}
+
+
v13;
}
while
( v13 < v14 );
v17
=
v66[
198
] | v66[
197
] | v66[
196
];
/
/
4
|
2
|
1
=
=
7
v18
=
inputlen2;
if
( v17 !
=
(inputvalue[
2
] ^ inputvalue[
1
] ^ inputvalue[
0
]) )
{
printf(
"\n%s"
, (char)
"你深深明白那些裤衩人在做什么,时不我待."
);
printf(
"\n%s\n%s"
,
(char)
"你加入了他们,前世作为高知识分子,你深深明白,赤手空拳的你,肯定不是鹿的对手."
);
printf(
"\n%s"
,
(char)
"虽然前世没有被酒色掏空了身体(没那个钱财).但是经常加班的你,灵魂里面根本没有动手能力这个概念."
);
printf(
"\n%s"
, (char)
"大公鸡攻击了你的小公鸡,GAME OVER ..."
);
goto LABEL_57;
}
...
...
hex_to_int(inputvalue, inputlen);
v13
=
v72;
v69
=
1
;
v68
=
v72
+
1
;
v14
=
v68;
do
{
v15
=
v13;
for
( j
=
1
; j <
200
;
+
+
j )
{
if
( (v15 &
1
) !
=
0
)
v15
=
3
*
v15
+
1
;
/
/
3n
+
1
else
v15 >>
=
1
;
v66[j]
=
v15;
}
+
+
v13;
}
while
( v13 < v14 );
v17
=
v66[
198
] | v66[
197
] | v66[
196
];
/
/
4
|
2
|
1
=
=
7
v18
=
inputlen2;
if
( v17 !
=
(inputvalue[
2
] ^ inputvalue[
1
] ^ inputvalue[
0
]) )
{
printf(
"\n%s"
, (char)
"你深深明白那些裤衩人在做什么,时不我待."
);
printf(
"\n%s\n%s"
,
(char)
"你加入了他们,前世作为高知识分子,你深深明白,赤手空拳的你,肯定不是鹿的对手."
);
printf(
"\n%s"
,
(char)
"虽然前世没有被酒色掏空了身体(没那个钱财).但是经常加班的你,灵魂里面根本没有动手能力这个概念."
);
printf(
"\n%s"
, (char)
"大公鸡攻击了你的小公鸡,GAME OVER ..."
);
goto LABEL_57;
}
...
...
const_9
=
v17
+
2
;
v20
=
v18
-
const_9
-
7
;
if
( inputvalue[
3
] !
=
20
)
/
/
chr
(
20
+
55
)
=
'K'
{
...
if
( inputvalue[
4
] !
=
12
)
/
/
'C'
{
...
if
( inputvalue[
5
] !
=
29
)
/
/
'T'
{
...
if
( inputvalue[
6
] !
=
15
)
/
/
'F'
{
...
...
const_9
=
v17
+
2
;
v20
=
v18
-
const_9
-
7
;
if
( inputvalue[
3
] !
=
20
)
/
/
chr
(
20
+
55
)
=
'K'
{
...
if
( inputvalue[
4
] !
=
12
)
/
/
'C'
{
...
if
( inputvalue[
5
] !
=
29
)
/
/
'T'
{
...
if
( inputvalue[
6
] !
=
15
)
/
/
'F'
{
...
...
v21
=
0
;
inputlen2
=
0
;
if
( const_9 >
0
)
{
v22
=
1
;
do
{
v23
=
inputvalue[v22
+
6
]
+
10
*
v70;
v24
=
v23
-
926365495
;
if
( v23 <
=
1262703685
)
v24
=
v23;
v70
=
v24;
if
( v24
%
v69 )
goto LABEL_50;
v21
=
inputlen2
+
1
;
v22
=
v69
+
1
;
inputlen2
=
v21;
+
+
v69;
}
while
( v21 < const_9 );
}
if
( v21 !
=
const_9 )
{
...
...
v21
=
0
;
inputlen2
=
0
;
if
( const_9 >
0
)
{
v22
=
1
;
do
{
v23
=
inputvalue[v22
+
6
]
+
10
*
v70;
v24
=
v23
-
926365495
;
if
( v23 <
=
1262703685
)
v24
=
v23;
v70
=
v24;
if
( v24
%
v69 )
goto LABEL_50;
v21
=
inputlen2
+
1
;
v22
=
v69
+
1
;
inputlen2
=
v21;
+
+
v69;
}
while
( v21 < const_9 );
}
if
( v21 !
=
const_9 )
{
...
def
checknum(s :
str
):
assert
len
(s)
=
=
9
for
i
in
range
(
1
,
10
):
n
=
int
(s[:i])
if
n
%
i:
return
False
return
True
def
checknum(s :
str
):
assert
len
(s)
=
=
9
for
i
in
range
(
1
,
10
):
n
=
int
(s[:i])
if
n
%
i:
return
False
return
True
...
v25
=
const_9
-
1
;
if
( const_9
-
1
>
0
)
{
v26
=
const_9
-
1
;
do
{
v27
=
0
;
if
( v25 >
0
)
{
do
{
v28
=
inputvalue[v27
+
7
];
v29
=
inputvalue[v27
+
8
];
if
( v28 > v29 )
{
inputvalue[v27
+
7
]
=
v29;
inputvalue[v27
+
8
]
=
v28;
}
+
+
v27;
}
while
( v27 < v25 );
v3
=
0
;
}
-
-
v25;
-
-
v26;
}
while
( v26 );
}
hex_to_int(
"1234567890_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
, const_9);
v30
=
0
;
if
( const_9 >
0
)
{
while
( a1234567890Abcd[v30]
=
=
inputvalue[v30
+
7
] )
{
if
(
+
+
v30 >
=
const_9 )
goto LABEL_41;
}
goto LABEL_49;
}
...
...
v25
=
const_9
-
1
;
if
( const_9
-
1
>
0
)
{
v26
=
const_9
-
1
;
do
{
v27
=
0
;
if
( v25 >
0
)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2022-6-26 00:51
被mb_mgodlfyn编辑
,原因: