Как запустить Exe на уровне пользователя с более высокого уровня - PullRequest
4 голосов
/ 12 января 2010

Я бы хотел, чтобы процесс всегда выполнялся на уровне пользователя. Либо когда он запускается установщиком (настраиваемым, а не msi), который запускается как на уровне администратора, либо когда пользователь входит в систему. Оглядываясь вокруг, я не уверен, что это возможно.

Ответы [ 5 ]

2 голосов
/ 06 января 2015

Самый простой способ - это 2 процесса. Один из них - обычный пользователь, и он запускает процесс с повышенными правами / admin. Затем процесс администрирования может использовать IPC, чтобы попросить обычный пользовательский процесс сделать что-то.

Если у вас нет нормального пользовательского процесса, тогда Раймонд Чен документы:

Переход от невыполненного процесса к высокому процессу прост. Вы можете запустить процесс с правами на повышение , передав глагол runas ShellExecute или ShellExecuteEx.

Идти по другому пути сложнее. Во-первых, действительно трудно взломать ваш токен, чтобы правильно удалить природу возвышения. И с другой стороны, даже если бы вы могли это сделать, это не правильно, потому что пользователь без прав доступа может отличаться от пользователя с повышенными правами.

Решение здесь - вернуться в Explorer и попросить Explorer запустить программу для вас. Поскольку Explorer работает как исходный пользователь без прав, программа (в данном случае веб-браузер) будет работать как Bob. Это также важно в том случае, если обработчик файла, который вы хотите открыть, работает как расширение внутри процесса, а не как отдельный процесс, так как в этом случае попытка разрыхления была бы бессмысленной, поскольку в нем не было создано никакого нового процесса. первое место. (И если обработчик файла пытается связаться с существующей неизмененной копией самого себя, из-за UIPI все может закончиться неудачей.)

Хорошо, я знаю, что Маленькие Программы не должны иметь мотивацию, но я не мог с собой поделать. Хватит болтовни. Давайте напишем код. (Помните, что Маленькие Программы мало или совсем не проверяют ошибки, потому что так они и работают.)

#define STRICT
#include <windows.h>
#include <shldisp.h>
#include <shlobj.h>
#include <exdisp.h>
#include <atlbase.h>
#include <stdlib.h>

void FindDesktopFolderView(REFIID riid, void **ppv)
{
 CComPtr<IShellWindows> spShellWindows;
 spShellWindows.CoCreateInstance(CLSID_ShellWindows);

 CComVariant vtLoc(CSIDL_DESKTOP);
 CComVariant vtEmpty;
 long lhwnd;
 CComPtr<IDispatch> spdisp;
 spShellWindows->FindWindowSW(
     &vtLoc, &vtEmpty,
     SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp);

 CComPtr<IShellBrowser> spBrowser;
 CComQIPtr<IServiceProvider>(spdisp)->
     QueryService(SID_STopLevelBrowser,
                  IID_PPV_ARGS(&spBrowser));

 CComPtr<IShellView> spView;
 spBrowser->QueryActiveShellView(&spView);

 spView->QueryInterface(riid, ppv);
}    

void GetDesktopAutomationObject(REFIID riid, void **ppv)
{
 CComPtr<IShellView> spsv;
 FindDesktopFolderView(IID_PPV_ARGS(&spsv));
 CComPtr<IDispatch> spdispView;
 spsv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&spdispView));
 spdispView->QueryInterface(riid, ppv);
}

Функция GetDesktopAutomationObject находит представление папки рабочего стола, а затем запрашивает объект диспетчеризации для представления. Затем мы возвращаем этот объект отправки в форме, запрошенной вызывающей стороной. Этот объект отправки представляет собой ShellFolderView, а интерфейс C ++ для этого - IShellFolderViewDual, поэтому большинство callres запрашивают этот интерфейс, но если вы мазохист, вы можете пропустить двойной интерфейс и напрямую поговорить с IDispatch.

void ShellExecuteFromExplorer(
    PCWSTR pszFile,
    PCWSTR pszParameters = nullptr,
    PCWSTR pszDirectory  = nullptr,
    PCWSTR pszOperation  = nullptr,
    int nShowCmd         = SW_SHOWNORMAL)
{
 CComPtr<IShellFolderViewDual> spFolderView;
 GetDesktopAutomationObject(IID_PPV_ARGS(&spFolderView));
 CComPtr<IDispatch> spdispShell;
 spFolderView->get_Application(&spdispShell);

 CComQIPtr<IShellDispatch2>(spdispShell)
    ->ShellExecute(CComBSTR(pszFile),
                   CComVariant(pszParameters ? pszParameters : L""),
                   CComVariant(pszDirectory ? pszDirectory : L""),
                   CComVariant(pszOperation ? pszOperation : L""),
                   CComVariant(nShowCmd));
}

Функция ShellExecuteFromExplorer запускается при получении объекта автоматизации папки рабочего стола. Мы используем рабочий стол не потому, что он имеет особое значение, а потому, что мы знаем, что он всегда будет там.

Как и в случае представления папки рабочего стола, объект ShellFolderView сам по себе не интересен. Нам это интересно, потому что объект находится в процессе, в котором размещается представление рабочего стола (которое является основным процессом Explorer). Из ShellFolderView мы запрашиваем свойство Application, чтобы мы могли получить доступ к основному объекту Shell.Application, который имеет интерфейс IShellDispatch (и его расширения IShellDispatch2 через IShellDispatch6) в качестве интерфейсов C ++. И именно метод IShellDispatch2 :: ShellExecute - это то, что мы действительно хотим.

И мы вызываем IShellDispatch2 :: ShellExecute с соответствующими параметрами. Обратите внимание, что параметры для IShellDispatch2 :: ShellExecute находятся в другом порядке по сравнению с параметрами для ShellExecute!

Хорошо, давайте поместим это в небольшую программу.

int __cdecl wmain(int argc, wchar_t **argv)
{
 if (argc < 2) return 0;

 CCoInitialize init;
 ShellExecuteFromExplorer(
    argv[1],
    argc >= 3 ? argv[2] : L"",
    argc >= 4 ? argv[3] : L"",
    argc >= 5 ? argv[4] : L"",
    argc >= 6 ? _wtoi(argv[5]) : SW_SHOWNORMAL);

 return 0;
}

Программа принимает обязательный аргумент командной строки, который должен выполняться, будь то программа, документ или URL. Необязательные параметры - это параметры выполняемой вещи, текущий используемый каталог, выполняемая операция и способ открытия окна.

Откройте командную строку с повышенными привилегиями, а затем запустите эту программу различными способами.

  • царапина http://www.msn.com/
    Откройте неровную веб-страницу в веб-браузере пользователя по умолчанию.
  • scratch cmd.exe "" C: \ Users "" 3
    Откройте неограниченную командную строку в C: \ Users, развернуто.
  • scratch C: \ Path \ To \ Image.bmp "" "" edit
    Отредактируйте растровое изображение в редакторе неровных изображений.
1 голос
/ 12 января 2010

Предполагая, что вы знаете, от какого пользователя вы хотите работать, и имеете его пароль, Функция сделает это.

1 голос
/ 13 января 2010

Есть много хакерских способов сделать это (использовать планировщик заданий, внедрить в explorer.exe и т. Д.)

Единственный способ получить правильного пользователя (тот, который запустил вашу программу до повышения прав UAC (это может быть не тот же пользователь, что и у оболочки / «логин» / «владелец сеанса»)), - запустить программу установки два экземпляры самого себя, один «внешний» экземпляр, который не повышен, он в основном просто запускает другой экземпляр, начиная себя с ShellExecute [Ex] с глагола runas. Когда приходит время запустить процесс среднего / низкого уровня, экземпляр с повышенными правами в какой-либо форме IPC указывает внешнему экземпляру запустить новый процесс.

Реализовать боль в шее, я бы порекомендовал просто , а не с галочкой запуска в конце вашего установщика.

1 голос
/ 12 января 2010

Каждый всегда ищет обходной путь.Anyhoo, этот код проекта должен помочь.

0 голосов
/ 14 января 2010

аналогично тому, что сказал Билл, вы также можете использовать API CreateProcessAsUser () для этого.

  1. Сначала используйте LogonUser () и получите токен доступа для пользователя, от которого должен запускаться процесс. Здесь, если пользователь принадлежит к группе администраторов (тогда вы получите разделенный токен, если передадите LOGON_FLAG как LOGON32_LOGON_INTERACTIVE). Поэтому, если вам нужен маркер администратора с повышенными правами, отметьте флаг как LOGON32_LOGON_BATCH.
  2. С токеном, полученным выше, вы можете вызвать CreateProcessAsUser (), передавая командную строку и параметры.
...