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 はひとつのトークンしか生成せず (リンクトトークンは生成されず)、プライマリトークンは昇格しているということがわかります。