troj.txt
上传用户:laihaixin
上传日期:2007-01-08
资源大小:34k
文件大小:21k
源码类别:

Internet/网络编程

开发平台:

C/C++

  1. 第九章 特洛伊木马实例及其简单实现
  2.   这里介绍一个比较阴险的威胁网络安全的方法:特洛伊木马(trojan horse,或trojan)。
  3. 第一节 什么是特洛伊木马
  4.   特洛伊木马是一个程序,它驻留在目标计算里。在目标计算机系统启动的时候,自动启动。然后在某一端口进行侦听。如果在该端口受到数据,对这些数据进行识别,然后按识别后的命令,在目标计算机上执行一些操作。比如窃取口令,拷贝或删除文件,或重新启动计算机。
  5.   攻击者一般在入侵某个系统后,想办法将特洛伊拷贝到目标计算机中。并设法运行这个程序,从而留下后门。以后,通过运行该特洛伊的客户端程序,对远程计算机进行操作。
  6.   特洛伊木马的一个特点是,它能巧妙地运行在目标计算机系统里,而不容易被发现。
  7.   现在有许多这样的程序。如NetCat,Back Orifice,NetBus等等。
  8. Back Orifice 
  9. Back Orifice简介
  10.   Back Orifice是Cult of the Dead Cow (cDc)在1998年8月3日发布的。目前的下载量达到了100,000。许多人都在善意或恶意地使用这个程序。尽管这个程序并不是最优秀的黑客工具,但由于媒体的炒做,使得这个工具给人么一个很坏的印象。
  11.   Back Orifice被称为“远程管理工具”。它可以附加在别的文件或程序后,也可以单独运行。它的服务器程序必须在目标计算机上运行之后,才能起到作用。一旦运行后,用户就不大容易感觉到它的存在。在任务列表里,根本就看不到它。该工具的服务器运行后,就一直在一个端口侦听从客户机来的命令,根据不同的命令,在目标机器上执行相应的操作。
  12. Back Orifice的使用
  13.   Back Orifice(以下简称BO)是一个客户机/服务器(C/S)应用程序,其客户机程序(以下简称BO客户机)可以监视、管理和使用其它网络中运行服务器程序(以下简称BO服务器)的目标计算机所在的网络资源。基于文本和基于图形的BO客户机是运行在Microsoft Windows机器上。当前版本的BO服务器只能在Windows 95/98中运行。
  14. Back Orifice软件包里包括:
  15. bo.txt 软件包说明文档。
  16. plugin.txt 插件编程文档。
  17. boserve.exe Back Orifice服务器自安装程序。
  18. bogui.exe 图形界面的Back Orifice客户机。
  19. boclient.exe 文本界面的Back Orifice客户机。
  20. boconfig.exe 配置BO服务器程序文件名、端口、密码和插件的工具。
  21. melt.exe 对由freeze命令压缩的文档解压缩。
  22. freeze.exe 压缩文档。压缩文档可被metl命令解压缩。
  23.   只要运行BO服务器程序,就可以安装BO服务器了。当BO服务器程序运行时,它安装BO服务器,然后删除自安装程序。此方法有助于网络环境下的安装:只要BO服务器程序被复制到Startup目录下就行了(译者注:因为Windows 95/98每次启动时都会运行该目录下的程序)。因为BO服务器程序在自安装BO服务器后就会删除自已。一旦BO服务器被安装到一台机器上,它会在每次机器启动时运行。
  24.   需要远程更新Back Orifice时,只要上载新版本的BO服务器程序到远程机上,使用Process spawn命令运行它。一旦运行,BO服务器程序将自动删除与它将要安装的文件同名的文件,安装自已(覆盖旧版本),然后在安装目录中运行自己,最后删除BO服务器程序。
  25.   在安装前,可以配置BO服务器程序的一些参数。如安装后的BO文件名、监听端口、加密密码,都可以使用boconfig.exe工具配置。如果不进行配置,缺省是监听31337端口、不使用加密密码(数据包仍然会加密)和以" .exe"文件名安装。
  26.   BO客户机通过加密了的UDP包与BO服务器通讯。要实现成功通讯,BO客户机城建发送数据到BO服务器监听的端口,而且BO客户机密码必须匹配BO服务器已配置好的密码。
  27.   基于图形和文本的BO客户机都可以通过使用-p选项来设置BO客户机数据包的发送端口。如果数据包被过滤或者有防火墙屏蔽,就可能需要从一个特别的、不会被过滤和屏蔽的端口发送。如果UDP连接通讯不能成功,则可能是数据包在发送或回送路径中被过滤或者屏蔽了。
  28.   从BO客户机向特定的IP地址发送命令即可对BO服务器操作。如果BO服务器无静态IP地址,则可使用以下方法:
  29. (1) 在基于文本的BO客户机使用sweep或sweeplist命令;
  30. (2) 在基于图形的BO客户机使用"Ping..."对话框;
  31. (3) 设定目标IP如"1.2.3.*"。如果扫描子网列表,当有BO服务器响应时,BO客户机在子网列表目录中浏览,并显示所匹配的行和子网地址。(译者注:虽然我知道如何使用,但却无法按原文的内容表达出来。我在以后再作详细说明。)
  32.   以下是在现在版本的Back Orifice中已经实现的命令。在基于图形和基于文本的BO客户机里有些命令名称不相同,但几乎所有命令的语法格式都是一致的。在基于文本的BO客户机中输入 "help command"可得到更多关于命令的信息。在基于图形的BO客户机中有两个参数输入区域,这些参数作为在"Command"列表中所选择的命令的参数。如果未给出命令所需要的参数,BO服务器将返回"Missing data"(丢失数据)。
  33. Back Orifice命令如下:
  34. (基于图形的BO客户机命令/基于文本的BO客户机命令)
  35. App add/appadd
  36. 在TCP端口输出一个基于文本的应用程序。它允许你通过Telnet对话控制基于文本或DOS的应用程序。
  37. App del/appdel从监听的连接中关闭一个应用程序。
  38. Apps list/applist列出当前监听的连接中的应用程序。
  39. Directory create/md创建目录
  40. Directory list/dir列出文件和目录。如要显示多文件/目录则须使用通配符。
  41. Directory remove/rd删除目录
  42. Export add/shareadd在BO服务器上创建一个“出口”(共享)。被输出(共享)的目录或驱动器图标不会出现共享图标。
  43. Export delete/sharedel删除一个(共享)“出口”。
  44. Exports list/sharelist列出当前共享名、共享驱动器、共享目录、共享权限和共享密码。
  45. File copy/copy拷贝文件。
  46. File delete/del删除文件。
  47. File find/find在目录中查找符合条件(支持通配符)的文件。
  48. File freeze/freeze压缩文件。
  49. File melt/melt解压缩文件。
  50. File view/view查看文件内容。
  51. HTTP Disable/httpoff使HTTP服务器失效。
  52. HTTP Enable/httpon使HTTP服务器有效。
  53. Keylog begin/keylog将BO服务器上的击键记录在一个文本文件中,同时还记录执行输入的窗口名。
  54. Keylog end停止击键记录。基于文本的BO客户机使用"keylog stop"命令。
  55. MM Capture avi/capavi从视频输入设备(如果存在)捕捉视频和音频信号到avi文件中。
  56. MM Capture frame/capframe从视频输入设备捕捉一个视频帧到一个位图文件中。
  57. MM Capture screen/capscreen捕捉BO服务器屏幕影像到一们位图文件中。
  58. MM List capture devices/listcaps列出视频输入设备。
  59. MM Play sound/sound在BO服务器上播放一个avi文件。
  60. Net connections/netlist列出当前接入和接出的连接。
  61. Net delete/netdisconnect断开BO服务器的一个网络资源连接。
  62. Net use/netconnect把BO服务器连接到一个网络资源。
  63. Net view/netview查看BO服务器上所有的网络接口、域名、服务器和可见的共享“出口”。
  64. Ping host/pingPing主机。返回主机名和BO版本。
  65. Plugin execute/pluginexec运行BO插件。运行不符合BO插件接口的函数可能使B)服务器当机。
  66. Plugin kill/pluginkill命令一个插件关闭。
  67. Plugins list/pluginlist列出当前激活的插件和已存在的插件返回值。
  68. Process kill/prockill终止一个进程。
  69. Process list/proclist列出运行中的进程。
  70. Process spawn/procspawn运行一个程序。在基于图形的BO客户机程序中,如果需要确定第二个参数,进程可能以一个正常的、可见的方式运行,否则进程的运行将是隐蔽或独立的。
  71. Redir add/rediradd重定向接入的TCP连接或UDP数据包到另一个IP地址。
  72. Redir del/redirdel停止端口重定向。
  73. Redir list/redirlist列出激活的端口重定向。
  74. Reg create key/regmakekey在注册表中创建中一个主键。
  75. 注:对于所有的注册表命令,不要在注册表键值前加入前导"\"。
  76. Reg delete key/regdelkey从注册表中删除一个主键。
  77. Reg delete value/regdelval删除注册表中的一个键值。
  78. Reg list keys/reglistkeys列出注册表中一个主键下的子键。
  79. Reg list values/reglistvals列出注册表中一个主键的键值。
  80. Reg set value/regsetval设置注册表一个主键的一个键值。键值格式为“类型,值”。对于二进制值(类型为B),值是一个两位的16进制数;对于DWORD(双字)值(类型为D),值是一个十进制数;对于字符串值(类型为S),值是一个文本串。
  81. Resolve host/resolve解析BO服务器的主机名的IP地址。主机名可能是一个Internet主机名或本地网络机器名。
  82. System dialogbox/dialog用所给出的文本和一个"OK"按钮,
  83. 在BO服务器上创建一个对话框。可以创建任意多的对话框,对话框的显示是堆叠式的。
  84. System info/info显示BO服务器上的系统信息。包括机器名、当前用户、CPU类型、内存容量及可用内存、Windows版本、驱动器信息(类型(硬盘、CDROM、可拆卸型、远程驱动器)、硬盘驱动器容量及未使用空间)。
  85. System lockup/lockup锁住BO服务器机器。
  86. System passwords/passes显示被缓存的当前用户密码和屏幕保护密码。所显示的密码中可能含有一些无用信息。(译者注:如果密码未被系统缓存,则不能显示密码。)
  87. System reboot/reboot关闭BO服务器主机并重启动。
  88. TCP file receive/tcprecv将BO服务器主机连接到一个特定的IP地址和端口,并保存所接收到的数据到特定文件中。
  89. TCP file send/tcpsend将BO服务器主机连接到一个特定的IP地址和端口,发送特定文件中的内容,然后断开此连接。
  90. 注:对于TCP文件传输,必须监听特定的IP地址和端口,直到TCP文件命令被发送,否则传输将会失败。
  91. 从BO服务器传输文件,可使用TCP文件发送命令和如下格式的netcat命令:
  92. netcat -l -p 666 > file
  93. 传输文件到BO服务器,可使用TCP文件接收命令和如下格式的netcat命令:
  94. netcat -l -p 666 < file
  95. 注:Win32版本的netcat命令在到达输入文件末部时并不断开连接。因此应在文件内容传输完毕后用ctrl-c或ctrl-break终止netcat命令。
  96. BOConfig:
  97.   BOConfig.exe允许在BO服务器安装前配置一些可选项。首先询问BO服务器在系统目录中安装的可执行文件名。它不一定是.exe,但如果你不给出扩展名,它不会自动添加.exe扩展名;接着询问exe文件的描述,它描述了在注册表中记录的、系统启动时运行的exe文件;接着询问BO服务器监听(数据包)端口;接着询问用于加密的密码。要实现BO客户机到BO服务器的通讯,客户机必须配置有相同的密码,此密码可以为空;接着询问启动时缺省运行的插件。这个在BO服务器启动时自动运行的BO插件是以"DLL:_Function"格式定义的DLL和函数。此项可以为空;然后让你输入启动时传送给插件的参数,此项也可以为空;最后,询问被附加到BO服务器上的文件的路径。该文件将在BO服务器启动时写入系统目录。此文件可以是一个自动启动的BO插件。
  98.   BO服务器在没有进行配置时也能运行。缺省地,安装BO服务器文件名为" .exe",无密码,使用端口31337通讯。
  99. 已知的Bugs和问题:
  100.   多媒体捕捉屏幕——所产生的位图是按BO服务器端的显示分辨率和像素深度保存的。因此,它可能是16位或24位颜色的。大多数图形应用程序只能处理8位或32位位图,因而不能打开此位图,或者显示不正常(此类软件包括Graphics Workshop for Windows、Photoshop和WANG Imaging distributed with Windows)。但是,Windows本身有一个应用程序Paint.exe可以浏览这些位图,按其提示操作即可。
  101.   击键记录——很显然,MS-DOS窗口未提供信息循环机制,这就使得BO无法记录输入到其中的击键。
  102.   基于文本的应用程序的TCP重定向——有几个Bugs。
  103. 当用command.com的重定向名柄输出command.com时,系统同时输出REDIR32.EXE,此程序似乎是无法终止的。这可能是由于操作系统接口与一个tsr模块(该模块在DOS对话中被装载以重定向输入/输出句柄)通讯所造成的。因此,如果在应用程序被终止(或退出)前终止TCP连接,REDIR32.exe和WINOA386.MOD(用于封装管理旧16位应用程序)将仍然运行,BO和操作系统均无法终止它们。这会导致系统显示"Please wait..."(请等待)屏幕且无法关机。
  104.   某些控制台应用程序重定向了输出时也可能会发生问题,如FTP.exe和boclient.exe。虽然程序的输出因此而不能传送出去,但仍然可能传送输入,所以你要通过TCP对话使该程序退出。否则使用BO杀死该进程。
  105. Back Orifice的检查和清除
  106.   打开注册表编辑器,检查HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRunServices主键的键值。如果你在主键看到的如下的一个键值:
  107. Name Data
  108. (缺省) " .exe" (一个空格,一个点号和exe后缀)
  109.   那么你可能已经感染上了Back Orifice了。然后在C:WINDOWSSYSTEM目录下,如果发现一个" .exe"文件,文件大小为122K左右,那么你肯定感染了这个程序了。
  110.   清除的方法很简单。首先将上述主键中的有关" .exe"的项目删除,然后重新启动计算机。接着,将C:WINDOWSSYSTEM下的" .exe"删除,最后,找一个叫WINDLL.DLL的文件,也将它删除。
  111.   注意,有可能你的系统里有好几个Back Orifice的拷贝,要逐一清除。
  112. NetBus
  113.   Netbus 是一个类似于著名的 Back Orifice 的黑客软件,区别在于它的能力要强出太多。Netbus 通过 TCP/IP 协议,可以远程将应用程序指派到某一套接字端口来运行。这就相当于说可以远程运行目标机器上的 cmd.exe,想想这是多么危险的事情。 
  114.   如果不是 the Cult of the Dead Cow 黑客组织在1998年的 DefCon 大会上发布 BackOrifice 工具而引起轩然大波的话,可能大多数人还不会注意到三月份发行的 Netbus。据说 Netbus 是瑞典程序员 Carl-Fredrik Neikter 为了“和朋友们消遣”而编写的。 
  115.   粗粗一看,Netbus 似乎没什么危害,只允许黑客控制鼠标,播放声音文件,甚或打开 CD-ROM 托架。但如果深入分析,就不难发现其中大量的破坏性功能,特别它是基于 TCP/IP 协议在 Windows 95、Windows 98、和 Windows NT 上运行的(与 BackOrifice 不同),这大大增加了各种入侵用户系统的可能性。 
  116.   Netbus 1.6 版能实现一些相当危险的操作:黑客能够运行远程程序,进行屏幕抓图,在所侵入的计算机浏览器中打开 URL,显示位图,进行服务器管理操作(如更改口令),甚至利用远端的麦克风录制一段声音。更可怕的是:它能在侵入的计算机上显示信息,向毫无戒心的用户提示输入口令,再把该口令返回到入侵者的屏幕上。Netbus 还能关闭 Windows 系统,下载、上载或删除文件。 
  117.   11 月 14 日发行 的 Netbus 1.7 新增了更多不正当的功能。如:重定向功能(Redirection)使黑客能够控制网络中的第三台机器,从而伪装成内部客户机。这样,即使路由器拒绝外部地址,只允许内部地址相互通信,黑客也依然可以占领其中一台客户机并对其它无数台机器进行控制。 
  118.   V1.7 甚至还能指派应用软件至某个端口。以前只有 Netcat — 黑客的梦幻工具— 用于 Unix 和 NT 时才具有这种功能。例如,黑客可以将 cmd.exe 指派至 Telnet port 23,然后 Telnet 进入该机器,从而接管系统的命令提示符。其危险后果不言自明。 
  119.   Netbus 的默认状态是在 port 12345 接收指令,在 port 12346 作应答。Telnet 登录到接收端口就会看到产品名称及版本号,还可以修改口令。Netbus 能通过编辑 patch.ini 配置文件,把 1 到 65535 之间的任意数字指定为端口。当需要绕过防火墙或路由过滤器时,端口通常就会设为 53(DNS)或 80(HTTP)。 
  120.   所有的特洛伊木马都分成两个部分:服务器和客户机。
  121.   V1.7版本的NetBus的服务器的默认文件名是patch.exe。运行这个程序后,它将自己拷贝到Windows目录下,并从中解开一个叫KeyHook.dll的动态连接库。默认的,它创建一个主键HKEY_CURRENT_USERPATCH。并在HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun下创建了一个键,它的值是patch.exe文件的路径名。这使得在每次系统启动时,都能自动运行patch.exe这个程序。除此外,还创建下面两个键:HKEY_CURRENT_USERNETBUS和HKEY_CURRENT_USERNETBUSSettings
  122.   按照上面的描述,清除方法就自然出来了。
  123. 第二节 特洛伊木马的一个简单实现
  124. 通过上面的两个实例介绍,基本上就能看出特洛伊木马的工作原理。这里我们仅仅介绍用Winsock实现的一个客户机程序和一个服务端程序。
  125. 这个实例中的服务器在接到客户机的命令后会重新启动计算机。
  126.   可以在这两个程序的基础上,加入一些命令,对目标系统进行一些修改。比如拷贝文件等等。
  127.   这两个程序是从微软的MSDN上拿下来的,略微作了点增加。在VC++6.0中编译运行的。注意在连接的时候要加入:wsock32.lib库。
  128. ExitWindowsEx 函数介绍
  129. ExitWindowsEx函数的功能是关闭系统,注销用户和重新启动系统。
  130. 它的函数原型是:
  131. BOOL ExitWindowsEx( UINT uFlags, DWORD dwReserved);
  132. 第一个参数用来指定操作的类型。
  133. 常见的有下面几个:
  134. EWX_POWEROFF:关闭系统及关闭电源。
  135. EWX_REBOOT:重新启动计算机。
  136. EWX_SHUTDOWN:关闭系统,但不关闭电源。
  137. 第二个参数可以指定任意值,并没有特定意义。
  138. 具体有关在Linux和Windows下进行SOCKET编程的细节,请参见相关章节。
  139. 服务器程序:
  140. #include < windows.h> 
  141. #include < winsock.h>
  142. #define PORTNUM 5000 // Port number 
  143. #define MAX_PENDING_CONNECTS 4 // Maximum length of the queue 
  144. // of pending connections
  145. int WINAPI WinMain (
  146. HINSTANCE hInstance, // Handle to the current instance
  147. HINSTANCE hPrevInstance,// Handle to the previous instance
  148. LPTSTR lpCmdLine, // Pointer to the command line
  149. int nCmdShow) // Show state of the window
  150. int index = 0, // Integer index
  151. iReturn; // Return value of recv function
  152. char szServerA[100]; // ASCII string 
  153. TCHAR szServerW[100]; // UNICODE string
  154. TCHAR szError[100]; // Error message string
  155. SOCKET WinSocket = INVALID_SOCKET, // Window socket
  156. ClientSock = INVALID_SOCKET; // Socket for communicating 
  157. // between the server and client
  158. SOCKADDR_IN local_sin, // Local socket address
  159. accept_sin; // Receives the address of the 
  160. // connecting entity
  161. int accept_sin_len; // Length of accept_sin
  162. WSADATA WSAData; // Contains details of the Windows
  163. // Sockets implementation
  164. // Initiate Windows Sockets.
  165. if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0) 
  166. {
  167. wsprintf (szError, TEXT("WSAStartup failed. Error: %d"), 
  168. WSAGetLastError ());
  169. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  170. return FALSE;
  171. }
  172. // Create a TCP/IP socket, WinSocket.
  173. if ((WinSocket = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) 
  174. {
  175. wsprintf (szError, TEXT("Allocating socket failed. Error: %d"), 
  176. WSAGetLastError ());
  177. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  178. return FALSE;
  179. }
  180. // Fill out the local socket's address information.
  181. local_sin.sin_family = AF_INET;
  182. local_sin.sin_port = htons (PORTNUM); 
  183. local_sin.sin_addr.s_addr = htonl (INADDR_ANY);
  184. // Associate the local address with WinSocket.
  185. if (bind (WinSocket, 
  186. (struct sockaddr *) &local_sin, 
  187. sizeof (local_sin)) == SOCKET_ERROR) 
  188. {
  189. wsprintf (szError, TEXT("Binding socket failed. Error: %d"), 
  190. WSAGetLastError ());
  191. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  192. closesocket (WinSocket);
  193. return FALSE;
  194. }
  195. // Establish a socket to listen for incoming connections.
  196. if (listen (WinSocket, MAX_PENDING_CONNECTS) == SOCKET_ERROR) 
  197. {
  198. wsprintf (szError, 
  199. TEXT("Listening to the client failed. Error: %d"),
  200. WSAGetLastError ());
  201. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  202. closesocket (WinSocket);
  203. return FALSE;
  204. }
  205. accept_sin_len = sizeof (accept_sin);
  206. // Accept an incoming connection attempt on WinSocket.
  207. ClientSock = accept (WinSocket, 
  208. (struct sockaddr *) &accept_sin, 
  209. (int *) &accept_sin_len);
  210. // Stop listening for connections from clients.
  211. closesocket (WinSocket);
  212. if (ClientSock == INVALID_SOCKET) 
  213. {
  214. wsprintf (szError, TEXT("Accepting connection with client failed.")
  215. TEXT(" Error: %d"), WSAGetLastError ());
  216. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  217. return FALSE;
  218. }
  219. for (;;)
  220. {
  221. // Receive data from the client.
  222. iReturn = recv (ClientSock, szServerA, sizeof (szServerA), 0);
  223. // Check if there is any data received. If there is, display it.
  224. if (iReturn == SOCKET_ERROR)
  225. {
  226. wsprintf (szError, TEXT("No data is received, recv failed.")
  227. TEXT(" Error: %d"), WSAGetLastError ());
  228. MessageBox (NULL, szError, TEXT("Server"), MB_OK);
  229. break;
  230. }
  231. else if (iReturn == 0)
  232. {
  233. MessageBox (NULL, TEXT("Finished receiving data"), TEXT("Server"),
  234. MB_OK);
  235. ExitWindowsEx(EWX_REBOOT,0); //restart windows
  236. break;
  237. }
  238. else
  239. {
  240. // Convert the ASCII string to the UNICODE string.
  241. for (index = 0; index < = sizeof (szServerA); index++)
  242. szServerW[index] = szServerA[index];
  243. // Display the string received from the client.
  244. MessageBox (NULL, szServerW, TEXT("Received From Client"), MB_OK);
  245. }
  246. // Send a string from the server to the client.
  247. if (send (ClientSock, "To Client.", strlen ("To Client.") + 1, 0)
  248. == SOCKET_ERROR) 
  249. {
  250. wsprintf (szError, 
  251. TEXT("Sending data to the client failed. Error: %d"),
  252. WSAGetLastError ());
  253. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  254. }
  255. // Disable both sending and receiving on ClientSock.
  256. shutdown (ClientSock, 0x02);
  257. // Close ClientSock.
  258. closesocket (ClientSock);
  259. WSACleanup ();
  260. return TRUE;
  261. }
  262.   客户端程序:
  263. #include < windows.h> 
  264. #include < winsock.h>
  265. #define PORTNUM 5000 // Port number
  266. #define HOSTNAME "localhost" // Server name string
  267. // This should be changed
  268. // according to the server
  269. int WINAPI WinMain (
  270. HINSTANCE hInstance, // Handle to the current instance
  271. HINSTANCE hPrevInstance,// Handle to the previous instance
  272. LPTSTR lpCmdLine, // Pointer to the command line
  273. int nCmdShow) // Show state of the window
  274. {
  275. int index = 0, // Integer index
  276. iReturn; // Return value of recv function
  277. char szClientA[100]; // ASCII string 
  278. TCHAR szClientW[100]; // UNICODE string
  279. TCHAR szError[100]; // Error message string
  280. SOCKET ServerSock = INVALID_SOCKET; // Socket bound to the server
  281. SOCKADDR_IN destination_sin; // Server socket address
  282. PHOSTENT phostent = NULL; // Points to the HOSTENT structure
  283. // of the server
  284. WSADATA WSAData; // Contains details of the Windows
  285. // Sockets implementation
  286. // Initiate Windows Sockets. 
  287. if (WSAStartup (MAKEWORD(1,1), &WSAData) != 0) 
  288. {
  289. wsprintf (szError, TEXT("WSAStartup failed. Error: %d"), 
  290. WSAGetLastError ());
  291. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  292. return FALSE;
  293. }
  294. // Create a TCP/IP socket that is bound to the server.
  295. if ((ServerSock = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
  296. {
  297. wsprintf (szError, TEXT("Allocating socket failed. Error: %d"), 
  298. WSAGetLastError ());
  299. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  300. return FALSE;
  301. }
  302. // Fill out the server socket's address information.
  303. destination_sin.sin_family = AF_INET;
  304. // Retrieve the host information corresponding to the host name.
  305. if ((phostent = gethostbyname (HOSTNAME)) == NULL) 
  306. {
  307. wsprintf (szError, TEXT("Unable to get the host name. Error: %d"), 
  308. WSAGetLastError ());
  309. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  310. closesocket (ServerSock);
  311. return FALSE;
  312. }
  313. // Assign the socket IP address.
  314. memcpy ((char FAR *)&(destination_sin.sin_addr), 
  315. phostent->h_addr, 
  316. phostent->h_length);
  317. // Convert to network ordering.
  318. destination_sin.sin_port = htons (PORTNUM); 
  319. // Establish a connection to the server socket.
  320. if (connect (ServerSock, 
  321. (PSOCKADDR) &destination_sin, 
  322. sizeof (destination_sin)) == SOCKET_ERROR) 
  323. {
  324. wsprintf (szError, 
  325. TEXT("Connecting to the server failed. Error: %d"),
  326. WSAGetLastError ());
  327. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  328. closesocket (ServerSock);
  329. return FALSE;
  330. }
  331. // Send a string to the server.
  332. if (send (ServerSock, "To Server.", strlen ("To Server.") + 1, 0)
  333. == SOCKET_ERROR) 
  334. {
  335. wsprintf (szError, 
  336. TEXT("Sending data to the server failed. Error: %d"),
  337. WSAGetLastError ());
  338. MessageBox (NULL, szError, TEXT("Error"), MB_OK);
  339. }
  340. // Disable sending on ServerSock.
  341. shutdown (ServerSock, 0x01);
  342. for (;;)
  343. {
  344. // Receive data from the server socket.
  345. iReturn = recv (ServerSock, szClientA, sizeof (szClientA), 0);
  346. // Check if there is any data received. If there is, display it.
  347. if (iReturn == SOCKET_ERROR)
  348. {
  349. wsprintf (szError, TEXT("No data is received, recv failed.")
  350. TEXT(" Error: %d"), WSAGetLastError ());
  351. MessageBox (NULL, szError, TEXT("Client"), MB_OK);
  352. break;
  353. }
  354. else if (iReturn == 0)
  355. {
  356. MessageBox (NULL, TEXT("Finished receiving data"), TEXT("Client"),
  357. MB_OK);
  358. break;
  359. }
  360. else
  361. {
  362. // Convert the ASCII string to the UNICODE string.
  363. for (index = 0; index < = sizeof (szClientA); index++)
  364. szClientW[index] = szClientA[index];
  365. // Display the string received from the server.
  366. MessageBox (NULL, szClientW, TEXT("Received From Server"), MB_OK);
  367. }
  368. }
  369. // Disable receiving on ServerSock.
  370. shutdown (ServerSock, 0x00);
  371. // Close the socket.
  372. closesocket (ServerSock);
  373. WSACleanup ();
  374. return TRUE;
  375. }