Windows patch.exeが管理者権限を要求してしまう

Windows 7/8で patch.exeが権限昇格を要求してきて はまったので覚書

症状

Windows UACの挙動でpatch.exeというファイル名で実行ファイルを作ると

「次の不明な発行元からのプログラムによるこのコンピューターへの変更を許可しますか?」といった権限昇格に関する警告を発します。

patchコマンドって何?

patchコマンドはunixで一般的に使われている差分適用ツールです。

diffを使って差分ファイルを作成し、それをpatchに入力する事で古いファイルを新しいファイルと同じ状態にしてくれたり戻したりできます。

なぜ権限昇格?

この目的であればソースファイル(ユーザの作成したファイル)に変更を適用するだけですので、管理者権限は本来不要です。なぜ権限昇格が発生するのでしょうか?

Windowsには過去に作成されたアプリケーションインストーラをサポートするために、Installer Detection Technologyと呼ばれる、実行した.exeファイルを「ただの実行ファイル」か「なんらかのインストール実行ファイル」かを判定する仕組み Installer Detection Technology が存在しています。

http://technet.microsoft.com/en-us/library/cc709628(WS.10).aspx

ここで、patch.exeはInstaller(Updaterか、Installerの一部のプロセス)と判定されてしまっているのが原因と思われます。

Installer Detection Technologyが動くのは以下の条件の場合のみです。

  1. 32 bit executables
  2. Applications without a requestedExecutionLevel
  3. Interactive processes running as a Standard User with LUA enabled

これらの条件に合致した場合に、リソースなどの細かな検証が行われInstallerか否かを判定しています。細かな条件は不明ですが、ファイル名に’patch’という名前が含まれる場合はInstallerと判定されてしまいます。

#余談ですが、’dispatch.exe’でもダメです(^^;。

対応方法

対応方法はいくつか考えられます。

64bit実行ファイルにするとか、制限ユーザを無効にする、権限昇格してしまう等の対処方法もありますが、ここではInstaller Detection Technologyが動く条件の一つである「requestedExecutionLevelが無い」のを何とかしてやる事にします。

このrequestedExecutionLevelというのは.exeファイルのmanifestに記載する「アプリケーションが必要とする実行権限」の事を言っています。

manifestは.exeとは別のファイルで提供する事ができ、たとえばpatch.exeであれば同じフォルダにあるpatch.exe.manifestというファイルにxmlで記入を行います。

# ただし、このpatch.exe.manifestという名前はlinkerで指定すれば変更する事も可能

manifestの中で要求権限をasInvokerとして明示的に実行者権限とすることで権限昇格がされなくなるため、件の警告が表示されなくなります。

ただ、manifestファイルを別ファイルとして用意すると、patch.exe一個でポータブルに扱えません。もう一工夫して.exeにmanifestを埋め込んでこのファイルを不要にします。

埋め込み方については以下の通り。

http://msdn.microsoft.com/ja-jp/library/ms235591(v=vs.90).aspx

mt.exe –manifest patch.exe.manifest -outputresource:patch.exe;1

# DLLの場合には リソースIDを2にします。

というわけで、長くなりましたが 以下の様なxmlファイルを作成して、mt.exeでmanifestを.exeのリソースに追加してやる事で件の警告は解決する事になります。

<?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="patch.exe"
     type="win32"/>

  <!-- Identify the application security requirements. -->
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel
          level="asInvoker"
          uiAccess="false"/>
        </requestedPrivileges>
       </security>
  </trustInfo>
</assembly>