2023HWS-Winter

2023HWS-Winter

题目难度简单-中等,少了VM、花指令、反调试、算法魔改以及某解释型语言的阅读题,多了一些脑洞和情节。

image-20230109202952589

author: Lu1u(|3x5)

RE

babyre

继承Application类解密目标DEX,后续实现DEX注入修改校检函数。

其实是一种插件化的编程方式,仅需修改注入dex的代码即可修改Android程序的功能,虽然不会缩减程序体积,但是在功能切换和打补丁上功能占优并且也能实现一定的代码保护。

相关编程参考: https://www.jianshu.com/p/29a1df4f4824

创建自己的Application,并在其中添加额外的初始化操作,需在AndroidManifest.xml中添加android:name属性。

本题中指定的Applicationandroid:name="com.me.crackme.d"

attachBaseContextonCreateApplication 的两个回调函数,用于初始化,并且先执行前者,在指定的Application重载了attachBaseContext函数,创建了c的对象。

image-20230109194455021

而c类在其构造函数中会解密出一个dex文件放到指定目录,解密算法为逐字节异或52,解密assets目录下的enc文件。

image-20230109135227014

之后在 onCreate函数中调用了b.a来实现DEX注入修改check逻辑。

image-20230109194916096

故真正的校检逻辑在解密的dex文件中,使用了AES/CBC加密,key和iv已知,解密即可。

image-20230109135452556

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import base64
from Crypto.Cipher import AES
s=base64.b64decode(b'9Kz3YlSdD3lB9KoxeKxXQT4YOEqJTVIuNU+IjW4iFQzjpU+NikF/UqCOsL+1g4eA')
# f=open(r'enc','rb')
# buf=f.read()
# f.close()
# dump=[]
# for i in range(len(buf)):
# dump.append(buf[i]^52)
# f=open(r'dump.dex','wb')
# f.write(bytes(dump))
# f.close()
key=base64.b64decode(b'FV8aOaQiak6txP09')
print(key)
iv=base64.b64decode(b'2Aq7SR5268ZzbouE')
aes=AES.new(b'FV8aOaQiak6txP09',AES.MODE_CBC,b'2Aq7SR5268ZzbouE')
ans=aes.decrypt(s)
print(ans)

easyre

加密算法在sub_7FF6AD2014A0,为常规XTEA

image-20230109140512719

在main函数之前使用initterm函数进行初始化指定的函数列表。

get_tea_key使用伪随机算法获取xxtea加密的秘钥,在check_data函数中创建了用于比对密文的校检线程,并且采用锁的机制来控制比对在加密输入之后进行。

image-20230109141235301

调试获取xtea的秘钥即可完成解题。

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
#include<iostream>
#define ut32 unsigned int
#define delta 0x9E3779B9
void XTea_Decrypt(ut32* enc, ut32* k) {
ut32 sum = delta * 0x20;
ut32 v0 = enc[0];
ut32 v1 = enc[1];
for (int i = 0; i < 0x20; i++) {
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);
}
enc[0] = v0;
enc[1] = v1;
}

void output(ut32* m, ut32 n) {
for (int i = 0; i < n; i++)
printf("0x%08x ", m[i]);
printf("\n");
}

int main() {
ut32 m[8] = { 0xC0B29B34, 0xEF30AF6A, 0x98CCB238, 0x85B6F195, 0xA2480685, 0xA63D9B59, 0xF191C71E, 0x6790767B };
ut32 k[4] = { 0x00000029, 0x00004823, 0x000018BE, 0x00006784 };
for(int i=0;i<8;i+=2)
XTea_Decrypt(m+i, k);
for (int i = 0; i < 32; i++) {
printf("%c", *((char*)m + i));
}
//9c3206a3942e0835dabaa182128d60bc
return 0;
}

repy

函数加了fla混淆,结合D-810插件分析,有些关键代码仍需查看原始伪代码。

main函数依次输入和check了两段字符,第一段要求输入为0-9,并且统计输入数字的hash表要求输入数字和hash表值相同。

image-20230107193141253

在去混淆中比对规则在伪码中没有显示,原本代码中包含 if ( s[v10] != buf[v10] - 48 ),之后经过异或还原内存中的一段数据。

image-20230107193407272

对输入的第二段字符先经过mem_table计算索引,之后又通过索引来取值,即第二段限定输入字符在mem_table中,之后md5加密。

image-20230107193716127

将hash值经过somd5平台解密可得yOUar3g0oD@tc4nd,观察可知其16个字符均不相同,而mem_table的值也为16,所以可以得知表中包含的字符,结合与0-9异或所得,可以逆推第一段输入字符。

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
mmk=[0x55, 0x46, 0x64, 0x03, 0x7F, 0x57, 0x55, 0x5F, 0x70, 0x04, 0x44, 0x53, 0x01, 0x49, 0x74, 0x5E]
s='yOUar3g0oD@tc4nd'
# for ch in range(len(mmk)):
# print('%d : '%ch,end='')
# for i in b'0123456789':
# print(chr(mmk[ch]^i),end=' ')
# print()
# 第二段somd5直接解
"""
0 : e d g f a ` c b m l -> c : 6
1 : v w t u r s p q ~ -> t : 2
2 : T U V W P Q R S \ ] -> U : 1
3 : 3 2 1 0 7 6 5 4 ; : -> 3 : 0
4 : O N M L K J I H G F -> O : 0
5 : g f e d c b a ` o n -> g : 0
6 : e d g f a ` c b m l -> d : 1
7 : o n m l k j i h g f -> o : 0
8 : @ A B C D E F G H I -> @ : 0
9 : 4 5 6 7 0 1 2 3 < = -> 4 : 0
10 : t u v w p q r s | } -> r : 6
11 : c b a ` g f e d k j -> a : 2
12 : 1 0 3 2 5 4 7 6 9 8 -> 0 : 1
13 : y x { z } | ~ q p -> y : 0
14 : D E F G @ A B C L M -> D :0
15 : n o l m j k h i f g -> n : 0

0 1 2 3 4 5 6 7 8 9
6 2 1 0 0 0 1 0 0 0
part1 :6210001000
part2 :yOUar3g0oD@tc4nd
"""

逆推求得的第一段字符为6210001000,逆推可以简化求第一段字符的过程。

根据题目名和第三部分的描述,应该为python系列逆向,而bin文件并不是pyc或pyd格式的文件,故再次回到程序中寻找可疑点,程序并未去符号,可见openssl中的AES_cbc_encrypt函数,通过交叉引用得知第三段逻辑的加密处理sub_402930函数。

其中混杂大量的垃圾代码,提取核心内容如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
__int64 __fastcall sub_402930(char *a1, char *a2){
s = a1;
v49 = a2;
v46 = 0;
v45 = strlen(a1);
for(v46=0;v46<16;v46++){ //取第一段输入 用2填充到16位
if(i<v45) v48[v46] = s[v46];
else v48[v46] = 2;
}
for(v46;v46<16;v46++){ //取第二段输入
v47[v46] = v49[v46]
}
...
strcpy(&v43[11], "nbdj`-ejof"); //magic.file
strcpy(v43, "qgapgv,`kl"); //解密出secret.bin 对文件内容加密处理
v43[v46 + 11] ^= 3u;
v43[v46] ^= 2u;
...
v12 = v47;
AES_set_encrypt_key((__int64)v12, v11, (__int64)v10) //v12指向AES的KEY
AES_cbc_encrypt(dest, v4, v8, v40, v48, 1LL); // v48指向iv
}

secret.bin是使用程序第一段输入填充2后作为iv,第二段输入作为key的AES CBC模式加密而来。

1
2
3
4
5
6
from Crypto.Cipher import  AES
key= b'yOUar3g0oD@tc4nd'
iv=b'6210001000'+b'\x02'*6
aes=AES.new(key,AES.MODE_CBC,iv)
buf=open(r'secret.bin','rb').read()
res=aes.decrypt(buf)

解密后的数据结合模数可知为py38的pyc文件,选择对应的解释器使用marshaldis库反汇编即可,当然其对字节码文件加了混淆。

image-20230107200417914

使用jmp offset 0x24来进行混淆,中间添加一些错误代码影响反汇编,结合dis.opmap,得到其硬编码为6E 24,直接修改二进制文件将其后36个字节修改为09(NOP)即可。

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
from string import ascii_uppercase, ascii_lowercase, digits

class II00O0III0o0o0o0oo:

def __init__(self): # 换表base64
table = 0
length = 1
temptable = 2
for _ in range(10):
table += length
length ^= table
temptable *= temptable
basetable = ascii_uppercase + ascii_lowercase + digits + '+/'
self.table = basetable
length = len(self.table)
temptable = list(self.table.encode('utf-8', **('encoding',)))
for i in range(0, length // 2):
for j in range(0, length - 1 - i):
if temptable[j] > temptable[j + 1]:
temp = temptable[j]
temptable[j] = temptable[j + 1]
temptable[j + 1] = temp
continue
continue
basetable = bytes(temptable).decode()
self.table = basetable
return None


def e(self = None, msg = None):
BASE_CHAR = self.table
CHARSET = 'ASCII'
b_msg = bytes(msg, CHARSET)
CHAR_PRE_GROUP = 3
zero_cnt = CHAR_PRE_GROUP - len(b_msg) % CHAR_PRE_GROUP
if zero_cnt == CHAR_PRE_GROUP:
zero_cnt = 0
msg += str(chr(0)) * zero_cnt
b_msg = bytes(msg, CHARSET)
msg = 0
encoded = 1
i_msg = 2
for _ in range(20):
encoded += i_msg
msg ^= encoded
i_msg *= i_msg
encoded = ''
for i in range(0, len(b_msg), 3):
i_msg = (lambda .0: [ int(i) for i in .0 ])(b_msg[i:i + 3])
new_msg = [
None] * 4
new_msg[0] = i_msg[0] >> 2
new_msg[1] = ((i_msg[0] & 3) << 6 | i_msg[1] >> 2) >> 2
new_msg[2] = ((i_msg[1] & 15) << 4 | i_msg[2] >> 4) >> 2
new_msg[3] = i_msg[2] & 63
None += None((lambda .0 = None: [ BASE_CHAR[i] for i in .0 ])(new_msg))
return encoded + '=' * zero_cnt



class IIoo00IIIo0o0oo0oo:

def __init__(self): # 魔改xxtea
self.d = 0x87654321L
k0 = 1732584193
k1 = 0xEFCDAB89L
k2 = 0x98BADCFEL
k3 = 271733878
self.k = [
k0,
k1,
k2,
k3]

def e(self, n, v):
c_uint32 = c_uint32
import ctypes

def MX(z = None, y = None, total = None, key = None, p = None, e = None):
temp1 = (z.value >> 6 ^ y.value << 4) + (y.value >> 2 ^ z.value << 5)
temp2 = (total.value ^ y.value) + (key[p & 3 ^ e.value] ^ z.value)
return c_uint32(temp1 ^ temp2)

key = self.k
delta = self.d
rounds = 6 + 52 // n
total = 0
z = 1
e = 2
for _ in range(10):
z += e
e ^= total
e *= z
total = c_uint32(0)
z = c_uint32(v[n - 1])
e = c_uint32(0)
if rounds > 0:
total.value += delta
e.value = total.value >> 2 & 3
for p in range(n - 1):
y = c_uint32(v[p + 1])
v[p] = c_uint32(v[p] + MX(z, y, total, key, p, e).value).value
z.value = v[p]
y = c_uint32(v[0])
v[n - 1] = c_uint32(v[n - 1] + MX(z, y, total, key, n - 1, e).value).value
z.value = v[n - 1]
rounds -= 1
continue
return v



class chall:

def __init__(self):
self.c1 = II00O0III0o0o0o0oo()
self.c2 = IIoo00IIIo0o0oo0oo()


def ints2bytes(self = None, v = None):
n = len(v)
res = b''
for i in range(n // 2):
res += int.to_bytes(v[2 * i], 4, 'little')
res += int.to_bytes(v[2 * i + 1], 4, 'little')
return res


def bytes2ints(self = None, cs = None)
def decode()
# 先调用魔改base64xxtea

以上是在线网站反编译的内容,对于main函数和一些关键流程还是要自己翻译,SETUP_FINALLY与异常处理有关,常见try-except结构。

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
def check(flag,flag,check_list):
cipher=chall()
output=list(cipher.decode())
if output==check_list:
return 1;
else:
return 0;
#main
rf=open('encrypted','rb')
data=list(rf.read())
check_list=data[:len(data)//2]
flag=0
flag= input('Please input the last part of the flag:')
times=0
res=check(flag,check_list)
if res:
print('sucess!')
exit(0)
else:
try:
if times!=0:
exit(times)
else:
print('Nope,try again!')
num=res//times # 除0异常
exit(num)
except:
xor_list=data[len(data)//2:]
for i in range(len(check_list)):
check_list[i]^=xor_list[i]

依次解密魔改xxtea和base64即可,不过密文是前后异或即走异常处理中的流程,仅解密前半段是假的flag。

处理数据

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
enc=open(r'encrypted','rb').read()
cc=list(enc[:len(enc)//2])
cc2=list(enc[len(enc)//2:])
for i in range(40):
cc[i]^=cc2[i]
lis=[]
for i in range(0,len(cc),4):
t=0
for j in range(4):
t|=(cc[i+j]<<(8*j))
lis.append(t)
print(lis)

from string import ascii_uppercase, ascii_lowercase, digits
def func():
table = 0
length = 1
temptable = 2
for _ in range(10):
table += length
length ^= table
temptable *= temptable
basetable = ascii_uppercase + ascii_lowercase + digits + '+/'
table = basetable
length = len(table)
temptable = list(table.encode())
for i in range(0, length // 2):
for j in range(0, length - 1 - i):
if temptable[j] > temptable[j + 1]:
temp = temptable[j]
temptable[j] = temptable[j + 1]
temptable[j + 1] = temp
continue
print(bytes(temptable))
func()
"""
b'ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz'
"""

解xxtea

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
#include<iostream>
#define ut32 unsigned int
#define delta 0x87654321
using namespace std;
void XXTea_Encrypt(ut32* src, ut32 n, ut32* key); //m是明文数组 n是块个数 key是秘钥
void XXTea_Decrypt(ut32* enc, ut32 n, ut32* key);
void output(ut32* m, ut32 len); //打印函数

void XXTea_Encrypt(ut32* src, ut32 n, ut32* key) {
ut32 y, z, sum = 0;
ut32 e, rounds;
int p; // 定义为无符号时 p-1>=0这个判断恒成立
rounds = 6 + 52 / n;
do {
z = src[n - 1];
sum += delta;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++) {
y = src[p + 1];
src[p] += (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)));
z = src[p];
}
y = src[0];
src[n - 1] += (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)));
} while (--rounds);

}

void XXTea_Decrypt(ut32* enc, ut32 n, ut32* key) {
ut32 y, z, sum;
ut32 e, rounds;
int p;
rounds = 6 + 52 / n;
sum = delta * rounds;

do {
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--) {
y = enc[(p + 1) % n];
z = enc[(p - 1)];
enc[p] -= (((z >> 6 ^ y << 4) + (y >> 2 ^ z << 5)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)));
}
y = enc[1];
z = enc[n - 1];
enc[0] -= (((z >> 6 ^ y << 4) + (y >> 2 ^ z << 5)) ^ ((sum ^ y) + (key[(0 & 3) ^ e] ^ z)));
sum -= delta;
} while (--rounds);

}

void output(ut32* m, ut32 len) {
for (int i = 0; i < len; i++)
printf("0x%08x ", m[i]);
printf("\n");
}

int main() {
ut32 enc[10] = { 2205310885, 1599168851, 2965138257, 852645047, 2259412685, 982377880, 3739627023, 3915974191, 1863053025, 3436002491 };
ut32 key[4] = { 1732584193 ,4023233417,2562383102,271733878 };
XXTea_Decrypt(enc, 10, key);
for (int i = 0; i < 40; i++) {
printf("%c", *((unsigned char*)enc + i));
}
return 0;
}
#0HZoSDBi3oh6QbVE9q5fS3dWR291TpYA=

在线cyberchef解换表base64即可,得到PytH0n_KZBxDwfkIzbEgUOY

Crypto

Numbers Game

MT19937还原,根据624组32bit的数据还原state之后逆推上一组state进而得到前12个32bit的随机数值。

参考: https://blog.csdn.net/zippo1234/article/details/109279944

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
from randcrack import *
from random import Random
from hashlib import md5
# right shift inverse
def inverse_right(res,shift,bits=32):
tmp = res
for i in range(bits//shift):
tmp = res ^ tmp >> shift
return tmp

# right shift with mask inverse
def inverse_right_values(res,shift,mask,bits=32):
tmp = res
for i in range(bits//shift):
tmp = res ^ tmp>>shift & mask
return tmp

# left shift inverse
def inverse_left(res,shift,bits=32):
tmp = res
for i in range(bits//shift):
tmp = res ^ tmp << shift
return tmp

# left shift with mask inverse
def inverse_left_values(res,shift,mask,bits=32):
tmp = res
for i in range(bits//shift):
tmp = res ^ tmp << shift & mask
return tmp

def backtrace(cur):
high = 0x80000000
low = 0x7fffffff
mask = 0x9908b0df
state = cur
for i in range(11,-1,-1): #逆求的32bit 组数 此处需要逆求12组
tmp = state[i+624]^state[i+397]
# recover Y,tmp = Y
if tmp & high == high:
tmp ^= mask
tmp <<= 1
tmp |= 1
else:
tmp <<=1
# recover highest bit
res = tmp&high
# recover other 31 bits,when i =0,it just use the method again it so beautiful!!!!
tmp = state[i-1+624]^state[i+396]
# recover Y,tmp = Y
if tmp & high == high:
tmp ^= mask
tmp <<= 1
tmp |= 1
else:
tmp <<=1
res |= (tmp)&low
state[i] = res
return state

def recover_state(out):
state = []
for i in out:
i = inverse_right(i,18)
i = inverse_left_values(i,15,0xefc60000)
i = inverse_left_values(i,7,0x9d2c5680)
i = inverse_right(i,11)
state.append(i)
return state

if __name__ == '__main__':
id=['d5d97afad7ef619b4badd8d2da10ee24', '67f4660a8335fb9f4152a9fbc44c9c77', '8cd43c85ebe9cc7036a37f47ccd1d1e4',
'ee3e8c62e8b0100027589d6de82677ef', '463bb2f3731ad0e786302bf78da08330', 'e245b1852a3b92734e46eb3421bd76c9',
'0b74736786b4ab94651e3b706a548e55', '79cb596b28c2b4e02738f93b5bfbe0d3', '5a9c46837952952045564b5b395acad1',
'd3c2d90a05d1a059fbeba4a05a608798', '4da0306c8ab58097d2fef9114e6fcb6d', '9707fabbd3c96de66917f15998ac9201',
'9dd3e46fc930abfb523fe31e8ee8a658', '3716a8fd05f7388e7151d09431e61ee1', '9acf027679a6d7a674a43dee4f5bea35',
'78702a2b125a940519337b1bf50aff8a', '262cf3b8c8072a602048a24756c83fcf', '092f8d227ec583c4734a6f449de521a3',
'712aa300302b57fed458553426348fce', '834d4a0ea451cc04b469636b18c56435', '754b5284b14402c61e3b1e56cb2d41e9',
'51d742ca6a341032afcb5dc645f54bfa', 'c1a33d104f47e33d6932905b483a2018', '3def7c2a14cff6b2864a2100956df07f',
'7e3606e4ec1c99fe5a8593ae44f25a70', '404c6139570883dbab8e5a299d7a5017', 'f07597079e1b68ebb4e2d16b83b7b484',
'0723daf5c65f8ba6cd6e43fcdf9d18dc', '4c54db12829f165837384b66978e8438', 'cd056e64e1f31461cab2e66ece9d3278',
'2f6ae16fab122cbce240e32464a1ab57', 'f86e0e9ee23498340f62d8617f6f5218', 'af4ebe2535885c783c89f8d8c4815076',
'c8eae5b5c7aca2c5fdb4f284e2cf65c5', 'bec0d8ecabedd9811a8ecb6052b21d8c', '731bd3421b6517aa101357fe1c49caf3',
'344f4a26cdaf1a782d9b32208e1a3e92', '892b1741d304878461dd0774a335ea3d', '56e2a484ca40f43e059bf5f0bd822bdc',
'd7c0762df71b31c14654147fb9a0595c', '57016a179ba5509f6b04a161ac628b34', 'e49a2d573522c1ee3e8348ceca0295a4',
'4b0f49c7e6469e82832e9cc90b9e17c0', 'eadc9d0c8b75127fe0a7f71881de1ea7', 'db9fe5537768207bd8cdf770bcd42dfa',
'ba2f57578752628d1ecac419b3a8bc36', '3752e70b5d2b578a8d412d84aab43705', '54e97795df8781c776cbb1ce4f5f31fc',
'32794880abc9f68102c24e92ad9c7cd5',
'b5eb7e651ca298f6873694c47d1cd3da', 'a188934777d2c67e3d59692135005497', '34c308fa1644b387169ea88c1b575490']
code=['2eebed894580fb900c3615d4866150e68322ff4d48e7509f85ff4543969b0cf6',
'017aefd63b4ce14eb376161902d92894a15f680e7b055ce25c3b02c6b49db0a6',
'e12d945904032887c967ae03a48c8b096abc79dc64134d872693599d4f6c91cc',
'0f8957f365f53a7209baa852905c5da5dba54ddb403ab17a4c9b3a051540d49c',
'091e3e41815cd32f482f2cf54ac3338fc918c2a657896af1aa1b23ea528664f4',
'5916cd18e8c48c545232112f2179aa7a722350a8a0ced4f1363cc61bc9d83630',
'37702710d47a1c17278743253123f6eac85b16d9393432ec65100143bc8657e8',
'c3a7006293c48957cba5c010f945483cfdc47650a79d0e8a8a9a52c174244a10',
'e1a90a475dd21da64d64ea1dd50a82a622061d08e9d4b3016982c4a0b42f1251',
'2f40ff85024765e58ed175927c53e0a279cda96ce755b602f89bfc171108ba3d',
'f4f8337dd7267d02638a9cc531c8a02fe0316dd5ff6f8c8aec898c060c6fb217',
'0df2f3fe1eb976944a2de5729fca4a12b83c8329b4f514869856ebb94b7d7bf9',
'abb2f1277b1cb5ad07254b7f7ed346bcdb73282b306123ce0b5befe42a9e796d',
'6ef31ed6a2a465bcd146c2438bf391bfd9f3187cf54afae512220a7a94714bf3',
'6981f99ba288923a5cd68908ecc8795bf301f1e7d081ac6580a63902fd52da01',
'b6b07975697de1c0342e3711b59165b849125794ef2541c6c60dcf40e689df7b',
'20e3af3a2bcedfd15199975cc9edcde14cb13fdff3ea0607a4747601e500aede',
'606aa1daf188b9dd5fd6141312f1828846f92baa519e70e5c6923a352421fe2f',
'1dc6a60112e99c5b884c0bb5430a7a54eba8aef34fada9cb96bce79a22456cf2',
'fd81e36f576119a19185cd12e87544b42f9fcc3dcb5e7ba282b1a128d73d63c5',
'7a01e947ca012a5c9a8dd20e693a7788cd6157a5c3fce5fa7c7e09014ea3266e',
'ccd162b182c773062514ffc3551ed47f32293700083782d902efc55b1e9795c6',
'dbb6115aefd2638eebf44d3be6e9525e09ff036269d954469a0f925b496327a7',
'ac08696fe64bb5e58cd3e558463213ca08ab7805e33f45459ae14b35fc5858c6',
'6e1594596ad1c656635af29d14b22a5ed10e545442eea5f4e056e20d11aa33b3',
'4afd17e64562603c66ce0ca42d544ca48511c3d560f9180c231a9ccb28a0e55e',
'06b2d2b24ca626e18fdcb3196e989e3b05150500815511f48200ddea9aacda48',
'947a11e8258fd161d02b0eb1b2e8fcd9ff1684a7c75f7c506ddee91f08316f56',
'a0e58b15736cab055be1d03860dedb6b8136f6739308c2e0ef6a7490c6b4a1f1',
'31476f64f96d72a398e7eb789068b8cfd61ed9cac95d76824a2bbf5b682ea72d',
'974259198846a4849d318afd325d860a6e40dfd39e1ed8c7b6d87c990e35efcf',
'e93d02ba7079c488c30e377794b4fcc62eeafb6c3f02197f1ebc059e3e5f7f07',
'ded96eec0d25c05a54671a001bcd99f5c6d3991d2fdf80afb8f0861a44f3fd64',
'86f34c1da65f07634de7c302a6df306dd545806022411a318900bd33b0aff9bd',
'59baf4cf3d3b85fcdefd1a9b60c3d78926ff73650ac375c616b30fe9063b377d',
'02f2ee251ecc19fa52dd42c0e0b609bc2e7a8ae11ce6ca35396a4bc74d12ac63',
'597d09b4c43012b1b4b040d8c62d5fb02d1c4249de4eea06e1447000ba53f50c',
'bb87bd8e1903db2df41c349914e9f3591bb032400be6e86ed10e7d292243a374',
'cec38960069fdc8090cfbdd166e15ec8a77ce5b4d6b350805a63d2b54cbf0187',
'1439d35a9c0caa9cacabe8e6179a02d51ebb9fb51125d5eeaba47ff6b8abcc97',
'820d72d49e0fd86ef47b022a3091b326be8b0d2a42f87cbc918737b9972ea62f',
'e625e82100031fa4a4410700034859cd4b35c086f5ac2870c6909c16a6831bfc',
'f0e22f5167d29331351e1718c17b5420f6a29d84357273e1bfb24c2ff34fa675',
'a5a7991f0c5c6a44f68c5c18661611057dbabeff7847623315ce784095645f75',
'07cd3f5c5c690214af5feda27b3aec257543a8f96bc509805028a0e95c5d98c6',
'6e5dd4405c1b446b9530e4d9356c05b71d1bfcf8a79778588143c3b6fec3fded',
'a33f821d277e6f73c09a5ecd14cef80bac29ffe2b917225c27725d2447ac0489',
'c18a4a02dd1f7ee65bf5596c53549c286a754afb0e3b90b2369cdd1e43c0b986',
'6b8df66aa27b40ca275bc133958b5d543167edf919e7e623a496c9afbf7594d6',
'c48124eeef995c7bb705bd240a26dbf6bdbe42ba29addf7ac78fa28dbed3debe',
'040eef11dc6e0f3bb3e58e12d2a57ee274071a9c6224f27db70e19a8aa7d4df2',
'4ecd0a955e52657fab8dfdac2df4d805f1d08b031df8bce22ac01fe20ca72c5b']

data = []
for i in range(len(id)):
t1 = int(id[i], 16)
for j in range(4):
data.append(t1 & 0xffffffff)
t1 >>= 32
t2 = int(code[i], 16)
for j in range(8):
data.append(t2 & 0xffffffff)
t2 >>= 32
print(len(data))
state1=recover_state(data)
state0=backtrace([0]*12+state1)[:624]
ran=Random()
ran.setstate((3,tuple(state0+[0]),None))
id0=ran.getrandbits(128)
code0=ran.getrandbits(256)
assert ran.getrandbits(32)==data[0]
flag=md5((hex(id0)[2:].zfill(32)+hex(code0)[2:].zfill(64)).encode()).hexdigest()
print("flag{%s}"%flag)

math

关键在于解出a和b两个参数,通过在线二元求解可以得到递推式。

1
2
D = 0x1337
assert a**2 - D*b**2 == 1

image-20230108204422417

之后求出c的全排列,根据递推式爆破a和b即可解密仿射。

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
from Crypto.Util.number import *
import gmpy2 as gp
import itertools

def get_flag(a:list,b:list):
c=['0010101111100011101101011111111001011000100110001001000000010001111011110101110011111', '0011010010010010110010011011001100110001100010101110001010001101110001100000111011010', '0110101101011101110000100001000000010001110110001010000000010110010101100100101110000', '0100111001011010000101100111100110101100011100100111011000110001111101000110110101101', '1100100110011101010011011111000101011011010000101100011001110100101000101101111110100', '1110111110001110000101100000000100111010110000001111010001101001100001010110101010001']
tb = [i for i in itertools.permutations([j for j in range(6)])]
for cp in tb:
enc=''.join([c[i] for i in cp])
enc=int(enc,2)
p = 11199186558148426014734492874345932099384932524559726349180064588241518696390926354448476750322781683505497782040786332571272422812867731614415519029276349
for ta in a:
for tb in b:
assert ta**2 - 0x1337*tb**2 ==1
res=((enc-tb)*gp.invert(ta,p))%p
m=long_to_bytes(res)
try:
print(m.decode())
print(a,b)
except: pass

P = 1809338099956399320
Q = 126898982449083908291
R = 25797719546469589
S = 1809338099956399320
x=1
y=0
for i in range(10):
assert x**2-0x1337*y**2 ==1
tx=P*x+Q*y
ty=R*x+S*y
get_flag([tx,-tx],[ty,-ty])
x=tx
y=ty
# flag{5b80aaa2-2bb2-0ef1-4aa0-a5a9387239d5}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!