Vista 以降におけるトークンの変更 ~ リンクト・トークン (フィルタード・トークン)

Vista 以降のトークンの変更

以前の Windows から比べると Windows Vista 以降では、ユーザー・トークンに大きな変更が加えられました。

Windows XP 以前の環境では、ユーザーがログオンするとユーザートークンはひとつだけ生成されました。 しかしながら、Windows Vista 以降ではユーザーがログオンした時に二つのトークンが生成される場合があります。

どのような場合にトークンが二つ生成されるかというと、ローカル Administrators グループに属するユーザーがログオンした場合です。 Administrators グループのユーザーがログオンすると、トークンが二つ生成されます。ひとつが通常のユーザーレベルのトークンで、 もうひとつが管理権限を持つトークンです。対になるトークンのことを、リンクト・トークン (linked token) とかフィルタード・トークン (filtered token) といいます。

また管理権限を持つ側のトークンは、昇格トークン (elevated token) とか フル・トークン (full token) といいます。

リンクト・トークンの情報を表示する

この資料では、実際にプロセスのプライマリトークンを取得して、そのトークンが昇格トークンであるかどうか確認します。 さらに、取得したトークンのリンクト・トークンを取得して、そのトークンの情報もみてみましょう。

#include <windows.h>
#include <stdio.h>

void DisplayTokenElevatedStatus( HANDLE hToken ) {

     BOOL            bRet = FALSE;
     TOKEN_ELEVATION elv;
     DWORD           cbSize;

     bRet = GetTokenInformation(
          hToken,
          TokenElevation,

          &elv,
          sizeof( elv ),
          &cbSize );

     if ( bRet ) {
          printf( "Token Is Elevated: %d (%p)\n", 

               elv.TokenIsElevated,
               hToken );
     }
     else {
          printf( "GetTokenInformation Failed.\n" );

     }

}


int main(int argc, char* argv[]) {

     BOOL     bRet = FALSE;
     HANDLE     hToken = NULL;
     TOKEN_LINKED_TOKEN tlt;
     DWORD cbSize;

     bRet = OpenProcessToken( 
          GetCurrentProcess(),
          TOKEN_QUERY,
          &hToken );

     if ( !bRet ) {
          printf( "OpenProcessToken Failed\n" );
          return 1;
     }


     //
     // 昇格トークンか?
     //

     DisplayTokenElevatedStatus ( hToken );


     //
     // リンクトトークンの取得
     //

     bRet = GetTokenInformation(
               hToken,
               TokenLinkedToken,
               &tlt,
               sizeof( tlt ),

               &cbSize );
     
     if ( bRet ) {
          DisplayTokenElevatedStatus ( tlt.LinkedToken );
     }
     else {
          printf( "GetTokenInformation Failed.\n" );
     }

     
     //
     // クリーンアップ
     //

     
     CloseHandle( hToken );
     
     return 0;

}

このプログラムの流れを簡単に説明すると、まず OpenProcessToken でプロセスのプライマリトークンを取得しています。 無事に取得できたら(取得できなかったらそこで終わり)、DisplayTokenElevatedStatus という自前の関数をよび、 その中で GetTokenInformation 関数で昇格に関する情報を取得します。

昇格の情報は TOKEN_ELEVATION という構造体に返され、昇格している場合は TokenIsElevated フィールドが 1 となり、 そうでない場合はこれが 0 となります。

続いて、GetTokenInformation 関数でリンクトトークンを取得します。

このときは TOKEN_LINKED_TOKEN 構造体のデータを渡し、関数が成功した場合 LinkedToken フィールドにリンクトトークンが返されます。

実験結果

さて、上記コードをビルドしてさっそく実行してみましょう。

UAC が有効な状況 において、管理権限のユーザーでコマンドプロンプトを立ち上げ (Run As Administrator ではない) このプログラムを実行します。

> token1.exe
Token Is Elevated: 0 (0000000000000028)
Token Is Elevated: 1 (000000000000002C)

>

結果は上記のように、プライマリートークンは昇格なし、リンクトトークンは昇格トークンであることがわかります。

次にコマンドプロンプトを管理者として実行 (Run As Administrator) して、その中からこのプログラムを実行します。すると、次の結果を得ました。

> token1.exe
Token Is Elevated: 1 (0000000000000028)
Token Is Elevated: 0 (000000000000002C)

>

今回は先ほどの結果とは逆に、プライマリトークンが昇格しており、リンクトトークンが昇格なしのトークンであることがわかります。

さて UAC を無効 として、上記と同様の実験を行います。

> token1.exe
Token Is Elevated: 1 (0000000000000028)
GetTokenInformation Failed.

ここでエラーコード 1312 が返っていることがわかったので、確認すると次のようなエラーです。

> net helpmsg 1312

A specified logon session does not exist. It may already have been terminated.

これによって、UAC が無効である場合は Windows はひとつのトークンしか生成せず (リンクトトークンは生成されず)、プライマリトークンは昇格しているということがわかります。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説