суббота, 3 апреля 2010 г.

О странностях UAC

Много слышал (и не раз видел), как здорово UAC защищает нас от всяких вредоносных программ, злых вирусов, которые так и норовят проникнуть в компьютер, раз пользователь работает с правами администратора. Снизошла на нас благодать Microsoft, сделали они User Access Control, чтобы каждое действия злого вируса сопровождалось запросом, а разрешить ли ему проникать на компьютер со своими злонамеренными целями или не разрешить. Оказывается, не только вируса. Оказывается, не только злонамеренного. Компилирую в Delphi 2010 под Windows 7 старый проект, имя проекта: ArgoInstaller. Компилируется без ошибок, а вот запускаться из-под среды не желает.

Unable to create process: Запрошенная операция требует повышения.
 
Запуск из-под проводника выводит запрос, разрешить ли программе неизвестного издателя внесение изменений на данном компьютере (хотя программа ни сном ни духом, ни в помыслах, никаких изменений вносить не намерена).
 
Сломал голову, искал, что же может быть причиной, пересмотрел все используемые секции initialization в проекте и в используемых компонентах - ничего криминального не нашел.
Поискал в гугле, как бы узнать, какое именно действие программы вызывает страшный диалог, но скорее, задавал вопрос слишком общо, потому что практически во всех найденных ссылках рассказывалось о том, как здорово, что у нас есть UAC или как его выключить совсем. О том, что UAC это здорово, я знаю и без ссылок в гугле, отключать его я не намерен, а вот в
http://msdn.microsoft.com/en-us/library/aa905330.aspx
обнаружилось, в UAC оказывается есть автодетектирование инсталлятора:
"Before a 32 bit process is created, the following attributes are checked to determine whether it is an installer:
•Filename includes keywords such as "install," "setup," and "update.""
•Keywords in the following Versioning Resource fields: Vendor, Company Name, Product Name, File Description, Original Filename, Internal Name, and Export Name.
•Keywords in the side-by-side application manifest embedded in the executable.
•Keywords in specific StringTable entries linked in the executable.
•Key attributes in the resource file data linked in the executable.
•Targeted sequences of bytes within the executable
 
Стоило переименовать проект, как он стал запускаться из-под среды и из проводника без запросов на разрешение внесения изменений.
 
Оказывается, такая проверка включена по умолчанию. Оказывается ее можно отключить. Стоит или не стоит отключать, решать каждому самостоятельно.
 
"Note The User Account Control: Detect application installations and prompt for elevation setting must be enabled for installer detection to detect installation programs. This setting is enabled by default and can be configured using the Security Policy Manager snap-in "
 
И быть внимательнее при выборе имен проектов :)
 
Что интересно, простой проект с формой, сохраненный с тем же именем ArgoInstaller или с именем UpdateSetupInstall, превосходно запустился из-под среды. Видимо, дело еще в
•Targeted sequences of bytes within the executable


потому что оригинальный проект, будучи переименованый в любое имя, содержащее setup, install или update вызывает диалог UAC и невозможность запуска из среды.

Перемудрили наши братья по разуму, с моей точки зрения :)

Upd #1: Наличествует этот же проект, когда-то скомпилированный Delphi 2006, в Windows 7 точно также выдает предупреждение UAC, разрешить ли этой программе внесение изменений. Интересная ситуация: программа скомпилирована с run-time packages и сначала выдается запрос UAC, а потом сообщение о невозможности запуска, так как отсутствует rtl100.bpl, то есть "автообнаружение инсталлятора" производится до анализа доступности DLL для разрешения импортируемых ссылок. Переименование старого Exe-шника в что-то безобидное типа foobar.exe, приводит к сообщению об отсутствии rtl100.bpl. Переименование нового приводит к его благополучному запуску. Переименование в IAmNotAnInstallerOrSetup.exe приводит к выдаче сообщения UAC :)

Upd #2: Понятно, почему сообщения об отсутствующих DLL выдаются после запроса UAC, в MSDN честно пишут, что Installation detection выполняется "Before 32-bit process is created", а разрешения импорта происходит уже после создания процесса. По совету сочувствующих, создал манифест в виде файла рядом с исполняемым модулем, ArgoInstaller.exe.manifest:


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0"
processorArchitecture="X86"
name="ArgoInstaller"
type="win32"/>
<description>Argo database installation application</description>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

При этом манифесте при запуске из Far/проводника сразу выдается сообщение: Запрошенная операция требует повышения, Cannot execute.

Upd#3, помогло включение манифеста в ресурсы приложения. Видимо, файл манифеста рядом с программой и то же содержимое, но в ресурсах - это с точки зрения UAC, две огромные разницы. Вдруг какой-то вредитель файлом манифеста пытается доблестный UAC обмануть и замаскировать коварный setup.

Upd#4
полезная статья по теме: http://blogs.msdn.com/cjacks/archive/2009/06/18/pca-changes-for-windows-7-how-to-tell-us-you-are-not-an-installer-take-2-because-we-changed-the-rules-on-you.aspx


ссылка на решение: http://technet.microsoft.com/en-us/library/dd638326(WS.10).aspx

Upd#5 Ларчик открывается гораздо проще, достаточно убить файл .res старого проекта, вынудить Delphi 2010 его пересоздать, внести туда нужные изменения, например икону проекта, и возможность отладки в среде как по волшебству появляется, и UAC не надоедает.
Благодарю http://www.delphimaster.ru/cgi-bin/forum.pl?n=3&id=1270305381&from=78

7 комментариев:

  1. По-моему, они просто забыли, что защищаются от злоумышленников, а не от инсталляторов. Плохим парням-то не составит труда файл иначе назвать.

    ОтветитьУдалить
  2. В MSDN честно написано:

    "Windows Vista heuristically detects installation programs and requests administrator credentials or administrator approval in order to run with access privileges."

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

    Видимо хеуристика у них срабатывает не всегда правильно, потому что мой подопытный проект мало того, что не пишет в системные каталоги или ключи реестра, он их даже не читает :)

    Проект работает исключительно с базой данных, читает, пишет и считает объекты этой базы.

    ОтветитьУдалить
  3. По поводу манифеста в файле: когда манифест в ресурсах - он применяется безусловно и секция assemblyIdentity может отсутствовать. Когда же манифест лежит отдельным файлом, то assemblyIdentity обязана присутствовать и точно идентифицировать программу. Если там записаны не те параметры, то манифест будет тихо игнорироваться.

    ОтветитьУдалить
  4. Манифест в файле не игнорируется. Он влияет, но странным образом: если в отсутствии манифеста при запуске программы выдается запрос UAC, то при наличии манифеста программа просто отказывается запускаться.

    ОтветитьУдалить
  5. Возможно, это просто игнорирование манифеста как-то скрещивается с эвристикой =)

    Если взять программу при запуске которой эвристика не срабатывает (а значит, не вылазит UAC), то неправильный манифест будет тихо проигнорирован. Приложение запустится, но будет рассматриваться как "старое", как если бы манифеста не было - это можно увидеть в колонке "Виртуализация" Диспетчера Задач. Напротив процесса будет стоять "Да" - что указывает на включение режима совместимости для него.

    Если же там стоит "Нет", то манифест был учтён, и теперь программа рассматривается как играющая по новым правилам, а значит хаки совместимости к ней не применяются.

    ОтветитьУдалить
  6. По поводу "когда манифест в ресурсах - он применяется безусловно и секция assemblyIdentity может отсутствовать. Когда же манифест лежит отдельным файлом, то assemblyIdentity обязана присутствовать и точно идентифицировать программу" - я здорово наврал во второй части.

    Оказывается, поведение в обоих случаях одинаково, а различие, которое я видел, происходило по банальной причине: Windows не проверяет манифест, если время модификации исполняемого файла не менялось с прошлого раза.

    Иными словами, если надо изменить манифест, хранящийся в отдельном файле без перекомпиляции программы, то необходимо также "touch" и самого исполняемого модуля.

    ОтветитьУдалить
  7. Подскажите как обмануть UAC и сделать фатальные изменения незаметно?

    ОтветитьУдалить