前回(保護モード+αなプロセスをCoCreateInstanceで作る(その1))の続きです。

今回は、もう1つの方法CLSCTX_ENABLE_CLOAKINGです。これは、CoCreateInstanceやCoGetClassObjectの実引数で指定する方法です。CoInitializeSecurityと違い、都度指定できる点が便利です。

ただし、Windows VistaからだとMSDNライブラリに書かれています(CLSCTX)。実際、Windows XPで使ってみるとHRESULT_FROM_WIN32でERROR_INVALID_PARAMETER、すなわち0x80070057が帰ってきて終わります。

クライアント側プログラムだけ掲載します。サーバー側は前回と同じです。このコードも前回との変更点は僅かです。CoInitializeSecurityを削り、CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKINGを追加しただけです。

#define UNICODE
#define _UNICODE
#define WIN32_LEAN_AND_MEAN
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _ATL_XP_TARGETING
 
#include <iostream>
#include <windows.h>
#include <VersionHelpers.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlutil.h>
#include <boost/scope_exit.hpp>
#include <boost/implicit_cast.hpp>
 
// {DCC853C7-52FD-446E-8BFC-6662D97FD935}
static const GUID CLSID_Hoge =
{ 0xdcc853c7, 0x52fd, 0x446e,
{ 0x8b, 0xfc, 0x66, 0x62, 0xd9, 0x7f, 0xd9, 0x35 } };
 
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();
}
 
ATL::CComPtr<IDispatch> CreateHoge()
{
  ATL::CHandle hToken(CreateProtectedToken());
  if (!ImpersonateLoggedOnUser(hToken))
  {
    throw ATL::CAtlException(OutputLastError(L"ImpersonateLoggedOnUser"));
  }
  BOOST_SCOPE_EXIT_ALL(&hToken)
  {
    if (!RevertToSelf())
    {
      abort();
    }
  };
  ATL::CComPtr<IDispatch> obj;
#if 0 // 1にしても動きます。
  ATL::CComPtr<IClassFactory> cf;
  ATLENSURE_SUCCEEDED(
    CoGetClassObject(CLSID_Hoge, CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING, nullptr, IID_PPV_ARGS(&cf)));
  ATLENSURE_SUCCEEDED(cf->CreateInstance(nullptr, IID_PPV_ARGS(&obj)));
#else
  ATLENSURE_SUCCEEDED(obj.CoCreateInstance(CLSID_Hoge, nullptr, CLSCTX_LOCAL_SERVER | CLSCTX_ENABLE_CLOAKING));
#endif
  return obj;
}
 
int main()
{
  std::locale loc(std::locale::classic(), "", std::locale::ctype);
  std::wclog.imbue(loc);
  std::wcout.imbue(loc);
  try
  {
    ATLENSURE_SUCCEEDED(CoInitializeEx(
      nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE));
    auto obj = CreateHoge();
    ATL::CComVariant v;
    DISPID dispid = DISPID_VALUE;
    ATLENSURE_SUCCEEDED(obj.Invoke0(dispid, &v));
    ATLENSURE_SUCCEEDED(v.ChangeType(VT_BSTR));
    if (v.bstrVal != nullptr)
    {
      std::wcout << v.bstrVal << std::endl;
    }
 
    std::cin.get();
  }
  catch(const ATL::CAtlException& e)
  {
    std::wclog << std::hex << std::showbase << e.m_hr << std::endl;
    std::wclog << boost::implicit_cast<PCWSTR>(
      ATL::AtlGetErrorDescription(e)) << std::endl;
  }
  CoUninitialize();
}

上記ではCLSCTX_LOCAL_SERVERにしましたが、CLSCTX_ALLとの組み合わせでもうまくいきました。

その2でいったん終わりにしようかと考えています。その3もあるのですが、少し別手法なので、しばらく間をおいてから(ほかに書きたいことを先に取り上げてから)にしようと思います。

スポンサード リンク

この記事のカテゴリ

  • ⇒ 保護モード+αなプロセスをCoCreateInstanceで作る(その2)
  • ⇒ 保護モード+αなプロセスをCoCreateInstanceで作る(その2)
  • ⇒ 保護モード+αなプロセスをCoCreateInstanceで作る(その2)
  • ⇒ 保護モード+αなプロセスをCoCreateInstanceで作る(その2)