ちょっと制限のあるプロセスを作ろうと思いました。

  • 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インタフェースを受け渡す)の内容とこれを組み合わせたいと考えています。

参考:

2015年4月19日追記:OutputErrorMessgaeの出力が文字化けするので直しました。


スポンサード リンク

この記事のカテゴリ

  • ⇒ 保護モードよりもう少しだけ制限の強いプロセスを作る
  • ⇒ 保護モードよりもう少しだけ制限の強いプロセスを作る
  • ⇒ 保護モードよりもう少しだけ制限の強いプロセスを作る