home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

技術/Windows/UACを触ってみたメモ (v1)

技術/Windows/UACを触ってみたメモ (v1)

技術 / Windows / UACを触ってみたメモ (v1)
id: 832 所有者: msakamoto-sf    作成日: 2010-11-12 23:13:34
カテゴリ: Windows プログラミング 

Win7(32bit)でUACを触ってみたメモ。
Administratorsグループに所属するユーザでログインし、コマンドプロンプトを2つ立ち上げ、ただし片方は「管理者として実行」していろいろ試してみました。

未来の自分向けであるのは勿論ですが、UACと付き合うときに試行錯誤しつつ作るであろう実験コードのサンプルになれば幸いです。


参考URL

例によりMSDNのURLについては2010-11-12時点でのURLです。将来変更された場合は、併記しているナビゲータを参考に辿り直してください。題名が長くて特徴的なMSDN記事については、検索エンジンでたどれると思いますのでナビゲーションは併記していません。

UACそのものについての参考URL:

技術/Windows/UACとRunAsについてのメモ でも紹介している、@ITの解説記事をまずお勧めします。

MSDN提供のドキュメントを参照する場合は、次の3本が軽めですのでまずはこちらでウォーミングアップ。

グループポリシーを使ったUACの微調整や、企業内での独自アプリ・インストーラの配布、アプリケーションの修正など、本格的にUACとお付き合いする場合は以下の2本でMicrosoftお勧めのお作法を学べます。その分、記事の分量もそれなりにあります。

オプション:ShellExecute(Ex)()の内部を解析して、"CreateProcessElevated()"なるAPIをメインとしたユーティリティライブラリを作った人が、その解説記事を書いてます。

前半「とりあえず権限昇格する前後のTOKENをいくつか見てみる」の参考URL:

"MSDN" > "MSDN Library" > "Windows Development" > "Security" > "Authorization" > ...

Web/DB プログラミング徹底解説シリーズ:

後半「権限昇格したプロセスから、未昇格状態のプロセスを起動する」の参考URL:

"Create process nonelevated from elevated process" でggったら一発でした。


とりあえず権限昇格する前後のTOKENをいくつか見てみる

OpenProcessToken()で現在プロセスのTokenハンドルを取得し、GetTokenInformation()で権限昇格(Elevation)の前後で内容が変わりそうな情報を取得、表示させてみます。

TokenElevation

TOKEN_ELEVATION構造体のTokenIsElevatedに権限昇格時は1, 未昇格時は0がセットされるようです。

通常のコマンドプロンプト:

> TokenElevation
TOKEN_ELEVATION = 0

「管理者として実行」コマンドプロンプト:

> TokenElevation
TOKEN_ELEVATION = 1

UACを無効にしてAdministratorsグループに所属するユーザーでログインしたコマンドプロンプト:

> TokenElevation
TOKEN_ELEVATION = 1

TokenElevationType

現在の権限昇格種別が取得できるみたいです。

通常のコマンドプロンプト:

> TokenElevationType
TOKEN_ELEVATION_TYPE = 3, TokenElevationTypeLimited

「管理者として実行」コマンドプロンプト:

> TokenElevationType
TOKEN_ELEVATION_TYPE = 2, TokenElevationTypeFull

UACを無効にしてAdministratorsグループに所属するユーザーでログインしたコマンドプロンプト:

> TokenElevationType
TOKEN_ELEVATION_TYPE = 1, TokenElevationTypeDefault

TokenPrivileges

与えられたPrivilegeの一覧を表示してみます。権限昇格前後での違いが一番良くわかる情報です。

通常のコマンドプロンプト:

> TokenPrivileges.exe
Privileges[0]:
        PrivilegeName = [SeShutdownPrivilege]
        PrivilegeAttributes:
Privileges[1]:
        PrivilegeName = [SeChangeNotifyPrivilege]
        PrivilegeAttributes:
                SE_PRIVILEGE_ENABLED
                SE_PRIVILEGE_ENABLED_BY_DEFAULT
                SE_PRIVILEGE_REMOVED
                SE_PRIVILEGE_USED_FOR_ACCESS
Privileges[2]:
        PrivilegeName = [SeUndockPrivilege]
        PrivilegeAttributes:
Privileges[3]:
        PrivilegeName = [SeIncreaseWorkingSetPrivilege]
        PrivilegeAttributes:
Privileges[4]:
        PrivilegeName = [SeTimeZonePrivilege]
        PrivilegeAttributes:

「管理者として実行」コマンドプロンプト:

> TokenPrivileges.exe
Privileges[0]:
        PrivilegeName = [SeIncreaseQuotaPrivilege]
        PrivilegeAttributes:
Privileges[1]:
        PrivilegeName = [SeSecurityPrivilege]
        PrivilegeAttributes:
Privileges[2]:
        PrivilegeName = [SeTakeOwnershipPrivilege]
        PrivilegeAttributes:
Privileges[3]:
        PrivilegeName = [SeLoadDriverPrivilege]
        PrivilegeAttributes:
Privileges[4]:
        PrivilegeName = [SeSystemProfilePrivilege]
        PrivilegeAttributes:
Privileges[5]:
        PrivilegeName = [SeSystemtimePrivilege]
        PrivilegeAttributes:
Privileges[6]:
        PrivilegeName = [SeProfileSingleProcessPrivilege]
        PrivilegeAttributes:
Privileges[7]:
        PrivilegeName = [SeIncreaseBasePriorityPrivilege]
        PrivilegeAttributes:
Privileges[8]:
        PrivilegeName = [SeCreatePagefilePrivilege]
        PrivilegeAttributes:
Privileges[9]:
        PrivilegeName = [SeBackupPrivilege]
        PrivilegeAttributes:
Privileges[10]:
        PrivilegeName = [SeRestorePrivilege]
        PrivilegeAttributes:
Privileges[11]:
        PrivilegeName = [SeShutdownPrivilege]
        PrivilegeAttributes:
Privileges[12]:
        PrivilegeName = [SeDebugPrivilege]
        PrivilegeAttributes:
Privileges[13]:
        PrivilegeName = [SeSystemEnvironmentPrivilege]
        PrivilegeAttributes:
Privileges[14]:
        PrivilegeName = [SeChangeNotifyPrivilege]
        PrivilegeAttributes:
                SE_PRIVILEGE_ENABLED
                SE_PRIVILEGE_ENABLED_BY_DEFAULT
                SE_PRIVILEGE_REMOVED
                SE_PRIVILEGE_USED_FOR_ACCESS
Privileges[15]:
        PrivilegeName = [SeRemoteShutdownPrivilege]
        PrivilegeAttributes:
Privileges[16]:
        PrivilegeName = [SeUndockPrivilege]
        PrivilegeAttributes:
Privileges[17]:
        PrivilegeName = [SeManageVolumePrivilege]
        PrivilegeAttributes:
Privileges[18]:
        PrivilegeName = [SeImpersonatePrivilege]
        PrivilegeAttributes:
                SE_PRIVILEGE_ENABLED
                SE_PRIVILEGE_ENABLED_BY_DEFAULT
                SE_PRIVILEGE_REMOVED
                SE_PRIVILEGE_USED_FOR_ACCESS
Privileges[19]:
        PrivilegeName = [SeCreateGlobalPrivilege]
        PrivilegeAttributes:
                SE_PRIVILEGE_ENABLED
                SE_PRIVILEGE_ENABLED_BY_DEFAULT
                SE_PRIVILEGE_REMOVED
                SE_PRIVILEGE_USED_FOR_ACCESS
Privileges[20]:
        PrivilegeName = [SeIncreaseWorkingSetPrivilege]
        PrivilegeAttributes:
Privileges[21]:
        PrivilegeName = [SeTimeZonePrivilege]
        PrivilegeAttributes:
Privileges[22]:
        PrivilegeName = [SeCreateSymbolicLinkPrivilege]
        PrivilegeAttributes:

TokenMandatoryPolicy

"Integrity Level"とかいうのに関連してるようですが、まだ理解し切れていません。

通常のコマンドプロンプト:

> TokenMandatoryPolicy.exe
TOKEN_MANDATORY_POLICY = 3, TOKEN_MANDATORY_POLICY_VALID_MASK

「管理者として実行」コマンドプロンプト:

> TokenMandatoryPolicy.exe
TOKEN_MANDATORY_POLICY = 1, TOKEN_MANDATORY_POLICY_NO_WRITE_UP

TokenIntegrityLevel

TokenMandatoryPolicyと併せて "Integrity Level" をあらわすSIDを取得できるようですが、まだ理解し切れていません。また、リソースの解放で間違いがあるのか、異常終了してしまいます。情けない話ですが、追いきれませんでした。

通常のコマンドプロンプト:

> TokenMandatoryLabel.exe
MandatoryLabel : SID = S-1-16-8192
        Attribute = 00000060

「管理者として実行」コマンドプロンプト:

> TokenMandatoryLabel.exe
MandatoryLabel : SID = S-1-16-12288
        Attribute = 00000060

表示されているSID自体は、MSDNの"Windows Integrity Mechanism Design"に記載されている内容と一致しています。
「管理者として実行」側の "S-1-16-12288" は "Mandatory Label\High Mandatory Level"、
通常側の "S-1-16-8192" は "Mandatory Label\Medium Mandatory Level" になりますので、他のUACドキュメントの説明どおりです。

TokenLinkedToken

Administratorsグループのユーザがログオンするとき、管理者としてのフルアクセス用トークンと通常ユーザとしての制限されたトークンが発行されます。この二つのトークンで、現在プロセスのトークンと対になるトークンがTokenLinkedTokenで取得できます。

通常のコマンドプロンプト:現在プロセスのTokenは制限されたトークンですので、LinkedTokenには対となる、フルアクセス用トークンが割り当てられています。

> TokenLinkedToken.exe
--------------- CURRENT TOKEN --------------------
Privileges[0]:
        PrivilegeName = [SeShutdownPrivilege]
        PrivilegeAttributes:
(省略)
Privileges[4]:
        PrivilegeName = [SeTimeZonePrivilege]
        PrivilegeAttributes:
--------------- LINKED TOKEN --------------------
Privileges[0]:
        PrivilegeName = [SeIncreaseQuotaPrivilege]
        PrivilegeAttributes:
(省略)
Privileges[22]:
        PrivilegeName = [SeCreateSymbolicLinkPrivilege]
        PrivilegeAttributes:

「管理者として実行」コマンドプロンプト:現在プロセスのTokenはフルアクセス用トークンですので、LinkedTokenには対となる、制限されたトークンが割り当てられています。

> TokenLinkedToken.exe
--------------- CURRENT TOKEN --------------------
Privileges[0]:
        PrivilegeName = [SeIncreaseQuotaPrivilege]
        PrivilegeAttributes:
(省略)
Privileges[22]:
        PrivilegeName = [SeCreateSymbolicLinkPrivilege]
        PrivilegeAttributes:
--------------- LINKED TOKEN --------------------
Privileges[0]:
        PrivilegeName = [SeShutdownPrivilege]
        PrivilegeAttributes:
(省略)
Privileges[4]:
        PrivilegeName = [SeTimeZonePrivilege]
        PrivilegeAttributes:

UACを無効にしてAdministratorsグループに所属するユーザーでログインしたコマンドプロンプト:
UACを無効にすると、制限トークンが発行されなくなります。したがってLinkedTokenは存在せず、管理者グループのユーザでログオンした場合はフルアクセス用トークンのみが発行されます。

> TokenLinkedToken.exe
--------------- CURRENT TOKEN --------------------
Privileges[0]:
        PrivilegeName = [SeIncreaseQuotaPrivilege]
        PrivilegeAttributes:
(省略)
Privileges[22]:
        PrivilegeName = [SeCreateSymbolicLinkPrivilege]
        PrivilegeAttributes:
GetTokenInformation() : 1312

最後のGetLastError() = 1312はLinkedTokenのGetTokenInformation()で発生しています。日本語メッセージは以下になります。

指定されたログオン セッションは存在しません。\
そのセッションは既に終了している可能性があります。

権限昇格したプロセスから、未昇格状態のプロセスを起動する

未昇格→未昇格プロセスのCreateProcess() : OK
未昇格→昇格プロセスのCreateProcess() : ERROR_ELEVATION_REQUIRED、ShellExecute(Ex)()を使う。
昇格→昇格プロセスのCreateProcess() : OK

では、
昇格→未昇格プロセスのCreateProcess()
するにはどうすれば良いでしょうか?

まずは実験用のCreateProcess()される側のプログラムを用意する。

セオリー通りにShellExecuteEx()で起動してみる

  • 通常コマンドプロンプト
    • asInvoker(manifest) → TOKEN_ELEVATION = 0
    • requireAdministrator(manifest) → UACプロンプト + TOKEN_ELEVATION = 1
  • 「管理者として実行」コマンドプロンプト
    • asInvoker(manifest) → TOKEN_ELEVATION = 1
    • requireAdministrator(manifest) → TOKEN_ELEVATION = 1

特に細工無しのCreateProcess()で起動してみる

  • 通常コマンドプロンプト
    • asInvoker(manifest) → TOKEN_ELEVATION = 0
    • requireAdministrator(manifest) → ERROR_ELEVATION_REQUIRED(GetLastError() = 740)
  • 「管理者として実行」コマンドプロンプト
    • asInvoker(manifest) → TOKEN_ELEVATION = 1
    • requireAdministrator(manifest) → TOKEN_ELEVATION = 1

MSDN Blogsの内容に従い、デスクトップユーザーのTokenをコピーしてCreateProcessWithTokenW()に渡してみる

  • 通常コマンドプロンプト:(権限昇格済みのプロセスからのCreateProcess()実験に付き対象外)
  • 「管理者として実行」コマンドプロンプト
    • asInvoker(manifest) →TOKEN_ELEVATION = 0
    • requireAdministrator(manifest) →ERROR_ELEVATION_REQUIRED(GetLastError() = 740)(CreateProcessWithTokenW())

以上、実験コードの足しになれば幸いです。

それにしてもWindowsのアクセス制御は複雑ですね。企業内で何百台ものクライアントPCを適切に管理したり、GUIのDesktopシステムとの組み合わせが発生する以上は仕方ないのかもしれません。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2010-11-12 23:26:58
md5:3733d1ea337c4e2ba62a85364c5ee48e
sha1:80885b9d188fde9238654015aff2ff6ddd63c0f8
コメント
コメントを投稿するにはログインして下さい。