NPC²CTF 2025 Reverse 方向复现

Week1

esrever

主逻辑

ida 中点击发现在 main 和 start 之间无限跳转,搜索字符串再 x 交叉引用到关键汇编,发现这部分汇编全部飘红,反编译失败

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
.text:0000000000001110                 jmp     loc_1286
.text:0000000000001115 ; ---------------------------------------------------------------------------
.text:0000000000001115 movzx ecx, cs:byte_4080
.text:000000000000111C jmp short loc_1152
.text:000000000000111E ; ---------------------------------------------------------------------------
.text:000000000000111E
.text:000000000000111E loc_111E: ; CODE XREF: .text:loc_12B0↓j
.text:000000000000111E call _printf
.text:0000000000001123 xor eax, eax
.text:0000000000001125 lea rdi, aRight ; "Right!"
.text:000000000000112C jmp short loc_115D
.text:000000000000112E ; ---------------------------------------------------------------------------
.text:000000000000112E
.text:000000000000112E loc_112E: ; CODE XREF: .text:0000000000001135↓j
.text:000000000000112E jz short loc_1143
.text:0000000000001130 cmp [rax], bl
.text:0000000000001132 movzx ebx, byte ptr [rdx]
.text:0000000000001135 jz short loc_112E
.text:0000000000001137
.text:0000000000001137 loc_1137: ; CODE XREF: .text:000000000000115B↓j
.text:0000000000001137 cmp rdx, rcx
.text:000000000000113A add rax, 1
.text:000000000000113E add rdx, 1
.text:0000000000001142 retn
.text:0000000000001143 ; ---------------------------------------------------------------------------
.text:0000000000001143
.text:0000000000001143 loc_1143: ; CODE XREF: .text:loc_112E↑j
.text:0000000000001143 pop rbx
.text:0000000000001144 xor eax, eax
.text:0000000000001146 add rsp, 100h
.text:000000000000114D call _printf
.text:0000000000001152
.text:0000000000001152 loc_1152: ; CODE XREF: .text:000000000000111C↑j
.text:0000000000001152 xor eax, eax
.text:0000000000001154 lea rdi, aWrong ; "Wrong!"
.text:000000000000115B jnz short loc_1137
.text:000000000000115D
.text:000000000000115D loc_115D: ; CODE XREF: .text:000000000000112C↑j
.text:000000000000115D ; .text:00000000000012D2↓j
.text:000000000000115D test rax, rax
.text:0000000000001160 lea rcx, [rdx+18h]
.text:0000000000001164 lea rdx, unk_4040
.text:000000000000116B call sub_188E
.text:0000000000001170 movaps xmmword ptr [rsp+0F0h], xmm0
.text:0000000000001178 movdqa xmm0, cs:xmmword_2260
.text:0000000000001180 movaps xmmword ptr [rsp+0E0h], xmm0
.text:0000000000001188 movdqa xmm0, cs:xmmword_2250
.text:0000000000001190 movaps xmmword ptr [rsp+0D0h], xmm0
.text:0000000000001198 movdqa xmm0, cs:xmmword_2240
.text:00000000000011A0 movaps xmmword ptr [rsp+0C0h], xmm0
.text:00000000000011A8 movdqa xmm0, cs:xmmword_2230
.text:00000000000011B0 movaps xmmword ptr [rsp+0B0h], xmm0
.text:00000000000011B8 movdqa xmm0, cs:xmmword_2220
.text:00000000000011C0 movaps xmmword ptr [rsp+0A0h], xmm0
.text:00000000000011C8 movdqa xmm0, cs:xmmword_2210
.text:00000000000011D0 movaps xmmword ptr [rsp+90h], xmm0
.text:00000000000011D8 movdqa xmm0, cs:xmmword_2200
.text:00000000000011E0 movaps xmmword ptr [rsp+80h], xmm0
.text:00000000000011E8 movdqa xmm0, cs:xmmword_21F0
.text:00000000000011F0 movaps xmmword ptr [rsp+70h], xmm0
.text:00000000000011F5 movdqa xmm0, cs:xmmword_21E0
.text:00000000000011FD movaps xmmword ptr [rsp+60h], xmm0
.text:0000000000001202 movdqa xmm0, cs:xmmword_21D0
.text:000000000000120A movaps xmmword ptr [rsp+50h], xmm0
.text:000000000000120F movdqa xmm0, cs:xmmword_21C0
.text:0000000000001217 movaps xmmword ptr [rsp+40h], xmm0
.text:000000000000121C movdqa xmm0, cs:xmmword_21B0
.text:0000000000001224 movaps xmmword ptr [rsp+30h], xmm0
.text:0000000000001229 movdqa xmm0, cs:xmmword_21A0
.text:0000000000001231 movaps xmmword ptr [rsp+20h], xmm0
.text:0000000000001236 movdqa xmm0, cs:xmmword_2190
.text:000000000000123E movaps xmmword ptr [rsp+10h], xmm0
.text:0000000000001243 movdqa xmm0, cs:xmmword_2180
.text:000000000000124B movaps xmmword ptr [rsp], xmm0
.text:000000000000124F mov rdi, rbx
.text:0000000000001252 mov rsi, rsp
.text:0000000000001255 movdqa xmm0, cs:xmmword_2170
.text:000000000000125D jnz short loc_127D
.text:000000000000125F
.text:000000000000125F loc_125F: ; CODE XREF: .text:000000000000126C↓j
.text:000000000000125F ; .text:0000000000001284↓j ...
.text:000000000000125F test sil, sil
.text:0000000000001262 mov dh, cl
.text:0000000000001264 movzx edx, sil
.text:0000000000001268 movzx esi, byte ptr [rax+1]
.text:000000000000126C jz short loc_125F
.text:000000000000126E
.text:000000000000126E loc_126E: ; CODE XREF: .text:000000000000127B↓j
.text:000000000000126E test cl, cl
.text:0000000000001270 add rax, 2
.text:0000000000001274 movzx ecx, byte ptr [rax+2]
.text:0000000000001278 mov [rax], dx
.text:000000000000127B jmp short loc_126E
.text:000000000000127D ; ---------------------------------------------------------------------------
.text:000000000000127D
.text:000000000000127D loc_127D: ; CODE XREF: .text:000000000000125D↑j
.text:000000000000127D lea rax, byte_4080
.text:0000000000001284 jz short loc_125F
.text:0000000000001286
.text:0000000000001286 loc_1286: ; CODE XREF: .text:0000000000001110↑j
.text:0000000000001286 test cl, cl
.text:0000000000001288 movzx ecx, cs:byte_4080
.text:000000000000128F jb short loc_12B0
.text:0000000000001291 cmp rdx, rax
.text:0000000000001294 mov [rax+1], cl
.text:0000000000001297 mov [rdx-1], sil
.text:000000000000129B sub rax, 1
.text:000000000000129F add rdx, 1
.text:00000000000012A3 movzx esi, byte ptr [rax]
.text:00000000000012A6 movzx ecx, byte ptr [rdx]
.text:00000000000012A9 lea rdx, byte_4080
.text:00000000000012B0
.text:00000000000012B0 loc_12B0: ; CODE XREF: .text:000000000000128F↑j
.text:00000000000012B0 jnb loc_111E
.text:00000000000012B6 cmp rbx, rax
.text:00000000000012B9 jnz short loc_12C8
.text:00000000000012BB cmp byte ptr [rax+1], 0
.text:00000000000012BF lea rdx, [rdx+1]
.text:00000000000012C3 mov rax, rdx
.text:00000000000012C6 jz short loc_125F
.text:00000000000012C8
.text:00000000000012C8 loc_12C8: ; CODE XREF: .text:00000000000012B9↑j
.text:00000000000012C8 mov rdx, rbx
.text:00000000000012CB cmp cs:byte_4080, 0
.text:00000000000012D2 jz loc_115D
.text:00000000000012D8 test al, al
.text:00000000000012DA call sub_14FE
.text:00000000000012DF mov rdi, rbx
.text:00000000000012E2 call ___isoc23_scanf
.text:00000000000012E7 mov rsi, rbx
.text:00000000000012EA xor eax, eax
.text:00000000000012EC lea rdi, aS ; "%s"
.text:00000000000012F3 call _printf
.text:00000000000012F8 sub rsp, 100h
.text:00000000000012FF lea rbx, byte_4080
.text:0000000000001306 xor eax, eax
.text:0000000000001308 lea rdi, aInputYourFlag ; "Input your flag:"
.text:000000000000130F push rbx
.text:0000000000001310 inc edi

但是观察后不难发现这里的汇编顺序是反的,往后翻的话还能找到几处类似的地方
上面的那部分汇编的逻辑大致是:
读取用户输入到 byte_4080,
有一个字节交换
调用加密函数
字符串比较判断

密文

密文在 unk_4040
提取出来为 131C175213525245143E3E114550053E16511A0F0006070D

flag 格式对比

第二处飘红的地方,比较输入的字符是否符合 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
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
.text:0000000000001410 loc_1410:                               ; DATA XREF: sub_10B0+1E↑o
.text:0000000000001410 mov rsi, [rdx+0A8h]
.text:0000000000001417 lea rax, unk_1098
.text:000000000000141E mov r8, rdx
.text:0000000000001421 cmp rsi, rax
.text:0000000000001424 jb short locret_1490
.text:0000000000001426 lea rdx, _term_proc
.text:000000000000142D cmp rsi, rdx
.text:0000000000001430 jnb short locret_1490
.text:0000000000001432 mov rdx, rsi
.text:0000000000001435 lea r9, unk_2040
.text:000000000000143C sub rdx, rax
.text:000000000000143F mov rax, rdx
.text:0000000000001442 mov ecx, edx
.text:0000000000001444 shr rax, 3
.text:0000000000001448 and ecx, 7
.text:000000000000144B movsx eax, byte ptr [r9+rax]
.text:0000000000001450 bt eax, ecx
.text:0000000000001453 jnb short locret_1490
.text:0000000000001455 sub rsi, 1
.text:0000000000001459 sub rdx, 1
.text:000000000000145D xor edi, edi
.text:000000000000145F
.text:000000000000145F loc_145F: ; CODE XREF: .text:0000000000001487↓j
.text:000000000000145F mov rax, rdx
.text:0000000000001462 mov ecx, edx
.text:0000000000001464 sub rdx, 1
.text:0000000000001468 shr rax, 3
.text:000000000000146C and ecx, 7
.text:000000000000146F movsx eax, byte ptr [r9+rax]
.text:0000000000001474 sar eax, cl
.text:0000000000001476 and eax, 1
.text:0000000000001479 add rdi, rax
.text:000000000000147C mov rax, rsi
.text:000000000000147F sub rsi, 1
.text:0000000000001483 cmp rdi, 2
.text:0000000000001487 jnz short loc_145F
.text:0000000000001489 mov [r8+0A8h], rax
.text:0000000000001490
.text:0000000000001490 locret_1490: ; CODE XREF: .text:0000000000001424↑j
.text:0000000000001490 ; .text:0000000000001430↑j ...
.text:0000000000001490 retn
.text:0000000000001490 ; ---------------------------------------------------------------------------
.text:0000000000001491 align 20h
.text:00000000000014A0 ; [00000001 BYTES: COLLAPSED FUNCTION nullsub_1. PRESS CTRL-NUMPAD+ TO EXPAND]
.text:00000000000014A1 ; ---------------------------------------------------------------------------
.text:00000000000014A1 pop rbp
.text:00000000000014A2 pop rbx
.text:00000000000014A3 mov eax, ebp
.text:00000000000014A5 add rsp, 8
.text:00000000000014A9 xor ebp, ebp
.text:00000000000014AB retn
.text:00000000000014AC ; ---------------------------------------------------------------------------
.text:00000000000014AC
.text:00000000000014AC loc_14AC: ; CODE XREF: .text:00000000000014EC↓j
.text:00000000000014AC pop rbp
.text:00000000000014AD pop rbx
.text:00000000000014AE mov eax, ebp
.text:00000000000014B0 add rsp, 8
.text:00000000000014B4 setz bpl
.text:00000000000014B8
.text:00000000000014B8 loc_14B8: ; CODE XREF: .text:00000000000014BC↓j
.text:00000000000014B8 ; .text:00000000000014CA↓j ...
.text:00000000000014B8 cmp byte ptr [rbx+17h], 7Dh ; '}'
.text:00000000000014BC jnz short loc_14B8
.text:00000000000014BE cmp eax, 17h
.text:00000000000014C1 call _strlen
.text:00000000000014C6 lea rdi, [rdi+1]
.text:00000000000014CA jnz short loc_14B8
.text:00000000000014CC cmp byte ptr [rdi+4], 7Bh ; '{'
.text:00000000000014D0 jnz short loc_14B8
.text:00000000000014D2 cmp byte ptr [rdi+3], 67h ; 'g'
.text:00000000000014D6 jnz short loc_14B8
.text:00000000000014D8 cmp byte ptr [rdi+2], 61h ; 'a'
.text:00000000000014DC jnz short loc_14B8
.text:00000000000014DE cmp byte ptr [rdi+1], 6Ch ; 'l'
.text:00000000000014E2 jnz short loc_14B8
.text:00000000000014E4 mov rbx, rdi
.text:00000000000014E7 cmp byte ptr [rdi], 66h ; 'f'
.text:00000000000014EA xor ebp, ebp
.text:00000000000014EC jz short loc_14AC
.text:00000000000014EE test rdi, rdi
.text:00000000000014F1 sub rsp, 8
.text:00000000000014F5 push rbx
.text:00000000000014F6 push rbp
.text:00000000000014F7 vfnmadd213sd xmm7, xmm0, qword ptr [rsp+28h]

主要加密

这部分可以看到有很多异或操作,并且是多次异或同一个值,一个 0x76 ,一个 0x72

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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
.text:00000000000015BC loc_15BC:                               ; CODE XREF: .text:loc_1865↓j
.text:00000000000015BC pop r15
.text:00000000000015BE pop r14
.text:00000000000015C0 pop r13
.text:00000000000015C2 pop r12
.text:00000000000015C4 pop rbp
.text:00000000000015C5 pop rbx
.text:00000000000015C6 mov rax, rcx
.text:00000000000015C9 add rsp, 8
.text:00000000000015CD mov byte ptr [rcx+rbp], 0
.text:00000000000015D1
.text:00000000000015D1 loc_15D1: ; CODE XREF: .text:0000000000001593↑j
.text:00000000000015D1 movsxd rbp, ebp
.text:00000000000015D4 mov [rcx+rax], dl
.text:00000000000015D7
.text:00000000000015D7 loc_15D7: ; CODE XREF: .text:00000000000015E1↓j
.text:00000000000015D7 ; .text:00000000000015F7↓j ...
.text:00000000000015D7 xor edx, 76h
.text:00000000000015DA movzx edx, byte ptr [r12+rax]
.text:00000000000015DF cdqe
.text:00000000000015E1 jle short loc_15D7
.text:00000000000015E3 cmp ebp, eax
.text:00000000000015E5 mov [rcx+rdx], sil
.text:00000000000015E9 xor esi, 76h
.text:00000000000015EC movzx esi, byte ptr [r12+rdx]
.text:00000000000015F1 add eax, 6
.text:00000000000015F4 movsxd rdx, edx
.text:00000000000015F7 jle short loc_15D7
.text:00000000000015F9 cmp ebp, edx
.text:00000000000015FB lea edx, [rax+5]
.text:00000000000015FE mov [rcx+rdx], sil
.text:0000000000001602 xor esi, 76h
.text:0000000000001605 movzx esi, byte ptr [r12+rdx]
.text:000000000000160A movsxd rdx, edx
.text:000000000000160D jle short loc_15D7
.text:000000000000160F cmp ebp, edx
.text:0000000000001611 lea edx, [rax+4]
.text:0000000000001614 mov [rcx+rdx], sil
.text:0000000000001618 xor esi, 76h
.text:000000000000161B movzx esi, byte ptr [r12+rdx]
.text:0000000000001620 movsxd rdx, edx
.text:0000000000001623 jge short loc_15D7
.text:0000000000001625 cmp edx, ebp
.text:0000000000001627 lea edx, [rax+3]
.text:000000000000162A mov [rcx+rdx], sil
.text:000000000000162E xor esi, 76h
.text:0000000000001631 movzx esi, byte ptr [r12+rdx]
.text:0000000000001636 movsxd rdx, edx
.text:0000000000001639 jge short loc_15D7
.text:000000000000163B cmp edx, ebp
.text:000000000000163D lea edx, [rax+2]
.text:0000000000001640 mov [rcx+rdx], sil
.text:0000000000001644 xor esi, 76h
.text:0000000000001647 movzx esi, byte ptr [r12+rdx]
.text:000000000000164C movsxd rdx, edx
.text:000000000000164F jle short loc_15D7
.text:0000000000001651 cmp ebp, edx
.text:0000000000001653 lea edx, [rax+1]
.text:0000000000001656 mov [rcx+rsi], dl
.text:0000000000001659 xor edx, 76h
.text:000000000000165C movzx edx, byte ptr [r12+rsi]
.text:0000000000001661 movsxd rsi, eax
.text:0000000000001664 jz loc_15D7
.text:000000000000166A
.text:000000000000166A loc_166A: ; CODE XREF: .text:000000000000168B↓j
.text:000000000000166A and esi, 7
.text:000000000000166D add eax, edx
.text:000000000000166F and edx, 0FFFFFFF8h
.text:0000000000001672 mov edx, esi
.text:0000000000001674 movq qword ptr [rcx+rdx], xmm0
.text:0000000000001679 pxor xmm0, xmm1
.text:000000000000167D movq xmm0, qword ptr [r12+rdx]
.text:0000000000001683 movq xmm1, qword ptr cs:xmmword_2160
.text:000000000000168B jbe short loc_166A
.text:000000000000168D cmp edi, 6
.text:0000000000001690 lea edi, [rsi-1]
.text:0000000000001693 sub esi, edx
.text:0000000000001695 mov esi, ebp
.text:0000000000001697 jz loc_15D7
.text:000000000000169D
.text:000000000000169D loc_169D: ; CODE XREF: .text:0000000000001597↑j
.text:000000000000169D cmp eax, ebp
.text:000000000000169F mov edx, eax
.text:00000000000016A1 and eax, 0FFFFFFF0h
.text:00000000000016A4 mov eax, ebp
.text:00000000000016A6 jnz short loc_16C1
.text:00000000000016A8 cmp rdx, rax
.text:00000000000016AB add rax, 10h
.text:00000000000016AF movups xmmword ptr [rcx+rax], xmm0
.text:00000000000016B3 pxor xmm0, xmm1
.text:00000000000016B7 movdqu xmm0, xmmword ptr [r12+rax]
.text:00000000000016BD shl rdx, 4
.text:00000000000016C1
.text:00000000000016C1 loc_16C1: ; CODE XREF: .text:00000000000016A6↑j
.text:00000000000016C1 shr edx, 4
.text:00000000000016C4 xor eax, eax
.text:00000000000016C6 movdqa xmm1, cs:xmmword_2160
.text:00000000000016CE mov edx, ebp
.text:00000000000016D0 jbe loc_15A5
.text:00000000000016D6 cmp esi, 0Eh
.text:00000000000016D9 jnz short loc_16F2
.text:00000000000016DB cmp eax, 0FFFFFFFFh
.text:00000000000016DE sub rax, 1
.text:00000000000016E2 mov [r12+rax], dl
.text:00000000000016E6 xor edx, 65h
.text:00000000000016E9 movzx edx, byte ptr [r13+rax+0]
.text:00000000000016EF movsxd rax, ebx
.text:00000000000016F2
.text:00000000000016F2 loc_16F2: ; CODE XREF: .text:00000000000016D9↑j
.text:00000000000016F2 mov [r13+rax+0], dl
.text:00000000000016F7
.text:00000000000016F7 loc_16F7: ; CODE XREF: .text:0000000000001701↓j
.text:00000000000016F7 ; .text:0000000000001718↓j ...
.text:00000000000016F7 xor edx, 72h
.text:00000000000016FA movzx edx, byte ptr [r14+rax]
.text:00000000000016FF cdqe
.text:0000000000001701 jle short loc_16F7
.text:0000000000001703 cmp ebp, eax
.text:0000000000001705 mov [r13+rdx+0], dil
.text:000000000000170A xor edi, 72h
.text:000000000000170D movzx edi, byte ptr [r14+rdx]
.text:0000000000001712 add eax, 6
.text:0000000000001715 movsxd rdx, edx
.text:0000000000001718 jle short loc_16F7
.text:000000000000171A cmp ebp, edx
.text:000000000000171C lea edx, [rax+5]
.text:000000000000171F mov [r13+rdx+0], dil
.text:0000000000001724 xor edi, 72h
.text:0000000000001727 movzx edi, byte ptr [r14+rdx]
.text:000000000000172C movsxd rdx, edx
.text:000000000000172F jle short loc_16F7
.text:0000000000001731 cmp ebp, edx
.text:0000000000001733 lea edx, [rax+4]
.text:0000000000001736 mov [r13+rdx+0], dil
.text:000000000000173B xor edi, 72h
.text:000000000000173E movzx edi, byte ptr [r14+rdx]
.text:0000000000001743 movsxd rdx, edx
.text:0000000000001746 jle short loc_16F7
.text:0000000000001748 cmp ebp, edx
.text:000000000000174A lea edx, [rax+3]
.text:000000000000174D mov [r13+rdx+0], dil
.text:0000000000001752 xor edi, 72h
.text:0000000000001755 movzx edi, byte ptr [r14+rdx]
.text:000000000000175A movsxd rdx, edx
.text:000000000000175D jle short loc_16F7
.text:000000000000175F cmp ebp, edx
.text:0000000000001761 lea edx, [rax+2]
.text:0000000000001764 mov [r13+rdx+0], dil
.text:0000000000001769 xor edi, 72h
.text:000000000000176C movzx edi, byte ptr [r14+rdx]
.text:0000000000001771 movsxd rdx, edx
.text:0000000000001774 jle short loc_16F7
.text:0000000000001776 cmp ebp, edx
.text:0000000000001778 lea edx, [rax+1]
.text:000000000000177B mov [r13+rdi+0], dl
.text:0000000000001780 xor edx, 72h
.text:0000000000001783 movzx edx, byte ptr [r14+rdi]
.text:0000000000001788 movsxd rdi, eax
.text:000000000000178B jz loc_16F7
.text:0000000000001791
.text:0000000000001791 loc_1791: ; CODE XREF: .text:00000000000017B4↓j
.text:0000000000001791 and edi, 7
.text:0000000000001794 add eax, edx
.text:0000000000001796 and edx, 0FFFFFFF8h
.text:0000000000001799 mov edx, edi
.text:000000000000179B movq qword ptr [r13+rdx+0], xmm0
.text:00000000000017A2 pxor xmm0, xmm1
.text:00000000000017A6 movq xmm0, qword ptr [r14+rdx]
.text:00000000000017AC movq xmm1, qword ptr cs:xmmword_2150
.text:00000000000017B4 jbe short loc_1791
.text:00000000000017B6 cmp r8d, 6
.text:00000000000017BA lea r8d, [rdi-1]
.text:00000000000017BE sub edi, edx
.text:00000000000017C0 mov edi, ebp
.text:00000000000017C2 jz loc_16F7
.text:00000000000017C8
.text:00000000000017C8 loc_17C8: ; CODE XREF: .text:00000000000015A0↑j
.text:00000000000017C8 cmp ebp, eax
.text:00000000000017CA mov edx, eax
.text:00000000000017CC and eax, 0FFFFFFF0h
.text:00000000000017CF mov eax, ebp
.text:00000000000017D1 jnz short loc_17EE
.text:00000000000017D3 cmp rax, rdx
.text:00000000000017D6 add rax, 10h
.text:00000000000017DA movups xmmword ptr [r13+rax+0], xmm0
.text:00000000000017E0 pxor xmm0, xmm1
.text:00000000000017E4 movdqu xmm0, xmmword ptr [r14+rax]
.text:00000000000017EA shl rdx, 4
.text:00000000000017EE
.text:00000000000017EE loc_17EE: ; CODE XREF: .text:00000000000017D1↑j
.text:00000000000017EE shr edx, 4
.text:00000000000017F1 xor eax, eax
.text:00000000000017F3 movdqa xmm1, cs:xmmword_2150
.text:00000000000017FB mov edx, ebp
.text:00000000000017FD jbe loc_15AE
.text:0000000000001803 cmp esi, 0Eh
.text:0000000000001806 lea esi, [rbp-1]
.text:0000000000001809 jz loc_15D7
.text:000000000000180F test ebp, ebp
.text:0000000000001811 jz loc_159C
.text:0000000000001817 test rax, rax
.text:000000000000181A mov rcx, rax
.text:000000000000181D call _malloc
.text:0000000000001822 mov rdi, r15
.text:0000000000001825 jz loc_159C
.text:000000000000182B test rax, rax
.text:000000000000182E mov r12, rax
.text:0000000000001831 call _malloc
.text:0000000000001836 mov rdi, r15
.text:0000000000001839 jz loc_159C
.text:000000000000183F test rax, rax
.text:0000000000001842 mov r13, rax
.text:0000000000001845 call _malloc
.text:000000000000184A mov rdi, r15
.text:000000000000184D movsxd r15, r15d
.text:0000000000001850
.text:0000000000001850 loc_1850: ; CODE XREF: .text:00000000000015A9↑j
.text:0000000000001850 lea r15d, [rbx+2]
.text:0000000000001854 jnz short loc_1865
.text:0000000000001856 cmp byte ptr [rax-1], 0
.text:000000000000185A add ebp, 1
.text:000000000000185D mov ebx, ebp
.text:000000000000185F add rax, 1
.text:0000000000001863 xor ebp, ebp
.text:0000000000001865
.text:0000000000001865 loc_1865: ; CODE XREF: .text:0000000000001854↑j
.text:0000000000001865 jz loc_15BC
.text:000000000000186B cmp byte ptr [rdi], 0
.text:000000000000186E sub rsp, 8
.text:0000000000001872 push rbx
.text:0000000000001873 push rbp
.text:0000000000001874 push r12
.text:0000000000001876 push r13
.text:0000000000001878 mov r14, rdi
.text:000000000000187B push r14
.text:000000000000187D lea rax, [rdi+1]
.text:0000000000001881 push r15
.text:0000000000001883 jz loc_1595
.text:0000000000001889 test rdi, rdi
.text:000000000000188C test edx, edx

解密

用密文异或 0x76 和 0x72 之后没得到可见明文字符,爆破出来第三个异或值是 0x65(后来在汇编中异或 0x76 和 异或 0x72 之间的部分看到有一个异或 0x65)

得到 r}v3r33$u__p$1d_w0{nagfl,可以看出这个是从后往前两个字符一组交换顺序,整理出来 flag 是
flag{nw0d_$1_pu_3$r3v3r}

原理

做题的时候就很好奇,为什么汇编是反着的,但是程序却能正常运行,解惑参考这篇文章

cccc

处理混淆

C# 逆向,动调之后基本能确定主要逻辑在 dll 中,被confuser 混淆了,先用 de4dot 去一下混淆

1
2
3
4
5
D:\CTF\Reverse\de4dot-Reactor5.0>de4dot.exe D:\aaa\NPCCTF\cccc\ccccapp.dll
Detected Unknown Obfuscator (D:\aaa\NPCCTF\cccc\ccccapp.dll)
Cleaning D:\aaa\NPCCTF\cccc\ccccapp.dll
Renaming all obfuscated symbols
Saving D:\aaa\NPCCTF\cccc\ccccapp-cleaned.dll

然后用 dnSpy 打开,发现关键类

可以看到它读取了输入之后进行了一系列操作,后面的数据应该是密文了

动调找程序逻辑,我最开始直接调试会报错,后面设置成这样就能调了(选中使用宿主可执行文件)

动调梳理

逐语句(F11) 一直调
到达用户输入的地方

这里在读取输入

找到一串字符 doyouknowcsharp,和输入的内容传入同一个函数,推测这个字符串应该是密钥

找到加密逻辑,魔改 RC4,array2[t3] = (byte)(A_1[t3] ^ array[(array[t] + array[t2]) % 256] ^ 100); 这部分多了一个异或 100

再往后就是比较完输出 Wrong

解密

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
def rc4_cccc_dec(cipher,key_str):
S = list(range(256))
j = 0
key = [ord(c) for c in key_str]

for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]

i = j = 0
plain = []
for c in cipher:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) % 256]

plain.append(c ^ K ^ 100)
return bytes(plain)

cipher = [
0xf8, 0xb1, 0x1e, 0xe8, 0x7f, 0x99, 0xde, 0x4e,
0x84, 0xb4, 0x15, 0x21, 0xb6, 0x8e, 0xd1, 0x2a,
0x8b, 0x9a, 0x4d, 0xe7, 0x8f, 0xda, 0x23, 0xc0,
0xa9, 0x62, 0x63, 0xe7, 0x02, 0x41, 0x90, 0x88,
0x77, 0x75, 0xba, 0x32, 0xc6, 0xb0, 0x84, 0x24,
0xa6, 0xa8, 0x45, 0xf6, 0xcd, 0x9c, 0x8a, 0x32
]

key_str = "doyouknowcsharp"
flag = rc4_cccc_dec(cipher,key_str)
print("Flag is :",flag)

flag 为 flag{y0u_r34lly_kn0w_m@ny_pr0gr@mm1ng_l@ngu@g3$}

ugly_world

处理混淆

main 函数初看很简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
__int64 __fastcall main(int a1, char **a2, char **a3)
{
_BYTE input[104]; // [rsp+0h] [rbp-70h] BYREF
unsigned __int64 v5; // [rsp+68h] [rbp-8h]

v5 = __readfsqword(0x28u);
puts("please input your flag:");
__isoc99_scanf("%40s", input);
sub_55555555E656((__int64)input, (__int64)&qword_555555561020);
if ( (unsigned __int8)sub_55555555E6A4(input, &byte_555555561040) )
sub_55555555E705();
else
sub_55555555E71F();
return 0LL;
}

读取了用户输入,sub_55555555E656 对 input 和地址 555555561020 处的数据(0x5566778811223344,0xCCDDEEFF9900AABB)进行处理,sub_55555555E656 函数中是一个循环,其中的 sub_555555555401 是一个很大的经过混淆了的函数,byte_555555561040 的位置是密文 0x0BD3BE58, 0xBE73BBFB, 0xC8C8AF4E, 0x0B3C7D86, 0xC0257C09, 0x1D8FE0B0, 0x8837180C, 0xF5CF9D23, 0xB7A8B599,0xAE630F3D,sub_55555555E705 输出 your are right!,else 输出 you are wrong!

1
2
3
4
5
6
7
8
9
__int64 __fastcall sub_55555555E656(__int64 a1, __int64 a2)
{
__int64 result; // rax
int i; // [rsp+1Ch] [rbp-4h]

for ( i = 0; i <= 9; i += 2 )
result = sub_555555555401((unsigned int *)(a1 + 4LL * i), a2);
return result;
}

对 sub_555555555401 中的函数逐个分析
sub_189 -> a1 + a2 -> ADD

1
2
3
4
5
6
7
8
9
10
11
12
13
__int64 __fastcall sub_555555555189(unsigned int a1, int a2)
{
int v5;

while (a2)
{
v5 = 2 * (a2 & a1); // 计算进位
a1 ^= a2; // 无进位加法 (异或)
a2 = v5; // 更新进位
}
return a1;
}

sub_1BB -> a1 - a2 -> SUB

1
2
3
4
5
6
7
__int64 __fastcall sub_5555555551BB(unsigned int a1, int a2)
{
int v3;

v3 = ADD(~a2, 1); // 计算 -a2
return ADD(a1, v3); // a1 + (-a2)
}

sub_2BF -> a1 >> a2 -> SHR

1
2
3
4
5
6
7
8
__int64 __fastcall sub_5555555552BF(unsigned int a1, signed int a2)
{
signed int i; // [rsp+14h] [rbp-4h]

for ( i = 0; i < a2; i = ADD(i, 1) )
a1 = SUB(a1 & 0xFFFFFFFE, (int)(a1 & 0xFFFFFFFE) / 2);
return a1;
}

sub_336 -> 把内存里连续的 4 个字节,拼成一个 小端序的 32 位整数 -> byte2dword

1
2
3
4
5
6
7
8
__int64 __fastcall sub_555555555366(__int64 a1, int a2)
{
return
(*(unsigned __int8 *)(4 * a2 + 1LL + a1) << 8) | // 第2个字节 → <<8
(*(unsigned __int8 *)(4 * a2 + 2LL + a1) << 16) | // 第3个字节 → <<16
(*(unsigned __int8 *)(4 * a2 + 3LL + a1) << 24) | // 第4个字节 → <<24
(unsigned int)*(unsigned __int8 *)(4 * a2 + a1); // 第1个字节 (低8位)
}

sub_31A -> a1 << a2 -> SHL

1
2
3
4
5
6
7
8
__int64 __fastcall sub_55555555531A(unsigned int a1, int a2)
{
unsigned int i;

for ( i = 0; (int)i < a2; i = ADD(i, 1LL) )
a1 = ADD(a1, a1);
return a1;
}

sub_1F2 -> (a1 ^ a2) & 1 -> XOR1

1
2
3
4
__int64 __fastcall sub_5555555551F2(char a1, char a2)
{
return (unsigned int)(((a1 & 1) + (a2 & 1)) % 2);
}

sub_21D -> a1 ^ a2 -> XOR

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__int64 __fastcall sub_55555555521D(int a1, int a2)
{
unsigned int v5 = 0;
int i;

for ( i = 0; i <= 31; ++i )
{
int v7 = XOR1((unsigned int)a1, (unsigned int)a2); // 取最低位异或
v5 = ADD(v5, v7 << i); // 累加到结果的第 i 位
a1 >>= 1;
a2 >>= 1;
}
return v5;
}

sub_28B -> (a1 ^ a2 ^ a3) -> XOR3

1
2
3
4
5
6
7
__int64 __fastcall sub_55555555528B(unsigned int a1, unsigned int a2, unsigned int a3)
{
unsigned int v3; // eax

v3 = XOR(a1, a2);
return XOR(v3, a3);
}

修改之后反编译界面如下

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
m0 = *input;
m1 = input[1];
//循环1
o1 = ADD(0, 0x3CA6F3E);
k1 = byte2dword(a2, 1);
v3 = SHR(m1, 1);
v4 = ADD(v3, k1);
v5 = ADD(m1, o1);
k2 = byte2dword(a2, 0);
v7 = SHL(m1, 1);
v8 = ADD(v7, k2);
v9 = XOR3(v8, v5, v4);
j = ADD(m0, v9);
k3 = byte2dword(a2, 3);
v11 = SHR(j, 1);
v12 = ADD(v11, k3);
v13 = ADD(j, o1);
v14 = byte2dword(a2, 2);
v15 = SHL(j, 1);
v16 = ADD(v15, v14);
v17 = XOR3(v16, v13, v12);
o2 = ADD(m1, v17);
//循环2
c2 = ADD(o1, 0xF2E1C7F1);
v18 = byte2dword(a2, 1);
v19 = SHR(o2, 3);
v20 = ADD(v19, v18);
v21 = ADD(o2, c2);
v22 = byte2dword(a2, 0);
v23 = SHL(o2, 4);
v24 = ADD(v23, v22);
v25 = XOR3(v24, v21, v20);
m0a = ADD(j, v25);
v26 = byte2dword(a2, 3);
v27 = SHR(m0a, 3);
v28 = ADD(v27, v26);
v29 = ADD(m0a, c2);
v30 = byte2dword(a2, 2);
v31 = SHL(m0a, 4);
v32 = ADD(v31, v30);
v33 = XOR3(v32, v29, v28);
m1a = ADD(o2, v33);
//循环3
o1a = ADD(c2, 2040670275);
v34 = byte2dword(a2, 1);
v35 = SHR(m1a, 4);
v36 = ADD(v35, v34);
v37 = ADD(m1a, o1a);
v38 = byte2dword(a2, 0);
v39 = SHL(m1a, 6);
v40 = ADD(v39, v38);
v41 = XOR3(v40, v37, v36);
m0b = ADD(m0a, v41);
v42 = byte2dword(a2, 3);
v43 = SHR(m0b, 4);
v44 = ADD(v43, v42);
v45 = ADD(m0b, o1a);
v46 = byte2dword(a2, 2);
v47 = SHL(m0b, 6);
v48 = ADD(v47, v46);
v49 = XOR3(v48, v45, v44);
m1b = ADD(m1a, v49);
//循环4
o1b = ADD(o1a, -729809763);
v50 = byte2dword(a2, 1);
v51 = SHR(m1b, 3);
v52 = ADD(v51, v50);
v53 = ADD(m1b, o1b);
v54 = byte2dword(a2, 0);
v55 = SHL(m1b, 6);
v56 = ADD(v55, v54);
v57 = XOR3(v56, v53, v52);
m0c = ADD(m0b, v57);
v58 = byte2dword(a2, 3);
v59 = SHR(m0c, 3);
v60 = ADD(v59, v58);
v61 = ADD(m0c, o1b);
v62 = byte2dword(a2, 2);
v63 = SHL(m0c, 6);
v64 = ADD(v63, v62);
v65 = XOR3(v64, v61, v60);
m1c = ADD(m1b, v65);
...
*input = m0ew;
result = (unsigned int)result;
input[1] = result;
return result;

加密同构

梳理第一个循环结构一下可以得到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
m0 = input[0]
m1 = input[1]
c1 = 0x3CA6F3E
k1 = 0x55667788
v3 = m1 >> 1
v4 = (m1 >> 1) + k1
v5 = m1 + 0x3CA6F3E
k2 = 0x11223344
v7 = m1 << 1
v8 = (m1 << 1) + k2
v9 = ((m1 << 1) + k2) ^ (m1 + 0x3CA6F3E) ^ ((m1 >> 1) + k1)
o1 = m0 + v9
k3 = 0xCCDDEEFF
v11 = o1 >> 1
v12 = (o1 >> 1) + k3
v13 = o1 + k1
k4 = 0x9900AABB
v15 = o1 << 1
v16 = (o1 << 1) + k4
v17 = ((o1 << 1) + k4) ^ (o1 + k1) ^ ((o1 >> 1) + k3)
o2 = m1 + v17

可以看出这个这是一个魔改的 TEA,一共有 128 轮,每轮的 delta 都不一样,并且每轮左移右移的数也不一样
提取出每一轮的 delta 和 移位值

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
delta = [
0x3CA6F3E, 0xF2E1C7F1, 0x79A22843, 0xD47FFC9D, 0xDD10F4C, 0x1DC368A1, 0x11B15F8A, 0x9469B3CD,
0x45D6DB5F, 0xBC6EE006, 0xA76D8146, 0xD542E337, 0x242E1155, 0xAA7F93DD, 0x88625ECB, 0x3738E499,
0xCEF27BB0, 0x134FF759, 0x358CA57E, 0x3461F310, 0x28540EE7, 0x81C0B176, 0xF725EE9C, 0xAF823A69,
0x61E8ECB3, 0xF4919548, 0x6AF44E11, 0x866162F3, 0x867F7E65, 0x6B26444C, 0x10216241, 0x9C1BA3CD,
0x1268FEAD, 0xF462B3B5, 0x5F7DE761, 0x72EAD5B6, 0xFBCE0C75, 0x44EF4142, 0x54DCC3C0, 0xAFFE805D,
0xC8833729, 0x3C944186, 0x261169A, 0xB547EA2F, 0x9B499585, 0xFE0190BF, 0x1EC74BE7, 0xAFC9292E,
0xC32F4EEF, 0x420A1A4, 0x94BEAB2B, 0xA0693238, 0x4DD5ADC1, 0x9F658F31, 0x1732EA46, 0x76BEE7DD,
0x12C63095, 0x9C202C7C, 0xAC9BB4C4, 0x1762AEAF, 0xCA41991E, 0xC0480F85, 0xBF534431, 0xF1C2780E,
0x990A7D6F, 0x69D22B81, 0x34DDECDE, 0x11ECD8F8, 0x22BB55D2, 0xFFA55B0, 0x6CC1AFBF, 0xA5610F61,
0x13190C95, 0xE09A5D29, 0xE7514731, 0x9AE21D7A, 0xB8D90F5A, 0x4C7299A9, 0xC4FDB94E, 0xA6475083,
0xBFB62E5, 0x8F7F77EB, 0xDA2568BB, 0x55C4DA9E, 0xC2932973, 0xCBC60B6D, 0xC46720FD, 0x2046D79D,
0x629CBD81, 0x932B1F48, 0x72ED29C0, 0xF4B566D3, 0xCBC53B21, 0x7836C87B, 0xBA4357B1, 0xCFD332E2,
0x4D488FCB, 0xA06DEFBF, 0x68211846, 0xC17F878D, 0x33B10E2C, 0xCFA0E756, 0x4C3C0691, 0x870BE107,
0x55B3FAF0, 0xFD39F8D7, 0x4B9A7795, 0x188CFA42, 0xAA79A09D, 0x620CF186, 0xEFDE898A, 0x2FA95D43,
0xD67359DB, 0x8625BC1B, 0x7A1A3BBC, 0xE6ECEF6C, 0xBA27A5C6, 0x559FE417, 0xF01DF04D, 0x3F910D52,
0x382B7BE, 0xAAECB195, 0x2E440D8E, 0xB3D58B0B, 0x3CA704B8, 0x63293098, 0x714CFD4D, 0x47C8D0F7]
SHL = [1, 4, 6, 6, 1, 2, 3, 3, 6, 3, 2, 5, 6, 2, 5, 4, 5, 6, 3, 4, 2, 3, 4, 2, 3, 3, 2, 2, 4, 6, 4, 2,
2, 4, 1, 3, 4, 2, 4, 1, 1, 5, 1, 1, 5, 5, 4, 5, 2, 1, 4, 3, 1, 6, 5, 3, 1, 5, 4, 4, 2, 1, 1, 6,
1, 3, 5, 6, 5, 2, 4, 3, 2, 3, 6, 1, 3, 3, 6, 2, 4, 2, 4, 1, 4, 3, 2, 3, 6, 5, 5, 5, 4, 6, 5, 1,
2, 3, 6, 5, 6, 5, 4, 2, 6, 2, 5, 1, 6, 1, 4, 6, 6, 3, 2, 6, 2, 6, 2, 3, 5, 1, 1, 6, 4, 2, 4, 3]
SHR = [1, 3, 4, 3, 4, 3, 3, 6, 4, 6, 2, 1, 6, 6, 1, 4, 5, 4, 1, 4, 4, 2, 5, 4, 6, 2, 2, 3, 4, 5, 5, 5,
4, 5, 1, 6, 4, 2, 3, 6, 5, 6, 6, 1, 2, 2, 4, 5, 2, 4, 6, 6, 3, 6, 2, 1, 1, 5, 3, 5, 3, 2, 6, 4,
6, 4, 2, 1, 4, 5, 4, 5, 6, 1, 5, 2, 2, 6, 2, 6, 3, 3, 5, 3, 3, 6, 6, 5, 4, 4, 2, 1, 5, 1, 2, 2,
1, 5, 3, 6, 1, 1, 5, 5, 1, 4, 4, 2, 4, 6, 6, 3, 4, 6, 5, 1, 1, 6, 5, 4, 3, 6, 5, 5, 2, 1, 4, 2]

核心加密处理

1
2
m[0] += ((m[1] << SHL0[i]) + key[0]) ^ (m[1] + sum) ^ ((m[1] >> SHR1[i]) + key[1])
m[1] += ((m[0] << SHL2[i]) + key[2]) ^ (m[0] + sum) ^ ((m[0] >> SHR3[i]) + key[3])

解密

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
def sar(value,shift):
if value & 0x80000000: # 如果 value 是负数
return (value >> shift) | (0xFFFFFFFF << (32 - shift))
else:
return value >> shift


def enc_tea_ugly(m,k,SHL,SHR,delta):
m0, m1 = m[0], m[1]
sum = 0
for i in range(128):
sum = (sum + delta[i]) & 0xFFFFFFFF
m0 = (m0 +(((m1 << SHL[i]) + k[1]) ^ (m1 + sum) ^ (sar(m1,SHR[i]) + k[0]))) & 0xFFFFFFFF
m1 = (m1 + (((m0 << SHL[i]) + k[3]) ^ (m0 + sum) ^ (sar(m0,SHR[i]) + k[2]))) & 0xFFFFFFFF
return [m0,m1]

def dec_tea_ugly(m,k,SHL,SHR,delta):
m0, m1 = m[0], m[1]

sum = 0
for i in range(128):
sum = (sum + delta[i]) & 0xFFFFFFFF

for i in range(127,-1,-1):
m1 = (m1 -(((m0 << SHL[i]) + k[3]) ^ (m0 + sum) ^ (sar(m0,SHR[i]) + k[2]))) & 0xFFFFFFFF
m0 = (m0 -(((m1 << SHL[i]) + k[1]) ^ (m1 + sum) ^ (sar(m1,SHR[i]) + k[0]))) & 0xFFFFFFFF
sum = (sum -delta[i]) & 0xFFFFFFFF
return [m0,m1]

def d2b(dword):
return b''.join(i.to_bytes(4,"little") for i in dword)

m = [0x31313131,0x31313131]
k = [0x55667788,0x11223344,0xCCDDEEFF,0x9900AABB]
SHL = [1, 4, 6, 6, 1, 2, 3, 3, 6, 3, 2, 5, 6, 2, 5, 4, 5, 6, 3, 4, 2, 3, 4, 2, 3, 3, 2, 2, 4, 6, 4, 2,
2, 4, 1, 3, 4, 2, 4, 1, 1, 5, 1, 1, 5, 5, 4, 5, 2, 1, 4, 3, 1, 6, 5, 3, 1, 5, 4, 4, 2, 1, 1, 6,
1, 3, 5, 6, 5, 2, 4, 3, 2, 3, 6, 1, 3, 3, 6, 2, 4, 2, 4, 1, 4, 3, 2, 3, 6, 5, 5, 5, 4, 6, 5, 1,
2, 3, 6, 5, 6, 5, 4, 2, 6, 2, 5, 1, 6, 1, 4, 6, 6, 3, 2, 6, 2, 6, 2, 3, 5, 1, 1, 6, 4, 2, 4, 3]
SHR = [1, 3, 4, 3, 4, 3, 3, 6, 4, 6, 2, 1, 6, 6, 1, 4, 5, 4, 1, 4, 4, 2, 5, 4, 6, 2, 2, 3, 4, 5, 5, 5,
4, 5, 1, 6, 4, 2, 3, 6, 5, 6, 6, 1, 2, 2, 4, 5, 2, 4, 6, 6, 3, 6, 2, 1, 1, 5, 3, 5, 3, 2, 6, 4,
6, 4, 2, 1, 4, 5, 4, 5, 6, 1, 5, 2, 2, 6, 2, 6, 3, 3, 5, 3, 3, 6, 6, 5, 4, 4, 2, 1, 5, 1, 2, 2,
1, 5, 3, 6, 1, 1, 5, 5, 1, 4, 4, 2, 4, 6, 6, 3, 4, 6, 5, 1, 1, 6, 5, 4, 3, 6, 5, 5, 2, 1, 4, 2]
delta = [
0x3CA6F3E, 0xF2E1C7F1, 0x79A22843, 0xD47FFC9D, 0xDD10F4C, 0x1DC368A1, 0x11B15F8A, 0x9469B3CD,
0x45D6DB5F, 0xBC6EE006, 0xA76D8146, 0xD542E337, 0x242E1155, 0xAA7F93DD, 0x88625ECB, 0x3738E499,
0xCEF27BB0, 0x134FF759, 0x358CA57E, 0x3461F310, 0x28540EE7, 0x81C0B176, 0xF725EE9C, 0xAF823A69,
0x61E8ECB3, 0xF4919548, 0x6AF44E11, 0x866162F3, 0x867F7E65, 0x6B26444C, 0x10216241, 0x9C1BA3CD,
0x1268FEAD, 0xF462B3B5, 0x5F7DE761, 0x72EAD5B6, 0xFBCE0C75, 0x44EF4142, 0x54DCC3C0, 0xAFFE805D,
0xC8833729, 0x3C944186, 0x261169A, 0xB547EA2F, 0x9B499585, 0xFE0190BF, 0x1EC74BE7, 0xAFC9292E,
0xC32F4EEF, 0x420A1A4, 0x94BEAB2B, 0xA0693238, 0x4DD5ADC1, 0x9F658F31, 0x1732EA46, 0x76BEE7DD,
0x12C63095, 0x9C202C7C, 0xAC9BB4C4, 0x1762AEAF, 0xCA41991E, 0xC0480F85, 0xBF534431, 0xF1C2780E,
0x990A7D6F, 0x69D22B81, 0x34DDECDE, 0x11ECD8F8, 0x22BB55D2, 0xFFA55B0, 0x6CC1AFBF, 0xA5610F61,
0x13190C95, 0xE09A5D29, 0xE7514731, 0x9AE21D7A, 0xB8D90F5A, 0x4C7299A9, 0xC4FDB94E, 0xA6475083,
0xBFB62E5, 0x8F7F77EB, 0xDA2568BB, 0x55C4DA9E, 0xC2932973, 0xCBC60B6D, 0xC46720FD, 0x2046D79D,
0x629CBD81, 0x932B1F48, 0x72ED29C0, 0xF4B566D3, 0xCBC53B21, 0x7836C87B, 0xBA4357B1, 0xCFD332E2,
0x4D488FCB, 0xA06DEFBF, 0x68211846, 0xC17F878D, 0x33B10E2C, 0xCFA0E756, 0x4C3C0691, 0x870BE107,
0x55B3FAF0, 0xFD39F8D7, 0x4B9A7795, 0x188CFA42, 0xAA79A09D, 0x620CF186, 0xEFDE898A, 0x2FA95D43,
0xD67359DB, 0x8625BC1B, 0x7A1A3BBC, 0xE6ECEF6C, 0xBA27A5C6, 0x559FE417, 0xF01DF04D, 0x3F910D52,
0x382B7BE, 0xAAECB195, 0x2E440D8E, 0xB3D58B0B, 0x3CA704B8, 0x63293098, 0x714CFD4D, 0x47C8D0F7]

# res = enc_tea_ugly(m, k, SHL, SHR, delta)
# print([hex(x) for x in res])

data =[0x0BD3BE58, 0xBE73BBFB, 0xC8C8AF4E, 0x0B3C7D86, 0xC0257C09,
0x1D8FE0B0, 0x8837180C, 0xF5CF9D23, 0xB7A8B599, 0xAE630F3D]

flag = []
for i in range(0,len(data),2):
block =[data[i],data[i+1]]
dec = dec_tea_ugly(block, k, SHL, SHR, delta)
flag.extend(dec) # 用 extend 不是 append

flag_str = d2b(flag)
print(flag_str)
print(flag_str.decode("utf-8", errors="ignore"))

flag 是flag{UG1y_T3A_m@k35_[m3]_fe31_NaU5Eou5!}

babyre

之前写过了,移步[NPC²CTF 2025]babyVM WP

week2

randomXor

分析

ida 反编译的 main 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int __fastcall main(int argc, const char **argv, const char **envp)
{
int i; // [xsp+1Ch] [xbp+1Ch]

puts("Welcome to house of jjkk");
__isoc99_scanf("%128s", input);
if ( strlen(input) == len )
{
srand(114514);
for ( i = 0; i <= 127; ++i )
input[i] ^= rand();
if ( !memcmp(input, &cipher, len) )
puts("Right! ");
else
puts("Wrong! ");
return 0;
}
else
{
puts("Lenth wrong! ");
return 0;
}
}

其中 srand 和 rand 组成了一个类似 MT19937 的伪随机数生成器

1
2
3
4
5
6
7
8
9
10
11
12
__int16 *__fastcall srand(int a1)
{
__int16 *result; // x0
unsigned int i; // [xsp+1Ch] [xbp-4h]

mt[0] = a1;
for ( i = 1; i <= 0x71; ++i )
mt[i] = (0xA7A25365 * (mt[i - 1] ^ ((unsigned int)mt[i - 1] >> 30)) + i) ^ 0x56;
result = &index1;
index1 = 114;
return result;
}
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
__int64 rand()
{
int v1; // [xsp+Ch] [xbp-14h]
unsigned int i; // [xsp+10h] [xbp-10h]
unsigned int v3; // [xsp+14h] [xbp-Ch]
unsigned int v4; // [xsp+1Ch] [xbp-4h]
unsigned int v5; // [xsp+1Ch] [xbp-4h]

v1 = (unsigned __int16)index1;
if ( (unsigned __int16)index1 > 0x71u )
{
for ( i = 0; i <= 0x71; ++i )
{
v3 = (mt[i] & 0x80000 | mt[(i + 1) % 0x72] & 0x7FFFFu) >> 1;
if ( (mt[(i + 1) % 0x72] & 1) != 0 )
v3 ^= 0x8908B0DF;
mt[i] = mt[(i + 514) % 0x72] ^ v3;
}
index1 = 0;
v1 = 0;
}
v4 = mt[v1];
index1 = v1 + 1;
v5 = v4 ^ (v4 >> 11) ^ ((v4 ^ (v4 >> 11)) << 7) & 0x9D2C5680;
return v5 ^ (v5 << 15) & 0xEFC60000 ^ ((v5 ^ (v5 << 15) & 0xEFC60000) >> 18);
}

& cipher 处提取出密文(128 字节)

1
2
3
4
5
6
7
8
9
10
11
12
13
0xCD, 0xC7, 0xE2, 0x86, 0x3A, 0x19, 0xB9, 0xB6, 0xF1, 0x81,
0x45, 0xB4, 0xB6, 0xE5, 0x0D, 0xD4, 0xB4, 0xA6, 0xD3, 0xF7,
0x33, 0x5D, 0x5F, 0x09, 0x95, 0xAF, 0x9A, 0xBE, 0x89, 0xEA,
0x54, 0x71, 0x68, 0xC6, 0x8B, 0x84, 0x05, 0x14, 0xBB, 0x41,
0xDD, 0x34, 0x91, 0x1B, 0x21, 0x83, 0xDE, 0x15, 0x52, 0x22,
0x8A, 0xE1, 0xBD, 0x33, 0x4D, 0x7E, 0xD2, 0xA3, 0xA9, 0x12,
0xF1, 0xE9, 0x88, 0x60, 0x24, 0xE6, 0xAB, 0x54, 0xCF, 0x02,
0x1B, 0x6B, 0x6B, 0xBA, 0x26, 0x09, 0xFB, 0x10, 0x97, 0xDF,
0x17, 0xBF, 0xCC, 0xE7, 0xB0, 0x42, 0xE5, 0x32, 0x4C, 0x0F,
0xE0, 0x60, 0x47, 0xD0, 0x5A, 0xE8, 0x48, 0xAE, 0x74, 0x4D,
0x98, 0x7A, 0xB3, 0xD2, 0xDE, 0x1B, 0x96, 0x91, 0x7A, 0x03,
0x67, 0xCF, 0xF0, 0x31, 0x32, 0x49, 0x9A, 0xE0, 0xC2, 0x3B,
0x51, 0x63, 0xFF, 0x84, 0x60, 0x5B, 0xC1, 0x8E

解密

伪随机算法已经反编译得很清楚了,稍作修改就可以了,要注意加密 input[i] ^= rand()是对单字节操作,所以获得 rand() 值时要取低八位

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
cipher = [
0xCD, 0xC7, 0xE2, 0x86, 0x3A, 0x19, 0xB9, 0xB6, 0xF1, 0x81,
0x45, 0xB4, 0xB6, 0xE5, 0x0D, 0xD4, 0xB4, 0xA6, 0xD3, 0xF7,
0x33, 0x5D, 0x5F, 0x09, 0x95, 0xAF, 0x9A, 0xBE, 0x89, 0xEA,
0x54, 0x71, 0x68, 0xC6, 0x8B, 0x84, 0x05, 0x14, 0xBB, 0x41,
0xDD, 0x34, 0x91, 0x1B, 0x21, 0x83, 0xDE, 0x15, 0x52, 0x22,
0x8A, 0xE1, 0xBD, 0x33, 0x4D, 0x7E, 0xD2, 0xA3, 0xA9, 0x12,
0xF1, 0xE9, 0x88, 0x60, 0x24, 0xE6, 0xAB, 0x54, 0xCF, 0x02,
0x1B, 0x6B, 0x6B, 0xBA, 0x26, 0x09, 0xFB, 0x10, 0x97, 0xDF,
0x17, 0xBF, 0xCC, 0xE7, 0xB0, 0x42, 0xE5, 0x32, 0x4C, 0x0F,
0xE0, 0x60, 0x47, 0xD0, 0x5A, 0xE8, 0x48, 0xAE, 0x74, 0x4D,
0x98, 0x7A, 0xB3, 0xD2, 0xDE, 0x1B, 0x96, 0x91, 0x7A, 0x03,
0x67, 0xCF, 0xF0, 0x31, 0x32, 0x49, 0x9A, 0xE0, 0xC2, 0x3B,
0x51, 0x63, 0xFF, 0x84, 0x60, 0x5B, 0xC1, 0x8E
]

mt = [0] * 0x72 # 114
# 状态数组
index1 = 114
# 当前随机数生成的位置索引

def srand(a): # 初始化伪随机数生成器
global mt, index1
mt[0] = a
for i in range(1,0x72):
mt[i] = (0xA7A25365 * (mt[i - 1] ^ (mt[i - 1] >> 30)) + i) ^ 0x56
mt[i] &= 0xFFFFFFFF
index1 = 114

def rand(): # 生成伪随机数
global mt,index1
v1 = index1
if index1 > 0x71:
for i in range(0x72):
v3 = (mt[i] & 0x80000 | mt[(i + 1) % 0x72] & 0x7FFFF) >> 1
if mt[(i + 1) % 0x72] & 1:
v3 ^= 0x8908B0DF
mt[i] = mt[(i + 514) % 0x72] ^ v3
index1 = 0
v1 = 0
v4 = mt[v1]
index1 = v1 + 1
v5 = v4 ^ (v4 >> 11) ^ ((v4 ^ (v4 >> 11)) << 7) & 0x9D2C5680
v5 = v5 ^ (v5 << 15) & 0xEFC60000 ^ ((v5 ^ ((v5 << 15) & 0xEFC60000)) >> 18)
return v5 & 0xFFFFFFFF

def dec(cipher):
srand(114514)
flag_bytes = []
for i in cipher:
r = rand() & 0xFF # 取低八位
flag_bytes.append(i ^ r)
return bytes(flag_bytes)

flag = dec(cipher)
print(flag.decode())

flag 为 flag{R4ndom_rand0m_happy_Funnny_R4ndom_1s_r3ally_funNy!!_hhh233HHH_this_1s_just_a_pi3ce_of_sh1t_fffkkkkkk_f4ck_jjjjKKKKKjjjjasd}

simple

java 层

主要逻辑在 com.example.simpleandroid.CheckActivity

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
public class CheckActivity extends AppCompatActivity {
private ActivityCheckBinding binding;

public native boolean CheckData(String str);

static {
System.loadLibrary("check");
}

public static synchronized void init() {
synchronized (CheckActivity.class) {
ShadowHook.init();
}
}

@Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
this.binding = ActivityCheckBinding.inflate(getLayoutInflater());
setContentView(this.binding.getRoot());
Button button = this.binding.check2;
button.setOnClickListener(new View.OnClickListener() { // from class: com.example.simpleandroid.CheckActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View v) {
EditText editText = CheckActivity.this.binding.inputFlag2;
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(30)});
String input = editText.getText().toString();
if (CheckActivity.this.isValidInput(input) && CheckActivity.this.CheckData(input)) {
Toast.makeText(CheckActivity.this, "You are right", 0).show();
} else {
Toast.makeText(CheckActivity.this, "You are wrong", 0).show();
}
}
});
}

/* JADX INFO: Access modifiers changed from: private */
public boolean isValidInput(String input) {
return input.startsWith("flag{") && input.endsWith("}") && input.length() == 32;
}
}

声明了一个 native 方法 CheckData,在本地库 libcheck.so 里
读取字符串输入之后,先调用 isValidInput(input) 做格式检查,再调用 native 方法 CheckData(input) 做进一步校验

native 层

先找到 CheckData

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
__int64 __fastcall Java_com_example_simpleandroid_CheckActivity_CheckData(__int64 a1, __int64 a2, __int64 a3)
{
_BYTE *v3; // x9
char v4; // w8
int i; // [xsp+4h] [xbp-2Ch]
__int64 StringUTFChars; // [xsp+8h] [xbp-28h]

StringUTFChars = _JNIEnv::GetStringUTFChars();
for ( i = 0; i < 32; ++i )
{
v3 = (_BYTE *)(StringUTFChars + i);
v4 = *v3 ^ (ee[i] != 0x7F);
*v3 = v4;
if ( v4 )
{
((void (__fastcall *)(__int64, __int64, __int64))_JNIEnv::ReleaseStringUTFChars)(a1, a3, StringUTFChars);
return 0;
}
}
((void (__fastcall *)(__int64, __int64, __int64))_JNIEnv::ReleaseStringUTFChars)(a1, a3, StringUTFChars);
return 1;
}

'''
ee = [
0x19, 0x13, 0x1E, 0x18, 0x04, 0x2B, 0x17, 0x16, 0x0C, 0x20,
0x12, 0x1E, 0x06, 0x20, 0x1D, 0x1A, 0x20, 0x1E, 0x20, 0x0C,
0x16, 0x12, 0x0F, 0x13, 0x1A, 0x20, 0x19, 0x13, 0x1E, 0x18,
0x5E, 0x02]
'''

可以看出 ee 数组中的每一个元素都不等于 0x7F,说明 ee[i] != 0x7F 的结果恒等于 1,所以只有当传入的字符串前 32 个字符是 32 个连续的 \x01 时,这个函数才会返回 1,否则返回 0

在 JNI_Onload 里面看到函数 sub_1C430

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
__int64 __fastcall sub_1C430(__int64 a1, __int64 a2, __int64 a3)
{
unsigned __int64 i; // [xsp+18h] [xbp-58h]
__int64 StringUTFChars; // [xsp+20h] [xbp-50h]
unsigned __int8 v8; // [xsp+44h] [xbp-2Ch]
_QWORD v9[5]; // [xsp+48h] [xbp-28h] BYREF

v9[4] = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
sub_1C010();
StringUTFChars = _JNIEnv::GetStringUTFChars();
sub_1C078(v9, StringUTFChars, kk);
eee[0] = 0xCD8413F20B6FCE4CLL;
qword_49828 = 0x5C9B1B43933043CFLL;
qword_49830 = 0x1C6EB6E1A546128ELL;
qword_49838 = 0x77C6E3D7AE009A3ELL;
for ( i = 0LL; i <= 3; ++i )
{
if ( v9[i] != eee[i] )
{
_JNIEnv::ReleaseStringUTFChars(a1, a3, StringUTFChars);
v8 = 0;
goto LABEL_7;
}
}
_JNIEnv::ReleaseStringUTFChars(a1, a3, StringUTFChars);
v8 = 1;
LABEL_7:
_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
return v8;
}

sub_1C010

1
2
3
4
5
6
7
8
__int64 sub_1C010()
{
__int64 result; // x0

result = shadowhook_hook_sym_addr(sub_11073, sub_21345, 0LL);
stub = result;
return result;
}

sub_11073

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
void __fastcall sub_11073(const char *a1)
{
int v1; // w9
int k; // [xsp+24h] [xbp-13Ch]
int v3; // [xsp+28h] [xbp-138h]
int j; // [xsp+2Ch] [xbp-134h]
unsigned int v5; // [xsp+30h] [xbp-130h]
unsigned int i; // [xsp+34h] [xbp-12Ch]
_OWORD v8[16]; // [xsp+50h] [xbp-110h] BYREF
__int64 v9; // [xsp+158h] [xbp-8h]

v9 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
for ( i = 0; i <= 0xFF; ++i )
ss[i] = i;
v5 = __strlen_chk(a1, 0xFFFFFFFFFFFFFFFFLL);
srand(0x217u);
memset(v8, 0, sizeof(v8));
for ( j = 0; j <= 255; ++j )
*((_BYTE *)v8 + j) = a1[j % v5];
v3 = 0;
for ( k = 0; k <= 255; ++k )
{
v1 = (unsigned __int8)(v3 + ss[k] + *((_BYTE *)v8 + k));
if ( v3 + ss[k] + *((unsigned __int8 *)v8 + k) <= 0 )
v1 = -(unsigned __int8)-(char)(v3 + ss[k] + *((_BYTE *)v8 + k));
v3 = v1;
sub_1BC30((char *)&ss[k], (char *)&ss[v1]);
}
_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
}

char *__fastcall sub_1BC30(char *result, char *a2)
{
char v2; // [xsp+Fh] [xbp-11h]

v2 = *result;
*result = *a2;
*a2 = v2;
return result;
}

sub_11073 主要实现了 RC4 里面的 KSA
等效 python 写法如下:

1
2
3
4
5
6
7
8
def KSA(key:bytes) -> list:
S = list(range(256))
key_len = len(key)
j = 0
for i in range(256):
j = (j + S[i] + key[i % key_len]) % 256
S[i], S[j] = S[j], S[i]
return S

这里面还有个 srand(0x217) 先放一边

sub_21345

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void __fastcall sub_21345(unsigned __int8 *a1)
{
void *v1; // x30
void (__fastcall *prev_func)(_BYTE *); // [xsp+8h] [xbp-58h]
int i; // [xsp+24h] [xbp-3Ch]
_BYTE v4[8]; // [xsp+30h] [xbp-30h] BYREF
_BYTE v5[13]; // [xsp+38h] [xbp-28h]
_BYTE v6[16]; // [xsp+48h] [xbp-18h] BYREF
__int64 v7; // [xsp+58h] [xbp-8h]

v7 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
ShadowhookStackScope::ShadowhookStackScope((ShadowhookStackScope *)v4, v1);
*(_QWORD *)&v5[5] = 0x3C37311A241A312CLL; //这是把 8 字节写入 v5[5]~v5[12]
*(_QWORD *)v5 = 0x1A312C1A20332C02LL; // 这是把 8 字节写入 v5[0]~v5[7]
for ( i = 0; i <= 12; ++i )
v6[i] = v5[i] ^ 0x45;
prev_func = (void (__fastcall *)(_BYTE *))shadowhook_get_prev_func(sub_11073);
prev_func(v6);
srand(0x159357u);
ShadowhookStackScope::~ShadowhookStackScope((ShadowhookStackScope *)v4);
_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
}

对 v5 数组中的前 13 个数据进行异或 0x45 得到 v6 数组 ,然后 hook 了函数 sub_11073,把 v6 作为参数传入,srand(0x159357)设置了一个随机数种子

计算出 v6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
v5 = [0] * 13

# 写入 v5[5]~v5[12] (小端序)
val1 = 0x3C37311A241A312C
v5_bytes_5_12 = [(val1 >> (8*i)) & 0xFF for i in range(8)]
v5[5:13] = v5_bytes_5_12

# 写入 v5[0]~v5[7] (小端序) 注意有覆盖
val2 = 0x1A312C1A20332C02
v5_bytes_0_7 = [(val2 >> (8*i)) & 0xFF for i in range(8)]
v5[0:8] = v5_bytes_0_7


v6 = ''.join(chr(v5[i] ^ 0x45) for i in range(13))
print(v6)

# Give_it_a_try

整理出加密

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
import random
key = "this_is_a_key"
cipher = [
0x19, 0x13, 0x1E, 0x18, 0x04, 0x2B, 0x17, 0x16, 0x0C, 0x20,
0x12, 0x1E, 0x06, 0x20, 0x1D, 0x1A, 0x20, 0x1E, 0x20, 0x0C,
0x16, 0x12, 0x0F, 0x13, 0x1A, 0x20, 0x19, 0x13, 0x1E, 0x18,
0x5E, 0x02]

def KSA(key:bytes) -> list:
S = list(range(256))
key_len = len(key)
j = 0
for i in range(256):
j = (j + S[i] + key[i % key_len]) % 256
S[i], S[j] = S[j], S[i]
return S

def PRGA_custom(S:list, data:bytes, seed = 0x159357)
random.seed(seed)

i = 0
j = 0
output = bytearray(data)
tmp_qword = 0
qwords = []

for idx in range(len(output)):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) % 256]
output[idx] ^= K

tmp_qword = (tmp_qword >> 8) | output[idx]

if (idx + 1) % 8 == 0:
if random.randint(0, 1):
shift = random.randint(0, 63)
tmp_qword ^= tmp_qword >> shift
else:
shift = random.randint(0, 63)
tmp_qword ^= (tmp_qword << shift) & 0xFFFFFFFFFFFFFFFF

qwords.append(tmp_qword)
tmp_qword = 0 # 重置

# 不足八字节的剩余部分
if tmp_qword != 0:
qwords.append(tmp_qword)

return bytes(output), qwords

NPC²CTF 2025 Reverse 方向复现
http://example.com/2025/08/26/NPCCTF2025/
作者
Eleven
发布于
2025年8月26日
许可协议