XHtmlTreeTest中的木马dll分析

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

概述

该样本是来自于VirusShare网站提供,于2022年3月15日在VirusTotal上被首次提交。拿到样本时只有一个dll文件,查看其资源节,发现有“XHtmlTreeTest.exe”等字符串信息,经网上搜索后怀疑其是在一个叫XHtmlTreeTest的XML和HTML解析工具上附带的木马dll。

详细分析

从该木马dll(因为该dll的原本名字未知,就先怎么称呼了)的DllMain函数开始分析,其通过sub_1007B390函数获取“kernel32.dll”、“ntdll.dll”,以及“msvcrt.dll”三个dll库的基址。该函数访问进程的ldr链表,遍历其中所有的导入库,并通过访问 LDR_DATA_TABLE_ENTRY 结构体中的DllBase可以获取到dll的基址。

XHtmlTreeTest中的木马dll分析

GetProcAddress2 函数是我自己重命名的,其作用就是通过访问前面获得的导入库基址,然后访问其对应的导出表获得目标函数地址。其中函数最后一个参数就是hash化的函数名,上面sub_1007B390函数的dll库名同样hash化了。此外,该木马dll中DllMain函数里调用的几个自定义函数都加入了大量的花指令混淆,如下图中的 GetProcAddress2 函数所示:

XHtmlTreeTest中的木马dll分析

花指令的特征:加或减 N*dword_100ABxxx 和 N*dword_100ABxxx << M。

发现访问了资源节,用ResourceHack打开看看,发现一个语言未知的项里保存了一个长达0x24000字节的二进制数据。用od调试一下这个dll,该dll获取到该资源后,申请了一个0x24000的空间,并通过memcpy函数拷贝资源的内容到该空间。发现拷贝的内容就是ResourceHack看到的二进制数据。

XHtmlTreeTest中的木马dll分析


XHtmlTreeTest中的木马dll分析


跳过一大堆CreateWindowExW函数后,sub_10072050函数使用密钥”D#PSqwp>oy@S#7dEfvT1uh?XI5X<$kuIz5qEdsD#GbBoy6I+fTJmEH$sG%kSLP_6m“进行扩展。sub_100707E0函数对该资源数据进行解密,此时会发现内存里多了一个叫”Y.dll“的模块。

XHtmlTreeTest中的木马dll分析


对sub_100707E0函数去花后,加密代码如下:

unsigned int __cdecl sub_100707E0(int a1, int a2, unsigned int a3)
{
  v11 = 0;
  v7 = 0;
  for ( i = 0; i < a3; ++i )
  {
    v11 = ( + v11 + 1) % 21765;
    v7 = (v7 + *(unsigned __int8 *)(a1 + v11)) % 21765;
    v10 = *(_BYTE *)(a1 + v11);
    *(_BYTE *)(a1 + v11) = *(_BYTE *)(a1 + v7);
    v4 = v7;
    *(_BYTE *)(a1 + v4) = v10;
    v5 = (*(unsigned __int8 *)(a1 + v7) + *(unsigned __int8 *)(a1 + v11)) % 21765;
    v6 = v5;
    v8 = v6;
    LOBYTE(v4) = *(_BYTE *)(a1 + v8);
    *(_BYTE *)(a2 + i) ^= v4;
    result = i + 1;
  }
  return result;
}

对sub_10070E70函数中仅调用sub_1007BE90函数,sub_1007BE90函数去花后,分析可知其主要是记录前面获得的几个函数地址以及计算出DllRegisterServer函数的地址,其代码如下:

DWORD *__cdecl sub_1007BE90(unsigned __int16 *a1, int a2, int (__cdecl *a3)(int, int, int, int, int), void (__cdecl *a4)(int, _DWORD, int, int), int a5, int a6, int a7, int a8)
{

  v30 = 0;
  if ( !sub_100701B0( a2 , 64) )
    return 0;
  v31 = a1;
  if ( *a1 != 23117)
    return 0;
  if ( !sub_100701B0( a2 , *((_DWORD *)v31 + 15) + 248 ) )
    return 0;
  v22 = (char *)a1 + *((_DWORD *)v31 + 15);
  if ( *(_DWORD *)v22 !=  17744 )
    return 0;
  if ( *((unsigned __int16 *)v22 + 2) != 332 )
    return 0;
  if ( (*((_DWORD *)v22 + 14) & ( 1 != 0 )
    return 0;
  v9 = (int)&v22[ 24 + *((unsigned __int16 *)v22 + 10) ];
  v21 =  v9 ;
  v27 = *((_DWORD *)v22 + 14);
  v32 = 0;
  while ( v32 < (unsigned int)*((unsigned __int16 *)v22 + 3) )
  {
    if ( *(_DWORD *)(v21 + 16) )
      v20 = *(_DWORD *)(v21 + 16) + *(_DWORD *)(v21 + 12) ;
    else
      v20 = v27 + *(_DWORD *)(v21 + 12) ;
    if ( v20 > v30 )
      v30 = v20 ;
    ++v32;
    v21 += 40;
  }
  v10 = &v25[0];
  kernel32_GetNativeSystemInfo(&v10[0]);
  v28 = sub_100703D0( *((_DWORD *)v22 + 20), v26 ) ;
  v11 = sub_100703D0( v30 , v26 );
  if ( v28 != v11 )
    return 0;
  v18 =  4 ;
  v12 =  0x2000 ;
  v29 = VirtualAlloc( *((_DWORD *)v22 + 13) , v28, 4096 ) | v12, v18, a8);
  if ( !v29 )
  {
    v19 = 4 ;
    v13 = 0x2000 ;
    v29 = VirtualAlloc( 0, v28 , 4096 ) | ( v13 ), v19, a8);
    if ( !v29 )
      return 0;
  }
  v14 = kernel32_GetProcessHeap( 8 , 64 );
  v15 = ntdll_RtlAllocateHeap(v14);
  v16 = v15 ;
  v24 = (_DWORD *)( v16 );
  if ( v24 )
  {
    v24[1] = v29;
    v24[5] = ( 0x2000 ) & *((unsigned __int16 *)v22 + 11)) != 0;
    v24[7] = a3;
    v24[8] = VirtualFree;
    v24[9] = a5;
    v24[10] = a6;
    v24[11] = a7;
    v24[13] = a8;
    v24[15] = v26 ;
    if ( sub_100701B0( a2 , *((_DWORD *)v22 + 21) )
      && (v33 = a3( v29, *((_DWORD *)v22 + 21) , 4096 , 4 , a8),
          msvcrt_memcpy(v33,v31,*((_DWORD *)v22 + 21)),*v24 = v33 + *((_DWORD *)v31 + 15),*(_DWORD *)(*v24 + 52) = + v29,
          sub_10076230(a1,a2,v22,&v24[0]))&& ((v23 =*(_DWORD *)(*v24 + 52) - *((_DWORD *)v22 + 13)) == 0 ? (v24[6] = 1) : (v17 = sub_10074F00(&v24[0],v23),v24[6] = v17),
          sub_1006D090(&v24[0])
       && sub_10079BD0(&v24[0])
       && sub_1006E5C0(&v24[0])) )
    {
      if ( *(_DWORD *)(*v24 + 40) )
      {
        if ( v24[5] )
        {
          dword_100AE7E0 = (int (__stdcall *)(_DWORD, _DWORD, _DWORD))(v29);
          v24[4] = 1;
        }
        else
        {
          v24[14] = *(_DWORD *)(*v24 + 40) + v29;
        }
      }
      else
      {
        v24[14] = 0;
      }
      result = v24;
    }
    else
    {
      sub_1006BFA0(v24);
      result = 0;
    }
  }
  else
  {
    VirtualFree(v29,0,0x8000,a8);
    result = 0;
  }
  return result;
}

该木马dll只导出了两个函数,分别是DllRegisterServer函数和DllUnregisterServer函数。该木马dll的DllRegisterServer函数会去调用Y.dll的DllRegisterServer函数。sub_10073000函数的作用就是寻找Y.dll中DllRegisterServer函数的地址。

XHtmlTreeTest中的木马dll分析

使用ollydump把Y.dll从内存中dump下来,用ida静态分析一下。Y.dll中导出函数只有一个DllRegisterServer函数,一个导入函数都没有,看来所有的导入函数都是动态获得的。DllRegisterServer函数里有两个函数,分别是sub_10021D63和sub_10004587。sub_10021D63函数明显是进行了控制流混淆,里面通过各种hash计算,套利多个switch分发。分析了部分分支的逻辑,发现其最后都会通过回调的形式访问Windows API,汇编中表现为”call eax“。所以,想到对Y.dll模块中所有的”call eax“指令下断点。又因为这些分支太多了,一个个下不实际,所以利用ollyscript来下断点。

XHtmlTreeTest中的木马dll分析


所有分支的底层函数示例如下:

XHtmlTreeTest中的木马dll分析


分享一下od下断脚本:

var target
var add1
var add2
var count

ask "输入hex,支持??,hex必须用##,比如查找#B8??00000001db#"
mov target,$RESULT
mov add1,eip
start:

mov add2,add1
mov $RESULT,target
find add2,$RESULT
cmp $RESULT,0
je over
add count,1
mov add1,$RESULT
add add1,1

bp $RESULT
jne start
over:
add count,"次下断"
msg count
ret

经过调试发现,其通过 SHFileOperationW 函数在”C:WindowsSysWOW64“目录下生成一个基于系统时间随机生成名字的子目录,并往该目录创建一个同样随机命名的文件。

XHtmlTreeTest中的木马dll分析


这里说一下 SHFileOperationW 函数的作用,如下:

XHtmlTreeTest中的木马dll分析


其中SHFILEOPSTRUCTA定义如下:

typedef struct _SHFILEOPSTRUCTA {
  HWND         hwnd;
  UINT         wFunc;
  PCZZSTR      pFrom;
  PCZZSTR      pTo;
  FILEOP_FLAGS fFlags;
  BOOL         fAnyOperationsAborted;
  LPVOID       hNameMappings;
  PCSTR        lpszProgressTitle;
} SHFILEOPSTRUCTA, *LPSHFILEOPSTRUCTA;

在od调试时断下,发现有一次 SHFILEOPSTRUCTA结构体中的pFrom指向木马dll的文件路径(这里我重命名该木马dll为virus.dll),pTo则是指向如上图所示的新路径。

XHtmlTreeTest中的木马dll分析


通过CreateProcessW函数调用Regsvr32.exe以安静模式运行将上面创建的文件写入注册表。因为Regsvr32常用于dll注册,那么可以知道其目的就是换个文件名把 该木马dll注册到操作系统里。因为该木马dll是32位的,所以其选择了”C:WindowsSysWOW64“目录。

XHtmlTreeTest中的木马dll分析

image-20220319175122377

不过我在分析时每次调用 SHFileOperationW 去创建文件的时候都失败了,以管理员权限运行也还是一样,不知道是什么原因。进程在反复调用几次SHFileOperationW 失败后就会终止。用rundll32去加载运行,用procmon去观察结果,依然是如此。也尝试过把后缀改为.exe,其结果是无法运行。因为不想硬肝那个控制流混淆,所以分析就到此为止了。


IOC

文件名 19c5b13e2635be7d9931a404ccbbce7015ea2414cc12d24fd27a2ab8ad7bbe3b
MD5 01d91a225f23340268641f2a88eddf7f
SHA1 ec385cf0d5dc90bc2b27d31d217356271368030e
SHA256 19c5b13e2635be7d9931a404ccbbce7015ea2414cc12d24fd27a2ab8ad7bbe3b
文件大小 1,020,928 bytes
文件类型 PE32 executable (DLL) (GUI) Intel 80386, for MS Windows
发现时间 2022-03-15 02:07:01 UTC

end


招新小广告

ChaMd5 Venom 招收大佬入圈

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

欢迎联系[email protected]



XHtmlTreeTest中的木马dll分析

原文始发于微信公众号(ChaMd5安全团队):XHtmlTreeTest中的木马dll分析

版权声明:admin 发表于 2022年4月17日 上午8:00。
转载请注明:XHtmlTreeTest中的木马dll分析 | CTF导航

相关文章

暂无评论

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