ちょっと制限のあるプロセスを作ろうと思いました。
- Integrity Levelを低にする
- CreateRestrictedTokenのDISABLE_MAX_PRIVILEGE | LUA_TOKENで制限付きのアクセストークンを作る
- 上記のアクセストークンでCreateProcessAsUserする
プロセスのアクセストークンについてこれより厳しくできないかとも試してみましたが、公開されているAPIではこれが限度のようでした。その話は別の機会にしたいと思います。そんなわけで、Internet Explorerの保護モード(低IL)よりほんの少しだけ制限が強まった程度になりました。
これがそのコードです。CreateRestrictedTokenとSetTokenInformationのTokenIntegrityLevel、そしてCreateProcessAsUserを順に呼び出しているだけです。
#define UNICODE #define _UNICODE #define WIN32_LEAN_AND_MEAN #define _ATL_NO_AUTOMATIC_NAMESPACE #include <iostream> #include <locale> #include <memory> #include <windows.h> #include <userenv.h> #include <atlbase.h> #include <atlutil.h> #pragma comment(lib, "userenv.lib") struct env_deleter { void operator()(void* env) const throw() { DestroyEnvironmentBlock(env); } }; std::unique_ptr<void, env_deleter> create_environment_block( _In_ HANDLE hToken, BOOL inherit) { void* tmp; if (CreateEnvironmentBlock(&tmp, hToken, inherit)) { return std::unique_ptr<void, env_deleter>(tmp); } else { return nullptr; } } HRESULT OutputErrorMessgae(_In_ PCWSTR functionName, HRESULT hr) { std::wclog << functionName << '\n'; std::wclog << std::showbase << std::hex << hr << '\n'; std::wclog << ATL::AtlGetErrorDescription(hr).GetString() << std::endl; return hr; } HRESULT OutputLastError(_In_ PCWSTR functionName) { auto hr = ATL::AtlHresultFromLastError(); return OutputErrorMessgae(functionName, hr); } int main() { std::wclog.imbue(std::locale(std::locale::classic(), "", std::locale::ctype)); ATL::CHandle hOriginalToken, hToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &hOriginalToken.m_h)) { return OutputLastError(L"CreatePipe"); } if (!CreateRestrictedToken( hOriginalToken, DISABLE_MAX_PRIVILEGE | LUA_TOKEN, 0, nullptr, 0, nullptr, 0, nullptr, &hToken.m_h)) { return OutputLastError(L"CreateRestrictedToken"); } SID lowIL{ SID_REVISION, 1, SECURITY_MANDATORY_LABEL_AUTHORITY, SECURITY_MANDATORY_LOW_RID, }; TOKEN_MANDATORY_LABEL tml{ { &lowIL, SE_GROUP_INTEGRITY, }, }; if (!SetTokenInformation(hToken, TokenIntegrityLevel, &tml, sizeof tml)) { return OutputLastError(L"SetTokenInformation"); } auto env = create_environment_block(hToken, FALSE); if (env == nullptr) { return OutputLastError(L"CreateEnvironmentBlock"); } STARTUPINFO si{ sizeof si }; PROCESS_INFORMATION pi{}; if (!CreateProcessAsUser( hToken, L"hello.exe", nullptr, nullptr, nullptr, TRUE, CREATE_UNICODE_ENVIRONMENT, env.get(), nullptr, &si, &pi)) { return OutputLastError(L"CreateProcessAsUser"); } WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } |
CreateProcessAsUserで指定しているHello.exeは、Hello worldを出力するだけのものです。
#include <stdio.h> int main() { puts("hello world"); getchar(); // 何かキーが押されるのを待ってから終了する } |
LUA_TOKENトークンの効果は、「管理者として実行」で起動すると分かります。具体的には、ビルトインのAdministratorsグループなどに対してSE_GROUP_USE_FOR_DENY_ONLYが付与されます。
なお、Chromium/Google Chromeのようにアクセストークン以外で制限する余地がまだあります。今回は見送りました。
今回はここまでです。次は前回(標準出力のパイプ経由でCOMインタフェースを受け渡す)の内容とこれを組み合わせたいと考えています。
参考:
- 整合性レベル (IntegrityLevel) の低いプロセスの作成方法 – Windows Vista – 社本@元ネオニート Blog
- http://blog.airesoft.co.uk/code/minimumprocperms.cpp
- Sandbox – The Chromium Projects
2015年4月19日追記:OutputErrorMessgaeの出力が文字化けするので直しました。
スポンサード リンク |