[Geek Challenge 2021] Reverse赛题复现
VNCTF和HGAME属实给👴整破防了,人直接自闭了半个月
现在拿这逼极客大挑战练个手,粗略看了眼wp还是有些新东西可以学的,顺便拿其中的简单题找下自信,争取下次TQLCTF👴能成功签到
Brute_force
第一次做golang逆向,本来ida报了个这个错
以为ida抽风了,想装个golanghelper帮帮忙,然后大爹评价到
那说明本萌新觉得看起来很奇怪的反编译其实是没有问题的🥺
我们猜测main_unnamed()
是另外一坨main函数,应该是得进去跑一跑的,那*(_QWORD *)(os_Args + 24) == 24LL
应该是在判断flag长度是否为24
在main_unnamed
中,main_encode()
应该是加密,main_cipher1
应该是正确的flag加后的样子
然后我们在main_encode()
里发现了一个函数叫crypto_md5_Sum()
,我选择相信出题人(
回到main_cipher1
处,我们可以发现一堆md5值
我们一个一个去网站上查
4ad50c4af2c5beda7aca217afbac9bd6 = 3_sl
5781f597ce91fb5f66057f35846bcb78 = r0g@
957a3926d4ff16d0d3bac4ed3044537b = 7h3_
ae4b9b5b2468a3d15b6b8690b761e160 = rm_1
d7bf94ada03842f20934c5605728fbc5 = g0_p
f40b339be4c5898741b8a0d2a8007bd5 = gned
剩下就是个misc题了(
SYC{7h3_g0_pr0g@rm_13_slgned}
另:正解其实应该从flag长度为24,md5有6个推出每个md5对应4字节,然后爆破md5的,这才是题目名字是Brute_force的原因,可惜出题人的网站没我的强😋
easypyc
那直接用pyinstxtractor解包
一个刚知道的小技巧:把easypyc.pyc的magic numberr替换成struct.pyc的第一行,就不用费那么大的劲去对magic number啥的了
然后用uncompyle6反编译
whatbox = [
0] * 256
def aaaaaaa(a, b):
k = [
0] * 256
t = 0
for m in range(256):
whatbox[m] = m
k[m] = ord(a[(m % b)])
else:
for i in range(256):
t = (t + whatbox[i] + k[i]) % 256
temp = whatbox[i]
whatbox[i] = whatbox[t]
whatbox[t] = temp
def bbbbbbbbbb(a, b):
q = 0
w = 0
e = 0
for k in range(b):
q = (q + 1) % 256
w = (w + whatbox[q]) % 256
temp = whatbox[q]
whatbox[q] = whatbox[w]
whatbox[w] = temp
e = (whatbox[q] + whatbox[w]) % 256
a[k] = a[k] ^ whatbox[e] ^ 102
def ccccccccc(a, b):
for i in range(b):
a[i] ^= a[((i + 1) % b)]
else:
for j in range(1, b):
a[j] ^= a[(j - 1)]
if __name__ == '__main__':
kkkkkkk = 'Geek2021'
tttttt = [117, 62, 240, 152, 195, 117, 103, 74, 240, 151, 173, 162, 17, 75, 141, 165, 136, 117, 113, 33, 98, 151, 174, 4, 48, 25, 254, 101, 185, 127, 131, 87]
ssss = input('Please input your flag:')
inp = [0] * len(ssss)
if len(ssss) != 32:
print('Length Error!!!!')
exit(0)
for i in range(len(ssss)):
inp[i] = ord(ssss[i])
else:
aaaaaaa(kkkkkkk, len(kkkkkkk))
bbbbbbbbbb(inp, 32)
ccccccccc(inp, 32)
for m in range(32):
if tttttt[m] != inp[m]:
raise Exception('sorry your flag is wrong')
print('success!!!!!!')
print('your flag is {}'.format(ssss))
很容易发现是个微调rc4加个异或,写出exp即可
#include <bits/stdc++.h>
using namespace std;
void init(int *s, char *key, int len)
{
int t[256] = {0};
char tmp = 0;
for (int i = 0; i < 256; ++i)
{
s[i] = i;
t[i] = key[i % len];
}
int j = 0;
for (int i = 0; i < 256; ++i)
{
j = (j + s[i] + t[i]) % 256;
swap(s[i], s[j]);
}
}
void crypt(int *s, char *data, int len)
{
int i = 0, j = 0, t = 0;
char tmp;
for (int k = 0; k < len; ++k)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
swap(s[i], s[j]);
t = (s[i] + s[j]) % 256;
data[k] ^= s[t] ^ 102;
}
}
char data[] = {117, 62, 240, 152, 195, 117, 103, 74, 240, 151, 173, 162, 17, 75, 141, 165, 136, 117, 113, 33, 98, 151, 174, 4, 48, 25, 254, 101, 185, 127, 131, 87};
char key[2333] = "Geek2021";
int s[260];
int main()
{
for (int i = 31; i >= 1; --i) data[i] ^= data[i - 1];
for (int i = 31; i >= 0; --i) data[i] ^= data[(i + 1) % 32];
int len = strlen(key);
init(s, key, len);
len = strlen(data);
crypt(s, data, len);
cout << data;
return 0;
}
得到flag:
SYC{Just_a_Eeeeeeasy_Rc4_right?}
new_language
exeinfo查一下发现是个c#的题
dnspy打开,在new_language处可以看到源码
using System;
namespace new___language
{
// Token: 0x02000002 RID: 2
internal class geek
{
// Token: 0x06000002 RID: 2 RVA: 0x00002058 File Offset: 0x00000258
public static int getNumFromSBox(char index)
{
int num = (int)(index >> 4);
int num2 = (int)(index & '\u000f');
return geek.sbox[num * 16 + num2];
}
// Token: 0x06000003 RID: 3 RVA: 0x00002080 File Offset: 0x00000280
private static void Main(string[] args)
{
Console.WriteLine("input:");
string text = Console.ReadLine();
int[] array = new int[34];
int[] array2 = new int[]
{
64,
249,
133,
69,
146,
253,
253,
207,
182,
4,
157,
207,
251,
4,
60,
81,
59,
77,
146,
77,
207,
26,
38,
207,
64,
77,
177,
77,
64,
195,
77,
253,
253
};
bool flag = text.Length != 38;
if (!flag)
{
bool flag2 = text.Substring(0, 4) != "SYC{" || text.Substring(37, 1) != "}";
if (!flag2)
{
text = text.Substring(4, 33);
for (int i = 0; i < 33; i++)
{
array[i] = geek.getNumFromSBox(text[i]);
}
for (int j = 0; j < 33; j++)
{
bool flag3 = array[j] != array2[j];
if (flag3)
{
return;
}
}
Console.WriteLine("good");
}
}
}
// Token: 0x04000001 RID: 1
private static int[] sbox = new int[]
{
99,
124,
119,
123,
242,
107,
111,
197,
48,
1,
103,
43,
254,
215,
171,
118,
202,
130,
201,
125,
250,
89,
71,
240,
173,
212,
162,
175,
156,
164,
114,
192,
183,
253,
147,
38,
54,
63,
247,
204,
52,
165,
229,
241,
113,
216,
49,
21,
4,
199,
35,
195,
24,
150,
5,
154,
7,
18,
128,
226,
235,
39,
178,
117,
9,
131,
44,
26,
27,
110,
90,
160,
82,
59,
214,
179,
41,
227,
47,
132,
83,
209,
0,
237,
32,
252,
177,
91,
106,
203,
190,
57,
74,
76,
88,
207,
208,
239,
170,
251,
67,
77,
51,
133,
69,
249,
2,
127,
80,
60,
159,
168,
81,
163,
64,
143,
146,
157,
56,
245,
188,
182,
218,
33,
16,
255,
243,
210,
205,
12,
19,
236,
95,
151,
68,
23,
196,
167,
126,
61,
100,
93,
25,
115,
96,
129,
79,
220,
34,
42,
144,
136,
70,
238,
184,
20,
222,
94,
11,
219,
224,
50,
58,
10,
73,
6,
36,
92,
194,
211,
172,
98,
145,
149,
228,
121,
231,
200,
55,
109,
141,
213,
78,
169,
108,
86,
244,
234,
101,
122,
174,
8,
186,
120,
37,
46,
28,
166,
180,
198,
232,
221,
116,
31,
75,
189,
139,
138,
112,
62,
181,
102,
72,
3,
246,
14,
97,
53,
87,
185,
134,
193,
29,
158,
225,
248,
152,
17,
105,
217,
142,
148,
155,
30,
135,
233,
206,
85,
40,
223,
140,
161,
137,
13,
191,
230,
66,
104,
65,
153,
45,
15,
176,
84,
187,
22
};
}
}
那简简单单爆个破就行了
#include <bits/stdc++.h>
using namespace std;
char enflag[] =
{
64,
249,
133,
69,
146,
253,
253,
207,
182,
4,
157,
207,
251,
4,
60,
81,
59,
77,
146,
77,
207,
26,
38,
207,
64,
77,
177,
77,
64,
195,
77,
253,
253
};
char sbox[] =
{
99,
124,
119,
123,
242,
107,
111,
197,
48,
1,
103,
43,
254,
215,
171,
118,
202,
130,
201,
125,
250,
89,
71,
240,
173,
212,
162,
175,
156,
164,
114,
192,
183,
253,
147,
38,
54,
63,
247,
204,
52,
165,
229,
241,
113,
216,
49,
21,
4,
199,
35,
195,
24,
150,
5,
154,
7,
18,
128,
226,
235,
39,
178,
117,
9,
131,
44,
26,
27,
110,
90,
160,
82,
59,
214,
179,
41,
227,
47,
132,
83,
209,
0,
237,
32,
252,
177,
91,
106,
203,
190,
57,
74,
76,
88,
207,
208,
239,
170,
251,
67,
77,
51,
133,
69,
249,
2,
127,
80,
60,
159,
168,
81,
163,
64,
143,
146,
157,
56,
245,
188,
182,
218,
33,
16,
255,
243,
210,
205,
12,
19,
236,
95,
151,
68,
23,
196,
167,
126,
61,
100,
93,
25,
115,
96,
129,
79,
220,
34,
42,
144,
136,
70,
238,
184,
20,
222,
94,
11,
219,
224,
50,
58,
10,
73,
6,
36,
92,
194,
211,
172,
98,
145,
149,
228,
121,
231,
200,
55,
109,
141,
213,
78,
169,
108,
86,
244,
234,
101,
122,
174,
8,
186,
120,
37,
46,
28,
166,
180,
198,
232,
221,
116,
31,
75,
189,
139,
138,
112,
62,
181,
102,
72,
3,
246,
14,
97,
53,
87,
185,
134,
193,
29,
158,
225,
248,
152,
17,
105,
217,
142,
148,
155,
30,
135,
233,
206,
85,
40,
223,
140,
161,
137,
13,
191,
230,
66,
104,
65,
153,
45,
15,
176,
84,
187,
22
};
int getNumFromSBox(char index)
{
int num = (int)(index >> 4);
int num2 = (int)(index & '\u000f');
return sbox[num * 16 + num2];
}
int main()
{
int len = strlen(enflag);
for (int i = 0; i < len; ++i)
{
for (int c = 0; c < 127; ++c)
{
if (getNumFromSBox(c) == enflag[i])
{
putchar(c);
break;
}
}
}
return 0;
}
得到flag:
SYC{right!!_y0u_c0mpIete_C#_reVer3e!!}
Re0
main函数没有任何代码逻辑,直接看字符串窗口就拿到了flag:
SYC{Welcome_to_Geek_challenge2021}
Re1
一个简单的异或+base64解密
#include <bits/stdc++.h>
using namespace std;
char data[233];
inline void init()
{
data[0] = 21;
data[1] = 113;
data[2] = 44;
data[3] = 4;
data[4] = 37;
data[5] = 113;
data[6] = 40;
data[7] = 16;
data[8] = 21;
data[9] = 44;
data[10] = 121;
data[11] = 40;
data[12] = 34;
data[13] = 45;
data[14] = 18;
data[15] = 38;
data[16] = 25;
data[17] = 45;
data[18] = 6;
data[19] = 58;
data[20] = 26;
data[21] = 20;
data[22] = 25;
data[23] = 112;
data[24] = 24;
data[25] = 114;
data[26] = 6;
data[27] = 57;
data[28] = 26;
data[29] = 22;
data[30] = 121;
data[31] = 112;
data[32] = 33;
data[33] = 7;
data[34] = 22;
data[35] = 38;
data[36] = 25;
data[37] = 45;
data[38] = 6;
data[39] = 58;
data[40] = 33;
data[41] = 24;
data[42] = 14;
data[43] = 38;
data[44] = 34;
data[45] = 114;
data[46] = 26;
data[47] = 38;
data[48] = 35;
data[49] = 45;
data[50] = 22;
data[51] = 114;
data[52] = 26;
data[53] = 24;
data[54] = 10;
data[55] = 58;
data[56] = 26;
data[57] = 24;
data[58] = 'p';
data[59] = '}';
}
int main()
{
init();
for (int i = 0; i <= 59; ++i ) data[i] ^= 0x40u, putchar(data[i]);
// then base64decode data[]
return 0;
}
得到flag:
SYC{XOR_and_base64_are_the_basis_of_reverse}
wasm
占坑,明天学wasm然后再填
win32
查下壳发现有upx壳,脱壳后在字符串窗口发现是个裸的base64
得到flag:
SYC{y0u_g3t_A_f1ag_by_cyberloafing_auth0r}
调试
main里面只有这玩意
好像没啥用,感觉是藏东西了?看看汇编
14A0没啥卵用,1455感觉像是在输出什么东西,那么直接把jnz patch成jz,然后尝试运行程序直接输出,就拿到了flag:
SYC{C0ngr@tuIatlOns_thls_1s_th3_r!gHt_f!ag}
刘壮桌面美化大师
是我最烦的apk :<
在desktopbeautifierConfigureActivity里面看不出来有啥加密方法,考虑去res/values/string.html(字符串文件)碰碰运气,然后得到flag。。。
SYC{We1c0m3_t0_4ndRo1d_ReV3rse!}
正解好像是Activity里面发现AppWidget方法,然后添加桌面小组件即可拿到flag
买Activity
是我最烦的apk :<
看来直接安装没啥卵用
那用jadx查看mainfest,发现与以前做的题有点不一样,这次有MainActivity和ExportedActivity两个Activity
MainActivity中看起来只是处理手机上显示的那段对话的
而Export里面onCreate函数看起来会直接打印flag
decode类中的关键代码如下
public final String getDecodedFlag() {
String str = stringFromNative().toString();
int length = str.length();
String str2 = "";
int i = 0;
while (i < length) {
char charAt = str.charAt(i);
i++;
str2 = Intrinsics.stringPlus(str2, Character.valueOf((char) (charAt ^ 16)));
}
return str2;
}
而我们会发现stringFromNative()
是一个native函数,我们得用ida打开so文件去找,才能拼出完整的加密代码
v24 = __readfsqword(0x28u);
std::string::basic_string<decltype(nullptr)>(&v21, "CSD!Os!yiyO#|iU`bu1");
std::string::basic_string<decltype(nullptr)>(&v18, "Ikxc$dFdOCBq!Oh dtm");
std::string::basic_string<decltype(nullptr)>(&v15, &unk_2AC18);
v1 = (char *)&v15 + 1;
for ( i = 0LL; i != 19; ++i )
{
v4 = &v22;
if ( (v21 & 1) != 0 )
v4 = (char *)ptr;
v5 = v4[i];
if ( (v15 & 1) != 0 )
{
v6 = v16;
v7 = (v15 & 0xFFFFFFFFFFFFFFFELL) - 1;
if ( v16 != v7 )
goto LABEL_8;
}
else
{
v6 = (unsigned __int64)(unsigned __int8)v15 >> 1;
v7 = 22LL;
if ( v6 != 22 )
{
LABEL_8:
if ( (v15 & 1) != 0 )
goto LABEL_9;
goto LABEL_12;
}
}
std::string::__grow_by(&v15, v7, 1LL, v7, v7, 0LL, 0LL);
if ( (v15 & 1) != 0 )
{
LABEL_9:
v8 = (char *)v17;
v16 = v6 + 1;
goto LABEL_13;
}
LABEL_12:
LOBYTE(v15) = 2 * v6 + 2;
v8 = (char *)&v15 + 1;
LABEL_13:
v8[v6] = v5;
v8[v6 + 1] = 0;
v9 = &v19;
if ( (v18 & 1) != 0 )
v9 = (char *)v20;
v10 = v9[i];
if ( (v15 & 1) != 0 )
{
v11 = v16;
v12 = (v15 & 0xFFFFFFFFFFFFFFFELL) - 1;
if ( v16 != v12 )
goto LABEL_17;
}
else
{
v11 = (unsigned __int64)(unsigned __int8)v15 >> 1;
v12 = 22LL;
if ( v11 != 22 )
{
LABEL_17:
if ( (v15 & 1) == 0 )
goto LABEL_2;
goto LABEL_21;
}
}
std::string::__grow_by(&v15, v12, 1LL, v12, v12, 0LL, 0LL);
if ( (v15 & 1) == 0 )
{
LABEL_2:
LOBYTE(v15) = 2 * v11 + 2;
v3 = (char *)&v15 + 1;
goto LABEL_3;
}
LABEL_21:
v3 = (char *)v17;
v16 = v11 + 1;
LABEL_3:
v3[v11] = v10;
v3[v11 + 1] = 0;
}
if ( (v15 & 1) != 0 )
v1 = (char *)v17;
v13 = (*(__int64 (__fastcall **)(__int64, char *))(*(_QWORD *)a1 + 1336LL))(a1, v1);
if ( (v15 & 1) == 0 )
{
if ( (v18 & 1) == 0 )
goto LABEL_26;
LABEL_30:
operator delete(v20);
if ( (v21 & 1) == 0 )
return v13;
LABEL_27:
operator delete(ptr);
return v13;
}
operator delete(v17);
if ( (v18 & 1) != 0 )
goto LABEL_30;
LABEL_26:
if ( (v21 & 1) != 0 )
goto LABEL_27;
return v13;
我的评价是:真几把恶心,这么长的代码,最终化简了就这几句话😅
看完wp发现这是出题人故意加的混淆,然而萌新并不懂混淆,只能大眼瞪了呜呜呜
char a[] = "CSD!Os!yiyO#|iU`bu1";
char b[] = "Ikxc$dFdOCBq!Oh dtm";
char enf[50];
for (int i = 0; i < 19; ++i)
{
enf[i * 2] = a[i];
enf[i * 2 + 1] = b[i];
}
拼一下就能写出exp了
#include <bits/stdc++.h>
using namespace std;
char a[] = "CSD!Os!yiyO#|iU`bu1";
char b[] = "Ikxc$dFdOCBq!Oh dtm";
char enf[50];
int main()
{
for (int i = 0; i < 19; ++i)
{
enf[i * 2] = a[i];
enf[i * 2 + 1] = b[i];
}
for (int i = 0; i < 38; ++i) enf[i] ^= 16, putchar(enf[i]);
return 0;
}
得到flag:
SYC{Th1s_4ct1Vity_iS_R3al1y_Exp0rted!}