WinXP/Win7/Win8通用shellcode

saucej發表於2014-09-17


轉自http://hi.baidu.com/egodcore/item/c13e67fe197c940fc6dc45f5

眾所周知,在windows xp時代未啟用ASLR(Address space layout randomization,堆疊地址隨機分佈),我們在編寫shellcode可以利用硬編碼法,將地址寫入shellcode,但是這種方法的缺點很明顯--不具備通用性。在xp sp2上能跑起來的,在xp sp3上有可能就執行不了。

因為在windows 7中_PEB_LDR_DATA表和以前的系統有了改變,直接查詢0x08方式在win7下失效,所以要通過遍歷的方法找到Kernel32.dll的基址。

首先我們看PEB的結構

 

ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 SpareBool        : UChar
   +0x004 Mutant           : Ptr32 Void
   +0x008 ImageBaseAddress : Ptr32 Void
   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA
   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
   +0x014 SubSystemData    : Ptr32 Void
   +0x018 ProcessHeap      : Ptr32 Void
   +0x01c FastPebLock      : Ptr32 _RTL_CRITICAL_SECTION
   +0x020 FastPebLockRoutine : Ptr32 Void
   +0x024 FastPebUnlockRoutine : Ptr32 Void
   +0x028 EnvironmentUpdateCount : Uint4B
   +0x02c KernelCallbackTable : Ptr32 Void
   +0x030 SystemReserved   : [1] Uint4B
   +0x034 AtlThunkSListPtr32 : Uint4B
   +0x038 FreeList         : Ptr32 _PEB_FREE_BLOCK
   +0x03c TlsExpansionCounter : Uint4B
   +0x040 TlsBitmap        : Ptr32 Void
   +0x044 TlsBitmapBits    : [2] Uint4B
   +0x04c ReadOnlySharedMemoryBase : Ptr32 Void
   +0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
   +0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
   +0x058 AnsiCodePageData : Ptr32 Void
   +0x05c OemCodePageData  : Ptr32 Void
   +0x060 UnicodeCaseTableData : Ptr32 Void

0x0ch為)PEB_LDR_DATA結構,下面是它的結構

ntdll!_PEB_LDR_DATA
   +0x000 Length           : Uint4B
   +0x004 Initialized      : UChar
   +0x008 SsHandle         : Ptr32 Void
   +0x00c InLoadOrderModuleList : _LIST_ENTRY
   +0x014 InMemoryOrderModuleList : _LIST_ENTRY
   +0x01c InInitializationOrderModuleList : _LIST_ENTRY
   +0x024 EntryInProgress  : Ptr32 Void


其實,LIST_ENTRY就是一雙向連結串列,我們注意看_PEB_LDR_DATA結構這幾項

+0x00c InLoadOrderModuleList : _LIST_ENTRY
+0x014 InMemoryOrderModuleList : _LIST_ENTRY
+0x01c InInitializationOrderModuleList : _LIST_ENTRY

它們指向以下結構_LDR_DATA_TABLE_ENTRY也就是_LDR_MODULE

ntdll!_LDR_DATA_TABLE_ENTRY
   +0x000 InLoadOrderLinks : _LIST_ENTRY
   +0x008 InMemoryOrderLinks : _LIST_ENTRY
   +0x010 InInitializationOrderLinks : _LIST_ENTRY
   +0x018 DllBase          : Ptr32 Void
   +0x01c EntryPoint       : Ptr32 Void
   +0x020 SizeOfImage      : Uint4B
   +0x024 FullDllName      : _UNICODE_STRING
   +0x02c BaseDllName      : _UNICODE_STRING
   +0x034 Flags            : Uint4B
   +0x038 LoadCount        : Uint2B
   +0x03a TlsIndex         : Uint2B
   +0x03c HashLinks        : _LIST_ENTRY
   +0x03c SectionPointer   : Ptr32 Void
   +0x040 CheckSum         : Uint4B
   +0x044 TimeDateStamp    : Uint4B
   +0x044 LoadedImports    : Ptr32 Void
   +0x048 EntryPointActivationContext : Ptr32 Void
   +0x04c PatchInformation : Ptr32 Void

用圖片表示一下上述文字


可以通過遍歷_LDR_MODULE來獲得kernel32.dll的基址,然後再通過字串比較尋找GetProcAddress的地址,隨後就一馬平川了

int main()
{
    __asm{
        push ebp;
        mov esi,fs:0x30;            //PEB
        mov esi, [esi + 0x0C];   //+0x00c Ldr              : Ptr32 _PEB_LDR_DATA
        mov esi, [esi + 0x1C];  //+0x01c InInitializationOrderModuleList : _LIST_ENTRY
next_module:
        mov ebp, [esi + 0x08];
        mov edi, [esi + 0x20];
        mov esi, [esi];
        cmp [edi + 12*2],cl;
        jne next_module;
        mov edi,ebp;
 
        //尋找GetProcAddress地址
        sub esp,100;
        mov ebp,esp;
        mov eax,[edi+3ch];//PE頭
        mov edx,[edi+eax+78h]
        add edx,edi;
        mov ecx,[edx+18h];//函式數量
        mov ebx,[edx+20h];
        add ebx,edi;
search:
        dec ecx;
        mov esi,[ebx+ecx*4];        
        add esi,edi;         
        mov eax,0x50746547;        
        cmp [esi],eax;         
        jne search;
        mov eax,0x41636f72;          
        cmp [esi+4],eax;   
        jne search;
        mov ebx,[edx+24h];
        add ebx,edi;
        mov cx,[ebx+ecx*2];
        mov ebx,[edx+1ch];
        add ebx,edi;
        mov eax,[ebx+ecx*4];
        add eax,edi;
        mov [ebp+76],eax;//eax為GetProcAddress地址
 
        //獲取LoadLibrary地址
        push 0;
        push 0x41797261;
        push 0x7262694c;
        push 0x64616f4c;
        push esp
        push edi
        call [ebp+76]
        mov[ebp+80],eax;
 
        //獲取ExitProcess地址
        push 0;
        push 0x737365;
        push 0x636f7250;
        push 0x74697845;
        push esp;
        push edi;
        call [ebp+76];
        mov [ebp+84],eax;
 
        //載入msvcrt.dll   LoadLibrary("msvcrt")
        push 0;
        push 0x7472;
        push 0x6376736d;
        push esp;
        call [ebp+80];
        mov edi,eax;
 
        //獲取system地址
        push 0;
        push 0x6d65;
        push 0x74737973;
        push esp;
        push edi;
        call [ebp+76];
        mov [ebp+88],eax;
 
        //system("calc")
        push 0;
        push 0x636c6163;
        push esp;
        call [ebp+88];
 
        //ExitProcess
        call [ebp+84];
    }
    return 0;
}

因為寫shellcode的時候沒有考慮堆疊平衡,所以執行shellcode的時候會報錯,所以我們在結束時直接呼叫ExitProcess來關閉程式。

相關文章