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;
}