BlackBasta首先通过 FindFirstVolumeW 与 FindNextVolumeW 实现系统中第一个卷的搜索和其余卷的遍历,之后通过 GetVolumePathNamesForVolumeNameW 检索指定卷的驱动器号和挂载的文件夹路径列表,然后通过 GetVolumeInformationW 获取关于指定卷的信息,具体代码如下所示。
- FindFirstVolumeW vs. FindNextVolumeW:FindFirstVolumeW函数是Windows API中的一个函数,用于搜索计算机上的第一个卷的相关信息。它会打开一个卷搜索句柄,并返回与第一个找到的卷相关的信息。这个函数通常与FindNextVolume函数一起使用,后者用于搜索其他的卷。通过使用FindFirstVolumeW函数,我们可以枚举计算机上的所有卷,获取它们的名称以及其他属性信息。
- GetVolumePathNamesForVolumeNameW:该函数用于检索指定卷的驱动器号和挂载的文件夹路径列表。它的功能是通过传入卷名,获取该卷对应的驱动器号以及挂载点的路径列表。这个函数的返回值是一个布尔类型,指示操作是否成功。当函数成功执行后,它会通过传入的缓冲区指针,返回驱动器号和挂载点路径的列表。返回的路径列表是以Null字符('\0')作为分隔符的字符串数组,以表示列表的结束。
- GetVolumeInformationW:该函数的作用是获取关于指定卷的信息。这个Windows API函数可以用于检索指定卷的文件系统、卷标、序列号、每个簇的字节数、总簇数、可用簇数等信息。通过调用GetVolumeInformationW函数,可以让程序获取有关特定卷的重要信息,这在文件系统管理和数据操作中非常有用。
_DWORD *__cdecl sub_40EE40(_DWORD *a1)
{
# 定义用于存储第一个卷的句柄
HANDLE FirstVolumeW; // esi
unsigned int v2; // kr00_4
_DWORD *v3; // eax
void *v4; // edx
DWORD cchReturnLength[2]; // [esp+Ch] [ebp-C40h] BYREF
HANDLE v7; // [esp+14h] [ebp-C38h]
int v8; // [esp+18h] [ebp-C34h]
DWORD FileSystemFlags[2]; // [esp+1Ch] [ebp-C30h] BYREF
void *Block[4]; // [esp+24h] [ebp-C28h] BYREF
__int64 v11; // [esp+34h] [ebp-C18h]
WCHAR szVolumePathNames[1024]; // [esp+3Ch] [ebp-C10h] BYREF
WCHAR szVolumeName[512]; // [esp+83Ch] [ebp-410h] BYREF
int v14; // [esp+C48h] [ebp-4h]
cchReturnLength[1] = (DWORD)a1;
*a1 = 0;
a1[1] = 0;
a1[2] = 0;
v14 = 0;
FileSystemFlags[1] = 1;
# 调用 FindFirstVolumeW 查找系统中的第一个卷
FirstVolumeW = FindFirstVolumeW(szVolumeName, 0x200u);
v7 = FirstVolumeW;
do
{
# 通过 GetVolumePathNamesForVolumeNameW 获取卷的路径
if ( GetVolumePathNamesForVolumeNameW(szVolumeName, szVolumePathNames, 0x400u, cchReturnLength)
# 获取卷路径相关信息
&& GetVolumeInformationW(szVolumePathNames, 0, 0, 0, 0, FileSystemFlags, 0, 0)
# 检测文件系统标识符
&& (FileSystemFlags[0] & 0x80000) == 0 )
{
v2 = wcslen(szVolumePathNames);
Block[0] = 0;
v11 = 0xF00000000i64;
sub_41B200(Block, (int)(2 * v2) >> 1);
LOBYTE(v8) = 0;
sub_403230(Block, (int)szVolumePathNames, (int)&szVolumePathNames[v2], v8);
v14 = 1;
v3 = (_DWORD *)a1[1];
if ( v3 == (_DWORD *)a1[2] )
{
sub_403640(v3, Block);
}
else
{
*v3 = 0;
v3[4] = 0;
v3[5] = 0;
*(_OWORD *)v3 = *(_OWORD *)Block;
*((_QWORD *)v3 + 2) = v11;
a1[1] += 24;
v11 = 0xF00000000i64;
LOBYTE(Block[0]) = 0;
}
LOBYTE(v14) = 0;
if ( HIDWORD(v11) >= 0x10 )
{
v4 = Block[0];
if ( (unsigned int)(HIDWORD(v11) + 1) >= 0x1000 )
{
v4 = (void *)*((_DWORD *)Block[0] - 1);
if ( (unsigned int)(Block[0] - v4 - 4) > 0x1F )
_invalid_parameter_noinfo_noreturn();
}
sub_43851F(v4);
}
FirstVolumeW = v7;
v11 = 0xF00000000i64;
LOBYTE(Block[0]) = 0;
}
}
# 通过 FindNextVolumeW 枚举系统中所有卷
while ( FindNextVolumeW(FirstVolumeW, szVolumeName, 0x200u) );
FindVolumeClose(FirstVolumeW);
return a1;
BlackBasta通过FindFirstFileW启动硬盘中文件的扫描,通过FindNextFileW实现文件枚举。不同于其他勒索软件,BlackBasta首先过滤指定的文件夹或文件(其他勒索软件会根据后缀过滤)。
- FindFirstFileW vs. FindNextFileW:FindFirstFileW函数是Windows API中的一个函数,用于在指定目录中查找第一个符合指定条件的文件或文件夹。这个函数可以帮助程序员遍历目录下的文件和文件夹,以便进行文件管理、处理和操作。通过调用FindFirstFileW函数,可以获取目录中符合条件的第一个文件或文件夹的信息,如文件名、大小、创建时间等。这对于编写文件管理、浏览器和其他类似应用程序非常有用。FindNextFileW通常与FindFirstFileW函数一起使用,用于在指定目录中继续查找与之前调用FindFirstFileW函数获得的文件或文件夹匹配的下一个文件或文件夹。
AvosLocker通过中也存在类似的操作(通过搜索字符串 FindFirstVolumeW ),值得注意的是上述两种勒索软件针对卷的扫描和针对文件的扫面是分开的。
void sub_414C40()
{
WCHAR *v0; // eax
WCHAR *v1; // edi
HANDLE FirstVolumeW; // esi
int v3; // esi
HANDLE v4; // [esp+10h] [ebp-220h]
DWORD cchReturnLength; // [esp+14h] [ebp-21Ch] BYREF
WCHAR RootPathName[2]; // [esp+18h] [ebp-218h] BYREF
int v7; // [esp+1Ch] [ebp-214h]
WCHAR szVolumePathNames[262]; // [esp+20h] [ebp-210h] BYREF
*(_DWORD *)RootPathName = 3801178;
v7 = 92;
cchReturnLength = 0;
v0 = (WCHAR *)malloc(0x10000u);
v1 = v0;
if ( v0 )
{
FirstVolumeW = FindFirstVolumeW(v0, 0x8000u);
v4 = FirstVolumeW;
do
{
if ( !GetVolumePathNamesForVolumeNameW(v1, szVolumePathNames, 0x78u, &cchReturnLength)
|| lstrlenW(szVolumePathNames) != 3 )
{
v3 = 0;
RootPathName[0] = 90;
while ( GetDriveTypeW(RootPathName) != 1 )
{
++v3;
--RootPathName[0];
if ( v3 >= 26 )
goto LABEL_10;
}
SetVolumeMountPointW(RootPathName, v1);
LABEL_10:
FirstVolumeW = v4;
}
}
while ( FindNextVolumeW(FirstVolumeW, v1, 0x8000u) );
FindVolumeClose(FirstVolumeW);
free(v1);
}
}