Home > itblogs > Разрядность ключа «Image File Execution Options».

Разрядность ключа «Image File Execution Options».

January 9th, 2008

Ключ «Image File Execution Options» знаком, наверное, всем кто вынужден тратить много времени на отладку приложений. В частности, с его помощью можно указать системе всегда запускать определённый процесс под отладчиком. В этом же ключе утилита gflags.exe сохраняет выбранные отладочные опции и т.д. За подробностями рекомендую обратиться в Google, там есть много полезного.

Я же хочу остановиться на другой особенности этого ключа. На 64-х битной системе, он, как и большинство других ключей в ветке «HKLM\SOFTWARE», существует в двух экземплярах. 64-х битные приложения используют « HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options», а 32-х битные – «HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options». Пока что всё просто и очевидно. Сложности начинаются, когда целевое приложение написано на .NET и скомпилировано как AnyCPU сборка. Такой .exe запускается как 32-х битный процесс на 32-х разрядной машине и как 64-х битный – на 64-х разрядной системе. Если вы попробуете запустить это приложение под отладчиком, воспользовавшись 64-х битной версией ключа «Image File Execution Options»:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\foobar.exe]
"Debugger"="c:\\dbg\\windbg.exe"

…то у вас ничего не выйдет.

Если же создать точно такое же значение в 32-х разрядной части реестра:

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\foobar.exe]
"Debugger"="c:\\dbg\\windbg.exe"

…то всё заработает как по волшебству. В чём тут дело? Ведь само приложение запускается как 64-х битный процесс?

Все дело в PE заголовке. Если вы помните, AnyCPU сборки указывают x86 в качестве целевой архитектуры в заголовке выполняемого файла. Значение «Debugger» читается родительским процессом, который проверяет PE заголовок запускаемого провеса, чтобы определить какой из ключей «Image File Execution Options» использовать – 32-х или 64-х битный. И в случае AnyCPU эта проверка даёт сбой.

Однако на этом сложности не заканчиваются. Если вы используете другие разрешенные значения, например «GlobalFlags», или пользуетесь утилитой gflags.exe, что, в общем-то, одно и то же, то для AnyCPU сборок вы должны создавать их в 64-х битной версии ключа «Image File Execution Options». В отличие от «Debugger», «GlobalFlags» и другие значения читаются самим процессом, а поскольку процесс 64-х битный, то и читаться они будут из 64-х битного ключа.

Полная схема «участников процесса» выглядит вот так:

  1. Ядро (в недрах NtCreateUserProcess) проверяет наличие ключа «Image File Execution Options» для данного запускаемого файла. При этом проверяется поле «machine» в PE заголовке. В зависимости от результатов проверки открывается 32-х битный или 64-х битный ключ;
  2. Родительский получает описатель открытого ключа из NtCreateUserProcess и если значение «Debugger» присутствует, то в командную строку добавляется команда для вызова отладчика и NtCreateUserProcess вызывается по новой. На этом этапе разрядность проверяемого ключа «Image File Execution Options» по-прежнему определяется полем «machine» в PE заголовке;
  3. Вновь созданный процесс заново открывает ключ «Image File Execution Options» и читает все остальные значения. На этот раз разрядность ключа определяется настоящей разрядностью процесса.

В общем, вот так все непросто.

  1. Alexander
    January 10th, 2008 at 01:13 | #1

    Круто. По сравнению с решением для Unix – скриптом-оберткой, который запускает экзешник под отладчиком – просто круто.

    • January 10th, 2008 at 07:11 | #2

      :-) Есть такое дело. Использование расширений файлов вместо “execution bit” было отличной, замечательной идеей. Но в корне неверной. :-(

Comments are closed.