虎符CTF2022 —shellcode

二木 王者

虎符CTF2022 —shellcode

打开这道题,我们可以发现这个是进行加壳了的软件

image-20230923175055902

我们进行动态调试,先准备手动脱壳的,脱的时候发现居然有反调试,准备动态调试将反调试的patch但是发现很难脱,脱了半天还在循环,可能太菜的原因(T _ T)。但是我们脱的时候可以发现,这个就是themida的壳。去网上一搜,果然是强壳,难脱。。。

去网上找了一个可以绕过这个壳反调试

image-20230923175116737

下载下来后拷贝对应版本的插件到你的x64dbg插件目录,如64位,拷贝SharpOD x64.dp64文件,然后重启调试器在插件菜单中配置

再将这个选中。

image-20230923175131708

这样我们就可以愉快的脱壳了。

将程序放入X32DBGz中进行分析,我们按F9运行几次,我们就可以运行到我们的OPE之中了。

image-20230923175149097

我们使用Syclla插件将可以将这个dump出来

或者记下这个地址,我们使用IDA的附加调试,将IDA附加到程序上,因为程序运行到了打印字符 了,所以壳肯定是解开了。因此我们可以就此直接找到解密后的代码处。

image-20230923175210269

我们可以找到我们的解密后的代码 开始分析

![Untitled 5](./Untitled 5.png)

首先我们可以知道,我们需要输入的shellcode是352位

进入这个函数

![Untitled 6](./Untitled 6.png)

![Untitled 9](/Untitled 9.png)

![Untitled 8](/Untitled 8.png)

进入之后,我们进行简单的分析可以发现,这个函数![Untitled 7](/Untitled 7.png)实现的是base64加密

往后分析我们可以发现有一个将数据右移了3位

这里特征很明显0x61C88647 和加密特征很明显,是xxtea加密,我们对比原版的XXtea我们可以发现

就进行魔改后的

![Untitled 10](./Untitled 10.png)

由此shellcode解密分析完毕,我们写一个脚本将其shellcoe出来

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
#include <stdio.h>
#include <stdlib.h>
#define delta 0x9e3779b9
char basetable[] = {
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x40,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x3E, 0x42, 0x42, 0x42, 0x3F, 0x34, 0x35, 0x36,
0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x42, 0x42, 0x42,
0x41, 0x42, 0x42, 0x42, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x1A, 0x1B, 0x1C, 0x1D,
0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31,
0x32, 0x33, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42};
int FindIndex(int x)
{
int i;

for (i = 0; i < 256; i++)
if (basetable[i] == x)
return i;
}

void BaseDecode(unsigned char *flag, int len, unsigned char *input)
{
int i, j;

for (i = 0, j = 0; i < len; i += 3, j += 4)
{
input[j] = (flag[i] >> 2) & 0x3F;
input[j + 1] = ((flag[i] & 0x3) << 4) | (flag[i + 1] & 0xF0) >> 4;
input[j + 2] = ((flag[i + 1] & 0xF) << 2) | (flag[i + 2] & 0xC0) >> 6;
input[j + 3] = flag[i + 2] & 0x3F;
}
for (i = 0; i < len / 3 * 4; i++)
input[i] = FindIndex(input[i]);
}
template <class T>
T ROL(T value, int count)

{

const unsigned int nbits = sizeof(T) * 8;

if (count > 0)

{

count %= nbits;

T high = value >> (nbits - count);

if (T(-1) < 0) // signed value

high &= ~((T(-1) << count));

value <<= count;

value |= high;
}

else

{

count = -count % nbits;

T low = value << (nbits - count);

value >>= count;

value |= low;
}

return value;
}
int main()
{
unsigned int v[66] = {0x4B6B89A1, 0x74C15453, 0x4092A06E, 0x429B0C07, 0x40281E84, 0x8B5B44C9, 0x66FEB37B, 0x3C77A603,
0x79C5892D, 0x0D7ADA97, 0x1D51AA56, 0x02D4D703, 0x4FA526BA, 0x32FAD64A, 0x0C0F6091, 0x562B7593,
0xDB9ADD67, 0x76165563, 0xA5F79315, 0x3AEB991D, 0x1AB721D4, 0xAACD9D2C, 0x825C2B27, 0x76A7761A,
0xB4005F18, 0x117F3763, 0x512CC540, 0xC594A16F, 0xD0E24F8C, 0x9CA3E2E9, 0x0A9CC2D5, 0x4629E61D,
0x637129E3, 0xCA4E8AD7, 0xF5DFAF71, 0x474E68AB, 0x542FBC3A, 0xD6741617, 0xAD0DBBE5, 0x62F7BBE3,
0xC8D68C07, 0x880E950E, 0xF80F25BA, 0x767A264C, 0x9A7CE014, 0x5C8BC9EE, 0x5D9EF7D4, 0xB999ACDE,
0xB2EC8E13, 0xEE68232D, 0x927C5FCE, 0xC9E3A85D, 0xAC74B56B, 0x42B6E712, 0xCD2898DA, 0xFCF11C58,
0xF57075EE, 0x5076E678, 0xD4D66A35, 0x95105AB9, 0x1BB04403, 0xB240B959, 0x7B4E261A, 0x23D129D8,
0xF5E752CD, 0x4EA78F70};
unsigned int key[4] = {116, 111, 114, 97};
unsigned int sum = 0;
unsigned int y, z, p, rounds, e;
int n = 66;
int i = 0;
rounds = 6 + 52 / n;
y = v[0];
sum = rounds * delta;
do
{
e = sum >> 2 & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
v[p] -= ((((z >> 6) ^ (y << 2)) + ((y >> 3) ^ (z << 4))) ^ ((key[(p & 3) ^ e] ^ z) + (y ^ sum)));
y = v[p];
}
z = v[n - 1];
v[0] -= (((key[(p ^ e) & 3] ^ z) + (y ^ sum)) ^ (((y << 2) ^ (z >> 6)) + ((z << 4) ^ (y >> 3))));
y = v[0];
sum = sum - delta;
} while (--rounds);
unsigned char *t = (unsigned char *)v;
unsigned char basecode[66 * 4];
for (int i = 0; i < n * 4; i++)
{
basecode[i] = ROL(t[i], -3);
printf("0x%x, ", basecode[i]);
}
unsigned char input[352];
BaseDecode(basecode, 66 * 4, input);
for (i = 0; i < 352; i++)
printf("%c", input[i]);
return 0;
}

然后我们再搓一个shellcode加载器将这个32位的shellcode加载出来

#include <string.h>
#include <Windows.h>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
unsigned char shellcode[] = {
0x60, 0xfc, 0x68, 0x4c, 0x77, 0x26, 0x7, 0x33, 0xd2, 0x64, 0x8b, 0x52, 0x30, 0x8b, 0x52, 0xc, 0x8b, 0x52, 0x14, 0x8b, 0x72, 0x28, 0xf, 0xb7, 0x4a, 0x26, 0x33, 0xff, 0x33, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x2, 0x2c, 0x20, 0xc1, 0xcf, 0xd, 0x3, 0xf8, 0xe2, 0xf0, 0x52, 0x57, 0x8b, 0x52, 0x10, 0x8b, 0x42, 0x3c, 0x3, 0xc2, 0x8b, 0x40, 0x78, 0x85, 0xc0, 0xf, 0x84, 0xbe, 0x0, 0x0, 0x0, 0x3, 0xc2, 0x50, 0x8b, 0x48, 0x18, 0x8b, 0x58, 0x20, 0x3, 0xda, 0x83, 0xf9, 0x0, 0xf, 0x84, 0xa9, 0x0, 0x0, 0x0, 0x49, 0x8b, 0x34, 0x8b, 0x3, 0xf2, 0x33, 0xff, 0x33, 0xc0, 0xac, 0xc1, 0xcf, 0xd, 0x3, 0xf8, 0x3a, 0xc4, 0x75, 0xf4, 0x3, 0x7c, 0x24, 0x4, 0x3b, 0x7c, 0x24, 0xc, 0x75, 0xd9, 0x33, 0xff, 0x33, 0xc9, 0x83, 0xc2, 0x50, 0xf, 0xb6, 0x4, 0xa, 0xc1, 0xcf, 0xd, 0x3, 0xf8, 0x41, 0x83, 0xf9, 0xe, 0x75, 0xf1, 0xc1, 0xcf, 0xd, 0x57, 0x33, 0xff, 0x33, 0xc9, 0x8b, 0x54, 0x24, 0x3c, 0x52, 0xf, 0xb6, 0x1c, 0xe, 0xb8, 0x67, 0x66, 0x66, 0x66, 0xf7, 0xeb, 0xd1, 0xfa, 0x8b, 0xc2, 0xc1, 0xe8, 0x1f, 0x3, 0xc2, 0x8d, 0x4, 0x80, 0x2b, 0xd8, 0x5a, 0xf, 0xb6, 0x4, 0xa, 0x2b, 0xc3, 0xc1, 0xcf, 0xd, 0x3, 0xf8, 0x41, 0x83, 0xf9, 0xe, 0x75, 0xd4, 0xc1, 0xcf, 0xd, 0x3b, 0x3c, 0x24, 0x74, 0x16, 0x68, 0x25, 0x73, 0x0, 0x0, 0x8b, 0xc4, 0x68, 0x6e, 0x6f, 0x0, 0x0, 0x54, 0x50, 0x8b, 0x5c, 0x24, 0x48, 0xff, 0xd3, 0xeb, 0x14, 0x68, 0x25, 0x73, 0x0, 0x0, 0x8b, 0xc4, 0x68, 0x79, 0x65, 0x73, 0x0, 0x54, 0x50, 0x8b, 0x5c, 0x24, 0x48, 0xff, 0xd3, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x61, 0xc3, 0x58, 0x5f, 0x5a, 0x8b, 0x12, 0xe9, 0xb, 0xff, 0xff, 0xff, };

int main()
{
PVOID p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (p == NULL)
{
return -1;
}
memcpy(p, shellcode, sizeof(shellcode));
((void(__stdcall*)())(p))();
return 0;
}

看分析还是比较简单,就是将原本程序里面的两端提示,进行加密

https://www.notion.so

写一个脚本将其解密

1
2
3
4
5
6
7
8
9
char data2[]="LoadLibraryExA";
char data1[]="is program can";
char flag[]={};
puts("\n");
for (int i = 0; i < sizeof(data1); i++)
{
printf("%c",data1[i]+data2[i]%5);
}
//jt"psojvcq!gan

然后将flag 进行md5操作即可

 评论