从 Windows 8 开始,微软引入了新的安全机制,AppConatiner 所有的 Store App 就是运行在应用容器之中,并且 IETab 也是运行在应用容器之中,应用容器在权限的管理上非常细致,也就是说非常“细粒度”。 微软也为传统的Desktop应用程序提供了一系列的API来创建一个AppContainer,并且使进程在AppContainer中启动。比如使用CreateAppContainerProfile创建一个容器SID,使用DeleteAppContainerProfile查找一个已知容器名的SID,删除一个容器DeleteAppContainerProfile配置文件。GetAppContainerFolderPath 获得容器目录。
通过 AppContainer 启动进程的一般流程是,通过 CreateAppContainerProfile 创建一个容器配置,得到 SID 指针,为了避免创建失败,先用 DeleteAppContainerProfile 删除此容器配置。细粒度的配置需要 WELL_KNOWN_SID_TYPE
得到容器配置后,启动进程时需要使用 STARTUPINFOEX 结构,使用 InitializeProcThreadAttributeList UpdateProcThreadAttribute 将 PSID 和 SECURITY_CAPABILITIES::Capabilities (也就是 WELL_KNOWN_SID_TYPE 得到的权限设置)添加到 STARTUPINFOEX::lpAttributeList 使用 CreateProcess 中第七个参数 添加 EXTENDED_STARTUPINFO_PRESENT,然后再用 reinterpret_cast 转换 STARTUPFINFOEX 指针变量输入到 CreateProcess 倒数第二个(C语言用强制转换)。
下面是一个完整的例子。
#include <vector>
#include <memory>
#include <type_traits>
#include <Windows.h>
#include <sddl.h>
#include <Userenv.h>
#include <iostream>
#pragma comment(lib,"Userenv")
#pragma comment(lib,"Shlwapi")
#pragma comment(lib,"kernel32")
#pragma comment(lib,"user32")
#pragma comment(lib,"Advapi32")
#pragma comment(lib,"Ole32")
#pragma comment(lib,"Shell32")
typedef std::shared_ptr<std::remove_pointer<PSID>::type> SHARED_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;
}
static bool MakeWellKnownSIDAttributes(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,
};
for(auto type:capabilitiyTypeList) {
if (!SetCapability(type, capabilities, capabilitiesSidList)) {
return false;
}
}
return true;
}
HRESULT AppContainerLauncherProcess(LPCWSTR app,LPCWSTR cmdArgs,LPCWSTR workDir)
{
wchar_t appContainerName[]=L"Phoenix.Container.AppContainer.Profile.v1.test";
wchar_t appContainerDisplayName[]=L"Phoenix.Container.AppContainer.Profile.v1.test\0";
wchar_t appContainerDesc[]=L"Phoenix Container Default AppContainer Profile Test,Revision 1\0";
DeleteAppContainerProfile(appContainerName);///Remove this AppContainerProfile
std::vector<SID_AND_ATTRIBUTES> capabilities;
std::vector<SHARED_SID> capabilitiesSidList;
if(!MakeWellKnownSIDAttributes(capabilities,capabilitiesSidList))
return S_FALSE;
PSID sidImpl;
HRESULT hr=::CreateAppContainerProfile(appContainerName,
appContainerDisplayName,
appContainerDesc,
(capabilities.empty() ? NULL : &capabilities.front()), capabilities.size(), &sidImpl);
if(hr!=S_OK){
std::cout<<"CreateAppContainerProfile Failed"<<std::endl;
return hr;
}
wchar_t *psArgs=nullptr;
psArgs=_wcsdup(cmdArgs);
PROCESS_INFORMATION pi;
STARTUPINFOEX siex = { sizeof(STARTUPINFOEX) };
siex.StartupInfo.cb = sizeof(STARTUPINFOEXW);
SIZE_T cbAttributeListSize = 0;
BOOL bReturn = InitializeProcThreadAttributeList(
NULL, 3, 0, &cbAttributeListSize);
siex.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize);
bReturn = InitializeProcThreadAttributeList(siex.lpAttributeList, 3, 0, &cbAttributeListSize);
SECURITY_CAPABILITIES sc;
sc.AppContainerSid = sidImpl;
sc.Capabilities = (capabilities.empty() ? NULL : &capabilities.front());
sc.CapabilityCount = capabilities.size();
sc.Reserved = 0;
if(UpdateProcThreadAttribute(siex.lpAttributeList, 0,
PROC_THREAD_ATTRIBUTE_SECURITY_CAPABILITIES,
&sc,
sizeof(sc) ,
NULL, NULL)==FALSE)
{
goto Cleanup;
}
BOOL bRet=CreateProcessW(app, psArgs, nullptr, nullptr,
FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, workDir, reinterpret_cast<LPSTARTUPINFOW>(&siex), &pi);
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
Cleanup:
DeleteProcThreadAttributeList(siex.lpAttributeList);
DeleteAppContainerProfile(appContainerName);
free(psArgs);
FreeSid(sidImpl);
return hr;
}
int wmain(int argc,wchar_t *argv[])
{
if(argc>=2)
{
std::wcout<<L"Start AppContainer App: "<<argv[1]<<L"\t Return Code[HRESULT]: "<<AppContainerLauncherProcess(nullptr,argv[1],nullptr)<<std::endl;
}
return 0;
}
使用 Process Explorer 查看进程属性可得到下图: