google2021年3月

beginners

simple changes using intel xmm instructions, these are docs

https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_xor_si128&expand=6170

https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8&expand=5153

https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_epi32&expand=94

It is worthy to notice that the docs are operate on bits

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
from z3 import *
from Crypto.Util.number import long_to_bytes

xord = [118, 88, 180, 73, 141, 26, 95, 56, 212, 35, 248, 52, 235, 134, 249, 170]
addd = [239, 190, 173, 222, 173, 222, 225, 254, 55, 19, 55, 19, 102, 116, 99, 103]
shuffle = [2, 6, 7, 1, 5, 11, 9, 14, 3, 15, 4, 8, 10, 12, 13, 0]
xordw = 0
adddw = 0
pack = lambda x,i:x[i]|(x[i+1]<<8)|(x[i+2]<<16)|(x[i+3]<<24)
xorp = [pack(xord,i) for i in range(0,16,4)]
addp = [pack(addd,i) for i in range(0,16,4)]
for i in range(4):
print(hex(xorp[i]),hex(addp[i]))
v = [BitVec("v%d"%i,32) for i in range(16)]
s = Solver()
for i in range(16):
s.add(v[i]>=0)
s.add(v[i]<=0xff)
for i in range(0,16,4):
s.add((v[i]|(v[i+1]<<8)|(v[i+2]<<16)|(v[i+3]<<24))^xorp[i//4]==(v[shuffle[i]]|(v[shuffle[i+1]]<<8)|(v[shuffle[i+2]]<<16)|(v[shuffle[i+3]]<<24))+addp[i//4])
s.add(v[0]==ord('C'))
s.add(v[1]==ord('T'))
s.add(v[2]==ord('F'))
s.add(v[3]==ord('{'))
res = []
if s.check()==sat:
m = s.model()
print(m)
for i in v:
res.append(m[i].as_long())
print(res,bytes(res))

[rev]ANDROID

open the apk file with jadx, you can see the main algorithm. I’m sorry I can’t break out reverse algorithm, so I brute it.

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

public class Main{
public static long[] m0(long a, long b) {
if (a == 0) {
return new long[]{0, 1};
}
long[] r = m0(b % a, a);
return new long[]{r[1] - ((b / a) * r[0]), r[0]};
}

static int a[] = new int[]{65, 112, 112, 97, 114, 101, 110, 116, 108, 121, 32, 116, 104, 105, 115, 32, 105, 115, 32, 110, 111, 116, 32, 116, 104, 101, 32, 102, 108, 97, 103, 46, 32, 87, 104, 97, 116, 39, 115, 32, 103, 111, 105, 110, 103, 32, 111, 110, 63};
static long cmpData[] = new long[]{40999019, 2789358025L, 656272715, 18374979, 3237618335l, 1762529471, 685548119, 382114257, 1436905469, 2126016673, 3318315423l, 797150821};
public static void main(String[] args){
long num = 4294967296L;
byte dic[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+{}_-/!?".getBytes();
int l = dic.length;
StringBuilder sbF = new StringBuilder();

for(int i=0;i<cmpData.length;i++){
boolean notOk=true;
for(int i1=0;i1<l&&notOk;i1++){
for(int i2=0;i2<l&&notOk;i2++){
for(int i3=0;i3<l&&notOk;i3++){
for(int i4=0;i4<l&&notOk;i4++){
long data = dic[i1]|(dic[i2]<<8)|(dic[i3]<<16)|(dic[i4]<<24);
if(((m0(data,num)[0]%num)+num)%num==cmpData[i]){
System.out.printf("0x%x\n",data);
System.out.printf("%c%c%c%c\n",dic[i1],dic[i2],dic[i3],dic[i4]);
sbF.append(new String(new byte[]{dic[i1],dic[i2],dic[i3],dic[i4]}));
notOk=false;
}
}
}
}
}

}
System.out.println(sbF.toString());
}
}

.net

https://mrt4ntr4.github.io/GoogleCTF-dotNet/

使用了下面的库,在运行时会动态patch代码
https://github.com/pardeike/Harmony

dnspy在程序上右键->转到入口点可以直接找到入口点。

一步一步找到检测函数:输入长度是30,先把输入单个字符base64解码转成列表,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static List<uint> GRUNDTAL_NORRVIKEN(string LINNMON)
{
List<uint> list = new List<uint>(LINNMON.Length);
int num = 0;
if (0 < LINNMON.Length)
{
do
{
list.Add(<Module>.DecodeBase64Bytewise((sbyte)LINNMON[num]));
num++;
}
while (num < LINNMON.Length);
}
return list;
}

然后判断每个字符都应该小于等于63。

执行按字节异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class FARGRIK
{
// Token: 0x0600014B RID: 331 RVA: 0x00001948 File Offset: 0x00000D48
public static void DAGSTORP(ref List<uint> primary, List<uint> filter)
{
int num = 0;
if (0 < primary.Count)
{
do
{
primary[num] = (filter[num % filter.Count] ^ primary[num]);
num++;
}
while (num < primary.Count);
}
}

计算checksum

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
internal static bool SMORBOLL(List<uint> IRMELIN)
{
if (IRMELIN.Count == 0)
{
return true;
}
uint num = 16U;
int num2 = 0;
if (0 < IRMELIN.Count)
{
do
{
if (num2 != IRMELIN.Count - 2)
{
num = IRMELIN[num2] + num;
if (num2 % 2 == 0)
{
num = IRMELIN[num2] + num;
}
int num3 = num2;
if (num3 - num3 / 3 * 3 == 0)
{
num = IRMELIN[num2] * 4294967294U + num;
}
int num4 = num2;
if (num4 - num4 / 5 * 5 == 0)
{
num = IRMELIN[num2] * 4294967293U + num;
}
int num5 = num2;
if (num5 - num5 / 7 * 7 == 0)
{
num = IRMELIN[num2] * 4U + num;
}
}
num2++;
}
while (num2 < IRMELIN.Count);
}
return (((uint)((sbyte)IRMELIN[IRMELIN.Count - 2]) == (num & 63U)) ? 1 : 0) != 0;
}

检测是否有重复

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
internal static bool VAXMYRA(List<uint> LYCKSELE)
{
int num = 0;
if (0 < LYCKSELE.Count)
{
do
{
int num2 = 0;
if (0 < num)
{
while (LYCKSELE[num] != LYCKSELE[num2])
{
num2++;
if (num2 >= num)
{
goto IL_29;
}
}
return false;
}
IL_29:
num++;
}
while (num < LYCKSELE.Count);
return true;
}
return true;
}

最终检测

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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
internal static string HEROISK(List<uint> MATHOPEN)
{
string result = "Invalid flag. Please check the number and try again.";
if (!<Module>.VAXMYRA(MATHOPEN))
{
return result;
}
if (MATHOPEN[1] != 25U)
{
return result;
}
if (MATHOPEN[2] != 23U)
{
return result;
}
if (MATHOPEN[9] != 9U)
{
return result;
}
if (MATHOPEN[20] != 45U)
{
return result;
}
if (MATHOPEN[26] != 7U)
{
return result;
}
if (MATHOPEN[8] < 15U)
{
return result;
}
if (MATHOPEN[12] > 4U)
{
return result;
}
if (MATHOPEN[14] < 48U)
{
return result;
}
if (MATHOPEN[29] < 1U)
{
return result;
}
int num = (int)MATHOPEN[4];
int num2 = (int)MATHOPEN[3];
int num3 = (int)MATHOPEN[2];
int num4 = (int)MATHOPEN[1];
if (((MATHOPEN[0] + (uint)num4 + (uint)num + (uint)num3 + (uint)num2 - 130U <= 10U) ? 1 : 0) == 0)
{
return result;
}
num4 = (int)MATHOPEN[9];
int num5 = (int)MATHOPEN[8];
int num6 = (int)MATHOPEN[7];
int num7 = (int)MATHOPEN[6];
if (((MATHOPEN[5] + (uint)num7 + (uint)num6 + (uint)num5 + (uint)num4 - 140U <= 10U) ? 1 : 0) == 0)
{
return result;
}
int num8 = (int)MATHOPEN[14];
int num9 = (int)MATHOPEN[13];
int num10 = (int)MATHOPEN[12];
int num11 = (int)MATHOPEN[11];
if (((MATHOPEN[10] + (uint)num11 + (uint)num10 + (uint)num9 + (uint)num8 - 150U <= 10U) ? 1 : 0) == 0)
{
return result;
}
int num12 = (int)MATHOPEN[19];
int num13 = (int)MATHOPEN[18];
int num14 = (int)MATHOPEN[17];
int num15 = (int)MATHOPEN[16];
if (((MATHOPEN[15] + (uint)num15 + (uint)num14 + (uint)num13 + (uint)num12 - 160U <= 10U) ? 1 : 0) == 0)
{
return result;
}
int num16 = (int)MATHOPEN[24];
int num17 = (int)MATHOPEN[23];
int num18 = (int)MATHOPEN[22];
int num19 = (int)MATHOPEN[21];
if (((MATHOPEN[20] + (uint)num19 + (uint)num18 + (uint)num17 + (uint)num16 - 170U <= 10U) ? 1 : 0) == 0)
{
return result;
}
int num20 = (int)MATHOPEN[25];
int num21 = (int)MATHOPEN[20];
int num22 = (int)MATHOPEN[15];
int num23 = (int)MATHOPEN[10];
int num24 = (int)MATHOPEN[5];
if (((MATHOPEN[0] + (uint)num24 + (uint)num23 + (uint)num22 + (uint)num21 + (uint)num20 - 172U <= 6U) ? 1 : 0) == 0)
{
return result;
}
int num25 = (int)MATHOPEN[26];
int num26 = (int)MATHOPEN[21];
int num27 = (int)MATHOPEN[16];
int num28 = (int)MATHOPEN[11];
int num29 = (int)MATHOPEN[6];
if (((MATHOPEN[1] + (uint)num29 + (uint)num28 + (uint)num27 + (uint)num26 + (uint)num25 - 162U <= 6U) ? 1 : 0) == 0)
{
return result;
}
int num30 = (int)MATHOPEN[27];
int num31 = (int)MATHOPEN[22];
int num32 = (int)MATHOPEN[17];
int num33 = (int)MATHOPEN[12];
int num34 = (int)MATHOPEN[7];
if (((MATHOPEN[2] + (uint)num34 + (uint)num33 + (uint)num32 + (uint)num31 + (uint)num30 - 152U <= 6U) ? 1 : 0) == 0)
{
return result;
}
int num35 = (int)MATHOPEN[23];
int num36 = (int)MATHOPEN[18];
int num37 = (int)MATHOPEN[13];
int num38 = (int)MATHOPEN[8];
if (((MATHOPEN[3] + (uint)num38 + (uint)num37 + (uint)num36 + (uint)num35 - 142U <= 6U) ? 1 : 0) == 0)
{
return result;
}
int num39 = (int)MATHOPEN[29];
int num40 = (int)MATHOPEN[24];
int num41 = (int)MATHOPEN[19];
int num42 = (int)MATHOPEN[14];
int num43 = (int)MATHOPEN[9];
if (((MATHOPEN[4] + (uint)num43 + (uint)num42 + (uint)num41 + (uint)num40 + (uint)num39 - 132U <= 6U) ? 1 : 0) == 0)
{
return result;
}
uint num44 = MATHOPEN[27] * 3U;
uint num45 = (MATHOPEN[7] + num44) * 3U - MATHOPEN[5] * 13U;
if (num45 - 57U > 28U)
{
return result;
}
num44 = MATHOPEN[20] * 5U;
num44 = (MATHOPEN[14] << 2) - num44;
num45 = MATHOPEN[22] * 3U + num44;
if (num45 - 12U > 70U)
{
return result;
}
num44 = MATHOPEN[18] * 2U;
num44 = (MATHOPEN[15] - num44) * 3U;
uint num46 = MATHOPEN[16] * 2U;
num46 = (MATHOPEN[14] + num46) * 2U + num44 - MATHOPEN[17] * 5U;
if (MATHOPEN[13] + num46 != 0U)
{
return result;
}
num46 = MATHOPEN[6] * 2U;
if (MATHOPEN[5] != num46)
{
return result;
}
if (MATHOPEN[29] + MATHOPEN[7] != 59U)
{
return result;
}
uint num47 = MATHOPEN[17] * 6U;
if (MATHOPEN[0] != num47)
{
return result;
}
num47 = MATHOPEN[9] * 4U;
if (MATHOPEN[8] != num47)
{
return result;
}
num47 = MATHOPEN[13] * 3U;
if (MATHOPEN[11] << 1 != num47)
{
return result;
}
if (MATHOPEN[13] + MATHOPEN[29] + MATHOPEN[11] + MATHOPEN[4] != MATHOPEN[19])
{
return result;
}
uint num48 = MATHOPEN[12] * 13U;
if (MATHOPEN[10] != num48)
{
return result;
}
return null;
}

sprint