文章目录
  1. 1. 思路
  2. 2. 具体分析

思路

这个题就是把输入的字符串先去掉ZCTF{}后,把括号里的字符串替换,然后进行了浮点运算,运算后的结果和0x19异或,得到的数值就是 . 7 , ) ! . ( , , ) . , , /

具体分析

载入IDA能看出flag格式为:

  1. 小于36字符
  2. 格式为ZCTF{}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
signed int __usercall start@<eax>(int a1@<esi>, _BYTE *a2@<ebx>)
{
signed int result; // eax@2
char v3; // [sp+1h] [bp-29h]@4
char Str; // [sp+2h] [bp-28h]@1
int v5; // [sp+3h] [bp-27h]@1
int v6; // [sp+7h] [bp-23h]@1
int v7; // [sp+Bh] [bp-1Fh]@1
int v8; // [sp+Fh] [bp-1Bh]@1
int v9; // [sp+13h] [bp-17h]@1
int v10; // [sp+17h] [bp-13h]@1
int v11; // [sp+1Bh] [bp-Fh]@1
char v12; // [sp+1Fh] [bp-Bh]@1
char *v13; // [sp+26h] [bp-4h]@8
Str = 0;
v5 = 0;
v6 = 0;
v7 = 0;
v8 = 0;
v9 = 0;
v10 = 0;
v11 = 0;
v12 = 0;
printf("Please input the flag : ");
scanf("%s", &Str);
if ( strlen(&Str) < 0x1E )
{
if ( SBYTE3(v5) == '{' && *(&v3 + strlen(&Str)) == '}' )
{
*(&v3 + strlen(&Str)) = 0;
BYTE3(v5) = 0;
if ( !stricmp(&Str, "ZCTF") )
{
v13 = &v6;
if ( sub_E912E0(a1, a2, &v6) )
printf("Congratulations!\n");
else
printf("Sorry! Flag error!\n");
result = 0;
}
else
{
printf("Sorry! Flag error!\n");
result = 1;
}
}
else
{
printf("Sorry! Flag error!\n");
result = 1;
}
}
else
{
printf("Sorry! Flag error!\n");
result = 1;
}
return result;
}

用OD进行动态调试,关键位置下好断点,来到如下位置

跟到上面的位置,发现大括号里面长度为17,然后取每一字符减去0x30再查询一个偏移表,然后通过跳转表跳转到指定位置初始化一个全局变量。
跳转表如下:

偏移表如下:

其中偏移表中填充了大量0x0B,查询到这个偏移后通过跳转表会直接跳转到函数结束的位置。这里要注意这两个表的跳转关系,输入的字符每一个减去0x30后,先和0x3F比较(偏移表的长度为0x3F,不能跑到这个表外面去),然后再加偏移表的首地址得到一个地址,里面的值就是偏移量,如果值是0,就对应分支表的第一个跳转,如果值是1就对应分支表的第二个跳转,依次类推。跳转到相对应的位置进行替换。
通过偏移表中对应的值的地址-偏移表起始地址+0x30反推输入与全局变量的关系如下:

1
2
3
4
5
6
7
8
9
10
11
0 .
o 0
e 1
T 2
H 3
U 4
_ 5
S 6
8 7
W 8
R 9

当然这种对应关系看IDA会更加清楚一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
char *__usercall sub_E91000@<eax>(int a1@<ebp>)
{
size_t v1; // eax@1
char *result; // eax@2
v1 = strlen(*(a1 + 8));
if ( v1 == 17 )
{
*(a1 - 4) = 0;
*(a1 - 5) = *(*(a1 - 4) + *(a1 + 8));
while ( 2 )
{
*(a1 - 12) = *(a1 - 5);
*(a1 - 12) -= 0x30;
switch ( *(a1 - 12) )
{
case 0:
*(&Str + *(a1 - 4)) = 0x2E;
goto LABEL_19;
case 0x3F:
*(&Str + *(a1 - 4)) = 0x30;
goto LABEL_19;
case 0x35:
*(&Str + *(a1 - 4)) = 0x31;
goto LABEL_19;
case 0x24:
*(&Str + *(a1 - 4)) = 0x32;
goto LABEL_19;
case 0x18:
*(&Str + *(a1 - 4)) = 0x33;
goto LABEL_19;
case 0x25:
*(&Str + *(a1 - 4)) = 0x34;
goto LABEL_19;
case 0x2F:
*(&Str + *(a1 - 4)) = 0x35;
goto LABEL_19;
case 0x23:
*(&Str + *(a1 - 4)) = 0x36;
goto LABEL_19;
case 8:
*(&Str + *(a1 - 4)) = 0x37;
goto LABEL_19;
case 0x27:
*(&Str + *(a1 - 4)) = 56;
goto LABEL_19;
case 0x22:
*(&Str + *(a1 - 4)) = 57;
LABEL_19:
*(a1 - 5) = *(++*(a1 - 4) + *(a1 + 8));
if ( *(a1 - 5) )
continue;
result = &Str;
break;
default:
result = 0;
break;
}
break;
}
}
else
{
result = 0;
}
return result;
}

然后将这个数值在00c61323这个函数里做浮点运算

运算后的结果和0x19异或后和字符串. 7 , ) ! . ( , , ) . , , / 进行比较,当然我们用0x19和字符串. 7 , ) ! . ( , , ) . , , / 异或后会得到正确的flag的浮点运算结果,然后逆推。
对应关系如下:

1
2
.7,)*!.(,,).,,*/**
7.5038715507553633

所以重点在浮点运算,我们看一下浮点运算函数的汇编代码

F7跟入函数



根据0xF13348处的浮点数一共算出四个结果,分析过程如上图。得到一元二次方程,我们解这个方程得到浮点运算前的数值,也就是刚开始时替换后的数值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!usr/bin/env python
# _*_ coding: utf-8 -*-
from sympy import *
"""
res1 = (Str - 1.864832709999999) * (6.51951822361*Str)
res2 = (Str - 5.778432978588) * (Str + 3.1415926) * 7.861418532
res3 = (Str*Str - 0.8521405969999999) * (8.7356198421365 - 2.0000)
res4 = (Str*Str * 4.93287651872 - Str * 9.542697368122542) * 2.681794561929999
result = res1 + res2 - res3 + res4 + 60.0000
"""
Str = symbols('Str')
jie = solve([-7.5038715507553633 +(Str - 1.864832709999999) * (6.51951822361*Str)
+(Str - 5.778432978588) * (Str + 3.1415926) * 7.861418532
-(Str*Str - 0.8521405969999999) * (8.7356198421365 - 2.0000)
+ (Str*Str * 4.93287651872 - Str * 9.542697368122542) * 2.681794561929999
+ 60.0000],[Str])
print jie

结果如下:

1
2
3
4
D:\Python27\python.exe C:/Users/Desktop/Math.py
[(-1.05058442661615,), (3.85205471562591,)]
Process finished with exit code 0

有两个解,[(-1.05058442661615,), (3.85205471562591,)]
上面的result,也就是7.5038715507553633是根据判断处的数据和0x19异或得到的。
解出来以后通过查上面的对应关系能得到FLAG。负解舍弃,保留正解3.85205471562591,但由于精度不够,最后一位字符没有对照,但完全可以猜出来,就是那17个字符8 , H , R , S , T , U , W , _ , e , o , 0 中的一个。最后flag为ZCTF{H0W_To_U8e_ST_Re8}

文章目录
  1. 1. 思路
  2. 2. 具体分析