UiAccess=trueにして、権限の高いアプリにWindowMessage(WM_xxx)を送る

前提

  • VisualStudio2022 version 17.11.2
  • Windows11 24H2

で実験。

UiAccess=trueとは?

下記のページに書かれてる内容。

Security Considerations for Assistive Technologies

https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-securityoverview

上に書かれてる内容を自分なりにまとめてみると...

  • UiAccessは、支援技術アプリケーション(Assistive technology applications)のためにある機能。
  • 支援技術アプリとは、他のアプリとやり取りして、情報を取得したりするアプリのこと。
  • その構成上、自分自身より高い権限で動くアプリとやり取りする必要がある。
  • UiAccessは、そういうアプリが、高い権限で動くアプリとやり取りするためにある。
  • ⇒UiAccessをtrueにすると、自分自身より高い権限で動くアプリとやり取りできるようになる。

Windowsアプリ開発で、他のアプリに対してなにかするような場合に使うための機能だと理解した。

なにか:WM_Msgやパイプ通信などで情報をget/setしたりすること??(とりあえず今回、権限が高いアプリに対してWM_Msgを送れることは見た)

UiAccess=trueにする方法(C++

C++のプロジェクトの.vcxprojファイルをエディタで開く。

<ItemDefinitionGroup>の中の<Link>の中に、下記を書く。

<UACUiAccess>true</UACUiAccess>

<ItemDefinitionGroup>は、デフォルトでDebugビルド用、Releaseビルド用が作られてるようなので、DebugビルドではUiAccess=false、Releaseではtrue、ということもできる。

下記のように書く。
<!--★ここ!-->の部分がそれ。それ以外はほぼデフォルトのまま。

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <VCProjectVersion>16.0</VCProjectVersion>
    <Keyword>Win32Proj</Keyword>
    <ProjectGuid>{b6b80323-ba5f-498f-8fe6-28e0bfbe4ed6}</ProjectGuid>
    <RootNamespace>WMMessageSender</RootNamespace>
    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v143</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="Shared">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <LanguageStandard>stdcpp17</LanguageStandard>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <UACUiAccess>true</UACUiAccess>                                                                  <!--★ここ!-->
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <SDLCheck>true</SDLCheck>
      <PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <ConformanceMode>true</ConformanceMode>
      <LanguageStandard>stdcpp17</LanguageStandard>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <UACUiAccess>true</UACUiAccess>                                                                  <!--★ここ!-->
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClInclude Include="framework.h" />
    <ClInclude Include="Resource.h" />
    <ClInclude Include="targetver.h" />
    <ClInclude Include="WM_MessageSender.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="WM_MessageSender.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="WM_MessageSender.rc" />
  </ItemGroup>
  <ItemGroup>
    <Image Include="small.ico" />
    <Image Include="WM_MessageSender.ico" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

UiAccess=trueにする方法(C#

C#のプロジェクトに「マニフェスト」を追加する。

C#プロジェクトを右クリック > [追加] > [新しい項目] を選ぶ。

「アプリケーションマニフェストファイル」を選ぶ。

デフォルトのマニフェストファイルが追加される。

デフォではすべての項目がコメントアウトされてるので、UiAccessに関するところだけコメントから出してやる。

<!-- ★ココ --> の部分がそれ。それ以外はほぼデフォルトのまま。

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <!-- UAC マニフェスト オプション
             Windows のユーザー アカウント制御のレベルを変更するには、
             requestedExecutionLevel ノードを以下のいずれかで置換します。

        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />

            requestedExecutionLevel 要素を指定すると、ファイルおよびレジストリの仮想化が無効にされます。
            アプリケーションが下位互換性を保つためにこの仮想化を要求する場合、この要素を
            削除します。
        -->
        <requestedExecutionLevel level="asInvoker" uiAccess="true" />  <!-- ★ココ -->
      </requestedPrivileges>
    </security>
  </trustInfo>

  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- このアプリケーションがテストされ、動作するよう設計された Windows バージョンの
           一覧。適切な要素をコメント解除すると、最も互換性のある環境を Windows が
           自動的に選択します。-->

      <!-- Windows Vista -->
      <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->

      <!-- Windows 7 -->
      <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->

      <!-- Windows 8 -->
      <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->

      <!-- Windows 8.1 -->
      <!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->

      <!-- Windows 10 -->
      <!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->

    </application>
  </compatibility>
    <asmv3:application >
        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <!-- See: https://docs.microsoft.com/en-us/windows/desktop/sbscs/application-manifests#disableWindowFiltering -->
            <disableWindowFiltering xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">true</disableWindowFiltering>
        </asmv3:windowsSettings>
    </asmv3:application>
  <!-- アプリケーションが DPI 対応であり、Windows によってそれ以上の DPI には自動的に拡大縮小されないことを
       示します。Windows Presentation Foundation (WPF) アプリケーションは自動的に DPI に対応し、オプトインする必要は
       ありません。さらに、この設定にオプトインする .NET Framework 4.6 を対象とする Windows フォーム アプリケーションは、
       app.config ファイルで 'EnableWindowsFormsHighDpiAutoResizing' 設定を 'true' に設定する必要があります。
       
       アプリケーションを長いパス対応にします。https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation をご覧ください -->
  <!--
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
      <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
    </windowsSettings>
  </application>
  -->

  <!-- Windows のコモン コントロールとダイアログのテーマを有効にします (Windows XP 以降) -->
  <!--
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
          type="win32"
          name="Microsoft.Windows.Common-Controls"
          version="6.0.0.0"
          processorArchitecture="*"
          publicKeyToken="6595b64144ccf1df"
          language="*"
        />
    </dependentAssembly>
  </dependency>
  -->

</assembly>

UiAccess=trueなexeの実行時の注意

UiAccess=trueにした場合、

  • 署名を付けていないといけない。
  • %WinDir% または、%ProgramFiles%以下のフォルダに置かれてないといけない。

という条件がある。
(通常は、%WinDir%は「C:\WINDOWS」、%ProgramFiles%は「C:\Program Files」)

上記を守っていないと、下記のような謎Msgのエラーが出る。

「サーバーから紹介が返ってきました。」とは...?

※署名のやり方(自己署名/オレオレ署名)のメモはこちら

また、UWPアプリでは使えないらしい。(未検証)

自分のUIを最前面に持ってきたいがために使ってくれるな!とある。
(逆に言うと、そういう使い方できちゃうってことか)

UiAccess=trueのアプリを実行しても、タスクマネージャーで「管理者権限=あり」には見えない

タスクマネージャー上では、こういう感じで見える。

でも、管理者権限で動いてるアプリ(例えばタスクマネージャー)に、WM_Msgを送れる。

UiAccess=trueになっているexeをC#から実行する方法

書きかけ。。。。(C#のProcess.Startするときは、UseShellExecuteをtrueにしないといけないとか?)

参考

UiAccess=trueとは?
Security Considerations for Assistive Technologies

https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-securityoverview

自己署名のやり方(自分の過去記事)

https://tera1707.com/entry/2025/01/05/233346

C++

https://learn.microsoft.com/ja-jp/cpp/build/reference/manifestuac-embeds-uac-information-in-manifest?view=msvc-170

UiAccess=trueの制約

http://www.hundredsoft.jp/win7blog/log/eid65.html

自己署名のやり方

http://www.hundredsoft.jp/win7blog/log/eid70.html