File indexing completed on 2024-03-24 17:01:21

0001 /******************************************************************
0002  *
0003  * kdbgwin - Helper application for DrKonqi
0004  *
0005  * This file is part of the KDE project
0006  *
0007  * SPDX-FileCopyrightText: 2010 Ilie Halip <lupuroshu@gmail.com>
0008  *
0009  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0010  *****************************************************************/
0011 
0012 #include "kdbgwin_process.h"
0013 
0014 Process::Process()
0015     : m_bValid(FALSE)
0016 {
0017 }
0018 
0019 // we need debug privileges to open the proces with PROCESS_ALL_ACCESS, and
0020 // to successfully use ReadProcessMemory()
0021 BOOL Process::EnableDebugPrivilege()
0022 {
0023     qCDebug(DRKONQI_LOG) << "Enabling debug privilege";
0024     HANDLE hToken = NULL;
0025 
0026     if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)) {
0027         if (GetLastError() == ERROR_NO_TOKEN) {
0028             if (!ImpersonateSelf(SecurityImpersonation)) {
0029                 qCCritical(DRKONQI_LOG) << "ImpersonateSelf() failed: " << GetLastError();
0030                 return FALSE;
0031             }
0032             if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &hToken)) {
0033                 qCCritical(DRKONQI_LOG) << "OpenThreadToken() #2 failed: " << GetLastError();
0034                 return FALSE;
0035             }
0036         } else {
0037             qCCritical(DRKONQI_LOG) << "OpenThreadToken() #1 failed: " << GetLastError();
0038             return FALSE;
0039         }
0040     }
0041 
0042     LUID luid;
0043     if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
0044         assert(false);
0045         qCCritical(DRKONQI_LOG) << "Cannot lookup privilege: " << GetLastError();
0046         SafeCloseHandle(hToken);
0047         return FALSE;
0048     }
0049 
0050     TOKEN_PRIVILEGES tp;
0051     tp.PrivilegeCount = 1;
0052     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
0053     tp.Privileges[0].Luid = luid;
0054 
0055     if (!AdjustTokenPrivileges(hToken, FALSE, &tp, NULL, (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) {
0056         assert(false);
0057         qCCritical(DRKONQI_LOG) << "Cannot adjust privilege: " << GetLastError();
0058         SafeCloseHandle(hToken);
0059         return FALSE;
0060     }
0061 
0062     SafeCloseHandle(hToken);
0063     return TRUE;
0064 }
0065 
0066 BOOL Process::GetInfo(const char *pid, const char *threadId)
0067 {
0068     qCDebug(DRKONQI_LOG) << "Trying to get info about pid=" << pid;
0069 
0070     DWORD dwPid = DWORD(atoi(pid));
0071     DWORD dwThread = DWORD(atoi(threadId));
0072 
0073     // get handle to the process
0074     HANDLE hProcess = NULL;
0075     hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
0076     assert(hProcess);
0077     if (hProcess == NULL) {
0078         qCCritical(DRKONQI_LOG) << "Cannot open process " << dwPid << ": " << GetLastError();
0079         return m_bValid;
0080     }
0081     m_dwPid = dwPid;
0082     m_hProcess = hProcess;
0083     m_dwThread = dwThread;
0084 
0085     TCHAR procPath[MAX_PATH * 2 + 1] = {0};
0086     GetModuleFileNameEx(hProcess, NULL, procPath, MAX_PATH * 2 + 1);
0087     m_path = QString::fromWCharArray(procPath);
0088 
0089     // we can't get the threads for a single process, so get all system's
0090     // threads, and enumerate through them
0091     HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
0092     if (hSnapshot == INVALID_HANDLE_VALUE) {
0093         qCCritical(DRKONQI_LOG) << "CreateToolhelp32Snapshot() failed: " << GetLastError();
0094         assert(false);
0095         return m_bValid;
0096     }
0097 
0098     // get process threads
0099     THREADENTRY32 te;
0100     ZeroMemory(&te, sizeof(te));
0101     te.dwSize = sizeof(te);
0102     if (Thread32First(hSnapshot, &te)) {
0103         do {
0104             if (te.th32OwnerProcessID == dwPid) {
0105                 qCDebug(DRKONQI_LOG) << "Found thread " << te.th32ThreadID << ", adding to list";
0106 
0107                 HANDLE hThread = NULL;
0108                 hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
0109                 assert(hThread);
0110                 if (hThread == NULL) {
0111                     qCCritical(DRKONQI_LOG) << "Cannot open thread " << te.th32ThreadID << ": " << GetLastError();
0112                     continue;
0113                 }
0114 
0115                 m_threads[te.th32ThreadID] = hThread;
0116                 // we have at least 1 thread, make this valid
0117                 m_bValid = TRUE;
0118             }
0119         } while (Thread32Next(hSnapshot, &te));
0120     }
0121     SafeCloseHandle(hSnapshot);
0122 
0123     assert(m_threads.size() > 0);
0124 
0125     // get process modules
0126     HMODULE hMods[1024];
0127     DWORD cbNeeded = 0;
0128     if (!EnumProcessModules(hProcess, hMods, ArrayCount(hMods), &cbNeeded)) {
0129         qCCritical(DRKONQI_LOG) << "Cannot enumerate modules: " << GetLastError();
0130         return m_bValid;
0131     }
0132     for (size_t i = 0; i < (cbNeeded / sizeof(hMods[0])); i++) {
0133         /*
0134          * In Windows, a wchar_t has 2 bytes; GCC defines wchar_t as int,
0135          * which is 4 bytes; so i can't use TCHAR here; better off using ushort
0136          * and casting when necessary
0137          */
0138         ushort szModName[MAX_PATH];
0139         if (GetModuleFileNameEx(hProcess, hMods[i], (LPTSTR)szModName, MAX_PATH)) {
0140             // QString str = QString::fromUtf16(szModName);
0141             // qCDebug(DRKONQI_LOG) << "Got module: " << str;
0142             // m_modules.push_back(QString::fromUtf16(szModName));
0143             m_modules[QString::fromUtf16(szModName)] = hMods[i];
0144         }
0145     }
0146 
0147     return m_bValid;
0148 }