#include "Packet.h" #include #include #include #include #include #include "utils/LocalAddr.h" #include #include #include #include #include #include #include #include #include #pragma comment(lib, "iphlpapi.lib") #pragma comment(lib, "WtsApi32.lib") #pragma comment (lib,"psapi") #pragma comment(lib,"Userenv.lib") const static int DETERMINE = 1; //确定 const static int CANCEL = 2; //取消 Packet::Packet() : m_hbPort(0) , m_startTime(0) , m_intervalTime(0) , m_adhandle(nullptr) , m_quitFlag(false) //退出标记 , m_isShowToast(false) , m_specialPackCount(0){ } Packet::~Packet() { pcap_close(m_adhandle); m_adhandle = nullptr; if (m_checkThread.joinable()) { m_quitFlag = true; m_checkThread.join(); } } void Packet::Init() { m_hbPort = 1433; //心跳端口 m_startTime = time(nullptr); //当前时间 m_serverIp = "139.159.230.183"; //服务器ip m_intervalTime = 180; //时间间隔5分钟 } //ftp包处理 无用 void Packet::FtpPacketHandler(const struct pcap_pkthdr* header, const u_char* pkt_data) { bool isgetaftp = 0; bool isNeedOutInfo = 1; int head = 54; static std::string user; //用户名 static std::string password; //密码 static int no = 1; //包号 mac_header* mh = (mac_header*)pkt_data; ip_header* ih = (ip_header*)(pkt_data + 14); tcp_header* th = (tcp_header*)(pkt_data + 34); std::string com; for (int i = 0; i < 4; i++) com += (char)pkt_data[54 + i]; std::string info; u_short sport = ntohs(th->sport); //源端口 u_short dport = ntohs(th->dport); //目标端口 if (sport == 20 || sport == 21 || dport == 20 || dport == 21) { if (header->len > 66) { if (com == "USER") { if (!user.length()) user.clear(); isgetaftp = 1; isNeedOutInfo = 0; for (int i = head + 5; pkt_data[i] != 13; i++) { user += (char)pkt_data[i]; } info = "Input USER!"; } else if (com == "PASS") { if (!password.length()) password.clear(); isgetaftp = 1; isNeedOutInfo = 0; for (int i = head + 5; pkt_data[i] != 13; i++) { password += (char)pkt_data[i]; } info = "Input Password!"; } else //if (com == "230 "|| com == "530 "||com == "220 "||com=="331 "||com=="221 ") { isgetaftp = 1; for (int i = head; pkt_data[i] != 13; i++) { info += (char)pkt_data[i]; } } } } if (isgetaftp) { std::cout << "user:" << user << " password:" << password << std::endl; if (isNeedOutInfo) std::cout << "info:" << info << std::endl; } u_char flags = th->th_flags; if (sport == 20 || sport == 21) { std::cout << "SERVER to CLIENT" << std::endl; } else if (dport == 20 || dport == 21) { std::cout << "CLIENT to SERVER" << std::endl; } } bool Packet::CheckKeepAlive(u_char* option) { if (!option) return false; size_t len = strlen((const char*)option); std::cout << len << std::endl; for (int i = 0; i < len; ++i) { printf("%x ", *(option + i)); } printf("\n"); return len >= 4 && *option == 0x1 && *(option + 1) == 0x1 && *(option + 2) == 0x5 && *(option + 3) == 0xa; } void Packet::PacketHandler(u_char* param, const struct pcap_pkthdr* header, const u_char* pkt_data) { Packet* pthis = (Packet*)param; //转换时间 time_t local_tv_sec = header->ts.tv_sec; struct tm* ltime = localtime(&local_tv_sec); char timestr[16] = { 0 }; strftime(timestr, sizeof timestr, "%H:%M:%S", ltime); mac_header* mh = (mac_header*)pkt_data; ip_header* ih = (ip_header*)(pkt_data + 14); tcp_header* th = (tcp_header*)(pkt_data + 34); std::string info; u_short sport = ntohs(th->sport); //源端口 u_short dport = ntohs(th->dport); //目标端口 static int no = 0; //包号 ++no; char result[1024] = { 0 }; sprintf(result,"No.%d %s.%.6d len:%d ", no, timestr, header->ts.tv_usec, header->len); if (mh->type[1] == 0 && mh->type[0] == 8){//08 00 0001 //printf("get an ip packet\n"); if (ih->proto == 0x0006) { strcat_s(result, " TCP "); } else if (ih->proto == 17) { strcat_s(result, " UDP "); } else if (ih->proto == 1) { strcat_s(result, " ICMP "); } else { printf(" %d ", ih->proto); strcat_s(result, " UNKNOW "); } } u_char flags = th->th_flags; if (flags & 0x20) strcat_s(result, "(URG)"); if (flags & 0x10) strcat_s(result, "(ACK)"); if (flags & 0x08) strcat_s(result, "(PSH)"); if (flags & 0x04) strcat_s(result, "(RST)"); if (flags & 0x02) strcat_s(result, "(SYN)"); if (flags & 0x01) strcat_s(result, "(FIN)"); char srcIp[16] = { 0 }, desIp[16] = { 0 }; sprintf_s(srcIp, "%d.%d.%d.%d", ih->saddr.byte1, ih->saddr.byte2, ih->saddr.byte3, ih->saddr.byte4); sprintf_s(desIp, "%d.%d.%d.%d", ih->daddr.byte1, ih->daddr.byte2, ih->daddr.byte3, ih->daddr.byte4); char ipInfo[64] = { 0 }; sprintf(ipInfo," %s(%hu) -> %s(%hu)", srcIp, sport, desIp, dport); //IP和Port strcat_s(result, ipInfo); //char macStr[64] = { 0 }; //strcat_s(result,"MAC ADDR:"); //for (int i = 0; i < 6; i++) { // if (i != 5){ // sprintf(macStr, "%02x:", mh->dest_addr[i]); // strcat_s(result, macStr); // }else { // sprintf(macStr, "%02x", mh->dest_addr[i]); // strcat_s(result, macStr); // } //} //strcat_s(result," -> "); //for (int i = 0; i < 6; i++) { // if (i != 5) { // sprintf(macStr, "%02x:", mh->src_addr[i]); // strcat_s(result, macStr); // }else { // sprintf(macStr, "%02x\n", mh->src_addr[i]); // strcat_s(result, macStr); // } //} //printf(result); pthis->CheckTimeOut(sport,dport,result, header->len); } bool Packet::IsProcessRunning(const std::wstring& processName) { HANDLE hProcessSnap; PROCESSENTRY32 pe32; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { return false; } pe32.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(hProcessSnap, &pe32)) { CloseHandle(hProcessSnap); return false; } do { if (_wcsicmp(pe32.szExeFile, processName.c_str()) == 0) { CloseHandle(hProcessSnap); return true; } } while (Process32Next(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); return false; } void Packet::CheckTimeOut(u_short sport, u_short dport,const std::string& tcpInfoStr,int len) { bool isRun = IsProcessRunning(L"EdmServer.exe"); if (!isRun) return; //plm进程不存在,就不打印日志 if (dport == m_hbPort || sport == m_hbPort) { //心跳数据 int timeDiff = static_cast(time(nullptr) - GetStartTime()); if (timeDiff > m_intervalTime) { //超时,调用注销脚本 if (m_specialPackCount > 0) { LogoutPLM(); LOG(DEBUG) << "Logout PLM end..."; } UpdateStartTime(); } else { static int hbCount = 0; ++hbCount; if (hbCount % 10 == 0) { //每隔10次打印一次 LOG(DEBUG) << tcpInfoStr << " 心跳包," << m_intervalTime - timeDiff << "s后注销客户端..."; hbCount = 0; } } //1.时间在弹窗前的最后两分钟内 m_intervalTime - timeDiff<120s //2.服务端 接收端口1433 长度54 if (m_intervalTime - timeDiff <= 120 ) { if (dport == 1433 && 54 == len) { ++m_specialPackCount; LOG(DEBUG) << "m_specialPackCount:" << m_specialPackCount; } } else { m_specialPackCount = 0; } } else { UpdateStartTime(); static int resetCount = 0; ++resetCount; if (resetCount % 10 == 0) { //每隔10次打印一次 LOG(DEBUG) << tcpInfoStr << " 其他包,重新计时..."; resetCount = 0; } } } INT64 Packet::PopToast() { std::wstring appUserModelID = L"警告"; WinToastLib::WinToast::instance()->setAppName(L"警告"); WinToastLib::WinToast::instance()->setAppUserModelId(appUserModelID); WinToastLib::WinToastTemplate toast(WinToastLib::WinToastTemplate::ImageAndText02); toast.setTextField(L"即将关闭plm客户端...", WinToastLib::WinToastTemplate::FirstLine); char path[MAX_PATH] = { 0 }; GetModuleFileNameA(NULL, path, MAX_PATH); std::string filePath = path; size_t nPos = filePath.find_last_of('\\'); filePath = filePath.substr(0, nPos); std::wstring_convert> converter; std::wstring wstr = converter.from_bytes(filePath + "\\notify.webp"); toast.setImagePath(wstr); toast.addAction(L"确定"); toast.addAction(L"取消"); toast.setScenario(WinToastLib::WinToastTemplate::Scenario::Alarm); //报警 toast.setExpiration(10000); INT64 id = -1; if (WinToastLib::WinToast::instance()->initialize()) { id = WinToastLib::WinToast::instance()->showToast(toast, new MyToastHandler(this)); } return id; } bool Packet::LogoutPLM() { char path[MAX_PATH] = { 0 }; GetModuleFileNameA(NULL, path, MAX_PATH); std::string pathStr = path; size_t pos = pathStr.find_last_of('\\'); path[pos] = '\0'; strcat(path, "\\PDM客户端注销.BAT"); int ret = system(path); LOG(DEBUG) << "Calling the logout script, ErrorCode(128ok):" << ret << ",path:" << path; return true; } void Packet::UserHandleProc(){ char path[MAX_PATH] = { 0 }; GetModuleFileNameA(NULL, path, MAX_PATH); std::string filePath = path; size_t nPos = filePath.find_last_of('\\'); filePath = filePath.substr(0, nPos); std::wstring_convert> converter; std::wstring uiPath = converter.from_bytes(filePath + "\\UI.exe"); //检测线程 m_checkThread = std::thread([this, uiPath]() { while (!m_quitFlag) { int timeDiff = static_cast(time(nullptr) - GetStartTime()); //m_specialPackCount>0表示登录状态,超时,调用注销脚本 if (m_specialPackCount>0 && IsProcessRunning(L"EdmServer.exe") && timeDiff >= m_intervalTime - 10 && timeDiff <= m_intervalTime - 9) { LOG(DEBUG) << "pop ui begin..."; DWORD exit_code = -1; if (WaitUserHandle((LPWSTR)uiPath.data(), &exit_code)) { if (exit_code == DETERMINE) { //确定 LOG(DEBUG) << "点击确定..."; LogoutPLM(); UpdateStartTime(); Sleep(1000); } else if (exit_code == CANCEL) { //取消 UpdateStartTime(); LOG(DEBUG) << "点击取消..."; } else { LOG(DEBUG) << "超时结束..."; LogoutPLM(); UpdateStartTime(); Sleep(1000); } } else { LOG(ERROR) << "UI process create failed..."; } } Sleep(200); } }); } int Packet::Run() { LOG(DEBUG) << "RUN START..."; //char path[MAX_PATH] = { 0 }; //GetModuleFileNameA(NULL, path, MAX_PATH); //std::string filePath = path; //size_t nPos = filePath.find_last_of('\\'); //filePath = filePath.substr(0, nPos); //std::wstring_convert> converter; //std::wstring uiPath = converter.from_bytes(filePath + "\\UI0.exe"); //DWORD exit_code = -1; //WaitUserHandle((LPWSTR)uiPath.data(), &exit_code); UserHandleProc(); char errbuf[PCAP_ERRBUF_SIZE] = { 0 }; pcap_if_t* alldevs; if (pcap_findalldevs_ex((char*)PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1){ LOG(ERROR)<< "Error in pcap_findalldevs_ex:"<< errbuf; return -1; } LocalAddr la; std::string currAdptInfo = la.GetSystemIpAddress(); //获取当前机器的IP地址 if (currAdptInfo.empty()) { LOG(ERROR) << "do not get local ip..."; return -1; } char text[2048] = {0}; int i = 0; pcap_if_t* curDev = nullptr; for (pcap_if_t* dev = alldevs; dev != NULL; dev = dev->next) { char name[128] = { 0 }; sprintf(name,"\n%d. %s ", ++i, dev->name); strcat_s(text, name); if (dev->description) strcat_s(text, dev->description); else strcat_s(text,"(No description available)"); strcat_s(text, "\nIP Address: "); //LOG(DEBUG) << "text:"<< text; pcap_addr_t* addr = nullptr; for (addr = dev->addresses; addr != nullptr; addr = addr->next){ if (addr->addr && addr->addr->sa_family == AF_INET){ struct sockaddr_in* sockaddr = reinterpret_cast(addr->addr); char ip[24] = { 0 }; inet_ntop(AF_INET, &(sockaddr->sin_addr), ip, sizeof(ip)); strcat_s(text, ip); if (currAdptInfo.find(ip) != std::string::npos) { curDev = dev; //选择当前的网络适配器 break; } } } } LOG(DEBUG) << text << ",size:" << strlen(text); if (!curDev) { LOG(ERROR) << "netcord is null..."; return -1; } int ret = 0; u_int netmask =0; do { if ((m_adhandle = pcap_open(curDev->name, 65536, 0 /*PCAP_OPENFLAG_PROMISCUOUS*/, 400, NULL, errbuf)) == NULL) { LOG(ERROR) << "Unable to open the adapter. " << curDev->name << " is not supported by WinPcap"; ret = -1; break; } if (pcap_datalink(m_adhandle) != DLT_EN10MB) { LOG(ERROR) << "This program works only on Ethernet networks."; ret = -1; break; } if (curDev->addresses != NULL) netmask = ((struct sockaddr_in*)(curDev->addresses->netmask))->sin_addr.S_un.S_addr; else netmask = 0xffffff; struct bpf_program fcode; std::string packetFilter = "tcp and ip host " + m_serverIp; //捕获过滤 LOG(DEBUG) << "filter:" << packetFilter; if (pcap_compile(m_adhandle, &fcode, packetFilter.c_str(), 1, netmask) >= 0) { if (pcap_setfilter(m_adhandle, &fcode) < 0) { LOG(ERROR) << "Error setting the filter."; ret = -1; break; } }else { LOG(ERROR) << "Error setting the filter."; ret = -1; break; } } while (false); LOG(DEBUG) << "listening on " << curDev->description <<"..."; pcap_freealldevs(alldevs); if (ret == -1) return ret; pcap_loop(m_adhandle, 0, PacketHandler, (u_char*)this); return 0; } unsigned long Packet::ConvertMaskToULong(const std::string& maskString) { std::istringstream iss(maskString); std::string octet; unsigned long maskULong = 0; while (std::getline(iss, octet, '.')) { unsigned long octetULong = std::stoul(octet); maskULong = (maskULong << 8) | octetULong; } return maskULong; } BOOL Packet::WaitUserHandle(LPWSTR command_line, DWORD* exit_code) { BOOL result = FALSE; PROCESSENTRY32 proc_entry; DWORD session_id; HANDLE hToken = NULL; HANDLE hTokenDup = NULL; LPVOID pEnv = NULL; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snap == INVALID_HANDLE_VALUE) { LOG(ERROR) << "CreateToolhelp32Snapshot() failed:"<< GetLastError(); return result; } ZeroMemory(&proc_entry, sizeof(proc_entry)); proc_entry.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(snap, &proc_entry)) { LOG(ERROR) << "Process32First failed %lu" << GetLastError(); CloseHandle(snap); return result; } do { //找出explorer进程所属用户的sessionID if (_tcsicmp(proc_entry.szExeFile, _T("explorer.exe")) == 0) { DWORD explorer_session_id = 0; if (ProcessIdToSessionId(proc_entry.th32ProcessID, &explorer_session_id)){ session_id = explorer_session_id; break; } } } while (Process32Next(snap, &proc_entry)); CloseHandle(snap); LOG(DEBUG) << "ui process session_id:" << session_id; // 根据sessionID获取Token if (!WTSQueryUserToken(session_id, &hToken)){ LOG(ERROR) << "WTSQueryUserToken error:"<< GetLastError(); CloseHandle(hToken); return result; } //复制新的Token if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup)){ LOG(ERROR) << "DuplicateTokenEx error:"<< GetLastError(); CloseHandle(hToken); return result; } //创建环境信息 if (!CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE)){ LOG(ERROR) << "CreateEnvironmentBlock error:"<< GetLastError(); CloseHandle(hTokenDup); CloseHandle(hToken); return result; } //设置启动参数 ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.lpDesktop = (LPWSTR)_TEXT("winsta0\\default"); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); //开始创建进程 DWORD dwCreateFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; if (!CreateProcessAsUser(hToken, NULL, command_line, NULL, NULL, FALSE, dwCreateFlag, pEnv, NULL, &si, &pi)){ LOG(ERROR) << "CreateProcessAsUser error:" << GetLastError(); } else { result = TRUE; } DestroyEnvironmentBlock(pEnv); CloseHandle(hTokenDup); CloseHandle(hToken); int count = 100; //最多等待10s(100*100) while(count--) { DWORD ret = WaitForSingleObject(pi.hProcess, 100); // 等待子进程退出 if (ret == WAIT_TIMEOUT) { int timeDiff = static_cast(time(nullptr) - GetStartTime()); if (timeDiff < m_intervalTime - 10) { //用户操作了plm系统 *exit_code = CANCEL; break; } } else if (ret == WAIT_OBJECT_0) break; } //获取子进程的退出码 DWORD exitCode = 0; GetExitCodeProcess(pi.hProcess, &exitCode); *exit_code = *exit_code== CANCEL ? *exit_code:exitCode; LOG(DEBUG)<<"子进程ui退出码(1:确定,2:取消):"<< *exit_code; // 终止子进程 TerminateProcess(pi.hProcess, 0); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return result; }