
概述
當(dāng)我們?cè)诰帉懸粋(gè)Shellcode Payload時(shí),我們總是擁有無(wú)限的可能性,尤其是在Windows平臺(tái)上。但我們要知道的是,想要編寫高質(zhì)量的Shellcode其實(shí)并非易事,因此我才決定要通過(guò)這篇文章跟大家聊一聊我對(duì)此的看法。就我個(gè)人而言,我比較喜歡用C語(yǔ)言(用Visual Studio編譯源碼)來(lái)完成我的工作。因?yàn)镃語(yǔ)言的源代碼非常優(yōu)美,而且編譯器可以最大程度地優(yōu)化源碼,如果你需要的話,也可以通過(guò)LLVM實(shí)現(xiàn)你自己的代碼混淆器。
為了方便演示,我將以x86 Shellcode作為樣例進(jìn)行講解。當(dāng)然了,你想將其用于x64平臺(tái)也是可以的。
查找基本的DLL
介紹
當(dāng)一個(gè)Shellcode Payload在Windows平臺(tái)中加載之后,第一步就是要定位我們所需要使用到的功能函數(shù)。首先,我們要搜索保存了系統(tǒng)功能函數(shù)的動(dòng)態(tài)鏈接庫(kù)(DLL)。為了實(shí)現(xiàn)這個(gè)目標(biāo),我們將會(huì)使用到多種不同的結(jié)構(gòu)體,請(qǐng)大家往下看。
線程環(huán)境塊(TEB)
TEB是Windows系統(tǒng)用于描述一個(gè)線程所使用到的一種結(jié)構(gòu)。每一個(gè)線程都可以通過(guò)FS寄存器(x86平臺(tái))以及GS寄存器(x86_64平臺(tái))來(lái)訪問(wèn)自己的TEB。TEB的結(jié)構(gòu)如下:
0:000> dt ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer: Ptr32 Void
+0x020ClientId : _CLIENT_ID
+0x028ActiveRpcHandle : Ptr32 Void
+0x02cThreadLocalStoragePointer : Ptr32 Void
+0x030ProcessEnvironmentBlock : Ptr32 _PEB
...
+0xff0 EffectiveContainerId :_GUID
因此,如果你想要訪問(wèn)進(jìn)程環(huán)境塊(PEB)的話,你只需要使用下面這段代碼即可:
PEB* getPeb() {
__asm {
mov eax,fs:[0x30];
}
}
進(jìn)程環(huán)境塊(PEB)
如果TEB提供的是有關(guān)一個(gè)線程的信息,那么PEB提供的就是進(jìn)程本身的信息了。而我們所需要的信息是那些基本的DLL所處的位置。實(shí)際上,當(dāng)Windows在內(nèi)存中加載一個(gè)進(jìn)程時(shí),至少會(huì)映射出兩個(gè)DLL:
1. ntdll.dll:它包含有可以進(jìn)行系統(tǒng)調(diào)用(syscall)的功能函數(shù)。所有以Nt*為前綴的dll文件都可以調(diào)用相應(yīng)的內(nèi)核函數(shù)(以Zw*開(kāi)頭)。
2. kernel32.dll:它是一個(gè)內(nèi)核級(jí)文件,它可以調(diào)用高層的NTDLL函數(shù)。比如說(shuō),kernel32!CreateFileA可以調(diào)用ntdll!NtCreateFileW,而ntdll!NtCreateFileW又可以調(diào)用ntoskrnl!ZwCreateFileW。
在Windows平臺(tái)下,其他的DLL可能已經(jīng)在內(nèi)存中加載了,但是為了方便講解,我們可以假設(shè)目前內(nèi)存中只加載了上述兩個(gè)DLL。
接下來(lái),讓我們一起看一看下面這個(gè)TEB結(jié)構(gòu):
0:000> dt nt!_PEB
+0x000InheritedAddressSpace : UChar
+0x001ReadImageFileExecOptions : UChar
+0x002BeingDebugged : UChar
+0x003BitField : UChar
+0x003ImageUsesLargePages : Pos 0, 1 Bit
+0x003IsProtectedProcess : Pos 1, 1 Bit
+0x003IsImageDynamicallyRelocated : Pos 2, 1 Bit
+0x003SkipPatchingUser32Forwarders : Pos 3, 1 Bit
+0x003IsPackagedProcess : Pos 4, 1 Bit
+0x003IsAppContainer : Pos 5, 1 Bit
+0x003IsProtectedProcessLight : Pos 6, 1 Bit
+0x003IsLongPathAwareProcess : Pos 7, 1 Bit
+0x004 Mutant : Ptr32 Void
+0x008ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
...
+0x25c WaitOnAddressHashTable :[128] Ptr32 Void
你可以看到其中有一個(gè)PEB.BeingDebugged(第4行),這部分信息是IsDebuggerPresent()所要使用到的信息。但有趣的地方就在于上面的PEB.Ldr(第16行),它所對(duì)應(yīng)的結(jié)構(gòu)如下:
0:000> dt nt!_PEB_LDR_DATA
+0x000 Length : Uint4B
+0x004Initialized : UChar
+0x008SsHandle : Ptr32 Void
+0x00cInLoadOrderModuleList : _LIST_ENTRY
+0x014InMemoryOrderModuleList : _LIST_ENTRY
+0x01cInInitializationOrderModuleList : _LIST_ENTRY
+0x024EntryInProgress : Ptr32 Void
+0x028ShutdownInProgress : UChar
+0x02c ShutdownThreadId : Ptr32Void
我們可以看到,PEB.Ldr->In*OrderModuleList(第5、6、7行)都是鏈表結(jié)構(gòu)(LIST_ENTRY),其中包含內(nèi)存中所有已經(jīng)加載的DLL。這三個(gè)鏈表指向的是相同的對(duì)象,但順序不同。我更愿意使用InLoadOrderModuleList,因?yàn)槲铱梢灾苯影阉?dāng)作指針(指向_LDR_DATA_TABLE_ENTRY)來(lái)使用。比如說(shuō),如果你想使用InMemoryOrderModuleList,那么_LDR_DATA_TABLE_ENTRY就直接位于_InMemoryOrderModuleList.Flink-0×10,因?yàn)镮nMemoryOrderModuleList.Flink指向的是下一個(gè)InMemoryOrderModuleList。
|