What I love about programming is that system programming can strike you back even if you are writing a simple desktop UI tool. For example, if you want it to be more secure, as I do. (it is Fancy Viewer tool in my case https://www.fancy-viewer.com/)
The tool uses ImageMagick library (plus plugins) which I completely trust, but vulnerabilities happen and it is better to run the parsers in some isolated environment, i.e. sandbox.
There are some Windows API functions for that:
CreateRestrictedToken
CreateProcessAsUserW
which work as charm:
Except you have to rewrite token's default DACL or the app refuses to start on Windows 7 (or on Windows 10 with "run as administrator").
Like here:
BOOL CreateProcessRestrictedW(LPWSTR lpCommandLine,
LPSTARTUPINFOW lpStartupInfo,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
OUT LPPROCESS_INFORMATION lpProcessInformation)
{
HANDLE hProcessToken = 0, hRestrictedToken = 0;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ALL_ACCESS | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY,
&hProcessToken))
{
return FALSE;
}
lsvu::HandleGuard processTokenGuard(hProcessToken);
// get current user sid
std::vector<char> currentUserSID;
if (QueryTokenSID_Silent(hProcessToken, ¤tUserSID))
{
return FALSE;
}
// collect other system sids
std::vector<char> adminSID;
if (GetWellKnownSid_Silent(WinBuiltinAdministratorsSid, adminSID))
{
return FALSE;
}
std::vector<char> localSystemSID;
if (GetWellKnownSid_Silent(WinLocalSystemSid, localSystemSID))
{
return FALSE;
}
SID_AND_ATTRIBUTES sidToDisable = { adminSID.data(), 0 };
// create the restricted token
if (!CreateRestrictedToken(hProcessToken,
DISABLE_MAX_PRIVILEGE | LUA_TOKEN,
1, &sidToDisable,
0, 0,
0, 0,
&hRestrictedToken))
{
return FALSE;
}
lsvu::HandleGuard restrictedTokenGuard(hRestrictedToken);
// Set the token to low integrity:
TOKEN_MANDATORY_LABEL tokenLabel = { 0 };
tokenLabel.Label.Attributes = SE_GROUP_INTEGRITY;
if (!ConvertStringSidToSidW(L"S-1-16-4096", &tokenLabel.Label.Sid))
{
return FALSE;
}
{
LocalGuard sidLabelGuard(tokenLabel.Label.Sid);
if (!SetTokenInformation(hRestrictedToken,
TokenIntegrityLevel,
&tokenLabel,
sizeof(tokenLabel) + GetLengthSid(tokenLabel.Label.Sid)))
{
return FALSE;
}
}
// Create new DACL
std::vector<char> dacl;
if (CreateACL_Silent(dacl, currentUserSID, adminSID, localSystemSID))
{
return FALSE;
}
TOKEN_DEFAULT_DACL newDefaulDACL = { (PACL)dacl.data() };
if (!SetTokenInformation(hRestrictedToken, TokenDefaultDacl,
&newDefaulDACL, sizeof(newDefaulDACL)))
{
return FALSE;
}
// Create a new process using the restricted token
BOOL result = CreateProcessAsUserW(hRestrictedToken,
NULL,
lpCommandLine,
NULL,
NULL,
bInheritHandles,
dwCreationFlags,
(LPVOID)lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation);
return result;
}
It isn't a full compilable source, but demonstrates the idia well enough.