某远程加载马样本分析学习

  1. 前言
  2. 用到的工具
  3. 分析过程
  4. 总结

前言

在freebuf上看到一篇名为:一个CS马伪装下的loader样本分析
跟着复现了一下,由于底子不够分析的可能不全。

用到的工具

Exeinfo
Detect Easy
IDA 7.5
API Monitor v2.0
Process Monitor
PEview
OD

分析过程

根据文章给出的样本下载链接查看:https://app.any.run/tasks/ffc1ecff-e461-4474-8352-551db7e7b06f/
先在app.any.run看了一下分析结果

请求了两个URL,其中一个是二进制数据
http://8.210.181.149:16678/9jhQ

目前得到的信息:
IP:8.210.181.149 - 归属地:香港
样本标记:Cobalt strike
执行方法疑似远程加载payload

微步社区查询该IP,已被标记

viz.greynoise.io未标记cs

VT查杀

将样本下载到本地分析
md5 hash:3f37fc95aa5c8f7c304aa0dfc3ffbf2e
打开属性看到个数字签名

Detect lt Easy拖进去查看,没有加壳,VC++写的

查看导入的dll,就发现一个kernel.dll。windows API隐藏导入
该技术参考链接:https://blog.scrt.ch/2020/07/15/engineering-antivirus-evasion-part-ii/

IDA静态分析
尝试搜索main函数,发现可以直接找到入口点(估计freebuf那篇文章作者用的是IDA 7.0没找到入口点)

跟到_main_0函数

首先跟踪__CheckForDebuggerJustMyCode

dword_517944值看不到定义的是什么

往下面能看到调用了一堆API

先不看这些API,继续分析_main_0。_CheckForDebuggerJustMycode后执行VirtualAlloc分配内存

之后调用_memmove函数,跟踪其unk_515000指针

数组合并,hex转换回字符串

在解码后看到远程下载链接的路径9jhQ

在payload尾部可以看见IP

j__memmove函数分析,把VirtualAlloc分配内存的指针传入,把&unk_515000指针传入该函数,传入大小799

memmove函数为一个解码payload用的函数

void *__cdecl memmove(void *a1, const void *Src, size_t Size)
{
  const __m128i *v3; // esi
  size_t v4; // ecx
  __m128i *v5; // edi
  void *result; // eax
  __int64 v7; // xmm1_8
  __m128i v8; // xmm1
  const __m128i *v9; // esi
  __m128i v10; // xmm3
  __m128i v11; // xmm0
  __m128i v12; // xmm5
  const __m128i *v13; // esi
  __m128i v14; // xmm1
  const __m128i *v15; // esi
  __m128i v16; // xmm3
  __m128i v17; // xmm0
  __m128i v18; // xmm5
  __m128i v19; // xmm1
  const __m128i *v20; // esi
  __m128i v21; // xmm3
  __m128i v22; // xmm0
  __m128i v23; // xmm5
  __m128i v24; // xmm1
  __int32 v25; // eax
  __int64 v26; // xmm1_8
  char v27; // dl
  size_t v28; // ecx
  const __m128i *v29; // esi
  __m128i *v30; // edi
  int v31; // edx
  char v32; // dl
  size_t v33; // ecx
  int v34; // edx
  __int8 *v35; // esi
  char *v36; // edi
  __m128i v37; // xmm1
  __m128i v38; // xmm2
  __m128i v39; // xmm3
  __m128i v40; // xmm4
  __m128i v41; // xmm5
  __m128i v42; // xmm6
  __m128i v43; // xmm7
  __m128i v44; // xmm1
  int v45; // eax
  size_t v46; // edx
  size_t j; // edx
  __m128i v48; // xmm1
  __m128i v49; // xmm2
  __m128i v50; // xmm3
  __m128i v51; // xmm5
  __m128i v52; // xmm6
  __m128i v53; // xmm7
  size_t k; // edx
  __m128i v55; // xmm1
  unsigned int v56; // ecx
  char v57; // al
  unsigned int l; // ecx
  int v59; // ecx
  unsigned int v60; // eax
  int v61; // ecx
  unsigned int i; // eax
  size_t v63; // [esp-4h] [ebp-Ch]

  v3 = (const __m128i *)Src;
  v4 = Size;
  v5 = (__m128i *)a1;
  if ( a1 > Src && a1 < (char *)Src + Size )
  {
    v29 = (const __m128i *)((char *)Src + Size);
    v30 = (__m128i *)((char *)a1 + Size);
    if ( Size >= 0x20 )
    {
      if ( _bittest(&dword_5153EC, 1u) )
      {
        for ( ; ((unsigned __int8)v30 & 0xF) != 0; v30->m128i_i8[0] = v29->m128i_i8[0] )
        {
          --v4;
          v29 = (const __m128i *)((char *)v29 - 1);
          v30 = (__m128i *)((char *)v30 - 1);
        }
        do
        {
          if ( v4 < 0x80 )
            break;
          v29 -= 8;
          v30 -= 8;
          v37 = _mm_loadu_si128(v29 + 1);
          v38 = _mm_loadu_si128(v29 + 2);
          v39 = _mm_loadu_si128(v29 + 3);
          v40 = _mm_loadu_si128(v29 + 4);
          v41 = _mm_loadu_si128(v29 + 5);
          v42 = _mm_loadu_si128(v29 + 6);
          v43 = _mm_loadu_si128(v29 + 7);
          *v30 = _mm_loadu_si128(v29);
          v30[1] = v37;
          v30[2] = v38;
          v30[3] = v39;
          v30[4] = v40;
          v30[5] = v41;
          v30[6] = v42;
          v30[7] = v43;
          v4 -= 128;
        }
        while ( (v4 & 0xFFFFFF80) != 0 );
        if ( v4 >= 0x20 )
        {
          do
          {
            v29 -= 2;
            v30 -= 2;
            v44 = _mm_loadu_si128(v29 + 1);
            *v30 = _mm_loadu_si128(v29);
            v30[1] = v44;
            v4 -= 32;
          }
          while ( (v4 & 0xFFFFFFE0) != 0 );
        }
      }
      else
      {
        if ( ((unsigned __int8)v30 & 3) != 0 )
        {
          v31 = (unsigned __int8)v30 & 3;
          v4 = Size - v31;
          do
          {
            v30[-1].m128i_i8[15] = v29[-1].m128i_i8[15];
            v29 = (const __m128i *)((char *)v29 - 1);
            v30 = (__m128i *)((char *)v30 - 1);
            --v31;
          }
          while ( v31 );
        }
        if ( v4 >= 0x20 )
        {
          v32 = v4;
          v33 = v4 >> 2;
          v34 = v32 & 3;
          v35 = &v29[-1].m128i_i8[12];
          v36 = &v30[-1].m128i_i8[12];
          while ( v33 )
          {
            *(_DWORD *)v36 = *(_DWORD *)v35;
            v35 -= 4;
            v36 -= 4;
            --v33;
          }
          switch ( v34 )
          {
            case 0:
              result = a1;
              break;
            case 1:
              v36[3] = v35[3];
              result = a1;
              break;
            case 2:
              v36[3] = v35[3];
              v36[2] = v35[2];
              result = a1;
              break;
            case 3:
              v36[3] = v35[3];
              v36[2] = v35[2];
              v36[1] = v35[1];
              result = a1;
              break;
          }
          return result;
        }
      }
    }
    for ( ; (v4 & 0xFFFFFFFC) != 0; v4 -= 4 )
    {
      v30 = (__m128i *)((char *)v30 - 4);
      v29 = (const __m128i *)((char *)v29 - 4);
      v30->m128i_i32[0] = v29->m128i_i32[0];
    }
    for ( ; v4; --v4 )
    {
      v30 = (__m128i *)((char *)v30 - 1);
      v29 = (const __m128i *)((char *)v29 - 1);
      v30->m128i_i8[0] = v29->m128i_i8[0];
    }
    result = a1;
  }
  else
  {
    if ( Size < 0x20 )
      goto CopyUpDwordMov;
    if ( Size < 0x80 )
    {
      if ( !_bittest(&dword_5153EC, 1u) )
        goto Dword_align;
      goto XmmCopySmallTest;
    }
    if ( _bittest(dword_51628C, 1u) )
    {
      qmemcpy(a1, Src, Size);
      return a1;
    }
    if ( (((unsigned int)Src ^ (unsigned int)a1) & 0xF) == 0 && _bittest(&dword_5153EC, 1u) )
    {
      v45 = (unsigned __int8)Src & 0xF;
      if ( ((unsigned __int8)Src & 0xF) != 0 )
      {
        v63 = Size - (16 - v45);
        v60 = 16 - v45;
        v61 = v60 & 3;
        if ( (v60 & 3) != 0 )
        {
          do
          {
            v5->m128i_i8[0] = v3->m128i_i8[0];
            v3 = (const __m128i *)((char *)v3 + 1);
            v5 = (__m128i *)((char *)v5 + 1);
            --v61;
          }
          while ( v61 );
        }
        for ( i = v60 >> 2; i; --i )
        {
          v5->m128i_i32[0] = v3->m128i_i32[0];
          v3 = (const __m128i *)((char *)v3 + 4);
          v5 = (__m128i *)((char *)v5 + 4);
        }
        v4 = v63;
      }
      v46 = v4;
      v4 &= 0x7Fu;
      for ( j = v46 >> 7; j; --j )
      {
        v48 = _mm_load_si128(v3 + 1);
        v49 = _mm_load_si128(v3 + 2);
        v50 = _mm_load_si128(v3 + 3);
        *v5 = _mm_load_si128(v3);
        v5[1] = v48;
        v5[2] = v49;
        v5[3] = v50;
        v51 = _mm_load_si128(v3 + 5);
        v52 = _mm_load_si128(v3 + 6);
        v53 = _mm_load_si128(v3 + 7);
        v5[4] = _mm_load_si128(v3 + 4);
        v5[5] = v51;
        v5[6] = v52;
        v5[7] = v53;
        v3 += 8;
        v5 += 8;
      }
XmmCopySmallTest:
      if ( !v4 )
        return a1;
      for ( k = v4 >> 5; k; --k )
      {
        v55 = _mm_loadu_si128(v3 + 1);
        *v5 = _mm_loadu_si128(v3);
        v5[1] = v55;
        v3 += 2;
        v5 += 2;
      }
CopyUpDwordMov:
      v56 = v4 & 0x1F;
      if ( v56 )
      {
        v57 = v56;
        for ( l = v56 >> 2; l; --l )
        {
          v5->m128i_i32[0] = v3->m128i_i32[0];
          v5 = (__m128i *)((char *)v5 + 4);
          v3 = (const __m128i *)((char *)v3 + 4);
        }
        v59 = v57 & 3;
        if ( (v57 & 3) != 0 )
        {
          do
          {
            v5->m128i_i8[0] = v3->m128i_i8[0];
            v3 = (const __m128i *)((char *)v3 + 1);
            v5 = (__m128i *)((char *)v5 + 1);
            --v59;
          }
          while ( v59 );
        }
      }
      return a1;
    }
    if ( !_bittest(dword_51628C, 0) || ((unsigned __int8)a1 & 3) != 0 )
    {
Dword_align:
      if ( ((unsigned __int8)a1 & 3) != 0 )
      {
        do
        {
          v5->m128i_i8[0] = v3->m128i_i8[0];
          --v4;
          v3 = (const __m128i *)((char *)v3 + 1);
          v5 = (__m128i *)((char *)v5 + 1);
        }
        while ( ((unsigned __int8)v5 & 3) != 0 );
      }
      goto Dword_align_Ok;
    }
    if ( ((unsigned __int8)Src & 3) != 0 )
    {
Dword_align_Ok:
      v27 = v4;
      if ( v4 >= 0x20 )
      {
        v28 = v4 >> 2;
        qmemcpy(v5, v3, 4 * v28);
        v13 = (const __m128i *)((char *)v3 + 4 * v28);
        v5 = (__m128i *)((char *)v5 + 4 * v28);
        switch ( v27 & 3 )
        {
          case 0:
            goto TrailingUp0;
          case 1:
            goto TrailingUp1;
          case 2:
            goto TrailingUp2;
          case 3:
            goto TrailingUp3;
        }
      }
      goto CopyUpDwordMov;
    }
    if ( _bittest((const int *)&v5, 2u) )
    {
      v4 = Size - 4;
      v3 = (const __m128i *)((char *)Src + 4);
      *(_DWORD *)a1 = *(_DWORD *)Src;
      v5 = (__m128i *)((char *)a1 + 4);
    }
    if ( _bittest((const int *)&v5, 3u) )
    {
      v7 = v3->m128i_i64[0];
      v4 -= 8;
      v3 = (const __m128i *)((char *)v3 + 8);
      v5->m128i_i64[0] = v7;
      v5 = (__m128i *)((char *)v5 + 8);
    }
    if ( ((unsigned __int8)v3 & 7) != 0 )
    {
      if ( _bittest((const int *)&v3, 3u) )
      {
        v8 = _mm_load_si128((const __m128i *)((char *)v3 - 12));
        v9 = (const __m128i *)((char *)v3 - 12);
        do
        {
          v10 = _mm_load_si128(v9 + 1);
          v4 -= 48;
          v11 = _mm_load_si128(v9 + 2);
          v12 = _mm_load_si128(v9 + 3);
          v9 += 3;
          *v5 = _mm_alignr_epi8(v10, v8, 12);
          v5[1] = _mm_alignr_epi8(v11, v10, 12);
          v8 = v12;
          v5[2] = _mm_alignr_epi8(v12, v11, 12);
          v5 += 3;
        }
        while ( v4 >= 0x30 );
        v13 = (const __m128i *)&v9->m128i_i8[12];
      }
      else
      {
        v19 = _mm_load_si128((const __m128i *)((char *)v3 - 4));
        v20 = (const __m128i *)((char *)v3 - 4);
        do
        {
          v21 = _mm_load_si128(v20 + 1);
          v4 -= 48;
          v22 = _mm_load_si128(v20 + 2);
          v23 = _mm_load_si128(v20 + 3);
          v20 += 3;
          *v5 = _mm_alignr_epi8(v21, v19, 4);
          v5[1] = _mm_alignr_epi8(v22, v21, 4);
          v19 = v23;
          v5[2] = _mm_alignr_epi8(v23, v22, 4);
          v5 += 3;
        }
        while ( v4 >= 0x30 );
        v13 = (const __m128i *)&v20->m128i_i8[4];
      }
    }
    else
    {
      v14 = _mm_load_si128((const __m128i *)((char *)v3 - 8));
      v15 = (const __m128i *)((char *)v3 - 8);
      do
      {
        v16 = _mm_load_si128(v15 + 1);
        v4 -= 48;
        v17 = _mm_load_si128(v15 + 2);
        v18 = _mm_load_si128(v15 + 3);
        v15 += 3;
        *v5 = _mm_alignr_epi8(v16, v14, 8);
        v5[1] = _mm_alignr_epi8(v17, v16, 8);
        v14 = v18;
        v5[2] = _mm_alignr_epi8(v18, v17, 8);
        v5 += 3;
      }
      while ( v4 >= 0x30 );
      v13 = (const __m128i *)&v15->m128i_i8[8];
    }
    while ( 2 )
    {
      if ( _bittest((const int *)&v4, 2u) )
      {
        v25 = v13->m128i_i32[0];
        v4 -= 4;
        v13 = (const __m128i *)((char *)v13 + 4);
        v5->m128i_i32[0] = v25;
        v5 = (__m128i *)((char *)v5 + 4);
      }
      if ( _bittest((const int *)&v4, 3u) )
      {
        v26 = v13->m128i_i64[0];
        v4 -= 8;
        v13 = (const __m128i *)((char *)v13 + 8);
        v5->m128i_i64[0] = v26;
        v5 = (__m128i *)((char *)v5 + 8);
      }
      switch ( v4 )
      {
        case 0u:
TrailingUp0:
          result = a1;
          break;
        case 1u:
TrailingUp1:
          v5->m128i_i8[0] = v13->m128i_i8[0];
          result = a1;
          break;
        case 2u:
TrailingUp2:
          v5->m128i_i8[0] = v13->m128i_i8[0];
          v5->m128i_i8[1] = v13->m128i_i8[1];
          result = a1;
          break;
        case 3u:
TrailingUp3:
          v5->m128i_i8[0] = v13->m128i_i8[0];
          v5->m128i_i8[1] = v13->m128i_i8[1];
          v5->m128i_i8[2] = v13->m128i_i8[2];
          result = a1;
          break;
        default:
          v24 = _mm_loadu_si128(v13);
          v4 -= 16;
          ++v13;
          *v5++ = v24;
          continue;
      }
      break;
    }
  }
  return result;
}

懒得分析解密过程,直接将样本关闭ASLR,拖入OD断点对应的位置分析
关闭ASLR参考链接:关闭ASLR
PEView查看对应的偏移地址将40 81改为00 81 (小端内存读为80 41)
(搜索 40 81的第一个位置修改)

(修改之后)

OD打开Ctrl+G转到对应的地址,断点

F8到把v4作为函数执行的时候

读取UA头和winnet

然后读完部分payload后读取自身
(这里是看freebuf那篇文章所理解的)

OD验证

之后获取Kernel.dll所有的函数

利用GetProcAddress获取了对应的API函数地址,并实例化该API

利用OD插件windows API断点下断GetProcAddress能看到所有实例化的API
(太多了就不一一列出来了)

原本想跟着IDA的函数调用图一步一步OD调,然后不知道为什么无法生成,直接OD定位到main函数地址调试

跟踪到Address:00453510的call执行完后就退出了,所以跟进去

跟进第一个call

得到wininet关键字

跟进call ebp发现获取自身加载的Module

加载了wchar.h,获取LoadLibraryExA关键字并实例化

加载twain_32.dll

解除IP地址

解密出UA头

在wininet下断点,得到返回的数据

23:26分
由于底子不行,调试到后面不会弄只能跟跟马子的行为
OD里的字符串

文章后面作者成功dump了下载的第二段payload并解密保存
(实在是断不到那个解密后得到PE的点)

目标行为
读取对应的注册表和收集cookie保存在某个txt上传

远程下载

总结

之前并没有这么分析过,经过这次分析学习到了一些东西

  • 样本关闭ASLR
  • IDA和OD调试对比
  • 断点的一些技巧

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。

文章标题:某远程加载马样本分析学习

本文作者:九世

发布时间:2020-12-18, 11:33:14

最后更新:2020-12-19, 01:02:57

原始链接:http://422926799.github.io/posts/8f916cea.html

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录