[网鼎杯 2020 青龙组]singal

此题目涉及到VM逆向保护

自己学的比较浅就放一下大佬的文章

https://xz.aliyun.com/t/3851


IDA32位直接打开

很容易找到主函数

1
2
3
4
5
6
7
8
9
10
nt __cdecl main(int argc, const char **argv, const char **envp)
{
int v4[117]; // [esp+18h] [ebp-1D4h] BYREF

__main();
qmemcpy(v4, &unk_403040, 456u);//拷贝opcode表
vm_operad(v4, 114);//关键函数
puts("good,The answer format is:flag {}");
return 0;
}

点进去关键函数

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
int __cdecl vm_operad(int *a1, int a2)
{
int result; // eax
char Str[200]; // [esp+13h] [ebp-E5h] BYREF
char v4; // [esp+DBh] [ebp-1Dh]
int v5; // [esp+DCh] [ebp-1Ch]
int v6; // [esp+E0h] [ebp-18h]
int v7; // [esp+E4h] [ebp-14h]
int v8; // [esp+E8h] [ebp-10h]
int v9; // [esp+ECh] [ebp-Ch]

v9 = 0;
v8 = 0;
v7 = 0;
v6 = 0;
v5 = 0;
while ( 1 )
{
result = v9;
if ( v9 >= a2 )
return result;
switch ( a1[v9] )
{
case 1:
Str[v6 + 100] = v4;
++v9;
++v6;
++v8;
break;
case 2:
v4 = a1[v9 + 1] + Str[v8];
v9 += 2;
break;
case 3:
v4 = Str[v8] - LOBYTE(a1[v9 + 1]);
v9 += 2;
break;
case 4:
v4 = a1[v9 + 1] ^ Str[v8];
v9 += 2;
break;
case 5:
v4 = a1[v9 + 1] * Str[v8];
v9 += 2;
break;
case 6:
++v9;
break;
case 7:
if ( Str[v7 + 100] != a1[v9 + 1] )
{
printf("what a shame...");
exit(0);
}
++v7;
v9 += 2;
break;
case 8:
Str[v5] = v4;
++v9;
++v5;
break;
case 10:
read(Str);
++v9;
break;
case 11:
v4 = Str[v8] - 1;
++v9;
break;
case 12:
v4 = Str[v8] + 1;
++v9;
break;
default:
continue;
}
}
}

自己分析了好长时间,也看了几篇WP,最容易理解的就是模拟算法。


首先注意到拷贝opcode表的数字是456,刚好是114的4倍,

再结合opcode里很多0x00可以推测出每4个组成一个操作指令

我在每一个条件之前都加了一些输出语句

虽然不是很清楚(估计只有我自己能看懂)

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

using namespace std;
unsigned char ida_chars[] =
{
0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x21, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x51, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x41, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3F, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
0x07, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00,
0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xA7, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x84, 0xFF,
0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xC1, 0xFF, 0xFF, 0xFF,
0x07, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00,
0x00, 0x00, 0x7A, 0x00, 0x00, 0x00
};
unsigned char opcode[114] = {0};
unsigned char input[1024] = "jcskanbcjkasbncjkascbnjksac";
int main()
{
for(size_t i = 0; i< 456; i++)
{
memcpy(&opcode[i], &ida_chars[i*4], 4);
}

int result; // eax
char v4; // [esp+DBh] [ebp-1Dh]
int v5; // [esp+DCh] [ebp-1Ch]
int v6; // [esp+E0h] [ebp-18h]
int v7; // [esp+E4h] [ebp-14h]
int v8; // [esp+E8h] [ebp-10h]
int v9; // [esp+ECh] [ebp-Ch]

v9 = 0;
v8 = 0;
v7 = 0;
v6 = 0;
v5 = 0;
while ( 1 )
{
result = v9;
if ( v9 >= 114 )
return result;
switch ( opcode[v9] )
{
case 1:
input[v6 + 100] = v4;
printf("%x\t#1\tinput[v6(%d) + 100](%d) = v4(%d);\n",v9,v6,input[v6+100],v4);
++v9;
++v6;
++v8;
break;
case 2:
v4 = opcode[v9 + 1] + input[v8];
printf("%x\t#2\tv4(%d) = opcode[v9(%d) + 1](%d) + input[v8(%d)](%d);\n",v9,v4,v9,opcode[v9+1],v8,input[v8]);
v9 += 2;
break;
case 3:
v4 = input[v8] - LOBYTE(opcode[v9 + 1]);
printf("%x\t#3\tv4(%d) = input[v8(%d)](%d) - LOBYTE(opcode[v9(%d) + 1](%d));\n",v9,v4,v8,input[v8],v9,opcode[v9+1]);
v9 += 2;
break;
case 4:
v4 = opcode[v9 + 1] ^ input[v8];
printf("%x\t#4\tv4(%d) = opcode[v9(%d) + 1](%d) ^ input[v8(%d)](%d);\n",v9,v4,v9,opcode[v9+1],v8,input[v8]);
v9 += 2;
break;
case 5:
v4 = opcode[v9 + 1] * input[v8];
printf("%x\t#4\tv4(%d) = opcode[v9(%d) + 1](%d) * input[v8(%d)](%d);\n",v9,v4,v9,opcode[v9+1],v8,input[v8]);
v9 += 2;
break;
case 6:
++v9;
break;
case 7:
if ( input[v7 + 100] != opcode[v9 + 1] )
{
printf("%x\t#7\tinput[v7(%d) + 100](%d) != opcode[v9(%d) + 1](%d)\n",v9,v7,input[v7+100],v9,opcode[v9+1]);
printf("what a shame...\n");
//exit(0);
}
++v7;
v9 += 2;
break;
case 8:
input[v5] = v4;
printf("%x\t#8\tinput[v5(%d)](%d) = v4(%d);\n",v9,v5,input[v5],v4);
++v9;
++v5;
break;
case 10:
++v9;
break;
case 11:
v4 = input[v8] - 1;
printf("%x\t#11\tv4(%d) = input[v8(%d)](%d) - 1;\n",v9,v4,v8,input[v8]);
++v9;
break;
case 12:
v4 = input[v8] + 1;
printf("%x\t#11\tv4(%d) = input[v8(%d)](%d) + 1;\n",v9,v4,v8,input[v8]);
++v9;
break;
default:
continue;
}
}
}

输出

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
1       #4      v4(122) = opcode[v9(1) + 1](16) ^ input[v8(0)](106);
3 #8 input[v5(0)](122) = v4(122);
4 #3 v4(117) = input[v8(0)](122) - LOBYTE(opcode[v9(4) + 1](5));
6 #1 input[v6(0) + 100](117) = v4(117);
7 #4 v4(67) = opcode[v9(7) + 1](32) ^ input[v8(1)](99);
9 #8 input[v5(1)](67) = v4(67);
a #4 v4(-55) = opcode[v9(10) + 1](3) * input[v8(1)](67);
c #1 input[v6(1) + 100](201) = v4(-55);
d #3 v4(113) = input[v8(2)](115) - LOBYTE(opcode[v9(13) + 1](2));
f #8 input[v5(2)](113) = v4(113);
10 #11 v4(112) = input[v8(2)](113) - 1;
11 #1 input[v6(2) + 100](112) = v4(112);
12 #11 v4(108) = input[v8(3)](107) + 1;
13 #8 input[v5(3)](108) = v4(108);
14 #4 v4(104) = opcode[v9(20) + 1](4) ^ input[v8(3)](108);
16 #1 input[v6(3) + 100](104) = v4(104);
17 #4 v4(35) = opcode[v9(23) + 1](3) * input[v8(4)](97);
19 #8 input[v5(4)](35) = v4(35);
1a #3 v4(2) = input[v8(4)](35) - LOBYTE(opcode[v9(26) + 1](33));
1c #1 input[v6(4) + 100](2) = v4(2);
1d #11 v4(109) = input[v8(5)](110) - 1;
1e #8 input[v5(5)](109) = v4(109);
1f #11 v4(108) = input[v8(5)](109) - 1;
20 #1 input[v6(5) + 100](108) = v4(108);
21 #4 v4(107) = opcode[v9(33) + 1](9) ^ input[v8(6)](98);
23 #8 input[v5(6)](107) = v4(107);
24 #3 v4(75) = input[v8(6)](107) - LOBYTE(opcode[v9(36) + 1](32));
26 #1 input[v6(6) + 100](75) = v4(75);
27 #2 v4(-76) = opcode[v9(39) + 1](81) + input[v8(7)](99);
29 #8 input[v5(7)](180) = v4(-76);
2a #4 v4(-112) = opcode[v9(42) + 1](36) ^ input[v8(7)](180);
2c #1 input[v6(7) + 100](144) = v4(-112);
2d #11 v4(107) = input[v8(8)](106) + 1;
2e #8 input[v5(8)](107) = v4(107);
2f #11 v4(106) = input[v8(8)](107) - 1;
30 #1 input[v6(8) + 100](106) = v4(106);
31 #4 v4(-42) = opcode[v9(49) + 1](2) * input[v8(9)](107);
33 #8 input[v5(9)](214) = v4(-42);
34 #2 v4(-5) = opcode[v9(52) + 1](37) + input[v8(9)](214);
36 #1 input[v6(9) + 100](251) = v4(-5);
37 #2 v4(-105) = opcode[v9(55) + 1](54) + input[v8(10)](97);
39 #8 input[v5(10)](151) = v4(-105);
3a #4 v4(-42) = opcode[v9(58) + 1](65) ^ input[v8(10)](151);
3c #1 input[v6(10) + 100](214) = v4(-42);
3d #2 v4(-109) = opcode[v9(61) + 1](32) + input[v8(11)](115);
3f #8 input[v5(11)](147) = v4(-109);
40 #4 v4(-109) = opcode[v9(64) + 1](1) * input[v8(11)](147);
42 #1 input[v6(11) + 100](147) = v4(-109);
43 #4 v4(38) = opcode[v9(67) + 1](3) * input[v8(12)](98);
45 #8 input[v5(12)](38) = v4(38);
46 #2 v4(75) = opcode[v9(70) + 1](37) + input[v8(12)](38);
48 #1 input[v6(12) + 100](75) = v4(75);
49 #4 v4(103) = opcode[v9(73) + 1](9) ^ input[v8(13)](110);
4b #8 input[v5(13)](103) = v4(103);
4c #3 v4(71) = input[v8(13)](103) - LOBYTE(opcode[v9(76) + 1](32));
4e #1 input[v6(13) + 100](71) = v4(71);
4f #2 v4(-92) = opcode[v9(79) + 1](65) + input[v8(14)](99);
51 #8 input[v5(14)](164) = v4(-92);
52 #11 v4(-91) = input[v8(14)](164) + 1;
53 #1 input[v6(14) + 100](165) = v4(-91);
54 #7 input[v7(0) + 100](117) != opcode[v9(84) + 1](34)
what a shame...
56 #7 input[v7(1) + 100](201) != opcode[v9(86) + 1](63)
what a shame...
58 #7 input[v7(2) + 100](112) != opcode[v9(88) + 1](52)
what a shame...
5a #7 input[v7(3) + 100](104) != opcode[v9(90) + 1](50)
what a shame...
5c #7 input[v7(4) + 100](2) != opcode[v9(92) + 1](114)
what a shame...
5e #7 input[v7(5) + 100](108) != opcode[v9(94) + 1](51)
what a shame...
60 #7 input[v7(6) + 100](75) != opcode[v9(96) + 1](24)
what a shame...
62 #7 input[v7(7) + 100](144) != opcode[v9(98) + 1](167)
what a shame...
64 #7 input[v7(8) + 100](106) != opcode[v9(100) + 1](49)
what a shame...
66 #7 input[v7(9) + 100](251) != opcode[v9(102) + 1](241)
what a shame...
68 #7 input[v7(10) + 100](214) != opcode[v9(104) + 1](40)
what a shame...
6a #7 input[v7(11) + 100](147) != opcode[v9(106) + 1](132)
what a shame...
6c #7 input[v7(12) + 100](75) != opcode[v9(108) + 1](193)
what a shame...
6e #7 input[v7(13) + 100](71) != opcode[v9(110) + 1](30)
what a shame...
70 #7 input[v7(14) + 100](165) != opcode[v9(112) + 1](122)
what a shame...

从最后的判断可以看出来flag总共是15位

再从最后的判断里条件里往上边的运算找,最后分别逆回去

比如第一位的结果是34,他分别做了+5和与16异或,结果是55,在ASCII码对照表中就是数字7

最后的flag

flag{757515121f3d478}

网上有更好的办法,只是我太菜了


findKey

无壳IDA32位打开

主函数被花过了,但是按P之后能直接反编译

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
int __userpurge sub_40194E@<eax>(int a1@<ecx>, int a2@<ebp>, int a3, int a4, int a5, int a6)
{
int v6; // edi
int v7; // eax
int v8; // eax

qmemcpy((void *)(a2 - 748), "0kk`d1a`55k222k2a776jbfgd`06cjjb", 4 * a1 + 1);
memset((void *)(a2 - 715), 0, 0xDCu);
v6 = a2 - 715 + 220;
*(_WORD *)v6 = 0;
*(_BYTE *)(v6 + 2) = 0;
strcpy((char *)(a2 - 760), "SS");
*(_DWORD *)(a2 - 757) = 0;
*(_WORD *)(a2 - 753) = 0;
*(_BYTE *)(a2 - 751) = 0;
v7 = strlen((const char *)(a2 - 748));
sub_401005((LPCSTR)(a2 - 760), a2 - 748, v7);//第一个加密,点进去看看
if ( _strcmpi(&String1, (const char *)(a2 - 748)) )
{
SetWindowTextA(*(HWND *)(a2 + 8), "flag{}");
MessageBoxA(*(HWND *)(a2 + 8), "Are you kidding me?", "^_^", 0);
ExitProcess(0);
}
memcpy((void *)(a2 - 1016), &unk_423030, 0x32u);
v8 = strlen((const char *)(a2 - 1016));
sub_401005((LPCSTR)(a2 - 492), a2 - 1016, v8);//这里还有加密
MessageBoxA(*(HWND *)(a2 + 8), (LPCSTR)(a2 - 1016), 0, 0x32u);
++dword_428D54;
return 0;
}

只是一个简单的异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
unsigned int __cdecl sub_401590(LPCSTR lpString, int a2, int a3)
{
unsigned int result; // eax
unsigned int i; // [esp+4Ch] [ebp-Ch]
unsigned int v5; // [esp+54h] [ebp-4h]

v5 = lstrlenA(lpString);
for ( i = 0; ; ++i )
{
result = i;
if ( i >= a3 )
break;
*(_BYTE *)(i + a2) ^= lpString[i % v5];
}
return result;
}

我们把代码写出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <stdio.h>
#include <windows.h>
using namespace std;
char str[1024] = "0kk`d1a`55k222k2a776jbfgd`06cjjb";
char str2[1024] = "SS";
int main()
{
int v7 = strlen(str);
for (size_t i = 0; i < v7; i++)
{
str[i] ^= str2[i % 2];
/* code */
}
printf("%s",str);//c8837b23ff8aaa8a2dde915473ce0991
//123321
return 0;
}

解密出来的str是MD5加密(一开始不知道)

解密的结果也不是flag

确实有输出提示

那我们继续往下看

W^RTI_01miF02n_02lW[TL

发现藏了一个这玩意,并且进行了相同的异或操作,只不过是与解密出来的MD5异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <stdio.h>
#include <windows.h>
using namespace std;
char str[1024] = "W^RTI_\x01miF\x02n_\x02lW[TL";//0kk`d1a`55k222k2a776jbfgd`06cjjb
char str2[1024] = "123321";//SS
int main()
{
int v7 = strlen(str);
for (size_t i = 0; i < v7; i++)
{
str[i] ^= str2[i % 6];
/* code */
}
printf("%s",str);
return 0;
}

flag{n0_Zu0_n0_die}


[网鼎杯 2020 青龙组]jocker

IDA32位打开

看网上的wp说是存在堆栈不平衡,但是我的IDA也顺利打开了,那就先走着

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
char Str[50]; // [esp+12h] [ebp-96h] BYREF
char Destination[80]; // [esp+44h] [ebp-64h] BYREF
DWORD flOldProtect; // [esp+94h] [ebp-14h] BYREF
size_t v7; // [esp+98h] [ebp-10h]
int i; // [esp+9Ch] [ebp-Ch]

__main();
puts("please input you flag:");
if ( !VirtualProtect(encrypt, 0xC8u, 4u, &flOldProtect) )
exit(1);
scanf("%40s", Str);
v7 = strlen(Str);
if ( v7 != 24 )
{
puts("Wrong!");
exit(0);
}
strcpy(Destination, Str);
wrong(Str);
omg(Str);
for ( i = 0; i <= 186; ++i )
*((_BYTE *)encrypt + i) ^= 0x41u;
if ( encrypt(Destination) )
finally(Destination);
return 0;
}

首先看见的是wrong和omg两个函数

wrong是一个异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char *__cdecl wrong(char *a1)
{
char *result; // eax
int i; // [esp+Ch] [ebp-4h]

for ( i = 0; i <= 23; ++i )
{
result = &a1[i];
if ( (i & 1) != 0 )
a1[i] -= i;
else
a1[i] ^= i;
}
return result;
}

omg是一个判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl omg(char *a1)
{
int result; // eax
int v2[24]; // [esp+18h] [ebp-80h] BYREF
int i; // [esp+78h] [ebp-20h]
int v4; // [esp+7Ch] [ebp-1Ch]

v4 = 1;
qmemcpy(v2, &unk_4030C0, sizeof(v2));
for ( i = 0; i <= 23; ++i )
{
if ( a1[i] != v2[i] )
v4 = 0;
}
if ( v4 == 1 )
result = puts("hahahaha_do_you_find_me?");
else
result = puts("wrong ~~ But seems a little program");
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
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <stdio.h>
#include <windows.h>
using namespace std;
unsigned char ida_chars[] =
{
0x66, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x63, 0x00,
0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00,
0x61, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
0x6B, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x7B, 0x00,
0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00,
0x50, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x5F, 0x00,
0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00,
0x71, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x37, 0x00,
0x00, 0x00, 0x66
};//fkcdFagd;Vka{&;Pc_MZqC7f
int main()
{
char str[] = "fkcdFagd;Vka{&;Pc_MZqC7f";
//int len = strlen(str);
// printf("%d",len);
for (size_t i = 0; i <= 23; i++)
{
if (i & str[i] != 0)
str[i] += i;
else
str[i] ^= i;


/* code */
}
printf("%s",str);//flag{fak3_alw35_sp_meX!}

return 0;

}

flag{fak3_alw35_sp_meX!}测试过后发现是一个假的flag

主函数还有一些函数,接着看看

报错了

网上找了一些方法,最好的方法就是动调,原理是那个for循环相当于一个脱壳

拖进21Slsec专用

中文搜索下了几个断点

推断这个就是加密函数,F7步入

没跑了,脱壳再IDA打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl start(int a1)
{
int v2[19]; // [esp+1Ch] [ebp-6Ch] BYREF
int v3; // [esp+68h] [ebp-20h]
int i; // [esp+6Ch] [ebp-1Ch]

v3 = 1;
qmemcpy(v2, &unk_403040, sizeof(v2));
for ( i = 0; i <= 18; ++i )
{
if ( (char)(*(_BYTE *)(i + a1) ^ aHahahahaDoYouF[i]) != v2[i] )
{
puts("wrong ~");
v3 = 0;
exit(0);
}
}
puts("come here");
return v3;
}

也是一个异或

解密出来不是完整的flag

flag{d07abccf8a410c

发现最后还藏了一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __cdecl sub_40159A(int a1)
{
unsigned int v1; // eax
int result; // eax
char v3[9]; // [esp+13h] [ebp-15h] BYREF
int v4; // [esp+1Ch] [ebp-Ch]

strcpy(v3, "%tp&:");
v1 = time(0);
srand(v1);
v4 = rand() % 100;
if ( (v3[*(_DWORD *)&v3[5]] != *(_BYTE *)(*(_DWORD *)&v3[5] + a1)) == v4 )
result = puts("Really??? Did you find it?OMG!!!");
else
result = puts("I hide the last part, you will not succeed!!!");
return result;
}

这个函数比较离谱,不知道做了什么

但是学长说过逆向一半靠猜

flag最后一位是‘}’,即’:‘与71异或

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
#include <iostream>
#include <stdio.h>
#include <windows.h>
using namespace std;
unsigned char ida_chars[] =
{
0x66, 0x00, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x00, 0x63, 0x00,
0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00,
0x61, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x64, 0x00,
0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
0x6B, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x7B, 0x00,
0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00,
0x50, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x5F, 0x00,
0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00,
0x71, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x37, 0x00,
0x00, 0x00, 0x66
};//fkcdFagd;Vka{&;Pc_MZqC7f
int main()
{
char str[] = "fkcdFagd;Vka{&;Pc_MZqC7f";
//int len = strlen(str);
// printf("%d",len);
for (size_t i = 0; i <= 23; i++)
{
if (i & str[i] != 0)
str[i] += i;
else
str[i] ^= i;
/* code */
}
printf("%s\n",str);//flag{fak3_alw35_sp_meX!}
string s = "hahahaha_do_you_find_me?";
string end = "%tp&:";
int a[] = {14, 13, 9, 6, 19, 5, 88, 86, 62, 6, 12, 60, 31, 87, 20, 107, 87, 89, 13};
for (int i = 0; i < 19; i++)
cout << (char)(s[i] ^ a[i]);
for (int i = 0; i < 5; i++)
cout << (char)(end[i] ^ 71);//flag{d07abccf8a410cb37a}
return 0;
}

flag{d07abccf8a410cb37a}


羊城杯[2020]easyre

64位无壳

拖进IDA找到主函数

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v3; // eax
int v4; // eax
int v5; // eax
int result; // eax
char Str[48]; // [rsp+20h] [rbp-60h] BYREF
char Str1[64]; // [rsp+50h] [rbp-30h] BYREF
char v9[64]; // [rsp+90h] [rbp+10h] BYREF
char v10[64]; // [rsp+D0h] [rbp+50h] BYREF
char Str2[60]; // [rsp+110h] [rbp+90h] BYREF
int v12; // [rsp+14Ch] [rbp+CCh] BYREF

_main(argc, argv, envp);
strcpy(Str2, "EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG");
puts("Hello, please input your flag and I will tell you whether it is right or not.");
scanf("%38s", Str);
if ( strlen(Str) != 38
|| (v3 = strlen(Str), (unsigned int)encode_one(Str, v3, v10, &v12))
|| (v4 = strlen(v10), (unsigned int)encode_two(v10, v4, v9, &v12))
|| (v5 = strlen(v9), (unsigned int)encode_three(v9, v5, Str1, &v12))
|| strcmp(Str1, Str2) )
{
printf("Something wrong. Keep going.");
result = 0;
}
else
{
puts("you are right!");
result = 0;
}
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
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
__int64 __fastcall encode_one(const char *a1, int a2, char *a3, int *a4)
{
int v5; // esi
int v6; // esi
int v7; // esi
int v8; // [rsp+34h] [rbp-1Ch]
int v9; // [rsp+38h] [rbp-18h]
int v11; // [rsp+48h] [rbp-8h]
int i; // [rsp+4Ch] [rbp-4h]
unsigned __int8 *v13; // [rsp+70h] [rbp+20h]

v13 = (unsigned __int8 *)a1;
if ( !a1 || !a2 )
return 0xFFFFFFFFi64;
v11 = 0;
if ( a2 % 3 )
v11 = 3 - a2 % 3;
v9 = a2 + v11;
v8 = 8 * (a2 + v11) / 6;
for ( i = 0; i < v9; i += 3 )
{
*a3 = alphabet[(char)*v13 >> 2];
if ( a2 + v11 - 3 == i && v11 )
{
if ( v11 == 1 )
{
v5 = (char)cmove_bits(*v13, 6u, 2u);
a3[1] = alphabet[v5 + (char)cmove_bits(v13[1], 0, 4u)];
a3[2] = alphabet[(char)cmove_bits(v13[1], 4u, 2u)];
a3[3] = 61;
}
else if ( v11 == 2 )
{
a3[1] = alphabet[(char)cmove_bits(*v13, 6u, 2u)];
a3[2] = 61;
a3[3] = 61;
}
}
else
{
v6 = (char)cmove_bits(*v13, 6u, 2u);
a3[1] = alphabet[v6 + (char)cmove_bits(v13[1], 0, 4u)];
v7 = (char)cmove_bits(v13[1], 4u, 2u);
a3[2] = alphabet[v7 + (char)cmove_bits(v13[2], 0, 6u)];
a3[3] = alphabet[v13[2] & 0x3F];
}
a3 += 4;
v13 += 3;
}
if ( a4 )
*a4 = v8;
return 0i64;
}

通过字符串可以分析出来是一个Base64加密

第二个

1
2
3
4
5
6
7
8
9
10
__int64 __fastcall encode_two(const char *a1, int a2, char *a3, int *a4)
{
if ( !a1 || !a2 )
return 0xFFFFFFFFi64;
strncpy(a3, a1 + 26, 0xDui64);
strncpy(a3 + 13, a1, 0xDui64);
strncpy(a3 + 26, a1 + 39, 0xDui64);
strncpy(a3 + 39, a1 + 13, 0xDui64);
return 0i64;
}

将加密过后的字符串换了下位置

第三个

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
__int64 __fastcall encode_three(const char *a1, int a2, char *a3, int *a4)
{
char v5; // [rsp+Fh] [rbp-11h]
int i; // [rsp+14h] [rbp-Ch]
const char *v8; // [rsp+30h] [rbp+10h]

v8 = a1;
if ( !a1 || !a2 )
return 0xFFFFFFFFi64;
for ( i = 0; i < a2; ++i )
{
v5 = *v8;
if ( *v8 <= 64 || v5 > 90 )
{
if ( v5 <= 96 || v5 > 122 )
{
if ( v5 <= 47 || v5 > 57 )
*a3 = v5;
else
*a3 = (v5 - 48 + 3) % 10 + 48;
}
else
{
*a3 = (v5 - 97 + 3) % 26 + 97;
}
}
else
{
*a3 = (v5 - 65 + 3) % 26 + 65;
}
++a3;
++v8;
}
return 0i64;
}

看网上的WP都说是凯撒加密,但我做的时候并不知道是凯撒加密,只知道能通过爆破脚本写出来

这道题加密还都是比较简单的

写一个C语言脚本

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
#include <iostream>
#include <stdio.h>
#include <windows.h>
char str2[] = "EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG";
char encode_three[] = "BjYjM2Mjk4NzMR1dIVHs2NzJjY0MTEzM2VhMn0=zQ3NzhhMzhlOD";
char flag[] = {0};
using namespace std;
int main()
{
int k = 0;
for(int i = 0;i < 52; i++)
{
for (int j = 0; j < 128; j++)
{
k = j;
if (j <= 64 || j > 90)
{
if (j <= 96 || j > 122)
{
if (j <= 47 || j > 57)
{
k = j;
}
else
k = (j - 48 + 3) % 10 + 48;
}
else
{
k = (j - 97 + 3) % 26 + 97;
}

}
else
{
k = (j - 65 + 3) % 26 + 65;
}
if (k == str2[i])
{
encode_three[i] = j;
}
else
continue;
}

}
char *a3 = flag;
char *a1 = encode_three;
strncpy(a3 + 26, a1, 13);
strncpy(a3, a1 + 13, 13);
strncpy(a3 + 39, a1 + 26, 13);
strncpy(a3 + 13, a1 + 39, 13);
printf("%s",flag);
return 0;
//GWHT{672cc4778a38e80cb362987341133ea2}
}

输出的字符串拿去Base64解密就能得到flag

//GWHT{672cc4778a38e80cb362987341133ea2}