他人の空似自作物置場

StartAppContainer.zip/StartAppContainer/StartAppContainer.cpp


#include <iostream>
#include <vector>

#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>

#include <Windows.h>
#include <sddl.h>
#include <Userenv.h>

#pragma comment(lib, "Userenv.lib")

const wchar_t * const AppContainerName = L"AppConteinerTest";

void MyLocalFree(PSID sid) {
  if (sid != NULL) {
    ::LocalFree(sid);
  }
}

typedef boost::shared_ptr<boost::remove_pointer<PSID>::type> SHARED_SID;
SHARED_SID ToSharedSID(PSID sid) {
  return SHARED_SID(sid, &MyLocalFree);
}

void MyFreeSid(PSID sid) {
  if (sid != NULL) {
    ::FreeSid(sid);
  }
}

SHARED_SID ToSharedSID2(PSID sid) {
  return SHARED_SID(sid, &MyFreeSid);
}

void MyDeleteProcThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST attrList) {
  if (attrList != NULL) {
    ::DeleteProcThreadAttributeList(attrList);
  }
}

typedef boost::shared_ptr<boost::remove_pointer<LPPROC_THREAD_ATTRIBUTE_LIST>::type> SHARED_ATTR_LIST;
SHARED_ATTR_LIST ToSharedAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST attrList) {
  return SHARED_ATTR_LIST(attrList, &MyDeleteProcThreadAttributeList);
}

class UnregistAppContainer {
public:
  UnregistAppContainer(SHARED_SID sid) : sid(sid) { }
  ~UnregistAppContainer() {
    typedef HRESULT(WINAPI* AppContainerUnregisterSidPtr)(PSID sid);
    AppContainerUnregisterSidPtr AppContainerUnregisterSid = reinterpret_cast<AppContainerUnregisterSidPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerUnregisterSid"));
    if (AppContainerUnregisterSid == NULL) {
      AppContainerUnregisterSid = reinterpret_cast<AppContainerUnregisterSidPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerUnregisterSid"));
      if (AppContainerUnregisterSid == NULL) {
        return;
      }
    }
    AppContainerUnregisterSid(sid.get());
  }
private:
  const SHARED_SID sid;
};

void MyAppContainerFreeMemory(void * const ptr) {
  typedef BOOLEAN(WINAPI* AppContainerFreeMemoryPtr)(void* ptr);
  AppContainerFreeMemoryPtr AppContainerFreeMemory = reinterpret_cast<AppContainerFreeMemoryPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerFreeMemory"));
  if (AppContainerFreeMemory == NULL) {
    AppContainerFreeMemory = reinterpret_cast<AppContainerFreeMemoryPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerFreeMemory"));
    if (AppContainerFreeMemory == NULL) {
      return;
    }
  }
  AppContainerFreeMemory(ptr);
}

bool existAppContainerSid(SHARED_SID sid) {
  typedef HRESULT(WINAPI* AppContainerLookupMonikerPtr)(PSID sid, LPWSTR* moniker);
  AppContainerLookupMonikerPtr AppContainerLookupMoniker = reinterpret_cast<AppContainerLookupMonikerPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerLookupMoniker"));
  if (AppContainerLookupMoniker == NULL) {
    AppContainerLookupMoniker = reinterpret_cast<AppContainerLookupMonikerPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerLookupMoniker"));
    if (AppContainerLookupMoniker == NULL) {
      return false;
    }
  }
  wchar_t *monikerImpl;
  if (FAILED(AppContainerLookupMoniker(sid.get(), &monikerImpl))) {
    return false;
  }
  boost::shared_ptr<wchar_t> moniker(monikerImpl, &MyAppContainerFreeMemory);
  if (!moniker || ::wcslen(moniker.get()) == 0) {
    return false;
  }
  std::wcout << moniker.get() << std::endl;
  return true;
}

void PrintSid(SHARED_SID sid) {
  wchar_t *sidStrImpl;
  if (::ConvertSidToStringSidW(sid.get(), &sidStrImpl) == FALSE) {
    return;
  }
  boost::shared_ptr<wchar_t> sidStr(sidStrImpl, &MyLocalFree);
  std::wcout << sidStr.get() << std::endl;
}

void PrintAppContainerSid(const wchar_t * const name) {
  PSID sidImpl;
  if (FAILED(::DeriveAppContainerSidFromAppContainerName(name, &sidImpl))) {
    return;
  }
  SHARED_SID sid = ToSharedSID2(sidImpl);
  PrintSid(sid);
}

void PrintAppContainerSid2(const wchar_t * const moniker) {
  typedef HRESULT(WINAPI* AppContainerDeriveSidFromMonikerPtr)(LPCWSTR moniker, PSID *sid);
  AppContainerDeriveSidFromMonikerPtr AppContainerDeriveSidFromMoniker = reinterpret_cast<AppContainerDeriveSidFromMonikerPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerDeriveSidFromMoniker"));
  if (AppContainerDeriveSidFromMoniker == NULL) {
    AppContainerDeriveSidFromMoniker = reinterpret_cast<AppContainerDeriveSidFromMonikerPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerDeriveSidFromMoniker"));
    if (AppContainerDeriveSidFromMoniker == NULL) {
      return;
    }
  }
  PSID sidImpl;
  if (FAILED(AppContainerDeriveSidFromMoniker(moniker, &sidImpl))) {
    return;
  }
  SHARED_SID sid(sidImpl, ::MyAppContainerFreeMemory);
  PrintSid(sid);
}

bool SetCapability(const WELL_KNOWN_SID_TYPE type, std::vector<SID_AND_ATTRIBUTES> &list, std::vector<SHARED_SID> &sidList) {
  SHARED_SID capabilitySid(new unsigned char[SECURITY_MAX_SID_SIZE]);
  DWORD sidListSize = SECURITY_MAX_SID_SIZE;
  if (::CreateWellKnownSid(type, NULL, capabilitySid.get(), &sidListSize) == FALSE) {
    return false;
  }
  if (::IsWellKnownSid(capabilitySid.get(), type) == FALSE) {
    return false;
  }
  SID_AND_ATTRIBUTES attr;
  attr.Sid = capabilitySid.get();
  attr.Attributes = SE_GROUP_ENABLED;
  list.push_back(attr);
  sidList.push_back(capabilitySid);
  return true;
}

bool RunOld(const boost::filesystem::path &path) {
  const wchar_t * const appContainerSid = L"S-1-15-2-1234567890-1234567890-1234567890-123456789-1234567890-123456789-1234567890";
  typedef HRESULT(WINAPI* AppContainerRegisterSidPtr)(PSID sid, LPCWSTR moniker, LPCWSTR display_name);
  AppContainerRegisterSidPtr AppContainerRegisterSid = reinterpret_cast<AppContainerRegisterSidPtr>(::GetProcAddress(::GetModuleHandleW(L"kernelbase.dll"), "AppContainerRegisterSid"));
  if (AppContainerRegisterSid == NULL) {
    AppContainerRegisterSid = reinterpret_cast<AppContainerRegisterSidPtr>(::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "AppContainerRegisterSid"));
    if (AppContainerRegisterSid == NULL) {
      return false;
    }
  }
  std::vector<SID_AND_ATTRIBUTES> capabilities;
  std::vector<SHARED_SID> capabilitiesSidList;
  const WELL_KNOWN_SID_TYPE capabilitiyTypeList[] = {
    WinCapabilityInternetClientSid, WinCapabilityInternetClientServerSid, WinCapabilityPrivateNetworkClientServerSid,
    WinCapabilityPicturesLibrarySid, WinCapabilityVideosLibrarySid, WinCapabilityMusicLibrarySid,
    WinCapabilityDocumentsLibrarySid, WinCapabilitySharedUserCertificatesSid, WinCapabilityEnterpriseAuthenticationSid,
    WinCapabilityRemovableStorageSid,
  };
  BOOST_FOREACH(const WELL_KNOWN_SID_TYPE type, capabilitiyTypeList) {
    if (!SetCapability(type, capabilities, capabilitiesSidList)) {
      return false;
    }
  }
  PSID sidImpl;
  if (::ConvertStringSidToSidW(appContainerSid, &sidImpl) == FALSE) {
    return false;
  }
  const SHARED_SID sid = ToSharedSID(sidImpl);
  UnregistAppContainer unregistAppContainer(sid); // AppContainerUnregisterSidを終了時に呼ぶためだけのクラス
  if (FAILED(AppContainerRegisterSid(sid.get(), AppContainerName, AppContainerName))) {
    return false;
  }
  SIZE_T size;
  InitializeProcThreadAttributeList(NULL, 3, 0, &size);
  const SHARED_ATTR_LIST attrList = ToSharedAttributeList(reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new unsigned char[size]));
  if (::InitializeProcThreadAttributeList(attrList.get(), 3, 0, &size) == FALSE) {
    return false;
  }
  SECURITY_CAPABILITIES sc;
  sc.AppContainerSid = sid.get();
  sc.Capabilities = (capabilities.empty() ? NULL : &capabilities.front());
  sc.CapabilityCount = capabilities.size();
  sc.Reserved = 0;
  if (::UpdateProcThreadAttribute(attrList.get(), 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, &sc, sizeof(sc), NULL, NULL) == FALSE) {
    return false;
  }
  STARTUPINFOEXW startupInfoEx = {0};
  startupInfoEx.StartupInfo.cb = sizeof(STARTUPINFOEXW); // StartupInfoのサイズではなくstartupInfoExのサイズである点に注意
  startupInfoEx.lpAttributeList = attrList.get();
  PROCESS_INFORMATION pi = {0};
  if (::CreateProcessW(path.wstring().c_str(), NULL, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFO>(&startupInfoEx), &pi) == FALSE) {
    return false;
  }
  ::WaitForSingleObject(pi.hProcess, INFINITE);
  ::CloseHandle(pi.hThread);
  ::CloseHandle(pi.hProcess);
  return true;
}

class DeleteAppContainer {
public:
  DeleteAppContainer(const wchar_t * const name) : name(name) { }
  ~DeleteAppContainer() {
    ::DeleteAppContainerProfile(name);
  }
private:
  const wchar_t * const name;
};

void MyCoTaskMemFree(void * const ptr) {
  if (ptr != NULL) {
    ::CoTaskMemFree(ptr);
  }
}

bool PrintAppContainerFolderPath(SHARED_SID sid) {
  wchar_t *sidStrImpl;
  if (::ConvertSidToStringSidW(sid.get(), &sidStrImpl) == FALSE) {
    return false;
  }
  const boost::shared_ptr<wchar_t> sidStr(sidStrImpl, &MyLocalFree);
  wchar_t *appContainerPathImpl;
  if (FAILED(::GetAppContainerFolderPath(sidStr.get(), &appContainerPathImpl))) {
    return false;
  }
  const boost::shared_ptr<wchar_t> appContainerPath(appContainerPathImpl, &MyCoTaskMemFree);
  std::wcout << appContainerPath.get() << std::endl;
  return true;
}

bool Run(const boost::filesystem::path &path) {
  std::vector<SID_AND_ATTRIBUTES> capabilities;
  std::vector<SHARED_SID> capabilitiesSidList;
  const WELL_KNOWN_SID_TYPE capabilitiyTypeList[] = {
    WinCapabilityInternetClientSid, WinCapabilityInternetClientServerSid, WinCapabilityPrivateNetworkClientServerSid,
    WinCapabilityPicturesLibrarySid, WinCapabilityVideosLibrarySid, WinCapabilityMusicLibrarySid,
    WinCapabilityDocumentsLibrarySid, WinCapabilitySharedUserCertificatesSid, WinCapabilityEnterpriseAuthenticationSid,
    WinCapabilityRemovableStorageSid,
  };
  BOOST_FOREACH(const WELL_KNOWN_SID_TYPE type, capabilitiyTypeList) {
    if (!SetCapability(type, capabilities, capabilitiesSidList)) {
      return false;
    }
  }
  PSID sidImpl;
  DeleteAppContainer deleteAppContainer(AppContainerName);
  if (FAILED(::CreateAppContainerProfile(AppContainerName, AppContainerName, AppContainerName, (capabilities.empty() ? NULL : &capabilities.front()), capabilities.size(), &sidImpl))) {
    return false;
  }
  const SHARED_SID sid = ToSharedSID2(sidImpl);
  const unsigned int attrCount = 3;
  SIZE_T size;
  ::InitializeProcThreadAttributeList(NULL, attrCount, 0, &size);
  const SHARED_ATTR_LIST attrList = ToSharedAttributeList(reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new unsigned char[size]));
  if (::InitializeProcThreadAttributeList(attrList.get(), attrCount, 0, &size) == FALSE) {
    return false;
  }
  SECURITY_CAPABILITIES sc;
  sc.AppContainerSid = sid.get();
  sc.Capabilities = (capabilities.empty() ? NULL : &capabilities.front());
  sc.CapabilityCount = capabilities.size();
  sc.Reserved = 0;
  if (::UpdateProcThreadAttribute(attrList.get(), 0, PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES, &sc, sizeof(sc), NULL, NULL) == FALSE) {
    return false;
  }
  STARTUPINFOEXW startupInfoEx = { 0 };
  startupInfoEx.StartupInfo.cb = sizeof(STARTUPINFOEXW); // StartupInfoのサイズではなくstartupInfoExのサイズである点に注意
  startupInfoEx.lpAttributeList = attrList.get();
  PROCESS_INFORMATION pi = { 0 };
  if (::CreateProcessW(path.wstring().c_str(), NULL, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFO>(&startupInfoEx), &pi) == FALSE) {
    std::wcout << GetLastError() << std::endl;
    return false;
  }
  ::WaitForSingleObject(pi.hProcess, INFINITE);
  ::CloseHandle(pi.hThread);
  ::CloseHandle(pi.hProcess);
  return true;
}

int main(const unsigned int argc, const char * const * const argv) {
  std::locale::global(std::locale("japanese"));
  if (argc != 2) {
    std::wcout << L"使い方: StartAppContainer.exe exe_path" << std::endl;
    return 0;
  }
  const boost::filesystem::path path(argv[1]);
  if (!Run(path)) {
    std::wcout << L"起動に失敗しました" << std::endl;
    ::getchar();
    return 1;
  }
  std::wcout << L"処理が正常に終了しました" << std::endl;
  ::getchar();
  return 0;
}