之前以为第四周的题目会很难,就没有去写了,今天第一次写才发现原来题目难度挺友好的,收获颇丰
PyPro
exe文件,但是题目提示了是使用python编写的,所以首先使用pyinstxtractor
解包exe
在解包的文件夹中,可以找到PyPro.pyc
文件,先使用DIE查查成分
python3.12版本,这个版本是不能使用uncompyle6反编译的,尝试使用pycdc反编译
警告反编译不完全,并且出现乱码,尝试使用pycdas得到python字节码
PyPro.pyc (Python 3.12)
[Code]
File Name: PyPro.py
Object Name: <module>
Qualified Name: <module>
Arg Count: 0
Pos Only Arg Count: 0
KW Only Arg Count: 0
Stack Size: 2
Flags: 0x00000000
[Names]
'base64'
'Crypto.Cipher'
'AES'
'Crypto.Util.number'
'long_to_bytes'
'key'
'PKCS5_pad'
'main'
'__name__'
[Locals+Names]
[Constants]
0
None
(
'AES'
)
(
'long_to_bytes'
)
0x554B134A029DE539438BD18604BF114L
[Code]
File Name: PyPro.py
Object Name: PKCS5_pad
Qualified Name: PKCS5_pad
Arg Count: 1
Pos Only Arg Count: 0
KW Only Arg Count: 0
Stack Size: 5
Flags: 0x00000003 (CO_OPTIMIZED | CO_NEWLOCALS)
[Names]
'len'
'ljust'
'to_bytes'
[Locals+Names]
'data'
'length'
[Constants]
None
48
[Disassembly]
0 RESUME 0
2 LOAD_GLOBAL 1: NULL + len
12 LOAD_FAST 0: data
14 CALL 1
22 LOAD_CONST 1: 48
24 COMPARE_OP 2 (<)
28 POP_JUMP_IF_FALSE 46 (to 122)
30 LOAD_CONST 1: 48
32 LOAD_GLOBAL 1: NULL + len
42 LOAD_FAST 0: data
44 CALL 1
52 BINARY_OP 10 (-)
56 STORE_FAST 1: length
58 LOAD_FAST 0: data
60 LOAD_ATTR 3: ljust
80 LOAD_CONST 1: 48
82 LOAD_FAST 1: length
84 LOAD_ATTR 5: to_bytes
104 CALL 0
112 CALL 2
120 RETURN_VALUE
122 RETURN_CONST 0: None
[Code]
File Name: PyPro.py
Object Name: main
Qualified Name: main
Arg Count: 0
Pos Only Arg Count: 0
KW Only Arg Count: 0
Stack Size: 5
Flags: 0x00000003 (CO_OPTIMIZED | CO_NEWLOCALS)
[Names]
'input'
'encode'
'len'
'print'
'range'
'exit'
'ord'
'AES'
'new'
'long_to_bytes'
'key'
'MODE_ECB'
'encrypt'
'PKCS5_pad'
'base64'
'b64encode'
'decode'
[Locals+Names]
'enc'
'i'
'chiper'
'result'
'data'
[Constants]
None
'鍦ㄨ繖閲岃緭鍏ヤ綘鐨刦lag:\n'
'utf-8'
44
'length error!'
123
6
'{'
-1
'}'
'format error'
1
'2e8Ugcv8lKVhL3gkv3grJGNE3UqkjlvKqCgJSGRNHHEk98Kd0wv6s60GpAUsU+8Q'
'flag姝g‘'
'閿欒'
[Disassembly]
0 RESUME 0
2 LOAD_GLOBAL 1: NULL + input
12 LOAD_CONST 1: '鍦ㄨ繖閲岃緭鍏ヤ綘鐨刦lag:\n'
14 CALL 1
22 LOAD_ATTR 3: encode
42 LOAD_CONST 2: 'utf-8'
44 CALL 1
52 STORE_FAST 0: enc
54 LOAD_GLOBAL 5: NULL + len
64 LOAD_FAST 0: enc
66 CALL 1
74 LOAD_CONST 3: 44
76 COMPARE_OP 55 (!=)
80 POP_JUMP_IF_FALSE 48 (to 178)
82 LOAD_GLOBAL 7: NULL + print
92 LOAD_CONST 4: 'length error!'
94 CALL 1
102 POP_TOP
104 LOAD_GLOBAL 9: NULL + range
114 LOAD_GLOBAL 5: NULL + len
124 LOAD_FAST 0: enc
126 CALL 1
134 CALL 1
142 GET_ITER
144 FOR_ITER 2 (to 150)
148 STORE_FAST 1: i
150 JUMP_BACKWARD 4 (to 144)
152 END_FOR
154 LOAD_GLOBAL 11: NULL + exit
164 LOAD_CONST 5: 123
166 CALL 1
174 POP_TOP
176 JUMP_FORWARD 57 (to 292)
178 LOAD_FAST 0: enc
180 LOAD_CONST 6: 6
182 BINARY_SUBSCR
186 LOAD_GLOBAL 13: NULL + ord
196 LOAD_CONST 7: '{'
198 CALL 1
206 COMPARE_OP 55 (!=)
210 POP_JUMP_IF_TRUE 17 (to 246)
212 LOAD_FAST 0: enc
214 LOAD_CONST 8: -1
216 BINARY_SUBSCR
220 LOAD_GLOBAL 13: NULL + ord
230 LOAD_CONST 9: '}'
232 CALL 1
240 COMPARE_OP 55 (!=)
244 POP_JUMP_IF_FALSE 23 (to 292)
246 LOAD_GLOBAL 7: NULL + print
256 LOAD_CONST 10: 'format error'
258 CALL 1
266 POP_TOP
268 LOAD_GLOBAL 11: NULL + exit
278 LOAD_CONST 11: 1
280 CALL 1
288 POP_TOP
290 NOP
292 LOAD_GLOBAL 15: NULL + AES
302 LOAD_ATTR 16: new
322 LOAD_GLOBAL 19: NULL + long_to_bytes
332 LOAD_GLOBAL 20: key
342 CALL 1
350 LOAD_GLOBAL 14: AES
360 LOAD_ATTR 22: MODE_ECB
380 CALL 2
388 STORE_FAST 2: chiper
390 LOAD_FAST 2: chiper
392 LOAD_ATTR 25: encrypt
412 LOAD_GLOBAL 27: NULL + PKCS5_pad
422 LOAD_FAST 0: enc
424 CALL 1
432 CALL 1
440 STORE_FAST 0: enc
442 LOAD_GLOBAL 29: NULL + base64
452 LOAD_ATTR 30: b64encode
472 LOAD_FAST 0: enc
474 CALL 1
482 STORE_FAST 3: result
484 LOAD_CONST 12: '2e8Ugcv8lKVhL3gkv3grJGNE3UqkjlvKqCgJSGRNHHEk98Kd0wv6s60GpAUsU+8Q'
486 STORE_FAST 4: data
488 LOAD_FAST 3: result
490 LOAD_ATTR 33: decode
510 CALL 0
518 LOAD_FAST 4: data
520 COMPARE_OP 40 (==)
524 POP_JUMP_IF_FALSE 12 (to 550)
526 LOAD_GLOBAL 7: NULL + print
536 LOAD_CONST 13: 'flag姝g‘'
538 CALL 1
546 POP_TOP
548 RETURN_CONST 0: None
550 LOAD_GLOBAL 7: NULL + print
560 LOAD_CONST 14: '閿欒'
562 CALL 1
570 POP_TOP
572 RETURN_CONST 0: None
'__main__'
[Disassembly]
0 RESUME 0
2 LOAD_CONST 0: 0
4 LOAD_CONST 1: None
6 IMPORT_NAME 0: base64
8 STORE_NAME 0: base64
10 LOAD_CONST 0: 0
12 LOAD_CONST 2: ('AES',)
14 IMPORT_NAME 1: Crypto.Cipher
16 IMPORT_FROM 2: AES
18 STORE_NAME 2: AES
20 POP_TOP
22 LOAD_CONST 0: 0
24 LOAD_CONST 3: ('long_to_bytes',)
26 IMPORT_NAME 3: Crypto.Util.number
28 IMPORT_FROM 4: long_to_bytes
30 STORE_NAME 4: long_to_bytes
32 POP_TOP
34 LOAD_CONST 4: 0x554B134A029DE539438BD18604BF114L
36 STORE_NAME 5: key
38 LOAD_CONST 5: <CODE> PKCS5_pad
40 MAKE_FUNCTION 0
42 STORE_NAME 6: PKCS5_pad
44 LOAD_CONST 6: <CODE> main
46 MAKE_FUNCTION 0
48 STORE_NAME 7: main
50 LOAD_NAME 8: __name__
52 LOAD_CONST 7: '__main__'
54 COMPARE_OP 40 (==)
58 POP_JUMP_IF_FALSE 8 (to 76)
60 PUSH_NULL
62 LOAD_NAME 7: main
64 CALL 0
72 POP_TOP
74 RETURN_CONST 1: None
76 RETURN_CONST 1: None
随便看了下,应该是先aes(ecb)加密,然后base64加密
Register
进入主函数,找到lpfnWndProc,双击这个函数
注册机用户名就写在第20行这里
显然那个buf1是待输入的序列号,进入28行的函数
这个23行的buf2就是待比较的序列号,上面22行为解密序列号的函数
调试调到这里自动解密出了buf2也就是序列号的值
验证成功
MineSweeper
第一次做unity的题目,拿到题目不知道干什么
稍微学了一下,在Minesweeper_Data/Managed
下找到了Assembly-CSharp.dll文件,是c#
编译的,要用dnSpy反编译
看了半天,才在NewGames函数这里找到生成雷的逻辑
感觉反编译的代码很好看,反编译器也可以直接修改伪代码(比ida还好用),把GenerateMines()里面mines改成0就行了,记住要点保存模块
然后启动游戏,点一下就出flag了,因为没有雷了
Tea2.0
这题初看下来只有一个普通的xtea加密,但是发现解密解不通,这是就要怀疑数据被改了
看一下函数表,有几个明显的tls回调函数
这里虽然有4个,但实际有意义的只有两个
果然修改了数据部分
在数据这里可以发现,事实上存在两个key
上面那个是用在tls中的,下面那个是用在主函数的xtea中的
分析这两个tls函数,发现第一个tls修改了第一个key,第二个tls将主函数中的数据进行了一次普通tea加密,使用的是上面那个key
这样思路就清晰了,要先把数据经过tea加密,然后再xtea解密,一共两轮,且key不一样
写攻击脚本
#include <stdio.h>
#include <stdint.h>
void en_tea(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 0;
uint32_t delta = 0x9e3779b9;
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
for (int i = 0; i < 32; i++) {
sum += delta;
v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
}
v[0] = v0; v[1] = v1;
}
void de_xtea(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
uint32_t v0 = v[0], v1 = v[1], delta = 0x9E3779B9, sum = delta * num_rounds;
for (int i = 0; i < num_rounds; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0; v[1] = v1;
}
int main()
{
unsigned int cipher[12] = {
0x018DC360, 0xD5835457, 0x8BEE2DCB, 0x92BB2DEE, 0xFDF4AD54, 0x043F8C2D, 0x61A232A9, 0x0F15F4D1,
0x16EA4979, 0x7C2BF6DA, 0xDCD5FA32, 0x76450819
};
unsigned int r = 64;
unsigned int key_tea[4] = {
0x00001245, 0x00003298, 0x00004756, 0x00001463
};
unsigned int key_xtea[4] = {
0x00004512, 0x00009832, 0x00005647, 0x00006314
};
for (int i = 0; i < 4; i++) {
key_tea[i] ^= 0xABCD;
}
for (int i = 0; i < 12; i += 2)
{
en_tea(&cipher[i], key_tea);
}
for (int i = 0; i < 12; i += 2)
{
de_xtea(64, &cipher[i], key_xtea);
}
printf("%s", (char*)cipher);
return 0;
}
EzAndroid
使用jeb反编译,直接可以看到主函数和加密函数
定义了一个base62加密函数,逻辑看起来不难
只需要注意加密得到的密文在R方法里面找
encoded = "J6IwkwOvgGFthiofcwab0ka7KrOMpVbfROQ9Jh5C5YMqfyLLdMrNoj4YGVh"
B62table = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
Base = 62
num = 0
for char in encoded:
num = num * Base + B62table.index(char)
byte_array = []
while num > 0:
byte_array.insert(0, num & 0xFF)
num >>= 8
decoded_bytes = bytes(byte_array)
print(decoded_bytes)