windows服务中以 管理员权限\普通权限 启动进程

原创文章禁止转载 www.alom.com.cn

管理员权限启动进程

// 管理员权限启动进程
#ifdef UNICODE
MMSYSSHARED_EXPORT bool CreateProcessWithAdmin(const std::wstring& exe, const std::wstring& param, bool show)
#else
MMSYSSHARED_EXPORT bool CreateProcessWithAdmin(const std::string& exe, const std::string& param, bool show)
#endif // UNICODE
{
    HANDLE hToken{ NULL };
    HANDLE hTokenDup{ NULL };
    LPVOID pEnvironment{ NULL };
    bool res{ false };
#ifdef UNICODE
    wchar_t* cmd = (wchar_t*)param.c_str();
#else
    char* cmd = (wchar_t*)param.c_str();
#endif

    do
    {
        if (exe.empty())
        {
            LOG_ERROR("exe is null!");
            break;
        }
        if (!GetTokenWithProcessName(L"explorer.exe", hToken))
        {
            LOG_ERROR("GetTokenWithProcessName Error: %u", GetLastError());
            break;
        }
        // 复制令牌,把调用方有效的所有访问权限给复制后的令牌.
        if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED/*TOKEN_ALL_ACCESS*/, NULL/*&sa*/, SecurityImpersonation, TokenPrimary, &hTokenDup))
        {
            LOG_ERROR("DuplicateTokenEx Error: %u", GetLastError());
            break;
        }
        STARTUPINFO si;
        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
#ifdef UNICODE
        wchar_t desk[]{ TEXT("WinSta0\\Default") };
#else
        char desk[]{ TEXT("WinSta0\\Default") };
#endif
        si.lpDesktop = desk;
        if (show)
        {
            si.wShowWindow = SW_SHOW;
        }
        else
        {
            si.wShowWindow = SW_HIDE;
        }
        si.dwFlags = STARTF_USESHOWWINDOW;
        PROCESS_INFORMATION pi;
        // 检索指定用户的环境变量。然后,可以将此块传递给 CreateProcessAsUser 函数。
        if (!CreateEnvironmentBlock(&pEnvironment, hTokenDup, FALSE))
        {
            LOG_ERROR("CreateEnvironmentBlock Error: %u", GetLastError());
            break;
        }
        // 缺少环境变量时某些依赖环境变量的程序打不开,或者运行不正常。
        if (!CreateProcessAsUser(hTokenDup, exe.c_str(), cmd, NULL, NULL, FALSE
            , NORMAL_PRIORITY_CLASS 
            /*| CREATE_NEW_CONSOLE  */ 
            | CREATE_UNICODE_ENVIRONMENT
            , pEnvironment, NULL, &si, &pi))
        {
            LOG_ERROR("CreateProcessAsUser Error: %u", GetLastError());
            break;
        }
        res = true;
    } while (0);
    // 清理
    if (cmd)
    {
        delete[]cmd;
    }
    if (pEnvironment)
    {
        DestroyEnvironmentBlock(pEnvironment);
    }
    if(hToken)
        CloseHandle(hToken);
    if (hTokenDup)
        CloseHandle(hTokenDup);
    return res;
}


普通用户权限启动进程

// 普通用户权限启动进程
#ifdef UNICODE
bool CreateProcessWithUser(const std::wstring& exePath, const std::wstring& param, bool show)
#else
bool CreateProcessWithUser(const std::string& exePath, const std::string& param, bool show)
#endif // UNICODE
{
    HANDLE hToken = 0;
    HANDLE hNewToken = 0;
    LPVOID pEnvironment{ NULL };
    bool res{ false };
    int l = param.length();
#ifdef UNICODE
    wchar_t* cmd = new wchar_t[l + 1];
    memcpy(cmd, param.c_str(), l * sizeof(wchar_t));
    cmd[l] = 0;
#else
    char* cmd = new char[l + 1];
    memcpy(cmd, param.c_str(), l * sizeof(char));
    cmd[l] = 0;
#endif // UNICODE

    do 
    {
        if (!GetTokenWithProcessName(L"explorer.exe", hToken))
        {
            LOG_ERROR("GetTokenWithProcessName Error: %u", GetLastError());
            break;
        }
        if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL/*&sa*/, SECURITY_MAX_IMPERSONATION_LEVEL, TokenPrimary, &hNewToken))
        {
            LOG_ERROR("DuplicateTokenEx Error: %u", GetLastError());
            break;
        }
        DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS /*| CREATE_NEW_CONSOLE*/ | CREATE_UNICODE_ENVIRONMENT;
        // 检索指定用户的环境变量。然后,可以将此块传递给 CreateProcessAsUser 函数。
        if (!CreateEnvironmentBlock(&pEnvironment, hNewToken, FALSE))
        {
            LOG_ERROR("CreateEnvironmentBlock Error: %u", GetLastError());
            break;
        }
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
#ifdef UNICODE
        wchar_t desktop[] = L"winsta0\\default";
#else
        char desktop[] = "winsta0\\default";
#endif 
        si.lpDesktop = desktop;
        si.dwFlags = STARTF_USESHOWWINDOW;
        if (show)
        {
            si.wShowWindow = SW_SHOW;
        }
        else
        {
            si.wShowWindow = SW_HIDE;
        }
        if (!CreateProcessAsUser(hNewToken, exePath.c_str(), cmd, 0, 0, FALSE, dwCreationFlag, pEnvironment, 0, &si, &pi))
        {
#ifdef UNICODE
            std::string ansicmd = mm::Charset::UnicodeToANSI(cmd);
            std::string ansibat = mm::Charset::UnicodeToANSI(exePath.c_str());
            LOG_ERROR("CreateProcessAsUser error! LastError=%ld, %s, %s", GetLastError(), ansibat.c_str(), ansicmd.c_str());
#else
            LOG_ERROR("CreateProcessAsUser error! LastError=%ld, %s, %s", GetLastError(), exePath.c_str(), cmd.c_str());
#endif // UNICODE
            break;
        }
        res = true;
    } while (0);
    // 清理
    delete[] cmd;
    if (hToken)
    {
        CloseHandle(hToken);
    }
    if (hNewToken) 
    {
        CloseHandle(hNewToken);
    }
    if (pEnvironment)
    {
        DestroyEnvironmentBlock(pEnvironment);
    }
    return res;
}

根据名字查找进程句柄


#ifdef UNICODE
    bool GetTokenWithProcessName(const wchar_t* szName, HANDLE& hToken)
#else
    bool GetTokenWithProcessName(const char* szName, HANDLE& hToken)
#endif // _DEBUG
    {
        // HANDLE hToken{ NULL };
        HANDLE hProcessSnap{ NULL };
        PROCESSENTRY32 pe32{ NULL }; 
        HANDLE hProcess{ NULL };
        bool res{ false };
        do 
        {
            // 多用户模式时任务管理器里可能出现多个explorer
            // 需要先获取当前会话ID,再通过枚举进程,通过比较sessionID进而得到token。
            //DWORD dwSessionId = WTSGetActiveConsoleSessionId();
            //PWTS_PROCESS_INFO ppi = NULL;
            //DWORD dwProcessCount = 0;
            //if (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1, &ppi, &dwProcessCount))
            //{
            //    for (int i = 0; i < dwProcessCount; i++)
            //    {      
            //        if (_wcsicmp(ppi[i].pProcessName, L"explorer.exe") == 0)
            //        {
            //            if (ppi[i].SessionId == dwSessionId)
            //            {
            //                break;
            //            }
            //        }
            //    }
            //    WTSFreeMemory(ppi);
            //}
            hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);       
            if (!hProcessSnap)
            {
                LOG_ERROR("CreateToolhelp32Snapshot error! %d", GetLastError());
                break;
            }
            pe32.dwSize = sizeof(PROCESSENTRY32);
            for (Process32First(hProcessSnap, &pe32); Process32Next(hProcessSnap, &pe32);)
            {
#ifdef UNICODE
                if (_wcsicmp((pe32.szExeFile), szName))
#else
                if (_stricmp((pe32.szExeFile), szName))
#endif // _DEBUG
                    continue;
                hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);
                if (!hProcess)
                {
                    LOG_ERROR("OpenProcess error! %d", GetLastError());
                    break;
                }
                BOOL ret = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken);
                if(!ret)
                {
                    LOG_ERROR("OpenProcess error! %d", GetLastError());
                    break;
                }
                res = true;
                break;
            }
        } while (0);
       
        if (hProcessSnap)
        {
            CloseHandle(hProcessSnap);
        }
        if (hProcess)
        {
            CloseHandle(hProcess);
        }
        return res;
    }
    

CreateToolhelp32Snapshot

获取指定进程的快照,以及这些进程使用的堆、模块和线程。

HANDLE CreateToolhelp32Snapshot(
  [in] DWORD dwFlags,
  [in] DWORD th32ProcessID
)
    1. [in] dwFlags
      要包含在快照中的系统部分。此参数可以是以下一个或多个值。
      TH32CS_INHERIT
      0x80000000
      指示快照句柄是可继承的。

      TH32CS_SNAPALL
      包括系统中的所有进程和线程,以及 th32ProcessID 中指定的进程的堆和模块。等效于指定使用 OR 运算 (‘|’) 组合的TH32CS_SNAPHEAPLIST、TH32CS_SNAPMODULE、TH32CS_SNAPPROCESS和TH32CS_SNAPTHREAD值。

      TH32CS_SNAPHEAPLIST
      0x00000001
      在快照中包括 th32ProcessID 中指定的进程的所有堆。若要枚举堆,请参阅 Heap32ListFirst。

      TH32CS_SNAPMODULE
      0x00000008
      包括在快照中 th32ProcessID 中指定的进程的所有模块。要枚举模块,请参见模块 32First。如果函数失败并ERROR_BAD_LENGTH,请重试该函数,直到成功。
      64 位视窗: 在 32 位进程中使用此标志包括 th32ProcessID 中指定的进程的 32 位模块,而在 64 位进程中使用它包括 64 位模块。若要从 64 位进程中包括 th32ProcessID 中指定的进程的 32 位模块,请使用 TH32CS_SNAPMODULE32 标志。

      TH32CS_SNAPMODULE32
      0x00000010
      从 64 位进程调用时,在快照中包括 th32ProcessID 中指定的进程的所有 32 位模块。此标志可以与TH32CS_SNAPMODULE或TH32CS_SNAPALL组合使用。如果函数失败并ERROR_BAD_LENGTH,请重试该函数,直到成功。

      TH32CS_SNAPPROCESS
      0x00000002
      在快照中包括系统中的所有进程。若要枚举进程,请参阅 Process32First。

      TH32CS_SNAPTHREAD
      0x00000004
      在快照中包括系统中的所有线程。若要枚举线程,请参阅 Thread32First。
      若要标识属于特定进程的线程,请在枚举线程时将其进程标识符与 THREADENTRY32 结构的 th32OwnerProcessID 成员进行比较。

    1. [in] th32ProcessID
      要包含在快照中的进程的进程标识符。此参数可以为零以指示当前进程。当指定TH32CS_SNAPHEAPLIST、TH32CS_SNAPMODULE、TH32CS_SNAPMODULE32或TH32CS_SNAPALL值时,
      将使用此参数。否则,它将被忽略,并且所有进程都包含在快照中。
      如果指定的进程是空闲进程或 CSRSS 进程之一,则此功能将失败,并且最后一个错误代码ERROR_ACCESS_DENIED,
      因为它们的访问限制会阻止用户级代码打开它们。
      如果指定的进程是 64 位进程,而调用方是 32 位进程,则此函数将失败,最后一个错误代码ERROR_PARTIAL_COPY (299)。

参考:

https://docs.microsoft.com/en-us/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以通过以下步骤来获取进程安装路径: 1. 获取进程名 您可以使用Windows API函数如 GetProcessImageFileName() 或 GetModuleFileNameEx() 来获取正在运行的进程的完整路径,例如: ```c++ DWORD pid = GetCurrentProcessId(); char path[MAX_PATH]; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProcess) { if (GetModuleFileNameEx(hProcess, NULL, path, MAX_PATH)) { // 获取到进程完整路径 } CloseHandle(hProcess); } ``` 2. 从注册表中获取安装路径 根据您的应用程序类型,您可以从以下注册表项中查找应用程序的安装路径: - 32位系统下的32位应用程序:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths - 64位系统下的32位应用程序:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\App Paths - 64位系统下的64位应用程序:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths 在这些注册表项下,您可以按照您的应用程序名称和版本号来查找安装路径。例如,如果您的应用程序名称为"myapp.exe",则可以在注册表中查找以下键: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\myapp.exe 然后,从该键值中获取应用程序的安装路径。例如,如果应用程序安装在"C:\Program Files\MyApp"目录下,则该键值可能为: "C:\Program Files\MyApp\myapp.exe" 请注意,您需要以管理员权限运行您的应用程序,才能访问注册表中的这些信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值