2021羊城杯
没空打 就写了两题

BabySmc

先写个脚本对抗Smc

1
2
3
4
5
6
7
8
9
10
11
12
13
import idc

def ror(v):
v = ((v&0xf8) >> 3) | ((v&7) << 5)
return v

st = 0x140001085
while st <= 0x140001D00:
value = idc.get_byte(st)
value = ror(value)
value ^= 0x5A
ida_bytes.patch_byte(st, value)
st += 1

去了Smc发现F5很难看,然后看汇编以及分析寄存器

可以知道是换表混淆base64

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
#include <stdio.h>

unsigned char table[] =
{
0xE4, 0xC4, 0xE7, 0xC7, 0xE6, 0xC6, 0xE1, 0xC1, 0xE0, 0xC0,
0xE3, 0xC3, 0xE2, 0xC2, 0xED, 0xCD, 0xEC, 0xCC, 0xEF, 0xCF,
0xEE, 0xCE, 0xE9, 0xC9, 0xE8, 0xC8, 0xEB, 0xCB, 0xEA, 0xCA,
0xF5, 0xD5, 0xF4, 0xD4, 0xF7, 0xD7, 0xF6, 0xD6, 0xF1, 0xD1,
0xF0, 0xD0, 0xF3, 0xD3, 0xF2, 0xD2, 0xFD, 0xDD, 0xFC, 0xDC,
0xFF, 0xDF, 0x95, 0x9C, 0x9D, 0x92, 0x93, 0x90, 0x91, 0x96,
0x97, 0x94, 0x8A, 0x8E
};

int find(int num)
{
for(int i = 0; i < 64; ++i)
{
if(num == table[i])
return i;
}
}

int main()
{
char cmp[] ="H>oQn6aqLr{DH6odhdm0dMe`MBo?lRglHtGPOdobDlknejmGI|ghDb<4";
for(int i = 0; cmp[i] ; i += 4)
{
char a1 = (find(cmp[i] ^ 0xA6) << 2) | (find(cmp[i+1] ^ 0xA3) >> 4);
char a2 = (find(cmp[i+1] ^ 0xA3) << 4) | (find(cmp[i+2] ^ 0xA9) >> 2);
char a3 = (find(cmp[i+2] ^ 0xA9) << 6) | find(cmp[i+3] ^ 0xAC);
printf("%c%c%c",a1,a2,a3);
}

SangFor{XSAYT0u5DQhaxveIR50X1U13M-pZK5A0}

safe box

第一段可以看出是输入一个int,在用这个输入去运算最后比较,

于是通过爆破解出第一段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

int main()
{
for(int i = 0; i < 0x7fffffff; ++i)
{
int v2 = (i % 0x2540BE3FF) & 0xff;
int v3 = ((i % 0x2540BE3FF) >> 8) & 0xF;
int v4 = ((i % 0x2540BE3FF) >> 20) & 0xFFF;
int v8 = v4 + ~v2;
int v7 = v3 + 1;
int v6 = ((i % 0x2540BE3FF) >> 12) & 0xff;
for(int j = 0; j < 16; ++j)
{
v3 += v3 ^ v8;
v2 += v4 | v2 & v7;
v6 += v6 / v7;
}
if (v3 == 58722033 && v2 == 29329 && v6 == 128)
printf("%d\n",i);
}
}//1915969329

这个程序由于是自我调试,通过管道来通信,既达到anti-debug的效果,又能够自解密

我正常输入第一段之后,程序就会进行自解密,并进入下一段

这里我选择dump出解密后的程序,再在其上分析,工具我用的是studyPE

并且将里面的CC patch以后就可以正常调试了

分析第二段可以发现,

输入的char都被放到int数组里储存,比如输入123,内存中是31000000 32000000 33000000

而后又每次取两个int作为sub_140001880的输入,经过运算后改变,再与固定数据作比较

遂又写爆破

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
void sub_7FF7547B1880(unsigned int *input)
{
unsigned int a1; // er9
unsigned int v4; // er10
char v6; // r8
int v7; // rbx
unsigned int v8; // ecx
unsigned int v9; // er10
unsigned int v10; // er9
unsigned int v11; // eax
int v12; // edx
unsigned int v13; // er9
unsigned int v14; // eax
int v15; // edx
unsigned int v16; // er9
unsigned int v17; // eax
unsigned int v18; // ecx
unsigned int v19; // er9
unsigned int a10; // eax
int a11; // edx
unsigned int a12; // er9
unsigned int a13; // eax
int a14; // edx
unsigned int a15; // er9
unsigned int a16; // eax
unsigned int a17; // ecx
unsigned int a18; // er9
unsigned int a19; // eax
int v30; // edx
unsigned int v31; // er9
unsigned int v32; // eax
int v33; // edx
unsigned int v34; // er9
unsigned int v35; // eax
int v36; // edx
unsigned int v37; // er9
unsigned int v38; // eax
int v39; // edx
unsigned int v40; // er9
unsigned int v41; // eax
int v42; // edx
unsigned int v43; // er9
unsigned int v44; // eax
unsigned int v45; // er9
unsigned int v46; // eax
int v47; // edx
unsigned int v48; // er9
unsigned int v49; // eax
int v50; // edx
unsigned int v51; // er9
unsigned int v52; // eax
int v53; // edx
int GWHT[] ={0x47,0x57,0x48,0x54};
a1 = input[0];
int a2 = input[1];
v4 = 0;
v6 = 0;
v7 = 2;
do
{
v8 = v4 + GWHT[v6 & 3];
v9 = v4 + 0x12345678;
v10 = (v8 ^ (a2 + ((32 * a2) ^ ((unsigned int)a2 >> 6)))) + a1;
v11 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v10 + ((32 * v10) ^ (v10 >> 6)))) + a2;
v12 = (v9 + GWHT[v9 & 3]) ^ (v11 + ((32 * v11) ^ (v11 >> 6)));
v9 += 0x12345678;
v13 = v12 + v10;
v14 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v13 + ((32 * v13) ^ (v13 >> 6)))) + v11;
v15 = (v9 + GWHT[v9 & 3]) ^ (v14 + ((32 * v14) ^ (v14 >> 6)));
v9 += 0x12345678;
v16 = v15 + v13;
v17 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v16 + ((32 * v16) ^ (v16 >> 6)))) + v14;
v18 = v9 + GWHT[v9 & 3];
v9 += 0x12345678;
v19 = (v18 ^ (v17 + ((32 * v17) ^ (v17 >> 6)))) + v16;
a10 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v19 + ((32 * v19) ^ (v19 >> 6)))) + v17;
a11 = (v9 + GWHT[v9 & 3]) ^ (a10 + ((32 * a10) ^ (a10 >> 6)));
v9 += 0x12345678;
a12 = a11 + v19;
a13 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (a12 + ((32 * a12) ^ (a12 >> 6)))) + a10;
a14 = (v9 + GWHT[v9 & 3]) ^ (a13 + ((32 * a13) ^ (a13 >> 6)));
v9 += 0x12345678;
a15 = a14 + a12;
a16 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (a15 + ((32 * a15) ^ (a15 >> 6)))) + a13;
a17 = v9 + GWHT[v9 & 3];
v9 += 0x12345678;
a18 = (a17 ^ (a16 + ((32 * a16) ^ (a16 >> 6)))) + a15;
a19 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (a18 + ((32 * a18) ^ (a18 >> 6)))) + a16;
v30 = (v9 + GWHT[v9 & 3]) ^ (a19 + ((32 * a19) ^ (a19 >> 6)));
v9 += 0x12345678;
v31 = v30 + a18;
v32 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v31 + ((32 * v31) ^ (v31 >> 6)))) + a19;
v33 = (v9 + GWHT[v9 & 3]) ^ (v32 + ((32 * v32) ^ (v32 >> 6)));
v9 += 0x12345678;
v34 = v33 + v31;
v35 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v34 + ((32 * v34) ^ (v34 >> 6)))) + v32;
v36 = (v9 + GWHT[v9 & 3]) ^ (v35 + ((32 * v35) ^ (v35 >> 6)));
v9 += 0x12345678;
v37 = v36 + v34;
v38 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v37 + ((32 * v37) ^ (v37 >> 6)))) + v35;
v39 = (v9 + GWHT[v9 & 3]) ^ (v38 + ((32 * v38) ^ (v38 >> 6)));
v9 += 0x12345678;
v40 = v39 + v37;
v41 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v40 + ((32 * v40) ^ (v40 >> 6)))) + v38;
v42 = (v9 + GWHT[v9 & 3]) ^ (v41 + ((32 * v41) ^ (v41 >> 6)));
v9 += 0x12345678;
v43 = v42 + v40;
v44 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v43 + ((32 * v43) ^ (v43 >> 6)))) + v41;
v45 = ((v9 + GWHT[v9 & 3]) ^ (v44 + ((32 * v44) ^ (v44 >> 6)))) + v43;
v9 += 0x12345678;
v46 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v45 + ((32 * v45) ^ (v45 >> 6)))) + v44;
v47 = (v9 + GWHT[v9 & 3]) ^ (v46 + ((32 * v46) ^ (v46 >> 6)));
v9 += 0x12345678;
v48 = v47 + v45;
v49 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v48 + ((32 * v48) ^ (v48 >> 6)))) + v46;
v50 = (v9 + GWHT[v9 & 3]) ^ (v49 + ((32 * v49) ^ (v49 >> 6)));
v9 += 0x12345678;
v51 = v50 + v48;
v52 = ((v9 + GWHT[(v9 >> 11) & 3]) ^ (v51 + ((32 * v51) ^ (v51 >> 6)))) + v49;
v53 = (v9 + GWHT[v9 & 3]) ^ (v52 + ((32 * v52) ^ (v52 >> 6)));
v4 = v9 + 0x12345678;
a1 = v53 + v51;
v6 = v4;
a2 = ((v4 + GWHT[(v4 >> 11) & 3]) ^ (a1 + ((32 * a1) ^ (a1 >> 6)))) + v52;
--v7;
}
while ( v7 );
input[0] = a1;
input[1] = a2;
}


int cmp[10] =
{
0x036C128C5, 0x0C4799A63,
0x0E8013E6C, 0x0A9F49003,
0x0607EF54A, 0x0542C2DDF,
0x0558BD01C, 0x065512CA2,
0x0BE1E3D05, 0x03C467DAD,
};

#include <stdio.h>

int main()
{
for(int i = 0; i < 5; ++i)
{
for(int j = 0; j < 255; ++j)
for(int k = 0; k < 255; ++k)
{
int a[2]= {j,k};
sub_7FF7547B1880(a);
if(cmp[i * 2] == a[0] && cmp[i * 2 + 1] == a[1])
{
//printf("%d : %c -> %x\t%c -> %x\n",i,j,j,k,k);
printf("%c%c",j,k);
}
}

}
}//S_s0_fuNny

第三段代码里面又插了个CC

分析处理debug事件的代码可以发现,改变了ecx的值

而这个ecx用作与srand()的参数

所以将代码patch成mov ecx,xxx 即可

这里也是将输入传入int数组

而在送进sub_1400025C0(v14, v13)里后v14是固定不变的

v13是输入与固定int数组经过运算得到的

而在这个函数之中,运算使用v14改变了传入的数的排列顺序,再与固定int数组比较

因为排列顺序是不变的,于是我对照传入时的v13与排列后的v13,在从cmp中一一对应

就得到了应该传入的v13

那么最后的问题就是输入与固定int数组经过了何种运算才得到了应该传入的v13了

1
2
3
4
5
6
7
8
9
movdqu  xmm1, xmmword ptr [rsp+rdi+1F8h+var_1D8]
movdqu xmm0, [rsp+rdi+1F8h+var_158]
lea rdi, [rdi+10h]
movdqa xmm2, xmm1
pand xmm2, xmm0
pxor xmm1, xmm0
pandn xmm2, xmm3
pand xmm2, xmm1
movdqu [rsp+rdi+1F8h+var_C8], xmm2

跟踪这一段,发现还是看的不是很懂

最后看了一下数据,发现有点像是异或,于是异或一下没想到出了

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
#include <stdio.h>
int main()
{
unsigned int rands[]=
{
0x4147,0x2F06,0x5017,0x7D6C,
0x1583,0x37EA,0x6FDC,0x0D03,
0x3F43,0x4156,0x0ED7,0x1094,
0x5C4F,0x173F,0x193A,0x1357,
};

unsigned int cmp[]=
{
0x4118,0x2F62,0x5027,0x7D33,
0x15DA,0x3785,0x6F89,0x0D5C,
0x3F72,0x413F,0x0EBC,0x10A7,
0x5C10,0x174B,0x190A,0x1338,
};

for(int i = 0; i < 4; ++i)
{
for(int k = 0; k < 4; ++k)
{
//for(unsigned int a = 0; a < 255; ++a)
//{
// if( (a & rands[i * 4 + k]) & (a ^ rands[i * 4 + k]) == cmp[i * 4 + k])
// printf("%d : %c -> %02x\n",i * 4 + k,a,a);
// //printf("%c",a);
//}
printf("%c",rands[i * 4 + k] ^ cmp[i * 4 + k]);
}

}
}//_d0_YoU_1ik3_t0o

所以最后的flag是

GWHT{1915969329S_s0_fuNny_d0_YoU_1ik3_t0o}

文章作者: Usher
文章链接: https://usher2008.github.io/2021/09/13/YCB2021/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Usher