如何編寫一段內(nèi)存蠕蟲?
我們怎么寫一段代碼,能夠在程序內(nèi)存里面不停移動(dòng)?就是讓shellcode代碼能在內(nèi)存中不停的復(fù)制自己,并且一直執(zhí)行下去,也就是內(nèi)存蠕蟲。我們要把shellcode代碼偏移出蠕蟲長度再復(fù)制到蠕蟲后面的內(nèi)存中,然后執(zhí)行。
我們在實(shí)現(xiàn)過程中同時(shí)把前面同長度代碼變成\x90,那個(gè)就是蟲子走過的路,最終吃掉所有的內(nèi)存。實(shí)現(xiàn)這個(gè)我們要知道shellcode長度,并且計(jì)算好shellcode每次移動(dòng)的位置是多少。我們的shllcode以調(diào)用printf函數(shù)為例。
1. 寫出printf程序
- #include "stdio.h"
- int main()
- {
- printf("begin\n");
- char *str="a=%d\n";
- __asm{
- mov eax,5
- push eax
- push str
- mov eax,0x00401070
- call eax
- add esp,8
- ret
- }
- return 0;
- }
0×00401070 是我機(jī)子上printf的地址,將自己機(jī)子上的printf地址更換一下就行,還要在最后加一個(gè)ret,因?yàn)閳?zhí)行完shellcode還要回到復(fù)制shellcode的代碼執(zhí)行。
上面匯編轉(zhuǎn)成shellcode形式,shellcode為:
- char shellcode[]="\xB8\x05\x00\x00\x00\x50\xFF\x75\xFC\xB8\x70\x10\x40\x00\xFF\xD0\x83\x**\x08\xc3";
2. 編寫蠕蟲代碼
- insect:mov bl,byte ptr ds:[eax+edx]
- mov byte ptr ds:[eax+edx+20],bl
- mov byte ptr ds:[eax+edx],0x90
- inc edx
- cmp edx,20
- je ee
- jmp insect
- ee: add eax,20
- push eax
- call eax
- pop eax
- xor edx,edx
- jmp insect
shellcode長度是20,假設(shè)數(shù)據(jù)的地址是s,我們把數(shù)據(jù)復(fù)制到地址為s+20處,原來的數(shù)據(jù)變?yōu)?×90,表示數(shù)據(jù)曾經(jīng)來過這里,insect段是用來復(fù)制數(shù)據(jù)用到,復(fù)制了20次,剛剛好把shellcode復(fù)制完。
因?yàn)閟hellcode相當(dāng)于向下移動(dòng)20位,所以我們要把eax加上20,還要把edx恢復(fù)成0,方便下次接著復(fù)制,然后去執(zhí)行我們的shellcode,接著跳轉(zhuǎn)到insect段繼續(xù)執(zhí)行,這是ee段干的事。
inscet和ee段加起來是復(fù)制我們的shellcode到其他地方,然后去執(zhí)行shellcode,然后再復(fù)制,循環(huán)下去。
3. 最終程序
- #include "stdio.h"
- char shellcode[]="\xB8\x05\x00\x00\x00\x50\xFF\x75\xFC\xB8\x70\x10\x40\x00\xFF\xD0\x83\x**\x08\xc3";
- int main()
- {
- printf("begin\n");
- char *str="a=%d\n";
- __asm{
- lea eax,shellcode
- push eax
- call eax
- pop eax
- xor edx,edx
- insect:mov bl,byte ptr ds:[eax+edx]
- mov byte ptr ds:[eax+edx+20],bl
- mov byte ptr ds:[eax+edx],0x90
- inc edx
- cmp edx,20
- je ee
- jmp insect
- ee: add eax,20
- push eax
- call eax
- pop eax
- xor edx,edx
- jmp insect
- }
- return 0;
- }
調(diào)試的時(shí)候找到shellcode位置,一步步調(diào)試能看見shellcode被復(fù)制,原來的轉(zhuǎn)成0×90,并且printf還被執(zhí)行
沒有復(fù)制前:
復(fù)制后:
4. 總結(jié)
我們要先計(jì)算出shellcode的長度,計(jì)算好shellcode每次移動(dòng)的位置是多少,然后寫出復(fù)制程序,并且還要有調(diào)轉(zhuǎn)到復(fù)制后的shellcode首地址程序,執(zhí)行復(fù)制后的shellcode,接著在復(fù)制再執(zhí)行,循環(huán)下去,當(dāng)然在一段內(nèi)存里循環(huán)執(zhí)行也可以,只要找到位置,跳轉(zhuǎn)過去就行