前回予告したとおり、今回は前2つの記事の合体です。アクセストークンで制限をかけたプロセス上で動作するCOMオブジェクトを作る話です。

「標準出力のパイプ経由でCOMインタフェースを受け渡す」で作ったクライアントプログラムc.exeはそのまま使います。

オブジェクトを作る側のコードを新しく書きました。プロセスを作る処理が前回のトークン作成処理とCreateProcessAsUserに変わっています。また、Windows XPへの対応を追加しました。

// cl process.cpp /link /SUBSYSTEM:Console,5.01
#define UNICODE
#define _UNICODE
#define WIN32_LEAN_AND_MEAN
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _ATL_XP_TARGETING
 
#include <iostream>
#include <memory>
#include <windows.h>
#include <userenv.h>
#include <VersionHelpers.h>
#include <atlbase.h>
#include <atlstr.h>
#include <atlutil.h>
#include "HandleStream.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();
  OutputErrorMessgae(functionName, hr);
  return hr;
}
 
HANDLE CreateProtectedToken()
{
  ATL::CHandle hOriginalToken, hToken;
  if (!OpenProcessToken(GetCurrentProcess(),
    TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE
    | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT,
    &hOriginalToken.m_h))
  {
    OutputLastError(L"OpenProcessToken");
    return nullptr;
  }
  DWORD flags = DISABLE_MAX_PRIVILEGE;
  if (IsWindowsVistaOrGreater())
  {
    flags |= LUA_TOKEN;
  }
  if (!CreateRestrictedToken(hOriginalToken, flags,
    0, nullptr, 0, nullptr, 0, nullptr, &hToken.m_h))
  {
    OutputLastError(L"CreateRestrictedToken");
    return nullptr;
  }
 
  if (IsWindowsVistaOrGreater())
  {
    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))
    {
      OutputLastError(L"SetTokenInformation");
      return nullptr;
    }
  }
  return hToken.Detach();
}
 
int main()
{
  std::wclog.imbue(std::locale(std::locale::classic(), "", std::locale::ctype));
  auto hrInit = CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY);
  if (FAILED(hrInit))
  {
    return hrInit;
  }
 
  ATL::CHandle hOutputRead, hOutputWrite;
  if (!CreatePipe(&hOutputRead.m_h, &hOutputWrite.m_h, nullptr, 0))
  {
    return OutputLastError(L"CreatePipe");
  }
  if (!SetHandleInformation(
    hOutputWrite, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
  {
    return OutputLastError(L"SetHandleInformation");
  }
 
  ATL::CHandle hToken(CreateProtectedToken());
  if (hToken == nullptr)
  {
    return 1;
  }
  auto env = create_environment_block(hToken, FALSE);
  if (env == nullptr)
  {
    return OutputLastError(L"CreateEnvironmentBlock");
  }
  STARTUPINFO si{sizeof si};
  si.dwFlags = STARTF_USESTDHANDLES;
  si.hStdOutput = hOutputWrite;
  PROCESS_INFORMATION pi{};
  if (!CreateProcessAsUser(
    hToken, L"child.exe", nullptr, nullptr, nullptr, TRUE,
    CREATE_UNICODE_ENVIRONMENT, env.get(), nullptr, &si, &pi))
  {
    return OutputLastError(L"CreateProcess");
  }
  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);
 
  ATL::CComObjectStack<HandleStream> s;
  s.m_h = hOutputRead;
 
  ATL::CComPtr<IDispatch> disp;
  auto hrUnmarshal = CoUnmarshalInterface(&s, IID_PPV_ARGS(&disp));
  if (FAILED(hrUnmarshal))
  {
    return OutputErrorMessgae(L"CoUnmarshalInterface", hrUnmarshal);
  }
 
  DISPID dispid = DISPID_VALUE;
  auto hr = disp.Invoke0(dispid); // Hoge::fの呼び出し
  if (FAILED(hr))
  {
    return OutputErrorMessgae(L"Hoge::f", hr);
  }
  disp.Release();
  std::cout << "完了" << std::endl;
 
  CoUninitialize();
}

アクセストークンでの制限をあまり厳しくしたらCOMでのプロセス間通信に支障を来すことはないだろうかと懸念を抱き、今回のコードを書き始めました。しかし、前回の記事に書いたように、あまり厳しくすると、そもそもプロセスの起動すらできなくなる調子でした。そのため、前回までのプログラムを単純に組み合わせただけで済みました。

もう少し、続きます。


スポンサード リンク

この記事のカテゴリ

  • ⇒ 保護モード+αのプロセス上で動作するCOMオブジェクトを作る
  • ⇒ 保護モード+αのプロセス上で動作するCOMオブジェクトを作る