PLMTool/Packet.cpp

616 lines
19 KiB
C++
Raw Normal View History

2024-02-28 10:20:51 +08:00
#include "Packet.h"
#include <string>
#include <vector>
#include <locale>
#include <codecvt>
#include <thread>
#include "utils/LocalAddr.h"
#include <process.h>
#include <Tlhelp32.h>
#include <tchar.h>
#include <psapi.h>
#include <stdio.h>
#include <STDLIB.H>
#include <WtsApi32.h>
#include <UserEnv.h>
#include <iostream>
#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) {
}
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 = 900; //时间间隔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);
}
bool 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) {
bool isRun = IsProcessRunning(L"EdmServer.exe");
if (!isRun) return; //plm进程不存在就不打印日志
if (dport == m_hbPort || sport == m_hbPort) { //心跳数据
int timeDiff = static_cast<int>(time(nullptr) - GetStartTime());
if (timeDiff > m_intervalTime) { //超时,调用注销脚本
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;
}
}
}
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<std::codecvt_utf8<wchar_t>> 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<std::codecvt_utf8<wchar_t>> converter;
std::wstring uiPath = converter.from_bytes(filePath + "\\UI.exe");
//检测线程
m_checkThread = std::thread([this, uiPath]() {
while (!m_quitFlag) {
int timeDiff = static_cast<int>(time(nullptr) - GetStartTime());
if (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<std::codecvt_utf8<wchar_t>> 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<struct sockaddr_in*>(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<int>(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退出码:"<< *exit_code;
// 终止子进程
TerminateProcess(pi.hProcess, 0);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return result;
}