Algorithm 版 (精华区)

发信人: Lerry (戒网·学习), 信区: Algorithm
标  题: 第六章——特洛伊木马
发信站: 哈工大紫丁香 (2001年12月07日13:22:14 星期五), 站内信件

特洛伊木马实例及其简单实现
  这里介绍一个比较阴险的威胁网络安全的方法:特洛伊木马(trojan horse,或tr
ojan)。
第一节 什么是特洛伊木马
  特洛伊木马是一个程序,它驻留在目标计算里。在目标计算机系统启动的时候,自
动启动。然后在某一端口进行侦听。如果在该端口受到数据,对这些数据进行识别,然
后按识别后的命令,在目标计算机上执行一些操作。比如窃取口令,拷贝或删除文件,
或重新启动计算机。
  攻击者一般在入侵某个系统后,想办法将特洛伊拷贝到目标计算机中。并设法运行
这个程序,从而留下后门。以后,通过运行该特洛伊的客户端程序,对远程计算机进行
操作。
  特洛伊木马的一个特点是,它能巧妙地运行在目标计算机系统里,而不容易被发现

  现在有许多这样的程序。如NetCat,Back Orifice,NetBus等等。
Back Orifice
Back Orifice简介
  Back Orifice是Cult of the Dead Cow (cDc)在1998年8月3日发布的。目前的下载
量达到了100,000。许多人都在善意或恶意地使用这个程序。尽管这个程序并不是最优秀
的黑客工具,但由于媒体的炒做,使得这个工具给人么一个很坏的印象。
  Back Orifice被称为“远程管理工具”。它可以附加在别的文件或程序后,也可以
单独运行。它的服务器程序必须在目标计算机上运行之后,才能起到作用。一旦运行后
,用户就不大容易感觉到它的存在。在任务列表里,根本就看不到它。该工具的服务器
运行后,就一直在一个端口侦听从客户机来的命令,根据不同的命令,在目标机器上执
行相应的操作。
Back Orifice的使用
  Back Orifice(以下简称BO)是一个客户机/服务器(C/S)应用程序,其客户机程序
(以下简称BO客户机)可以监视、管理和使用其它网络中运行服务器程序(以下简称BO
服务器)的目标计算机所在的网络资源。基于文本和基于图形的BO客户机是运行在Micr
osoft Windows机器上。当前版本的BO服务器只能在Windows 95/98中运行。
Back Orifice软件包里包括:
bo.txt 软件包说明文档。
plugin.txt 插件编程文档。
boserve.exe Back Orifice服务器自安装程序。
bogui.exe 图形界面的Back Orifice客户机。
boclient.exe 文本界面的Back Orifice客户机。
boconfig.exe 配置BO服务器程序文件名、端口、密码和插件的工具。
melt.exe 对由freeze命令压缩的文档解压缩。
freeze.exe 压缩文档。压缩文档可被metl命令解压缩。
  只要运行BO服务器程序,就可以安装BO服务器了。当BO服务器程序运行时,它安装
BO服务器,然后删除自安装程序。此方法有助于网络环境下的安装:只要BO服务器程序
被复制到Startup目录下就行了(译者注:因为Windows 95/98每次启动时都会运行该目
录下的程序)。因为BO服务器程序在自安装BO服务器后就会删除自已。一旦BO服务器被
安装到一台机器上,它会在每次机器启动时运行。
  需要远程更新Back Orifice时,只要上载新版本的BO服务器程序到远程机上,使用
Process spawn命令运行它。一旦运行,BO服务器程序将自动删除与它将要安装的文件同
名的文件,安装自已(覆盖旧版本),然后在安装目录中运行自己,最后删除BO服务器
程序。
  在安装前,可以配置BO服务器程序的一些参数。如安装后的BO文件名、监听端口、
加密密码,都可以使用boconfig.exe工具配置。如果不进行配置,缺省是监听31337端口
、不使用加密密码(数据包仍然会加密)和以" .exe"文件名安装。
  BO客户机通过加密了的UDP包与BO服务器通讯。要实现成功通讯,BO客户机城建发送
数据到BO服务器监听的端口,而且BO客户机密码必须匹配BO服务器已配置好的密码。
  基于图形和文本的BO客户机都可以通过使用-p选项来设置BO客户机数据包的发送端
口。如果数据包被过滤或者有防火墙屏蔽,就可能需要从一个特别的、不会被过滤和屏
蔽的端口发送。如果UDP连接通讯不能成功,则可能是数据包在发送或回送路径中被过滤
或者屏蔽了。
  从BO客户机向特定的IP地址发送命令即可对BO服务器操作。如果BO服务器无静态IP
地址,则可使用以下方法:
(1) 在基于文本的BO客户机使用sweep或sweeplist命令;
(2) 在基于图形的BO客户机使用"Ping..."对话框;
(3) 设定目标IP如"1.2.3.*"。如果扫描子网列表,当有BO服务器响应时,BO客户机在子
网列表目录中浏览,并显示所匹配的行和子网地址。(译者注:虽然我知道如何使用,
但却无法按原文的内容表达出来。我在以后再作详细说明。)
  以下是在现在版本的Back Orifice中已经实现的命令。在基于图形和基于文本的BO
客户机里有些命令名称不相同,但几乎所有命令的语法格式都是一致的。在基于文本的
BO客户机中输入 "help command"可得到更多关于命令的信息。在基于图形的BO客户机中
有两个参数输入区域,这些参数作为在"Command"列表中所选择的命令的参数。如果未给
出命令所需要的参数,BO服务器将返回"Missing data"(丢失数据)。
Back Orifice命令如下:
(基于图形的BO客户机命令/基于文本的BO客户机命令)
App add/appadd
在TCP端口输出一个基于文本的应用程序。它允许你通过Telnet对话控制基于文本或DOS
的应用程序。
App del/appdel从监听的连接中关闭一个应用程序。
Apps list/applist列出当前监听的连接中的应用程序。
Directory create/md创建目录
Directory list/dir列出文件和目录。如要显示多文件/目录则须使用通配符。
Directory remove/rd删除目录
Export add/shareadd在BO服务器上创建一个“出口”(共享)。被输出(共享)的目录
或驱动器图标不会出现共享图标。
Export delete/sharedel删除一个(共享)“出口”。
Exports list/sharelist列出当前共享名、共享驱动器、共享目录、共享权限和共享密
码。
File copy/copy拷贝文件。
File delete/del删除文件。
File find/find在目录中查找符合条件(支持通配符)的文件。
File freeze/freeze压缩文件。
File melt/melt解压缩文件。
File view/view查看文件内容。
HTTP Disable/httpoff使HTTP服务器失效。
HTTP Enable/httpon使HTTP服务器有效。
Keylog begin/keylog将BO服务器上的击键记录在一个文本文件中,同时还记录执行输入
的窗口名。
Keylog end停止击键记录。基于文本的BO客户机使用"keylog stop"命令。
MM Capture avi/capavi从视频输入设备(如果存在)捕捉视频和音频信号到avi文件中

MM Capture frame/capframe从视频输入设备捕捉一个视频帧到一个位图文件中。
MM Capture screen/capscreen捕捉BO服务器屏幕影像到一们位图文件中。
MM List capture devices/listcaps列出视频输入设备。
MM Play sound/sound在BO服务器上播放一个avi文件。
Net connections/netlist列出当前接入和接出的连接。
Net delete/netdisconnect断开BO服务器的一个网络资源连接。
Net use/netconnect把BO服务器连接到一个网络资源。
Net view/netview查看BO服务器上所有的网络接口、域名、服务器和可见的共享“出口
”。
Ping host/pingPing主机。返回主机名和BO版本。
Plugin execute/pluginexec运行BO插件。运行不符合BO插件接口的函数可能使B)服务
器当机。
Plugin kill/pluginkill命令一个插件关闭。
Plugins list/pluginlist列出当前激活的插件和已存在的插件返回值。
Process kill/prockill终止一个进程。
Process list/proclist列出运行中的进程。
Process spawn/procspawn运行一个程序。在基于图形的BO客户机程序中,如果需要确定
第二个参数,进程可能以一个正常的、可见的方式运行,否则进程的运行将是隐蔽或独
立的。
Redir add/rediradd重定向接入的TCP连接或UDP数据包到另一个IP地址。
Redir del/redirdel停止端口重定向。
Redir list/redirlist列出激活的端口重定向。
Reg create key/regmakekey在注册表中创建中一个主键。
注:对于所有的注册表命令,不要在注册表键值前加入前导"\\"。
Reg delete key/regdelkey从注册表中删除一个主键。
Reg delete value/regdelval删除注册表中的一个键值。
Reg list keys/reglistkeys列出注册表中一个主键下的子键。
Reg list values/reglistvals列出注册表中一个主键的键值。
Reg set value/regsetval设置注册表一个主键的一个键值。键值格式为“类型,值”。
对于二进制值(类型为B),值是一个两位的16进制数;对于DWORD(双字)值(类型为
D),值是一个十进制数;对于字符串值(类型为S),值是一个文本串。
Resolve host/resolve解析BO服务器的主机名的IP地址。主机名可能是一个Internet主
机名或本地网络机器名。
System dialogbox/dialog用所给出的文本和一个"OK"按钮,
在BO服务器上创建一个对话框。可以创建任意多的对话框,对话框的显示是堆叠式的。

System info/info显示BO服务器上的系统信息。包括机器名、当前用户、CPU类型、内存
容量及可用内存、Windows版本、驱动器信息(类型(硬盘、CDROM、可拆卸型、远程驱
动器)、硬盘驱动器容量及未使用空间)。
System lockup/lockup锁住BO服务器机器。
System passwords/passes显示被缓存的当前用户密码和屏幕保护密码。所显示的密码中
可能含有一些无用信息。(译者注:如果密码未被系统缓存,则不能显示密码。)
System reboot/reboot关闭BO服务器主机并重启动。
TCP file receive/tcprecv将BO服务器主机连接到一个特定的IP地址和端口,并保存所
接收到的数据到特定文件中。
TCP file send/tcpsend将BO服务器主机连接到一个特定的IP地址和端口,发送特定文件
中的内容,然后断开此连接。
注:对于TCP文件传输,必须监听特定的IP地址和端口,直到TCP文件命令被发送,否则
传输将会失败。
从BO服务器传输文件,可使用TCP文件发送命令和如下格式的netcat命令:
netcat -l -p 666 > file
传输文件到BO服务器,可使用TCP文件接收命令和如下格式的netcat命令:
netcat -l -p 666 < file
注:Win32版本的netcat命令在到达输入文件末部时并不断开连接。因此应在文件内容传
输完毕后用ctrl-c或ctrl-break终止netcat命令。
BOConfig:
  BOConfig.exe允许在BO服务器安装前配置一些可选项。首先询问BO服务器在系统目
录中安装的可执行文件名。它不一定是.exe,但如果你不给出扩展名,它不会自动添加
.exe扩展名;接着询问exe文件的描述,它描述了在注册表中记录的、系统启动时运行的
exe文件;接着询问BO服务器监听(数据包)端口;接着询问用于加密的密码。要实现B
O客户机到BO服务器的通讯,客户机必须配置有相同的密码,此密码可以为空;接着询问
启动时缺省运行的插件。这个在BO服务器启动时自动运行的BO插件是以"DLL:_Function
"格式定义的DLL和函数。此项可以为空;然后让你输入启动时传送给插件的参数,此项
也可以为空;最后,询问被附加到BO服务器上的文件的路径。该文件将在BO服务器启动
时写入系统目录。此文件可以是一个自动启动的BO插件。
  BO服务器在没有进行配置时也能运行。缺省地,安装BO服务器文件名为" .exe",无
密码,使用端口31337通讯。
已知的Bugs和问题:
  多媒体捕捉屏幕——所产生的位图是按BO服务器端的显示分辨率和像素深度保存的
。因此,它可能是16位或24位颜色的。大多数图形应用程序只能处理8位或32位位图,因
而不能打开此位图,或者显示不正常(此类软件包括Graphics Workshop for Windows、
Photoshop和WANG Imaging distributed with Windows)。但是,Windows本身有一个应
用程序Paint.exe可以浏览这些位图,按其提示操作即可。
  击键记录——很显然,MS-DOS窗口未提供信息循环机制,这就使得BO无法记录输入
到其中的击键。
  基于文本的应用程序的TCP重定向——有几个Bugs。
当用command.com的重定向名柄输出command.com时,系统同时输出REDIR32.EXE,此程序
似乎是无法终止的。这可能是由于操作系统接口与一个tsr模块(该模块在DOS对话中被
装载以重定向输入/输出句柄)通讯所造成的。因此,如果在应用程序被终止(或退出)
前终止TCP连接,REDIR32.exe和WINOA386.MOD(用于封装管理旧16位应用程序)将仍然
运行,BO和操作系统均无法终止它们。这会导致系统显示"Please wait..."(请等待)
屏幕且无法关机。
  某些控制台应用程序重定向了输出时也可能会发生问题,如FTP.exe和boclient.ex
e。虽然程序的输出因此而不能传送出去,但仍然可能传送输入,所以你要通过TCP对话
使该程序退出。否则使用BO杀死该进程。
Back Orifice的检查和清除
  打开注册表编辑器,检查HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Curr
entVersion\RunServices主键的键值。如果你在主键看到的如下的一个键值:
Name Data
(缺省) " .exe" (一个空格,一个点号和exe后缀)
  那么你可能已经感染上了Back Orifice了。然后在C:\WINDOWS\SYSTEM目录下,如果
发现一个" .exe"文件,文件大小为122K左右,那么你肯定感染了这个程序了。
  清除的方法很简单。首先将上述主键中的有关" .exe"的项目删除,然后重新启动计
算机。接着,将C:\WINDOWS\SYSTEM下的" .exe"删除,最后,找一个叫WINDLL.DLL的文
件,也将它删除。
  注意,有可能你的系统里有好几个Back Orifice的拷贝,要逐一清除。
NetBus
  Netbus 是一个类似于著名的 Back Orifice 的黑客软件,区别在于它的能力要强出
太多。Netbus 通过 TCP/IP 协议,可以远程将应用程序指派到某一套接字端口来运行。
这就相当于说可以远程运行目标机器上的 cmd.exe,想想这是多么危险的事情。
  如果不是 the Cult of the Dead Cow 黑客组织在1998年的 DefCon 大会上发布 B
ackOrifice 工具而引起轩然大波的话,可能大多数人还不会注意到三月份发行的 Netb
us。据说 Netbus 是瑞典程序员 Carl-Fredrik Neikter 为了“和朋友们消遣”而编写
的。
  粗粗一看,Netbus 似乎没什么危害,只允许黑客控制鼠标,播放声音文件,甚或打
开 CD-ROM 托架。但如果深入分析,就不难发现其中大量的破坏性功能,特别它是基于
 TCP/IP 协议在 Windows 95、Windows 98、和 Windows NT 上运行的(与 BackOrific
e 不同),这大大增加了各种入侵用户系统的可能性。
  Netbus 1.6 版能实现一些相当危险的操作:黑客能够运行远程程序,进行屏幕抓图
,在所侵入的计算机浏览器中打开 URL,显示位图,进行服务器管理操作(如更改口令
),甚至利用远端的麦克风录制一段声音。更可怕的是:它能在侵入的计算机上显示信
息,向毫无戒心的用户提示输入口令,再把该口令返回到入侵者的屏幕上。Netbus 还能
关闭 Windows 系统,下载、上载或删除文件。
  11 月 14 日发行 的 Netbus 1.7 新增了更多不正当的功能。如:重定向功能(Re
direction)使黑客能够控制网络中的第三台机器,从而伪装成内部客户机。这样,即使
路由器拒绝外部地址,只允许内部地址相互通信,黑客也依然可以占领其中一台客户机
并对其它无数台机器进行控制。
  V1.7 甚至还能指派应用软件至某个端口。以前只有 Netcat — 黑客的梦幻工具—
 用于 Unix 和 NT 时才具有这种功能。例如,黑客可以将 cmd.exe 指派至 Telnet po
rt 23,然后 Telnet 进入该机器,从而接管系统的命令提示符。其危险后果不言自明。

  Netbus 的默认状态是在 port 12345 接收指令,在 port 12346 作应答。Telnet 
登录到接收端口就会看到产品名称及版本号,还可以修改口令。Netbus 能通过编辑 pa
tch.ini 配置文件,把 1 到 65535 之间的任意数字指定为端口。当需要绕过防火墙或
路由过滤器时,端口通常就会设为 53(DNS)或 80(HTTP)。
  所有的特洛伊木马都分成两个部分:服务器和客户机。
  V1.7版本的NetBus的服务器的默认文件名是patch.exe。运行这个程序后,它将自己
拷贝到Windows目录下,并从中解开一个叫KeyHook.dll的动态连接库。默认的,它创建
一个主键HKEY_CURRENT_USER\PATCH。并在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\W
indows\CurrentVersion\Run下创建了一个键,它的值是patch.exe文件的路径名。这使
得在每次系统启动时,都能自动运行patch.exe这个程序。除此外,还创建下面两个键:
HKEY_CURRENT_USER\NETBUS和HKEY_CURRENT_USER\NETBUS\Settings
  按照上面的描述,清除方法就自然出来了。
第二节 特洛伊木马的一个简单实现
通过上面的两个实例介绍,基本上就能看出特洛伊木马的工作原理。这里我们仅仅介绍
用Winsock实现的一个客户机程序和一个服务端程序。
这个实例中的服务器在接到客户机的命令后会重新启动计算机。
  可以在这两个程序的基础上,加入一些命令,对目标系统进行一些修改。比如拷贝
文件等等。
  这两个程序是从微软的MSDN上拿下来的,略微作了点增加。在VC++6.0中编译运行的
。注意在连接的时候要加入:wsock32.lib库。
ExitWindowsEx 函数介绍
ExitWindowsEx函数的功能是关闭系统,注销用户和重新启动系统。
它的函数原型是:
BOOL ExitWindowsEx( UINT uFlags, DWORD dwReserved);
第一个参数用来指定操作的类型。
常见的有下面几个:
EWX_POWEROFF:关闭系统及关闭电源。
EWX_REBOOT:重新启动计算机。
EWX_SHUTDOWN:关闭系统,但不关闭电源。
第二个参数可以指定任意值,并没有特定意义。
具体有关在Linux和Windows下进行SOCKET编程的细节,请参见相关章节。
服务器程序:
#include < windows.h>
#include < winsock.h>
#define PORTNUM 5000 // Port number
#define MAX_PENDING_CONNECTS 4 // Maximum length of the queue
// of pending connections
int WINAPI WinMain (
HINSTANCE hInstance, // Handle to the current instance
HINSTANCE hPrevInstance,// Handle to the previous instance
LPTSTR lpCmdLine, // Pointer to the command line
int nCmdShow) // Show state of the window
{
int index = 0, // Integer index
iReturn; // Return value of recv function
char szServerA[100]; // ASCII string
TCHAR szServerW[100]; // UNICODE string
TCHAR szError[100]; // Error message string
SOCKET WinSocket = INVALID_SOCKET, // Window socket
ClientSock = INVALID_SOCKET; // Socket for communicating
// between the server and client
SOCKADDR_IN local_sin, // Local socket address
accept_sin; // Receives the address of the
// connecting entity
int accept_sin_len; // Length of accept_sin
WSADATA WSAData; // Contains details of the Windows
// Sockets implementation
// Initiate Windows Sockets.
if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
{
wsprintf (szError, TEXT("WSAStartup failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
// Create a TCP/IP socket, WinSocket.
if ((WinSocket = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
wsprintf (szError, TEXT("Allocating socket failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
// Fill out the local socket's address information.
local_sin.sin_family = AF_INET;
local_sin.sin_port = htons (PORTNUM);
local_sin.sin_addr.s_addr = htonl (INADDR_ANY);
// Associate the local address with WinSocket.
if (bind (WinSocket,
(struct sockaddr *) &local_sin,
sizeof (local_sin)) == SOCKET_ERROR)
{
wsprintf (szError, TEXT("Binding socket failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (WinSocket);
return FALSE;
}
// Establish a socket to listen for incoming connections.
if (listen (WinSocket, MAX_PENDING_CONNECTS) == SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Listening to the client failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (WinSocket);
return FALSE;
}
accept_sin_len = sizeof (accept_sin);
// Accept an incoming connection attempt on WinSocket.
ClientSock = accept (WinSocket,
(struct sockaddr *) &accept_sin,
(int *) &accept_sin_len);
// Stop listening for connections from clients.
closesocket (WinSocket);
if (ClientSock == INVALID_SOCKET)
{
wsprintf (szError, TEXT("Accepting connection with client failed.")
TEXT(" Error: %d"), WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
for (;;)
{
// Receive data from the client.
iReturn = recv (ClientSock, szServerA, sizeof (szServerA), 0);
// Check if there is any data received. If there is, display it.
if (iReturn == SOCKET_ERROR)
{
wsprintf (szError, TEXT("No data is received, recv failed.")
TEXT(" Error: %d"), WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Server"), MB_OK);
break;
}
else if (iReturn == 0)
{
MessageBox (NULL, TEXT("Finished receiving data"), TEXT("Server"),
MB_OK);
ExitWindowsEx(EWX_REBOOT,0); //restart windows
break;
}
else
{
// Convert the ASCII string to the UNICODE string.
for (index = 0; index < = sizeof (szServerA); index++)
szServerW[index] = szServerA[index];
// Display the string received from the client.
MessageBox (NULL, szServerW, TEXT("Received From Client"), MB_OK);
}
}
// Send a string from the server to the client.
if (send (ClientSock, "To Client.", strlen ("To Client.") + 1, 0)
== SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Sending data to the client failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
}
// Disable both sending and receiving on ClientSock.
shutdown (ClientSock, 0x02);
// Close ClientSock.
closesocket (ClientSock);
WSACleanup ();
return TRUE;
}
  客户端程序:
#include < windows.h>
#include < winsock.h>
#define PORTNUM 5000 // Port number
#define HOSTNAME "localhost" // Server name string
// This should be changed
// according to the server
int WINAPI WinMain (
HINSTANCE hInstance, // Handle to the current instance
HINSTANCE hPrevInstance,// Handle to the previous instance
LPTSTR lpCmdLine, // Pointer to the command line
int nCmdShow) // Show state of the window
{
int index = 0, // Integer index
iReturn; // Return value of recv function
char szClientA[100]; // ASCII string
TCHAR szClientW[100]; // UNICODE string
TCHAR szError[100]; // Error message string
SOCKET ServerSock = INVALID_SOCKET; // Socket bound to the server
SOCKADDR_IN destination_sin; // Server socket address
PHOSTENT phostent = NULL; // Points to the HOSTENT structure
// of the server
WSADATA WSAData; // Contains details of the Windows
// Sockets implementation
// Initiate Windows Sockets.
if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0)
{
wsprintf (szError, TEXT("WSAStartup failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
// Create a TCP/IP socket that is bound to the server.
if ((ServerSock = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
{
wsprintf (szError, TEXT("Allocating socket failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
return FALSE;
}
// Fill out the server socket's address information.
destination_sin.sin_family = AF_INET;
// Retrieve the host information corresponding to the host name.
if ((phostent = gethostbyname (HOSTNAME)) == NULL)
{
wsprintf (szError, TEXT("Unable to get the host name. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (ServerSock);
return FALSE;
}
// Assign the socket IP address.
memcpy ((char FAR *)&(destination_sin.sin_addr),
phostent->h_addr,
phostent->h_length);
// Convert to network ordering.
destination_sin.sin_port = htons (PORTNUM);
// Establish a connection to the server socket.
if (connect (ServerSock,
(PSOCKADDR) &destination_sin,
sizeof (destination_sin)) == SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Connecting to the server failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
closesocket (ServerSock);
return FALSE;
}
// Send a string to the server.
if (send (ServerSock, "To Server.", strlen ("To Server.") + 1, 0)
== SOCKET_ERROR)
{
wsprintf (szError,
TEXT("Sending data to the server failed. Error: %d"),
WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Error"), MB_OK);
}
// Disable sending on ServerSock.
shutdown (ServerSock, 0x01);
for (;;)
{
// Receive data from the server socket.
iReturn = recv (ServerSock, szClientA, sizeof (szClientA), 0);
// Check if there is any data received. If there is, display it.
if (iReturn == SOCKET_ERROR)
{
wsprintf (szError, TEXT("No data is received, recv failed.")
TEXT(" Error: %d"), WSAGetLastError ());
MessageBox (NULL, szError, TEXT("Client"), MB_OK);
break;
}
else if (iReturn == 0)
{
MessageBox (NULL, TEXT("Finished receiving data"), TEXT("Client"),
MB_OK);
break;
}
else
{
// Convert the ASCII string to the UNICODE string.
for (index = 0; index < = sizeof (szClientA); index++)
szClientW[index] = szClientA[index];
// Display the string received from the server.
MessageBox (NULL, szClientW, TEXT("Received From Server"), MB_OK);
}
}
// Disable receiving on ServerSock.
shutdown (ServerSock, 0x00);
// Close the socket.
closesocket (ServerSock);
WSACleanup ();
return TRUE;
}

--
  不在乎天长地久,就怕你从来没有!

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 天外飞仙]
※ 修改:·Lerry 於 12月07日13:28:53 修改本文·[FROM: 天外飞仙]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:208.673毫秒