N1 Junoir 2025 Reverse Writeup

N1 Junoir 2025 Reverse Writeup

两只羊 Lv1

你做出了过去最想做出的n1 junoir,却再也回不到从前了

img

5mc

体力活,这题就是进到动调进到每个加密函数分析

image-20250212165015264

大概就是16次的加密过程

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
#include<stdio.h>

unsigned char box[]={
0xB0, 0xF0, 0x21, 0xCF, 0xF2, 0x04, 0x3A, 0x68, 0x84, 0x7B,
0x39, 0x86, 0x36, 0x87, 0x9B, 0xF7, 0x3D, 0x18, 0x1E, 0x61,
0x1B, 0x2E, 0x6C, 0xDF, 0x2C, 0xAE, 0x65, 0x9D, 0xEB, 0x2F,
0xDA, 0xF4, 0xDE, 0xCA, 0x56, 0x92, 0x75, 0x3B, 0x62, 0x45,
0x06, 0x3C, 0x52, 0x33, 0x6E, 0x25, 0xCE, 0xA3, 0xD2, 0x44,
0xA1, 0x4A, 0x58, 0xB1, 0xA0, 0x2A, 0x47, 0x0A, 0x02, 0xAF,
0x50, 0xC3, 0xDC, 0xEA, 0xE5, 0x0D, 0x67, 0x91, 0xE1, 0x51,
0xE3, 0xC1, 0xAA, 0x95, 0x5C, 0x79, 0x72, 0x1C, 0x3F, 0xB8,
0xE8, 0x1F, 0xFF, 0x7A, 0x73, 0x26, 0x54, 0x9E, 0xED, 0xA9,
0x41, 0x20, 0xEF, 0xA6, 0x48, 0x97, 0x4F, 0xD4, 0xBB, 0x23,
0x66, 0xD9, 0xE4, 0x0B, 0x30, 0x15, 0xD7, 0x6B, 0x19, 0xCD,
0xC4, 0x08, 0xB4, 0xC8, 0x14, 0xFD, 0x7F, 0x28, 0x0E, 0x05,
0x0F, 0x4B, 0x6F, 0xF5, 0x90, 0x76, 0xBF, 0x60, 0xE7, 0x24,
0x78, 0x6D, 0x71, 0xA8, 0x43, 0xB5, 0x0C, 0x31, 0xF9, 0xA2,
0x9C, 0x99, 0xF6, 0x2D, 0xDB, 0xB7, 0xC9, 0x85, 0x81, 0x03,
0x64, 0x1D, 0x07, 0x34, 0x5A, 0xBD, 0x37, 0x4C, 0xA7, 0x5F,
0x46, 0xE9, 0x35, 0x93, 0x8D, 0xA5, 0xFB, 0x42, 0x01, 0xC2,
0x17, 0x12, 0x1A, 0x77, 0xC6, 0x53, 0x83, 0x4D, 0xB2, 0x10,
0x2B, 0xF8, 0x88, 0x6A, 0x3E, 0xD0, 0x7C, 0x63, 0x40, 0x27,
0xBE, 0xD5, 0x38, 0xD1, 0x74, 0xB6, 0x57, 0x94, 0xAB, 0x8A,
0xB9, 0xBC, 0x7D, 0xB3, 0x96, 0x7E, 0xFC, 0xAD, 0x22, 0x4E,
0xFA, 0xE0, 0xCB, 0x8B, 0xEE, 0x32, 0xA4, 0x16, 0xFE, 0x5B,
0x13, 0xDD, 0xC0, 0x9A, 0x5E, 0x8E, 0x29, 0xF3, 0x8F, 0x49,
0xE6, 0x9F, 0xF1, 0xC5, 0x70, 0x55, 0x8C, 0x11, 0xCC, 0x5D,
0xEC, 0x00, 0xAC, 0x89, 0xD3, 0x82, 0x69, 0xD6, 0xBA, 0xD8,
0x59, 0x98, 0x09, 0x80, 0xE2, 0xC7
};

unsigned char inv_box(unsigned char a)
{
for(int i = 0; i < 256; i++) {
if(box[i] == a) {
return i;
}
}
}
unsigned char box1[] =
{
0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06,
0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05, 0x0E, 0x03, 0x12, 0x04,
0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B,
0x17, 0x0A
};
unsigned char box2[] =
{
0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13,
0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF, 0x18, 0x4F, 0x26, 0x18,
0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9,
0x9E, 0xC4
};
unsigned char box3[] =
{
0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41,
0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8, 0x1E, 0xBA, 0x6A, 0xBE,
0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C,
0xE2, 0x43
};

unsigned char input[]={ 0x5B, 0x2D, 0xE9, 0x66, 0xED, 0x39, 0x90, 0x23, 0xAF, 0xDA,
0xEB, 0x2E, 0xD1, 0x0D, 0xBB, 0xBD, 0x57, 0x52, 0x02, 0xB0,
0xBA, 0x9D, 0x52, 0xFA, 0x67, 0xEE, 0xA3, 0x85, 0xA9, 0x84,
0xE2, 0x6F};

unsigned char ROR(unsigned char a, int n)
{
return (a >> n) | (a << (8 - n));
}

unsigned char ROL(unsigned char a, int n)
{
return (a << n) | (a >> (8 - n));
}

int main()
{
unsigned buffer1[32];


for(int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 7);
input[i] = (input[i] ^ box2[i]) - box3[i];
}


for(int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 6);
input[i] = (input[i] - box3[i]) ^ box2[i];
}

for(int i = 0; i < 32; i++) {
buffer1[i] = input[box1[i]];
}

for(int i = 0; i < 32; i++) {
input[i] = buffer1[box1[i]];
}

for(int i = 0; i < 32; i++) {
input[i] = inv_box(input[i]);
}


for(int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 3);
input[i] = (input[i] ^ box2[i]) - box3[i];
}


for(int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 5);
input[i] = (input[i] - box3[i]) ^ box2[i];
}

for(int i = 0; i < 32; i++) {
buffer1[i] = input[box1[i]];
}

for(int i = 0; i < 32; i++) {
input[i] = buffer1[box1[i]];
}

for(int i = 0; i < 32; i++) {
input[i] = inv_box(input[i]);
}


for(int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 4);
input[i] = (input[i] ^ box2[i]) - box3[i];
}

for(int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 2);
input[i] = (input[i] - box3[i]) ^ box2[i];
}

for(int i = 0; i < 32; i++) {
buffer1[i] = input[box1[i]];
}

for(int i = 0; i < 32; i++) {
input[i] = buffer1[box1[i]];
}

for(int i = 0; i < 32; i++) {
input[i] = inv_box(input[i]);
}


for(int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 1);
input[i] = (input[i] ^ box2[i]) - box3[i];
}

for(int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 5);
input[i] = (input[i] - box3[i]) ^ box2[i];
}

for(int i = 0; i < 32; i++) {
buffer1[i] = input[box1[i]];
}

for(int i = 0; i < 32; i++) {
input[i] = buffer1[box1[i]];
}

for(int i = 0; i < 32; i++) {
input[i] = inv_box(input[i]);
}
for(int i = 0; i < 32; i++) {
printf("%c", input[i]);
}
printf("\n");
}

df5

这题比较奇怪的一个点是,是通过当前加密的字节来决定加密函数的

通过题目名字,不难想到要用dfs(深度优先算法)遍历爆破

将四种加密的逆运算求一遍,然后检验是否对的上

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
#include<stdio.h>
typedef void (*funcs)(unsigned char*);

unsigned char box[] = {
0xB0, 0xF0, 0x21, 0xCF, 0xF2, 0x04, 0x3A, 0x68, 0x84, 0x7B,
0x39, 0x86, 0x36, 0x87, 0x9B, 0xF7, 0x3D, 0x18, 0x1E, 0x61,
0x1B, 0x2E, 0x6C, 0xDF, 0x2C, 0xAE, 0x65, 0x9D, 0xEB, 0x2F,
0xDA, 0xF4, 0xDE, 0xCA, 0x56, 0x92, 0x75, 0x3B, 0x62, 0x45,
0x06, 0x3C, 0x52, 0x33, 0x6E, 0x25, 0xCE, 0xA3, 0xD2, 0x44,
0xA1, 0x4A, 0x58, 0xB1, 0xA0, 0x2A, 0x47, 0x0A, 0x02, 0xAF,
0x50, 0xC3, 0xDC, 0xEA, 0xE5, 0x0D, 0x67, 0x91, 0xE1, 0x51,
0xE3, 0xC1, 0xAA, 0x95, 0x5C, 0x79, 0x72, 0x1C, 0x3F, 0xB8,
0xE8, 0x1F, 0xFF, 0x7A, 0x73, 0x26, 0x54, 0x9E, 0xED, 0xA9,
0x41, 0x20, 0xEF, 0xA6, 0x48, 0x97, 0x4F, 0xD4, 0xBB, 0x23,
0x66, 0xD9, 0xE4, 0x0B, 0x30, 0x15, 0xD7, 0x6B, 0x19, 0xCD,
0xC4, 0x08, 0xB4, 0xC8, 0x14, 0xFD, 0x7F, 0x28, 0x0E, 0x05,
0x0F, 0x4B, 0x6F, 0xF5, 0x90, 0x76, 0xBF, 0x60, 0xE7, 0x24,
0x78, 0x6D, 0x71, 0xA8, 0x43, 0xB5, 0x0C, 0x31, 0xF9, 0xA2,
0x9C, 0x99, 0xF6, 0x2D, 0xDB, 0xB7, 0xC9, 0x85, 0x81, 0x03,
0x64, 0x1D, 0x07, 0x34, 0x5A, 0xBD, 0x37, 0x4C, 0xA7, 0x5F,
0x46, 0xE9, 0x35, 0x93, 0x8D, 0xA5, 0xFB, 0x42, 0x01, 0xC2,
0x17, 0x12, 0x1A, 0x77, 0xC6, 0x53, 0x83, 0x4D, 0xB2, 0x10,
0x2B, 0xF8, 0x88, 0x6A, 0x3E, 0xD0, 0x7C, 0x63, 0x40, 0x27,
0xBE, 0xD5, 0x38, 0xD1, 0x74, 0xB6, 0x57, 0x94, 0xAB, 0x8A,
0xB9, 0xBC, 0x7D, 0xB3, 0x96, 0x7E, 0xFC, 0xAD, 0x22, 0x4E,
0xFA, 0xE0, 0xCB, 0x8B, 0xEE, 0x32, 0xA4, 0x16, 0xFE, 0x5B,
0x13, 0xDD, 0xC0, 0x9A, 0x5E, 0x8E, 0x29, 0xF3, 0x8F, 0x49,
0xE6, 0x9F, 0xF1, 0xC5, 0x70, 0x55, 0x8C, 0x11, 0xCC, 0x5D,
0xEC, 0x00, 0xAC, 0x89, 0xD3, 0x82, 0x69, 0xD6, 0xBA, 0xD8,
0x59, 0x98, 0x09, 0x80, 0xE2, 0xC7
};


unsigned char box1[] =
{
0x13, 0x1F, 0x10, 0x1D, 0x01, 0x0D, 0x07, 0x15, 0x08, 0x06,
0x16, 0x00, 0x0F, 0x0C, 0x02, 0x05, 0x0E, 0x03, 0x12, 0x04,
0x18, 0x14, 0x1A, 0x1C, 0x1E, 0x19, 0x09, 0x1B, 0x11, 0x0B,
0x17, 0x0A
};
unsigned char box2[] =
{
0x7D, 0xB7, 0x24, 0x7E, 0xC3, 0x6B, 0xBD, 0xD8, 0x7F, 0x13,
0x6E, 0x0F, 0x43, 0xCD, 0x6B, 0xCF, 0x18, 0x4F, 0x26, 0x18,
0x12, 0x2A, 0x7E, 0x9B, 0x27, 0x4C, 0x33, 0x67, 0x40, 0xC9,
0x9E, 0xC4
};
unsigned char box3[] =
{
0x91, 0xDB, 0x9F, 0x5F, 0x26, 0x27, 0xD6, 0xA8, 0xBF, 0x41,
0x16, 0x79, 0xDE, 0x73, 0x16, 0xF8, 0x1E, 0xBA, 0x6A, 0xBE,
0xC6, 0x12, 0xB2, 0x39, 0x9E, 0xF3, 0x12, 0x4E, 0x02, 0x1C,
0xE2, 0x43
};

unsigned char map_table[] = {
29, 19, 16, 28, 0, 12, 26, 9, 8, 22,
1, 3, 5, 15, 2, 13, 14, 23, 18, 11,
7, 6, 31, 24, 21, 25, 10, 27, 30, 17,
20, 4 };
unsigned char input[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef";
unsigned char buffer[32] = { 0 };
void func1(unsigned char* input)
{


for (int i = 0; i < 32; i++) {
buffer[box1[i]] = input[i];
}
for (int i = 0; i < 32; i++) {
input[box1[i]] = buffer[i];
}
}


void inv_func1(unsigned char* input)
{
for (int i = 0; i < 32; i++) {
buffer[map_table[i]] = input[i];

//input
}
for (int i = 0; i < 32; i++) {
input[i] = buffer[i];

//input
}
}

unsigned char ROR(unsigned char a, int n)
{
return (a >> n) | (a << (8 - n));
}

unsigned char ROL(unsigned char a, int n)
{
return (a << n) | (a >> (8 - n));
}

void func0(unsigned char* input)
{
for (int i = 0; i < 32; i++) {
input[i] = box[input[i]];
}
}

void inv_func0(unsigned char* input) {
for (int i = 0; i < 32; i++) {
for (int k = 0; k < 256; k++) {
if (box[k] == input[i]) {
input[i] = k;
break;
}
}
}
}

void func2(unsigned char* input) {
for (int i = 0; i < 32; i++) {
input[i] ^= box2[i];
input[i] += box3[i];
}
}

void inv_func2(unsigned char* input) {
for (int i = 0; i < 32; i++) {
input[i] -= box3[i];
input[i] ^= box2[i];

}
}

void func3(unsigned char* input)
{
for (int i = 0; i < 32; i++) {
input[i] = ROR(input[i], 3);
}
}

void inv_func3(unsigned char* input)
{
for (int i = 0; i < 32; i++) {
input[i] = ROL(input[i], 3);
}
}

funcs funcTable[] = { func0, func1, func2, func3 };
funcs inv_funcTable[] = {inv_func0, inv_func1, inv_func2, inv_func3};
unsigned char cipher[] = { 0x65, 0x3E, 0x43, 0xB8, 0xBA, 0xDB, 0xF6, 0x88, 0x25, 0x1B,
0x28, 0xC7, 0xC0, 0x54, 0xA6, 0x4A, 0x90, 0x37, 0xBC, 0x29,
0x41, 0xAA, 0x28, 0xDB, 0x9A, 0x59, 0x63, 0x9E, 0x4B, 0xCF,
0x2E, 0x41 };


void dfs(unsigned char* input, int index)
{
if (index < 0) {
for (int i = 0; i < 32; i++) {
if (input[i] <= 32 || input[i] >= 127) return;
}
for (int i = 0; i < 32; i++) printf("%c", input[i]);
printf("\n");
return;
}

unsigned char buffer[33] = { 0 };
memcpy(buffer, input, 32);
for (int i = 0; i < 4; i++) {
memcpy(input, buffer, 32);
inv_funcTable[i](input);
if ((input[index] & 3) == i) {
//printf("%d => %x \n",index, i);
dfs(input, index - 1);
}
}
}
int main()
{
dfs(cipher, 31);

}

//flag{Ea5y_enCrypt_And_decrYpt!!}

easy-re

查壳,发现是android aarch64(arm64)架构的elf,并且qemu运行会提示缺少一些安卓环境的库,需要有一台真机环境调试

image-20250212165525194

打开程序,可以看到有混淆,静态分析不现实

image-20250212165605745

输入通过参数传递,要在ida中设置

image-20250212171216691

直接给出结论:

init_array中的constructor函数起到了反调试的作用,会有对TracerPid的检测

TracerPid就是调试此进程的pid,在同一时刻只能有一个进程调试本进程

如果没有别的进程调试此进程,pid则为0

image-20250212165827130

因此绕过的思路就是在检测到tracerpid字段的时候,将其字符串中的tracerpid: xxxxxx改为tracerpid: 0即可

image-20250212170726422

image-20250212170927809

除此之外的绕过方法是不可行的,因为tracerpid的字符串后面会用来sbox的初始化

因此我们在调试的时候,会发现我们可能同一个输入,加密出来的结果不一样,因为我们在不断重新开始调试的过程中,tracerpid可能发生了变化。

后面是一个rc4的魔改,这里就不细究了,直接拿到xor_key

image-20250212171016772

image-20250212171051821

最后爆破一波

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
#include<iostream>
using namespace std;
unsigned char input[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef";
unsigned char output[32], save[32];
unsigned char x[32]={0x36, 0x71, 0xF4, 0x67, 0xFA, 0x9A, 0xF9, 0xA, 0x5E, 0xA0, 0xB6, 0xB0, 0x11, 0xAB, 0x7A, 0x2D, 0xD0, 0xD3, 0xA, 0xCA, 0xE8, 0x91, 0x9A, 0xC2, 0x64, 0x8E, 0x12, 0x8, 0xBA, 0x46, 0x4A, 0x6E};
unsigned char cipher[] = { 0x50, 0x4C, 0x8B, 0x94, 0x86, 0x6D, 0x72, 0xFB, 0x54, 0xF3,
0x17, 0x0F, 0xEE, 0xE4, 0xC5, 0x1E, 0xB8, 0x1A, 0xC7, 0xDF,
0x2D, 0x3D, 0x4E, 0x51, 0xE7, 0xAD, 0x97, 0x55, 0xF3, 0xF5,
0x41, 0x79};

int main()
{
unsigned char tmp, save = 0;
for (int i = 0; i < 32; i++) {


for (int l = 32; l <= 127; l++) {

tmp = l ^ i;
tmp = tmp ^ x[i];
//printf("%x ", tmp);
for (int k = 0; k < i; k++) {
tmp ^= cipher[k];
}
if (tmp == cipher[i]) {
printf("%c", l);
output[i] = l;
break;
}
}

//printf("%x \n", tmp);
}


}

//flag{welcome-re-world!go!go!go!}
  • 标题: N1 Junoir 2025 Reverse Writeup
  • 作者: 两只羊
  • 创建于 : 2025-02-12 16:25:05
  • 更新于 : 2025-05-09 17:52:22
  • 链接: https://twogoat.github.io/2025/02/12/N1-Junoir-2025-Reverse-Writeup/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
N1 Junoir 2025 Reverse Writeup