当前位置:网站首页 > 网络安全培训 > 正文

XHtmlTreeTest中的木马dll分析

freebuffreebuf 2022-04-18 339 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的基址。

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

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

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

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

使用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来下断点。


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


分享一下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:\Windows\SysWOW64“目录下生成一个基于系统时间随机生成名字的子目录,并往该目录创建一个同样随机命名的文件。

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

其中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则是指向如上图所示的新路径。

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

image-20220319175122377

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

IOC

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

转载请注明来自网盾网络安全培训,本文标题:《XHtmlTreeTest中的木马dll分析》

标签:dwordunsigneddll文件sub

关于我

欢迎关注微信公众号

关于我们

网络安全培训,黑客培训,渗透培训,ctf,攻防

标签列表