保護モードは、悪意のあるコードがソフトウェアの脆弱性を突いてユーザーの認識なくインストールされないようにすることで、Windows Internet Explorer 7 が脅威から受ける影響と蔓延を防止します。保護モードは、より高い整合性レベルでプロセス、ファイル、レジストリ キーへのアクセスを制限する、Microsoft Windows Vista の整合性メカニズムを使用して、この目的を実現しています。保護モード API は、ソフトウェア ベンダが、保護モードの Internet Explorer など、整合性レベルの低いプロセスからファイル システムやレジストリと通信できる Microsoft Internet Explorer 用の拡張機能やアドオンを開発できるようにします。
このトピックのセクションは、次のとおりです。
整合性レベルの低い書き込み先の特定
Internet Explorer 7 以降用に開発した拡張機能は、既定では Temporary Internet Files フォルダなど、整合性レベルの低い場所にファイルや設定を書き込みます。整合性レベルの低い場所では、権限レベルの低いプロセスからの書き込みアクセスが許可されています。整合性レベルの低い場所への書き込みは、インターネットから侵入する悪意があると考えられるデータからシステムを保護する上で有効です。
Internet Explorer が保護モードかどうかを確認するには、保護モードの IEIsProtectedModeProcess 関数 (英語) を呼び出します。また、インプロセス Internet Explorer 拡張からの書き込みが可能な、整合性レベルの低いファイルまたはレジストリの場所を特定するには、IEGetWriteableFolderPath 関数 (英語) または IEGetWriteableHKCU 関数 (英語)を呼び出します。
次の例では、保護モード API を使用して、Internet Explorer の整合性レベルを確認し、整合性レベルの低いレジストリ設定の書き込み先を特定しています。
#include iepmapi.h HRESULT WriteSetting(LPCTSTR pszKey, LPCTSTR pszValue, LPCTSTR pszData) { BOOL bIsProtected; HRESULT hr = IEIsProtectedMode(*bIsProtected); if (SUCCEEDED(hr) && bIsProtected) { HKEY hKey; hr = IEGetWriteableHKCU(&hKey;); if (SUCCEEDED(hr)) { HKEY hMyKey; DWORD dwDisposition; LONG lRes = RegCreateKeyEx( hKey, // 整合性レベルの低い書き込み先 pszKey, // 目的のサブキー 0L, // 予約済み NULL, // クラス REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, // セキュリティ記述子 &hMyKey;, // 新しいキーまたは既存のキー &dwDisposition;); if (ERROR_SUCCESS == lRes) { lRes = RegSetValueEx(hMyKey, pszValue, NULL, REG_SZ, (CONST BYTE*)pszData, strlen(pszData) + 1)); hr = HRESULT_FROM_WIN32(lRes); RegCloseKey(hMyKey); } else hr = HRESULT_FROM_WIN32(lRes); // 整合性レベルの低い書き込み先用のハンドルを閉じます RegCloseKey(hKey); } } else { // IE は保護モードではありません } return hr; }
保護モードでのファイルの保存
保護モードで実行すると、Microsoft ActiveX コントロールやその他の拡張機能は、Temporary Internet Files、History、Cookies、および Temp フォルダ以外から、直接ファイルをダウンロードできません。これら以外の場所に書き込みを行う操作はインターセプトされ、整合性レベルの低い領域の "仮想化された" 場所にリダイレクトされます。このような仮想化された場所以外にファイルを保存する必要のある拡張機能は、次の 2 つの保護モード API 関数を使用できます。
-
IEShowSaveFileDialog (英語) — ユーザーによるファイルの保存先となる場所を設定してこの関数を呼び出します。ユーザーの画面には [名前を付けて保存] コモン ダイアログ ボックスが表示され、この関数によりユーザーが指定したファイルの保存先のパスが返されます。
-
IESaveFile (英語) — この前の操作で返されたハンドルとダウンロード先となる一時的なファイル パスを設定してこの関数を呼び出します。保護モードのユーザー ブローカー プロセスにより、一時的な保存場所から目的の保存場所にファイルがコピーされます。ファイルを保存せずに割り当てられたメモリを解放するには、IECancelSaveFile 関数 (英語)を呼び出します。
次の例では、保護モード API を使用して、権限を昇格したファイル保存操作を実行する方法を示しています。この例では、保存操作の前にデータが一時的な保存場所に書き込まれ、保存操作により、ユーザーモード操作のファイルがより権限の高い領域にコピーされています。ファイルが既にインターネット キャッシュにダウンロードされている場合は、この処理は必要ありません。
#include iepmapi.h // 注 : 呼び出し側が CoTaskMemFree により *ppszDest を解放する必要があります。 HRESULT SaveFileData( LPWSTR pszName, // 目的のファイル名とパス BYTE* pbData, // 保存するデータ UINT cbBytes, // pbData 内のバイト数 LPWSTR* ppszDest) // 出力 : 最終保存先 { LPWSTR pszTempPath; HRESULT hr; hr = IEGetWriteableFolderPath( FOLDERID_InternetCache, // Temporary Internet Files &pszTempPath;); if (S_OK == hr) // フォルダへのアクセス許可がない場合は S_FALSE { // 一時ファイルを作成します。 TCHAR szTempName[MAX_PATH]; GetTempFileNameW( pszTempPath, // 一時ファイルのディレクトリ _T("tmp"), // 一時ファイル名のプレフィックス 0, // 一意名を作成 szTempName); // 名前用のバッファ HANDLE hTempFile; hTempFile = CreateFile( (LPTSTR)szTempName, // ファイル名 GENERIC_READ | GENERIC_WRITE, // 読み取りおよび書き込み操作のために開きます 0, // 共有しません NULL, // 既定のセキュリティ CREATE_ALWAYS, // 既存のファイルを上書きします FILE_ATTRIBUTE_NORMAL, // 標準ファイル NULL); // テンプレートなし if (INVALID_HANDLE_VALUE != hTempFile) { DWORD dwBytesWritten; // ファイルを保存します WriteFile(hTempFile, pbData, cbBytes, &dwBytesWritten;, NULL); ASSERT(dwBytesWritten == cbBytes); CloseHandle(hTempFile); // [名前を付けて保存] ダイアログ ボックスを表示します hr = SaveFileProtected(pszName, (LPWSTR)szTempName, ppszDest); DeleteFile((LPCTSTR)szTempName); } else { // 一時ファイルを作成できなかった場合 hr = HRESULT_FROM_WIN32(GetLastError()); } // メモリを解放します CoTaskMemFree(pszTempPath); } return hr; } // 戻り値 : S_OK、キャンセルされた場合は S_FALSE // 注 : 呼び出し側が CoTaskMemFree により *ppszDest を解放する必要があります。 HRESULT SaveFileProtected( LPWSTR pszName, // 目的の名前とパス LPWSTR pszSource, // 現在のファイルの場所 LPWSTR* ppszDest) // 出力 : 保存されたファイルのパス { LPCWSTR pszExt = L"Text Files|*.txt|All Files|*.*|"; LPCWSTR pszDefExt = L"txt"; HANDLE hState; // これに対する CloseHandle の呼び出しは不要 if (ppszDest) *ppszDest = NULL; HRESULT hr = IEShowSaveFileDialog( g_hwnd, // アプリケーション ウィンドウ (グローバル) pszName, // 最初のファイル名とパス NULL, // ファイル名のパスを使用します pszExt, // 拡張フィルタの一覧 pszDefExt, // 既定の拡張 1, // フィルタのインデックス OFN_ENABLESIZING | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT, ppszDest, // 指定された保存先 &hState;); // 操作を完了するために使用 if (S_OK == hr) // ユーザーが操作をキャンセルした場合は S_FALSE { hr = IESaveFile(hState, pszSource); hState = NULL; // hState を再び使用しないように、NULL を設定 } return hr; }