Sandboxie/Sandboxie/core/dll/sxs.c

2352 lines
64 KiB
C

/*
* Copyright 2004-2020 Sandboxie Holdings, LLC
* Copyright 2020 David Xanatos, xanasoft.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
// WinSxS Services
//---------------------------------------------------------------------------
#include "dll.h"
#include "common/my_version.h"
#include <stdlib.h>
#include <stdio.h>
//---------------------------------------------------------------------------
// Structures and Types
//---------------------------------------------------------------------------
typedef struct _SXS_ARGS {
ULONG ArchId;
ULONG LangId;
WCHAR *LangNames;
WCHAR *Directory;
WCHAR *SourcePath;
UCHAR *ManifestText;
WCHAR *ConfigPath;
UCHAR *ConfigText;
} SXS_ARGS;
#define SXS_PATH_LEN (2 * 1024)
#define SXS_TEXT_LEN (512 * 1024)
//---------------------------------------------------------------------------
// Functions
//---------------------------------------------------------------------------
static BOOLEAN Sxs_AllocOrFreeBuffers(SXS_ARGS *args, BOOLEAN alloc);
static BOOLEAN Sxs_GetLanguage(ACTCTX *ActCtx, SXS_ARGS *args);
static BOOL Sxs_GetManifestResource_Helper(
HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam);
static BOOL Sxs_GetManifestResource(
HMODULE hModule, ULONG *ResourceId, HRSRC *hResource);
static BOOL Sxs_ReadTextAndClose(HANDLE hFile, UCHAR *Text);
static void Sxs_ConvertUnicodeToAscii(UCHAR *Text);
static BOOLEAN Sxs_GetPathAndText(ACTCTX *ActCtx, SXS_ARGS *args);
static void *Sxs_CallService(SXS_ARGS *args, BOOLEAN *UseAltCreateActCtx);
static void Sxs_ActivationContextNotificationRoutine(
ULONG Operation,
HANDLE ActivationContext,
ULONG_PTR MappedViewBaseAddress,
ULONG_PTR Unknown1,
ULONG_PTR Unknown2,
BOOLEAN *pSuccess);
static HANDLE Sxs_CreateActCtxW_Alt(ACTCTX *ActCtx);
static BOOL Sxs_QueryActCtxW(DWORD dwFlags, HANDLE hActCtx,
void *pvSubInstance, ULONG ulInfoClass, void *pvBuffer,
SIZE_T cbBuffer, SIZE_T *pcbWrittenOrRequired);
static void Sxs_QueryActCtxW_2(ULONG *p_len, WCHAR **p_path);
static BOOL Sxs_SxsInstallW(void *info);
static BOOLEAN Sxs_CheckCompatLayer(
const WCHAR *DosPath, const WCHAR *Setting);
static BOOLEAN Sxs_CheckCompatLayer_2(
const WCHAR *DosPath, BOOLEAN User, WCHAR *Text, ULONG Length);
static BOOLEAN Sxs_CheckCompatLayer_3(
const WCHAR *Text, const WCHAR *Setting);
//---------------------------------------------------------------------------
static NTSTATUS Sxs_NtSetInformationThread(
HANDLE ThreadHandle,
THREADINFOCLASS ThreadInformationClass,
PVOID ThreadInformation,
ULONG ThreadInformationLength);
static NTSTATUS Sxs_NtCreateTransaction(
HANDLE *TransactionHandle,
ACCESS_MASK DesiredAccess,
OBJECT_ATTRIBUTES *ObjectAttributes,
void *UnknownParameter04,
void *UnknownParameter05,
void *UnknownParameter06,
void *UnknownParameter07,
void *UnknownParameter08,
void *UnknownParameter09,
void *UnknownParameter10);
static NTSTATUS Sxs_NtOpenTransaction(
HANDLE *TransactionHandle,
ACCESS_MASK DesiredAccess,
OBJECT_ATTRIBUTES *ObjectAttributes,
void *UnknownParameter04,
void *UnknownParameter05);
static NTSTATUS Sxs_NtCommitTransaction(
HANDLE TransactionHandle,
ULONG_PTR UnknownParameter02);
static NTSTATUS Sxs_NtRollbackTransaction(
HANDLE TransactionHandle,
ULONG_PTR UnknownParameter02);
static void Sxs_RtlRaiseException(EXCEPTION_RECORD *ExceptionRecord);
static BOOL Sxs_CheckTokenMembership(
HANDLE hToken, void *pSid, BOOL *IsMember);
//---------------------------------------------------------------------------
typedef HANDLE (*P_CreateActCtx)(void *pActCtx);
typedef BOOL (*P_QueryActCtx)(DWORD dwFlags, HANDLE hActCtx,
void *pvSubInstance, ULONG ulInfoClass, void *pvBuffer,
SIZE_T cbBuffer, SIZE_T *pcbWrittenOrRequired);
typedef BOOL (*P_SxsInstall)(void *info);
typedef NTSTATUS (*P_RtlCreateActivationContext)(
ULONG_PTR Zero1,
void *ActivationContextMappedBase,
ULONG_PTR Zero2,
ULONG_PTR CallbackRoutine,
ULONG_PTR CallbackRoutineData,
HANDLE *OutActCtx);
typedef LANGID (*P_GetUserDefaultUILanguage)(void);
typedef LANGID (*P_SetThreadUILanguage)(WORD LangId);
typedef NTSTATUS (*P_RtlGetThreadPreferredUILanguages)(
ULONG_PTR Flags, ULONG *Count, WCHAR *Buffer, ULONG *Length);
typedef NTSTATUS (*P_RtlSetThreadPreferredUILanguages)(
ULONG_PTR Flags, WCHAR *Buffer, ULONG *Count);
typedef void (*P_RtlRaiseException)(EXCEPTION_RECORD *ExceptionRecord);
//---------------------------------------------------------------------------
static P_CreateActCtx __sys_CreateActCtxW = NULL;
static P_QueryActCtx __sys_QueryActCtxW = NULL;
static P_RtlCreateActivationContext
__sys_RtlCreateActivationContext = NULL;
static P_RtlGetThreadPreferredUILanguages
__sys_RtlGetThreadPreferredUILanguages = NULL;
static P_RtlSetThreadPreferredUILanguages
__sys_RtlSetThreadPreferredUILanguages = NULL;
static P_SetThreadUILanguage __sys_SetThreadUILanguage = NULL;
static P_GetUserDefaultUILanguage __sys_GetUserDefaultUILanguage = NULL;
P_NtSetInformationThread __sys_NtSetInformationThread = NULL;
static P_NtCreateTransaction __sys_NtCreateTransaction = NULL;
static P_NtOpenTransaction __sys_NtOpenTransaction = NULL;
static P_NtCommitTransaction __sys_NtCommitTransaction = NULL;
static P_NtRollbackTransaction __sys_NtRollbackTransaction = NULL;
static P_RtlRaiseException __sys_RtlRaiseException = NULL;
static P_SxsInstall __sys_SxsInstallW = NULL;
extern P_NtOpenKey __sys_NtOpenKey;
//---------------------------------------------------------------------------
// Variables
//---------------------------------------------------------------------------
static BOOLEAN Sxs_UseAltCreateActCtx = FALSE;
static void *Sxs_ActivateDefaultManifest_ImageBase = NULL;
static const WCHAR *Sxs_manifest = L".manifest";
static const WCHAR *Sxs_config = L".config";
static const WCHAR *Sxs_QueueName = L"RPCSS_SXS";
static const WCHAR *Sxs_Manifest_Length = L"Manifest Length (%d)";
extern const WCHAR *File_BQQB;
//---------------------------------------------------------------------------
// Sxs_AllocOrFreeBuffers
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_AllocOrFreeBuffers(SXS_ARGS *args, BOOLEAN alloc)
{
if (alloc) {
ULONG size = /* SourcePath */ SXS_PATH_LEN * sizeof(WCHAR)
+ /* ManifestText */ SXS_TEXT_LEN * sizeof(UCHAR)
+ /* ConfigPath */ SXS_PATH_LEN * sizeof(WCHAR)
+ /* ConfigText */ SXS_TEXT_LEN * sizeof(UCHAR);
UCHAR *buf = VirtualAlloc(0, size,
MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE);
if (! buf)
return FALSE;
args->SourcePath = (WCHAR *)buf;
buf += SXS_PATH_LEN * sizeof(WCHAR); // skip SourcePath
args->ManifestText = buf;
buf += SXS_TEXT_LEN * sizeof(UCHAR); // skip ManifestText
args->ConfigPath = (WCHAR *)buf;
buf += SXS_PATH_LEN * sizeof(WCHAR); // skip ConfigPath
args->ConfigText = buf;
} else {
if (args->SourcePath)
VirtualFree(args->SourcePath, 0, MEM_RELEASE);
}
return TRUE;
}
//---------------------------------------------------------------------------
// Sxs_GetLanguage
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_GetLanguage(ACTCTX *ActCtx, SXS_ARGS *args)
{
BOOLEAN ok;
//
// basic parameter checking
//
if ((ActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) && (! ActCtx->wLangId))
return FALSE;
//
// get language code or language name
//
ok = TRUE;
if (Dll_OsBuild >= 6000) {
//
// Windows Vista and later
//
ULONG count, len = 256;
BOOLEAN ok = TRUE;
args->LangNames = Dll_AllocTemp(len * sizeof(WCHAR));
if ((! __sys_RtlGetThreadPreferredUILanguages) ||
(! __sys_RtlSetThreadPreferredUILanguages) ||
(! __sys_SetThreadUILanguage)) {
return FALSE;
}
if (ActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) {
ULONG OrigCount;
WCHAR *OrigLangNames = Dll_AllocTemp(len * sizeof(WCHAR));
--len;
if (__sys_RtlGetThreadPreferredUILanguages(
0x08, &OrigCount, OrigLangNames, &len) != 0) {
ok = FALSE;
} else {
if (__sys_SetThreadUILanguage(ActCtx->wLangId) == 0) {
ok = FALSE;
} else {
if (__sys_RtlGetThreadPreferredUILanguages(
0x38, &count, args->LangNames, &len) != 0) {
ok = FALSE;
}
__sys_RtlSetThreadPreferredUILanguages(
0x08, OrigLangNames, &OrigCount);
}
}
Dll_Free(OrigLangNames);
} else {
if (__sys_RtlGetThreadPreferredUILanguages(
0x38, &count, args->LangNames, &len) != 0) {
ok = FALSE;
}
}
if (ok) {
for (count = 0; count < len; ++count) {
if (args->LangNames[count] == L'\0')
args->LangNames[count] = L'_';
}
args->LangNames[len] = L'\0';
}
} else {
//
// Windows XP
//
if (ActCtx->dwFlags & ACTCTX_FLAG_LANGID_VALID) {
args->LangId = ActCtx->wLangId;
} else {
args->LangId = __sys_GetUserDefaultUILanguage();
}
}
return ok;
}
//---------------------------------------------------------------------------
// Sxs_GetManifestResource_Helper
//---------------------------------------------------------------------------
_FX BOOL Sxs_GetManifestResource_Helper(
HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
{
if (lpszType != RT_MANIFEST || (! lpszName))
return TRUE;
if (lParam) {
ULONG_PTR *args = (ULONG_PTR *)lParam;
if (IS_INTRESOURCE(lpszName))
args[0] = (ULONG_PTR)lpszName;
else if (*lpszName == L'#')
args[0] = (USHORT)_wtoi(lpszName);
args[1] = (ULONG_PTR) FindResource(hModule, lpszName, lpszType);
}
return FALSE;
}
//---------------------------------------------------------------------------
// Sxs_GetManifestResource
//---------------------------------------------------------------------------
_FX BOOL Sxs_GetManifestResource(
HMODULE hModule, ULONG *ResourceId, HRSRC *hResource)
{
ULONG_PTR args[2] = { 0, 0 };
EnumResourceNames(hModule, RT_MANIFEST,
Sxs_GetManifestResource_Helper, (LONG_PTR)args);
if (args[1]) {
if (ResourceId)
*ResourceId = (ULONG)args[0];
if (hResource)
*hResource = (HRSRC)args[1];
SetLastError(ERROR_SUCCESS);
return TRUE;
} else {
if (ResourceId)
*ResourceId = 0;
if (hResource)
*hResource = 0;
SetLastError(ERROR_RESOURCE_TYPE_NOT_FOUND);
return FALSE;
}
}
//---------------------------------------------------------------------------
// Sxs_ReadTextAndClose
//---------------------------------------------------------------------------
_FX BOOL Sxs_ReadTextAndClose(HANDLE hFile, UCHAR *Text)
{
ULONG LastError;
ULONG len;
BOOL ok = ReadFile(hFile, Text, SXS_TEXT_LEN, &len, NULL);
if (ok && ((! len) || (len >= SXS_TEXT_LEN))) {
if (len >= SXS_TEXT_LEN)
SbieApi_Log(2205, Sxs_Manifest_Length, len);
LastError = ERROR_SXS_MANIFEST_FORMAT_ERROR;
ok = FALSE;
} else
LastError = GetLastError();
CloseHandle(hFile);
if (ok)
Text[len] = L'\0';
else
SetLastError(LastError);
return ok;
}
//---------------------------------------------------------------------------
// Sxs_GetPathAndText
//---------------------------------------------------------------------------
_FX void Sxs_ConvertUnicodeToAscii(UCHAR *Text)
{
UCHAR *ptri, *ptro;
BOOLEAN warn = FALSE;
if (Text[0] != 0xFF || Text[1] != 0xFE)
return;
ptro = Text;
ptri = Text + 2;
while (*ptri) {
if (ptri[1] != '\0')
warn = TRUE;
*ptro = *ptri;
++ptro;
++ptri;
++ptri;
}
*ptro = '\0';
ptri = strstr(Text, "encoding=\"");
if (ptri) {
ptri += 10;
ptro = strchr(ptri, '\"');
if (ptro && (ptro - ptri) == 5)
memcpy(ptri, "UTF-8", 5);
else
warn = TRUE;
}
if (warn)
SbieApi_Log(2205, L"SXS/UNICODE");
}
//---------------------------------------------------------------------------
// Sxs_GetPathAndText
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_GetPathAndText(ACTCTX *ActCtx, SXS_ARGS *args)
{
ULONG LastError;
ULONG len;
HANDLE hFile;
ULONG ResourceId = 0;
void *ImageBase = NULL;
BOOLEAN ShouldUnmap = FALSE;
BOOLEAN IsExe = FALSE;
if (ActCtx->dwFlags & ACTCTX_FLAG_HMODULE_VALID) {
//
// if ACTCTX_FLAG_HMODULE_VALID was passed, we're clearly
// dealing with an image file
//
ImageBase = ActCtx->hModule;
if (! GetModuleFileName(
ImageBase, args->SourcePath, SXS_PATH_LEN - 2))
return FALSE;
args->SourcePath[SXS_PATH_LEN - 2] = L'\0';
if (Sxs_ActivateDefaultManifest_ImageBase == ImageBase) {
//
// when called from Sxs_ActivateDefaultManifest, we need to
// emulate the behavior of the Windows loader and disregard
// the resource number for external manifest/config files
//
IsExe = TRUE;
}
} else if (! ActCtx->lpSource) {
//
// without the ACTCTX_FLAG_HMODULE_VALID, we require lpSource
//
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
} else {
//
// open lpSource and try to map it as an image
//
HANDLE hSection;
len = wcslen(ActCtx->lpSource);
if (len > (SXS_PATH_LEN - 2))
len = SXS_PATH_LEN - 2;
wmemcpy(args->SourcePath, ActCtx->lpSource, len);
args->SourcePath[len] = L'\0';
hFile = CreateFile(
args->SourcePath, FILE_READ_DATA, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
//
// we can get a file not found error if lpSource does not specify
// a path, in which case we retry with lpAssemblyDirectory
//
if ((hFile == INVALID_HANDLE_VALUE)
&& (ActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID)
&& ActCtx->lpAssemblyDirectory) {
ULONG dir_len = wcslen(ActCtx->lpAssemblyDirectory);
if ((dir_len < SXS_PATH_LEN)
&& (dir_len + len <= (SXS_PATH_LEN - 2))) {
wmemcpy(args->SourcePath,
ActCtx->lpAssemblyDirectory, dir_len);
args->SourcePath[dir_len] = L'\\';
wmemcpy(&args->SourcePath[dir_len + 1],
ActCtx->lpSource, len);
args->SourcePath[dir_len + 1 + len] = L'\0';
hFile = CreateFile(
args->SourcePath, FILE_READ_DATA, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
}
}
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
hSection = CreateFileMapping(
hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
if (! hSection) {
//
// map failed, which is acceptable if the file is not an image
//
LastError = GetLastError();
if ((LastError != ERROR_BAD_EXE_FORMAT) ||
(ActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID)) {
CloseHandle(hFile);
if (LastError == ERROR_BAD_EXE_FORMAT)
RtlNtStatusToDosError(STATUS_INVALID_IMAGE_FORMAT);
SetLastError(LastError);
return FALSE;
} else {
//
// this is probably a text file
//
if (! Sxs_ReadTextAndClose(hFile, args->ManifestText))
return FALSE;
}
} else {
//
// this is an EXE or a DLL file
//
CloseHandle(hFile);
ImageBase = MapViewOfFileEx(
hSection, FILE_MAP_READ, 0, 0, 0, NULL);
LastError = GetLastError();
CloseHandle(hSection);
if (! ImageBase) {
SetLastError(LastError);
return FALSE;
}
ShouldUnmap = TRUE;
}
}
//
// for an image source, find resource ID
//
if (ImageBase) {
HRSRC hResource = NULL;
BOOLEAN ok = FALSE;
BOOLEAN CheckExternalManifest = FALSE;
if (ActCtx->dwFlags & ACTCTX_FLAG_RESOURCE_NAME_VALID) {
if (! ActCtx->lpResourceName) {
SetLastError(ERROR_INVALID_PARAMETER);
goto unmap_and_return_false;
} else {
if (IS_INTRESOURCE(ActCtx->lpResourceName))
ResourceId = (ULONG)(ULONG_PTR)ActCtx->lpResourceName;
hResource = FindResource(
ImageBase, ActCtx->lpResourceName, RT_MANIFEST);
LastError = GetLastError();
}
} else {
Sxs_GetManifestResource(ImageBase, &ResourceId, &hResource);
LastError = GetLastError();
}
//
// decide if we should check for an external manifest file
//
if (Dll_OsBuild >= 6000) {
//
// Windows Vista only looks for external manifest file for
// the main EXE, and if it has an embedded resource id != 1,
// or if there is no embedded manifest at all
//
// note that behavior should be same as XP if the setting
// PreferExternalManifest is enabled, but we ignore that
//
if (IsExe && ResourceId != 1)
CheckExternalManifest = TRUE;
} else {
//
// Windows XP:
// for EXEs, always look for an external manifest file
// for DLLs, only we found or were given a manifest resource id
//
if (ResourceId || IsExe)
CheckExternalManifest = TRUE;
}
//
// external manifest file can override embedded manifest
// note that we use ConfigPath as temporary storage
//
if (CheckExternalManifest) {
wcscpy(args->ConfigPath, args->SourcePath);
args->ConfigPath[SXS_PATH_LEN - 10] = L'\0';
if ((! IsExe) && ResourceId > 1) {
len = wcslen(args->ConfigPath);
args->ConfigPath[len] = L'.';
_itow(ResourceId, &args->ConfigPath[len + 1], 10);
}
wcscat(args->ConfigPath, Sxs_manifest);
hFile = CreateFile(
args->ConfigPath, FILE_READ_DATA, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
if (! Sxs_ReadTextAndClose(hFile, args->ManifestText))
goto unmap_and_return_false;
wcscpy(args->SourcePath, args->ConfigPath);
hResource = NULL;
ok = TRUE;
}
}
if (hResource) {
len = SizeofResource(ImageBase, hResource);
if ((! len) || (len >= SXS_TEXT_LEN)) {
if (len >= SXS_TEXT_LEN)
SbieApi_Log(2205, Sxs_Manifest_Length, len);
LastError = ERROR_SXS_MANIFEST_FORMAT_ERROR;
} else {
HGLOBAL hGlobal = LoadResource(ImageBase, hResource);
if (hGlobal) {
memcpy(args->ManifestText, LockResource(hGlobal), len);
ok = TRUE;
}
}
}
if (! ok) {
SetLastError(LastError);
goto unmap_and_return_false;
}
//
// if we were called from Sxs_ActivateDefaultManifest, then neither
// ACTCTX_FLAG_RESOURCE_NAME_VALID nor lpResourceName were given.
// we fill these missing fields now, in case Sxs_CallService fails,
// and we end up calling the system CreateActCtx.
//
if (Sxs_ActivateDefaultManifest_ImageBase == ImageBase) {
ULONG ActCtxResourceId = ResourceId ? ResourceId : 1;
ActCtx->lpResourceName = (WCHAR *)(ULONG_PTR)ActCtxResourceId;
ActCtx->dwFlags |= ACTCTX_FLAG_RESOURCE_NAME_VALID;
}
}
Sxs_ConvertUnicodeToAscii(args->ManifestText);
//
// read config file
//
wcscpy(args->ConfigPath, args->SourcePath);
args->ConfigPath[SXS_PATH_LEN - 10] = L'\0';
if (ImageBase) {
if ((! IsExe) && ResourceId > 1) {
len = wcslen(args->ConfigPath);
args->ConfigPath[len] = L'.';
_itow(ResourceId, &args->ConfigPath[len + 1], 10);
}
wcscat(args->ConfigPath, Sxs_config);
} else {
WCHAR *dot = wcsrchr(args->ConfigPath, L'.');
if (dot && _wcsicmp(dot, Sxs_manifest) == 0)
wcscpy(dot, Sxs_config);
else
wcscat(args->ConfigPath, Sxs_config);
}
hFile = CreateFile(
args->ConfigPath, FILE_READ_DATA, FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE)
*args->ConfigPath = L'\0';
else if (! Sxs_ReadTextAndClose(hFile, args->ConfigText))
goto unmap_and_return_false;
Sxs_ConvertUnicodeToAscii(args->ConfigText);
//
// successful exit
//
if (ShouldUnmap)
UnmapViewOfFile(ImageBase);
SetLastError(ERROR_SUCCESS);
return TRUE;
//
// error exit
//
unmap_and_return_false:
if (ShouldUnmap) {
LastError = GetLastError();
UnmapViewOfFile(ImageBase);
SetLastError(LastError);
}
return FALSE;
}
//---------------------------------------------------------------------------
// Sxs_CallService
//---------------------------------------------------------------------------
_FX void *Sxs_CallService(SXS_ARGS *args, BOOLEAN *UseAltCreateActCtx)
{
void *MappedBase = NULL;
ULONG len1 = sizeof(ULONG) // signature
+ sizeof(ULONG)
+ sizeof(ULONG) // ArchId
+ sizeof(ULONG) // LangId
+ (wcslen(args->LangNames) + 1) * sizeof(WCHAR)
+ (wcslen(args->Directory) + 1) * sizeof(WCHAR)
+ (wcslen(args->SourcePath) + 1) * sizeof(WCHAR)
+ (wcslen(args->ConfigPath) + 1) * sizeof(WCHAR)
+ (strlen(args->ManifestText) + 1) * sizeof(UCHAR)
+ (strlen(args->ConfigText) + 1) * sizeof(UCHAR)
+ sizeof(UCHAR); // final '*'
ULONG *buf1 = Dll_AllocTemp(len1);
WCHAR *ptr2;
UCHAR *ptr1;
HANDLE handle;
ULONG RequestId;
ULONG status;
ULONG retries;
ULONG len2;
ULONG *buf2;
LARGE_INTEGER i64;
ACCESS_MASK DesiredAccess;
//
// prepare memory block that will be read by the RpcSs SxS service
// see Sxs_Generate in RpcSs/sxs.c
//
*(ULONG *)(buf1 + 0) = tzuk; // signature
*(ULONG *)(buf1 + 1) = 0;
*(ULONG *)(buf1 + 2) = args->ArchId;
*(ULONG *)(buf1 + 3) = args->LangId;
ptr2 = (WCHAR *)(buf1 + 4);
wcscpy(ptr2, args->LangNames);
ptr2 += wcslen(ptr2) + 1;
wcscpy(ptr2, args->Directory);
ptr2 += wcslen(ptr2) + 1;
wcscpy(ptr2, args->SourcePath);
ptr2 += wcslen(ptr2) + 1;
wcscpy(ptr2, args->ConfigPath);
ptr2 += wcslen(ptr2) + 1;
ptr1 = (UCHAR *)ptr2;
strcpy(ptr1, args->ManifestText);
ptr1 += strlen(ptr1) + 1;
strcpy(ptr1, args->ConfigText);
ptr1 += strlen(ptr1) + 1;
*ptr1 = '*';
//
// send the request message through an SbieSvc queue
//
for (retries = 0; retries < 3; ++retries) {
status = SbieDll_QueuePutReq(
Sxs_QueueName, buf1, len1, &RequestId, &handle);
if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
if (Dll_ProcessFlags & SBIE_FLAG_FORCED_PROCESS) {
status = STATUS_BAD_INITIAL_PC; // see below
break;
} else {
WCHAR EvtName[128];
HANDLE EvtHandle;
wcscpy(EvtName, SBIE_BOXED_);
wcscat(EvtName, Sxs_QueueName);
wcscat(EvtName, L"_READY");
EvtHandle = CreateEvent(NULL, TRUE, FALSE, EvtName);
SbieDll_StartCOM(FALSE);
WaitForSingleObject(EvtHandle, 30 * 1000);
CloseHandle(EvtHandle);
continue;
}
} else if (status != 0)
break;
status = WaitForSingleObject(handle, 30 * 1000);
CloseHandle(handle);
if (status != 0)
continue;
status = SbieDll_QueueGetRpl(Sxs_QueueName, RequestId, &buf2, &len2);
break;
}
Dll_Free(buf1);
if (status != 0) {
if (status == STATUS_PRIVILEGE_NOT_HELD) {
//
// SbieSvc could not open our caller process, for instance Avira
// blocks access to its avscan.exe process
//
Sxs_UseAltCreateActCtx = TRUE;
*UseAltCreateActCtx = TRUE;
} else if (status == STATUS_BAD_INITIAL_PC) {
//
// if we are a forced process then we probably don't rely on
// SXS assemblies in the sandbox, so if the RPCSS/SXS service
// is not yet ready, then just use the system CreateActCtx
//
*UseAltCreateActCtx = TRUE;
} else {
SbieApi_Log(2203, L"%S - %S [%08X]",
Sxs_QueueName, Dll_ImageName, status);
}
return NULL;
}
if (len2 == sizeof(ULONG) && *(ULONG *)buf2 == -1) {
Dll_Free(buf2);
return NULL;
}
//
// check for special and esoteric case where SandboxieRpcSs
// is telling us to call the system CreateActCtx instead.
// see also Sxs_Request and Sxs_GenerateHelper in apps/com/RpcSs/sxs.c
//
if (len2 == 20 && memcmp(buf2, "*UseAltCreateActCtx*", 20) == 0) {
*UseAltCreateActCtx = TRUE;
Dll_Free(buf2);
return NULL;
}
//
// create a section and fill it with the data from the reply
//
i64.QuadPart = len2;
DesiredAccess = STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ;
status = NtCreateSection(&handle, DesiredAccess, NULL, &i64,
PAGE_READWRITE, SEC_COMMIT, NULL);
if (NT_SUCCESS(status)) {
const ULONG xViewShare = 1;
SIZE_T ViewSize = len2;
i64.QuadPart = 0;
status = NtMapViewOfSection(
handle, NtCurrentProcess(), &MappedBase, 0, 0,
&i64, &ViewSize, xViewShare, MEM_PHYSICAL, PAGE_READWRITE);
if (NT_SUCCESS(status)) {
memcpy(MappedBase, buf2, len2);
NtUnmapViewOfSection(NtCurrentProcess(), MappedBase);
MappedBase = NULL;
ViewSize = 0;
i64.QuadPart = 0;
status = NtMapViewOfSection(
handle, NtCurrentProcess(), &MappedBase, 0, 0,
&i64, &ViewSize, xViewShare, MEM_PHYSICAL, PAGE_READONLY);
if (! NT_SUCCESS(status))
MappedBase = 0;
}
NtClose(handle);
}
Dll_Free(buf2);
return MappedBase;
}
//---------------------------------------------------------------------------
// Sxs_ActivationContextNotificationRoutine
//---------------------------------------------------------------------------
_FX void Sxs_ActivationContextNotificationRoutine(
ULONG Operation,
HANDLE ActivationContext,
ULONG_PTR MappedViewBaseAddress,
ULONG_PTR Unknown1,
ULONG_PTR Unknown2,
BOOLEAN *pSuccess)
{
//
// ideally we would pass kernel32!BasepSxsActivationContextNotification
// to RtlCreateActivationContext, however that is not an exported symbol
// and the simplest solution is to duplicate its functionality
//
if (Operation == 1) {
NtUnmapViewOfSection(
NtCurrentProcess(), (void *)MappedViewBaseAddress);
} else
*pSuccess = TRUE;
}
//---------------------------------------------------------------------------
// Sxs_CreateActCtxW
//---------------------------------------------------------------------------
_FX HANDLE Sxs_CreateActCtxW(ACTCTX *ActCtx)
{
static const WCHAR *_Empty = L"";
SXS_ARGS args;
ULONG LastError;
ULONG_PTR *pActivationContextData = NULL;
HANDLE hActCtx = INVALID_HANDLE_VALUE;
//
// special processing if we are running in the context of SandboxieRpcSs
//
if (Sxs_UseAltCreateActCtx)
return Sxs_CreateActCtxW_Alt(ActCtx);
//
// otherwise normal processing
//
memzero(&args, sizeof(args));
//
// processor architecture
//
if (ActCtx->dwFlags & ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID) {
args.ArchId = ActCtx->wProcessorArchitecture;
if (args.ArchId != PROCESSOR_ARCHITECTURE_INTEL &&
args.ArchId != PROCESSOR_ARCHITECTURE_MSIL &&
args.ArchId != PROCESSOR_ARCHITECTURE_AMD64 &&
args.ArchId != PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 &&
args.ArchId != PROCESSOR_ARCHITECTURE_UNKNOWN) {
LastError = ERROR_INVALID_PARAMETER;
goto finish;
}
} else {
#ifdef _WIN64
args.ArchId = PROCESSOR_ARCHITECTURE_AMD64;
#else
args.ArchId = (Dll_IsWow64 ? PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
: PROCESSOR_ARCHITECTURE_INTEL);
#endif _WIN64
}
//
// language id and name
//
args.LangNames = (WCHAR *)_Empty;
if (! Sxs_GetLanguage(ActCtx, &args)) {
LastError = ERROR_INVALID_PARAMETER;
goto finish;
}
//
// source file and manifest text
//
if (! Sxs_AllocOrFreeBuffers(&args, TRUE)) {
LastError = STATUS_INSUFFICIENT_RESOURCES;
goto finish;
}
if (! Sxs_GetPathAndText(ActCtx, &args)) {
LastError = GetLastError();
goto finish;
}
//
// assembly store directory
//
if (ActCtx->dwFlags & ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID) {
args.Directory = (WCHAR *)ActCtx->lpAssemblyDirectory;
} else {
WCHAR *ptr;
ULONG len = wcslen(args.SourcePath);
args.Directory = Dll_AllocTemp((len + 4) * sizeof(WCHAR));
wmemcpy(args.Directory, args.SourcePath, len + 1);
ptr = wcsrchr(args.Directory, L'\\');
if (ptr)
*ptr = L'\0';
else {
LastError = ERROR_INVALID_PARAMETER;
goto finish;
}
}
//
// prepare to set process default activation context
//
if (ActCtx->dwFlags & ACTCTX_FLAG_SET_PROCESS_DEFAULT) {
#ifdef _WIN64
pActivationContextData = (ULONG_PTR *)(NtCurrentPeb() + 0x2F8);
#else
pActivationContextData = (ULONG_PTR *)(NtCurrentPeb() + 0x1F8);
#endif _WIN64
if (*pActivationContextData) {
LastError = ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET;
goto finish;
}
}
//
// generate activation context data and create a handle to it
//
if (! __sys_RtlCreateActivationContext) {
LastError = ERROR_PROC_NOT_FOUND;
goto finish;
} else {
BOOLEAN UseAltCreateActCtx = FALSE;
void *MappedBase = Sxs_CallService(&args, &UseAltCreateActCtx);
if (MappedBase) {
//
// process result from SXS service in SandboxieRpcSs
//
NTSTATUS status = __sys_RtlCreateActivationContext(
0, MappedBase, 0,
(ULONG_PTR)Sxs_ActivationContextNotificationRoutine, 0,
&hActCtx);
if (! NT_SUCCESS(status)) {
NtUnmapViewOfSection(NtCurrentProcess(), (void *)MappedBase);
} else if (pActivationContextData) {
*pActivationContextData = (ULONG_PTR)MappedBase;
}
} else if (UseAltCreateActCtx) {
//
// we get here if Sxs_CallService cannot talk to RPCSS/SXS
//
hActCtx = Sxs_CreateActCtxW_Alt(ActCtx);
LastError = GetLastError();
goto finish;
}
}
if (hActCtx == INVALID_HANDLE_VALUE) {
LastError = ERROR_SXS_CANT_GEN_ACTCTX;
goto finish;
}
//
// finish
//
finish:
if (args.LangNames && args.LangNames != _Empty)
Dll_Free(args.LangNames);
Sxs_AllocOrFreeBuffers(&args, FALSE);
if (args.Directory &&
args.Directory != (WCHAR *)ActCtx->lpAssemblyDirectory)
Dll_Free(args.Directory);
SetLastError(LastError);
return hActCtx;
}
//---------------------------------------------------------------------------
// Sxs_CreateActCtxW_Alt
//---------------------------------------------------------------------------
_FX HANDLE Sxs_CreateActCtxW_Alt(ACTCTX *ActCtx)
{
//
// the SandboxieRpcSs process implements our SXS service, so it is
// not reliable to use our SXS service from the SandboxieRpcSs process
// for at least two reasons.
//
// - the service pipe may not be ready for use yet
// - even if the service pipe (and related thread) are ready,
// some other thread in the SandboxieRpcSs process may block the
// request. for example, by holding the loader lock.
//
// workaround: in the context of RpcSs, use the real SXS from CSRSS.
//
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
ACTCTX MyActCtx;
WCHAR *MySource = NULL;
HANDLE hActCtx;
ULONG LastError;
//
// get the real path to lpSource if it specifies a file in the sandbox
//
if (ActCtx->lpSource) {
HANDLE hFile = CreateFileW(ActCtx->lpSource, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
NTSTATUS status;
BOOLEAN IsBoxedPath;
MySource = Dll_AllocTemp(sizeof(WCHAR) * 8192);
status = SbieDll_GetHandlePath(hFile, MySource, &IsBoxedPath);
CloseHandle(hFile);
if (NT_SUCCESS(status) && IsBoxedPath) {
if (SbieDll_TranslateNtToDosPath(MySource)) {
memcpy(&MyActCtx, ActCtx, sizeof(ACTCTX));
MyActCtx.lpSource = MySource;
ActCtx = &MyActCtx;
++TlsData->proc_create_process;
}
}
}
}
//
// invoke the system service and finish. note that we use the
// proc_create_process flag to prevent File_RtlGetFullPathName_U
// from changing the adjusted lpSource back into true path form
//
hActCtx = __sys_CreateActCtxW(ActCtx);
LastError = GetLastError();
if (ActCtx == &MyActCtx)
--TlsData->proc_create_process;
if (MySource)
Dll_Free(MySource);
SetLastError(LastError);
return hActCtx;
}
//---------------------------------------------------------------------------
// Sxs_QueryActCtxW
//---------------------------------------------------------------------------
_FX BOOL Sxs_QueryActCtxW(DWORD dwFlags, HANDLE hActCtx,
void *pvSubInstance, ULONG ulInfoClass, void *pvBuffer,
SIZE_T cbBuffer, SIZE_T *pcbWrittenOrRequired)
{
ULONG err;
BOOL ok;
ok = __sys_QueryActCtxW(dwFlags, hActCtx, pvSubInstance, ulInfoClass,
pvBuffer, cbBuffer, pcbWrittenOrRequired);
err = GetLastError();
if (ok && (! dwFlags) && (! hActCtx) && (! pvSubInstance) &&
ulInfoClass == ActivationContextDetailedInformation) {
ACTIVATION_CONTEXT_DETAILED_INFORMATION *info =
(ACTIVATION_CONTEXT_DETAILED_INFORMATION *)pvBuffer;
Sxs_QueryActCtxW_2( (ULONG *)&info->ulRootManifestPathChars,
(WCHAR **)&info->lpRootManifestPath);
Sxs_QueryActCtxW_2( (ULONG *)&info->ulRootConfigurationPathChars,
(WCHAR **)&info->lpRootConfigurationPath);
Sxs_QueryActCtxW_2( (ULONG *)&info->ulAppDirPathChars,
(WCHAR **)&info->lpAppDirPath);
}
SetLastError(err);
return ok;
}
//---------------------------------------------------------------------------
// Sxs_QueryActCtxW_2
//---------------------------------------------------------------------------
_FX void Sxs_QueryActCtxW_2(ULONG *p_len, WCHAR **p_path)
{
if (*p_len && *p_path) {
WCHAR *TruePath = File_GetTruePathForBoxedPath(*p_path, TRUE);
if (TruePath) {
if ((*p_path)[*p_len - 1] == L'\\') {
ULONG TruePath_len = wcslen(TruePath);
if (TruePath_len && TruePath[TruePath_len - 1] != L'\\') {
WCHAR *TruePath2 =
Dll_AllocTemp((TruePath_len + 2) * sizeof(WCHAR));
wmemcpy(TruePath2, TruePath, TruePath_len);
TruePath2[TruePath_len] = L'\\';
TruePath2[TruePath_len + 1] = L'\0';
Dll_Free(TruePath);
TruePath = TruePath2;
}
}
}
if (TruePath) {
ULONG TruePath_len = wcslen(TruePath);
if (TruePath_len <= *p_len) {
wmemcpy(*p_path, TruePath, TruePath_len + 1);
*p_len = TruePath_len;
}
Dll_Free(TruePath);
}
}
}
//---------------------------------------------------------------------------
// Sxs_NtSetInformationThread
//---------------------------------------------------------------------------
_FX NTSTATUS Sxs_NtSetInformationThread(
HANDLE ThreadHandle,
THREADINFOCLASS ThreadInformationClass,
PVOID ThreadInformation,
ULONG ThreadInformationLength)
{
return __sys_NtSetInformationThread(ThreadHandle,
ThreadInformationClass,
ThreadInformation,
ThreadInformationLength);
}
//---------------------------------------------------------------------------
// Sxs_NtCreateTransaction
//---------------------------------------------------------------------------
_FX NTSTATUS Sxs_NtCreateTransaction(
HANDLE *TransactionHandle,
ACCESS_MASK DesiredAccess,
OBJECT_ATTRIBUTES *ObjectAttributes,
void *UnknownParameter04,
void *UnknownParameter05,
void *UnknownParameter06,
void *UnknownParameter07,
void *UnknownParameter08,
void *UnknownParameter09,
void *UnknownParameter10)
{
*TransactionHandle = NULL;
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// Sxs_NtOpenTransaction
//---------------------------------------------------------------------------
_FX NTSTATUS Sxs_NtOpenTransaction(
HANDLE *TransactionHandle,
ACCESS_MASK DesiredAccess,
OBJECT_ATTRIBUTES *ObjectAttributes,
void *UnknownParameter04,
void *UnknownParameter05)
{
*TransactionHandle = NULL;
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// Sxs_NtCommitTransaction
//---------------------------------------------------------------------------
_FX NTSTATUS Sxs_NtCommitTransaction(
HANDLE TransactionHandle,
ULONG_PTR UnknownParameter02)
{
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// Sxs_NtRollbackTransaction
//---------------------------------------------------------------------------
_FX NTSTATUS Sxs_NtRollbackTransaction(
HANDLE TransactionHandle,
ULONG_PTR UnknownParameter02)
{
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
// Sxs_RtlRaiseException
//---------------------------------------------------------------------------
_FX void Sxs_RtlRaiseException(EXCEPTION_RECORD *ExceptionRecord)
{
ULONG code = ExceptionRecord->ExceptionCode;
if ((code & 0xFFFF0000) != 0x40010000) // ignore debug exceptions
SbieApi_Log(2205, L"TrustedInstaller %08X", code);
__sys_RtlRaiseException(ExceptionRecord);
}
//---------------------------------------------------------------------------
// Sxs_CheckTokenMembership
//---------------------------------------------------------------------------
_FX BOOL Sxs_CheckTokenMembership(
HANDLE hToken, void *pSid, BOOL *IsMember)
{
*IsMember = TRUE;
SetLastError(ERROR_SUCCESS);
return TRUE;
}
//---------------------------------------------------------------------------
// Sxs_SxsInstallW
//---------------------------------------------------------------------------
_FX BOOL Sxs_SxsInstallW(void *info)
{
BOOL ok = __sys_SxsInstallW(info);
if (! ok) {
SbieApi_Log(2205, L"SxsInstallW");
SetLastError(0);
ok = TRUE;
}
return ok;
}
//---------------------------------------------------------------------------
// Sxs_InitKernel32
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_InitKernel32(void)
{
HMODULE module;
void *CreateActCtxW;
void *NtSetInformationThread;
void *NtCreateTransaction;
void *NtOpenTransaction;
void *NtCommitTransaction;
void *NtRollbackTransaction;
void *RtlRaiseException;
//
// CreateActCtx function is only supported in Windows XP, so hook
// only if we find it in kernel32.dll (kernelbase.dll on Windows 8)
//
// note that the real CreateActCtxA internally calls CreateActCtxW
// after doing ANSI-to-UNICODE conversion, so we need not hook it
//
if (Dll_OsBuild >= 8400)
module = Dll_KernelBase;
else
module = Dll_Kernel32;
CreateActCtxW = GetProcAddress(module, "CreateActCtxW");
if (CreateActCtxW) {
//
// import stuff that CreateActCtx is going to need
//
#define SXS_IMPORT(b,a) __sys_##a = (P_##a) GetProcAddress(b, #a);
SXS_IMPORT(Dll_Ntdll, RtlCreateActivationContext);
SXS_IMPORT(Dll_Kernel32, GetUserDefaultUILanguage);
if (Dll_OsBuild >= 6000) {
SXS_IMPORT(Dll_Ntdll, RtlGetThreadPreferredUILanguages);
SXS_IMPORT(Dll_Ntdll, RtlSetThreadPreferredUILanguages);
SXS_IMPORT(Dll_Kernel32, SetThreadUILanguage);
}
#undef SXS_IMPORT
//
// disable in-sandbox SXS resolutions in three cases:
//
// if this is the SandboxieRpcSs process which itself implements
// the in-sandbox SXS service
//
// if the sandbox setting DisableBoxedWinSxS=y
//
if (Dll_ImageType == DLL_IMAGE_SANDBOXIE_RPCSS || Dll_AppContainerToken ||
Config_GetSettingsForImageName_bool(L"DisableBoxedWinSxS", FALSE)) {
Sxs_UseAltCreateActCtx = TRUE;
}
//
// hook CreateActCtx
//
SBIEDLL_HOOK(Sxs_,CreateActCtxW);
}
//
// hook QueryActCtx in the context of a forced program because because
// the activation context might have been with sandboxed paths
//
if (Dll_ProcessFlags & SBIE_FLAG_FORCED_PROCESS) {
void *QueryActCtxW = GetProcAddress(module, "QueryActCtxW");
if (QueryActCtxW) {
SBIEDLL_HOOK(Sxs_,QueryActCtxW);
}
}
module = Dll_Ntdll;
//
// Opera hooks NtSetInformationThread. SboxDll calls __sys_NtSetInformationThread to bypass Opera hook.
// See the comment about Thread_SetInformationThread_ChangeNotifyToken in Gui_ConnectToWindowStationAndDesktop
//
NtSetInformationThread = GetProcAddress(Dll_Ntdll, "NtSetInformationThread");
if (NtSetInformationThread) {
SBIEDLL_HOOK(Sxs_, NtSetInformationThread);
}
//
// place ntdll.dll hooks only if TrustedInstaller
//
if (Dll_ImageType != DLL_IMAGE_TRUSTED_INSTALLER)
return TRUE;
NtCreateTransaction = GetProcAddress(module, "NtCreateTransaction");
NtOpenTransaction = GetProcAddress(module, "NtOpenTransaction");
NtCommitTransaction = GetProcAddress(module, "NtCommitTransaction");
NtRollbackTransaction = GetProcAddress(module, "NtRollbackTransaction");
RtlRaiseException = GetProcAddress(module, "RtlRaiseException");
if (NtCreateTransaction) {
SBIEDLL_HOOK(Sxs_,NtCreateTransaction);
}
if (NtOpenTransaction) {
SBIEDLL_HOOK(Sxs_,NtOpenTransaction);
}
if (NtCommitTransaction) {
SBIEDLL_HOOK(Sxs_,NtCommitTransaction);
}
if (NtRollbackTransaction) {
SBIEDLL_HOOK(Sxs_,NtRollbackTransaction);
}
if (RtlRaiseException) {
SBIEDLL_HOOK(Sxs_,RtlRaiseException);
}
//
// In Windows 7, the TrustedInstaller service mounts HKLM\COMPONENTS
// if the registry key/hive is not present. Which means it will not
// mount the hive when the corresponding sandbox key has been created.
// to work around this, we try to explicitly mount the hive here.
//
if (Dll_OsBuild >= 7600) {
OBJECT_ATTRIBUTES TargetObjectAttributes;
OBJECT_ATTRIBUTES SourceObjectAttributes;
UNICODE_STRING TargetObjectName;
UNICODE_STRING SourceObjectName;
WCHAR buf[MAX_PATH + 48];
GetSystemWindowsDirectory(buf + 4, MAX_PATH);
wmemcpy(buf, File_BQQB, 4);
wcscat(buf, L"\\System32\\config\\COMPONENTS");
RtlInitUnicodeString(&SourceObjectName, buf);
RtlInitUnicodeString(&TargetObjectName,
L"\\REGISTRY\\MACHINE\\COMPONENTS");
InitializeObjectAttributes(&SourceObjectAttributes,
&SourceObjectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
InitializeObjectAttributes(&TargetObjectAttributes,
&TargetObjectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
NtLoadKey(&TargetObjectAttributes, &SourceObjectAttributes);
}
//
// on Windows 8, hook kernelbase!CheckTokenMembership which is
// called from TiWorker!AclCheckTrustedInstallerAccess
//
if (Dll_OsBuild >= 8400) {
module = Dll_KernelBase;
typedef BOOL (*P_CheckTokenMembership)(
HANDLE hToken, void *pSid, BOOL *IsMember);
P_CheckTokenMembership CheckTokenMembership =
(P_CheckTokenMembership) GetProcAddress(
Dll_KernelBase, "CheckTokenMembership");
P_CheckTokenMembership __sys_CheckTokenMembership;
SBIEDLL_HOOK(Sxs_,CheckTokenMembership);
}
return TRUE;
}
//---------------------------------------------------------------------------
// Sxs_Init
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_Init(HMODULE module)
{
P_SxsInstall SxsInstallW;
SxsInstallW = (P_SxsInstall)GetProcAddress(module, "SxsInstallW");
SBIEDLL_HOOK(Sxs_,SxsInstallW);
return TRUE;
}
//---------------------------------------------------------------------------
// Sxs_ActivateDefaultManifest
//---------------------------------------------------------------------------
_FX void Sxs_ActivateDefaultManifest(void *ImageBase)
{
if (! __sys_CreateActCtxW)
return;
if (Dll_ProcessFlags & SBIE_FLAG_FORCED_PROCESS) {
//
// if we are a forced process then csrss already applied the
// process default activation context
//
return;
}
//
// reset the process default activation context that was created
// by our dummy manifest/config files. but note that don't do this
// if we are a ForcedProcessComServer where the activaton context
// was already set by csrss.
//
if (! Sxs_UseAltCreateActCtx) {
ULONG_PTR *pActivationContextData;
#ifdef _WIN64
pActivationContextData = (ULONG_PTR *)(NtCurrentPeb() + 0x2F8);
#else
pActivationContextData = (ULONG_PTR *)(NtCurrentPeb() + 0x1F8);
#endif _WIN64
*pActivationContextData = 0;
}
//
// create and activate process default activation context
//
if (! Sxs_UseAltCreateActCtx) {
ACTCTX ActCtx;
WCHAR *DosPath =
Dll_Alloc((wcslen(Ldr_ImageTruePath) + 4) * sizeof(WCHAR));
wcscpy(DosPath, Ldr_ImageTruePath);
SbieDll_TranslateNtToDosPath(DosPath);
memzero(&ActCtx, sizeof(ACTCTX));
ActCtx.cbSize = sizeof(ACTCTX);
ActCtx.dwFlags = ACTCTX_FLAG_HMODULE_VALID
| ACTCTX_FLAG_SET_PROCESS_DEFAULT;
ActCtx.hModule = ImageBase;
ActCtx.lpSource = DosPath;
Sxs_ActivateDefaultManifest_ImageBase = ImageBase;
Sxs_CreateActCtxW(&ActCtx);
Sxs_ActivateDefaultManifest_ImageBase = NULL;
Dll_Free(DosPath);
}
}
//---------------------------------------------------------------------------
// Sxs_CheckManifestForElevation
//---------------------------------------------------------------------------
_FX ULONG Sxs_CheckManifestForElevation(
const WCHAR* DosPath,
BOOLEAN *pAsInvoker,
BOOLEAN *pRequireAdministrator,
BOOLEAN *pHighestAvailable)
{
ACTCTX ActCtx;
SXS_ARGS args;
ULONG rc;
if (Dll_OsBuild < 6000)
return STATUS_NOT_IMPLEMENTED;
//
// invoke Sxs_GetPathAndText to get the manifest text
//
memzero(&args, sizeof(args));
if (! Sxs_AllocOrFreeBuffers(&args, TRUE))
return STATUS_INSUFFICIENT_RESOURCES;
memzero(&ActCtx, sizeof(ACTCTX));
ActCtx.cbSize = sizeof(ACTCTX);
ActCtx.lpSource = DosPath;
rc = STATUS_UNSUCCESSFUL;
if (Sxs_GetPathAndText(&ActCtx, &args)) {
rc = STATUS_SUCCESS; // manifest found
_strlwr(args.ManifestText);
if (pAsInvoker) *pAsInvoker =
(strstr(args.ManifestText, "level='asinvoker'")
|| strstr(args.ManifestText, "level=\"asinvoker\""));
if (pRequireAdministrator) *pRequireAdministrator =
(strstr(args.ManifestText, "level='requireadministrator'")
|| strstr(args.ManifestText, "level=\"requireadministrator\""));
if (pHighestAvailable) *pHighestAvailable =
(strstr(args.ManifestText, "level='highestavailable'")
|| strstr(args.ManifestText, "level=\"highestavailable\""));
}
Sxs_AllocOrFreeBuffers(&args, FALSE);
return rc;
}
//---------------------------------------------------------------------------
// Sxs_CheckManifestForCreateProcess
//---------------------------------------------------------------------------
_FX ULONG Sxs_CheckManifestForCreateProcess(const WCHAR *DosPath)
{
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
ULONG rc, ElvType;
BOOLEAN AsInvoker, RequireAdministrator, HighestAvailable;
//
// Windows Vista UAC auto-elevates program names that includes words
// like setup/installer/update. a program may specify
// requestedExecutionLevel level="asInvoker"
// in its manifest to inhibit auto-elevation. but since we generally
// use an empty manifest file, it interferes with the asInvoker request.
//
// in this function we examine the real manifest, and if it specifies
// asInvoker then we will set a flag to use alternate manifest/config
// files that also specify asInvoker.
//
TlsData->proc_create_process_as_invoker = FALSE;
if (! __sys_CreateActCtxW)
return 0;
if (Dll_OsBuild < 6000)
return 0;
//
// if we are already administrator then pretend asInvoker
// was used, to prevent any more interference from UAC
//
ElvType = SbieDll_GetTokenElevationType();
if (ElvType == TokenElevationTypeFull) {
TlsData->proc_create_process_as_invoker = TRUE;
return 0;
}
rc = Sxs_CheckManifestForElevation(DosPath, &AsInvoker, &RequireAdministrator, &HighestAvailable);
if (NT_SUCCESS(rc)) {
//
// asInvoker means to use alternate manifest files in
// Sxs_FileCallback, see there
//
// highestAvailable or requireAdministrator means we tell
// our Proc_CreateProcess caller to use SH32_DoRunAs
//
if (AsInvoker)
TlsData->proc_create_process_as_invoker = TRUE;
if (RequireAdministrator ||
(HighestAvailable && ElvType != TokenElevationTypeDefault)) {
//
// if we are running in the SbieSvc UAC elevation process
// then we cannot return ERROR_ELEVATION_REQUIRED because
// that would cause an infinite loop
//
if (Dll_ImageType != DLL_IMAGE_SANDBOXIE_SBIESVC) {
if (Sxs_CheckCompatLayer(DosPath, L"RunAsInvoker"))
TlsData->proc_create_process_as_invoker = TRUE;
else
rc = ERROR_ELEVATION_REQUIRED;
}
}
}
return rc;
}
//---------------------------------------------------------------------------
// Sxs_PreferExternal
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_PreferExternal(THREAD_DATA *TlsData)
{
if (!TlsData->proc_image_path)
return FALSE;
//
// KB5014019 breaks Edge, it seems that making Edge to start its child processes with
// PreferExternalManifest fixes the issue, but the main process must be loaded normally
// hence we have ExternalManifestHack that checks the parent and not the target
//
if (Config_GetSettingsForImageName_bool(L"ExternalManifestHack", FALSE))
return TRUE;
WCHAR *ptr1 = wcsrchr(TlsData->proc_image_path, L'\\');
WCHAR value[16];
SbieDll_GetSettingsForName(NULL, ptr1 + 1, L"PreferExternalManifest", value, sizeof(value), NULL);
return Config_String2Bool(value, FALSE);
}
//---------------------------------------------------------------------------
// Sxs_KeyCallback
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_KeyCallback(const WCHAR *path, HANDLE *out_handle)
{
//
// this callback is invoked by Key_NtCreateKey when it is used during
// CreateProcess. this allows us to intercept the open for SideBySide
// key so we can redirect to the SbieSvc service key which includes
// a pre-set value for PreferExternalManifest
//
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
if (!Sxs_PreferExternal(TlsData))
return FALSE;
if (_wcsnicmp(path, L"\\Registry\\Machine\\", 18) == 0) {
BOOLEAN redirect = FALSE;
path += 18;
if (_wcsnicmp(path, L"Components", 10) == 0)
redirect = TRUE;
else if (_wcsnicmp(path, L"Software\\", 9) == 0) {
path += 9;
if (_wcsnicmp(path, L"Wow6432Node\\", 12) == 0)
path += 12;
if (0 == _wcsicmp(path,
L"Microsoft\\Windows\\CurrentVersion\\SideBySide"))
redirect = TRUE;
}
if (redirect) {
const WCHAR *ValueName = L"PreferExternalManifest";
extern WCHAR *Support_SbieSvcKeyPath;
UNICODE_STRING objname;
OBJECT_ATTRIBUTES objattrs;
HANDLE handle;
InitializeObjectAttributes(
&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
RtlInitUnicodeString(&objname, Support_SbieSvcKeyPath);
if (0 != __sys_NtOpenKey(&handle, KEY_READ, &objattrs))
handle = NULL;
if (handle) {
union {
KEY_VALUE_PARTIAL_INFORMATION kvpi;
ULONG space[6];
} info;
ULONG len;
RtlInitUnicodeString(&objname, ValueName);
if (0 != NtQueryValueKey(
handle, &objname, KeyValuePartialInformation,
&info, sizeof(info), &len))
info.kvpi.Type = 0;
if (info.kvpi.Type == REG_DWORD &&
info.kvpi.DataLength == sizeof(ULONG) &&
*(ULONG *)info.kvpi.Data != 0) {
//WCHAR txt[1024];
//Sbie_snwprintf(txt, 1024, L"REDIR KEY - %s\n", path);
//OutputDebugString(txt);
*out_handle = handle;
return TRUE;
}
CloseHandle(handle);
}
SbieApi_Log(2205, ValueName);
}
}
return FALSE;
}
//---------------------------------------------------------------------------
// Sxs_FileCallback
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_FileCallback(const WCHAR *path, HANDLE *out_handle)
{
//
// this callback is invoked by File_NtCreateFile when it is used during
// CreateProcess. this allows us to intercept any opens for .manifest
// and .config files and redirect them to our dummy/empty manifest from
// our installation home directory
//
THREAD_DATA *TlsData = Dll_GetTlsData(NULL);
if (!Sxs_PreferExternal(TlsData))
return FALSE;
const WCHAR *_Manifest_Txt = L"\\Manifest1.txt";
const WCHAR *_Config_Txt = L"\\Manifest2.txt";
const WCHAR *_Empty_Txt = L"\\Manifest0.txt";
const WCHAR *FileName = NULL;
ULONG FileSize = 0;
WCHAR *ptr1 = wcsrchr(TlsData->proc_image_path, L'\\');
WCHAR *ptr2 = wcsrchr(path, L'\\');
ULONG len = 0;
if (ptr1)
len = wcslen(ptr1);
if (len && ptr2 && _wcsnicmp(ptr1, ptr2, len) == 0) {
if (_wcsicmp(ptr2 + len, Sxs_manifest) == 0) {
FileName = _Manifest_Txt;
FileSize = 364;
} else if (_wcsicmp(ptr2 + len, Sxs_config) == 0) {
FileName = _Config_Txt;
FileSize = 92;
}
}
if (FileName && (! TlsData->proc_create_process_as_invoker)) {
//
// if the EXE does not explicitly say in its manifest:
// requestedExecutionLevel level="asInvoker"
// then we use the empty manifest/config files, to allow
// UAC to use its auto-elevation heuristics
//
FileName = _Empty_Txt;
FileSize = 2;
}
if (FileName) {
HANDLE handle;
WCHAR *FilePath = Dll_AllocTemp(MAX_PATH * 2 * sizeof(WCHAR));
wcscpy(FilePath, Dll_HomeDosPath);
wcscat(FilePath, FileName);
//OutputDebugString(L"*** *** ***\n");
//OutputDebugString(FilePath);
//OutputDebugString(L"*** *** ***\n");
handle = CreateFile(FilePath, FILE_READ_DATA, FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL);
Dll_Free(FilePath);
if (handle == INVALID_HANDLE_VALUE)
handle = NULL;
if (handle) {
IO_STATUS_BLOCK IoStatusBlock;
FILE_NETWORK_OPEN_INFORMATION open_info;
NTSTATUS status = NtQueryInformationFile(
handle, &IoStatusBlock, &open_info,
sizeof(FILE_NETWORK_OPEN_INFORMATION),
FileNetworkOpenInformation);
if (NT_SUCCESS(status) &&
open_info.EndOfFile.QuadPart == FileSize) {
//WCHAR txt[1024];
//Sbie_snwprintf(txt, 1024, L"REDIR FILE - %s\n", path);
//OutputDebugString(txt);
*out_handle = handle;
return TRUE;
}
CloseHandle(handle);
}
SbieApi_Log(2205, FileName + 1);
}
return FALSE;
}
//---------------------------------------------------------------------------
// Sxs_CheckCompatLayer
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_CheckCompatLayer(const WCHAR *DosPath, const WCHAR *Setting)
{
BOOLEAN HaveSetting = FALSE;
WCHAR *text = Dll_AllocTemp(1024 * sizeof(WCHAR));
text[0] = 0;
GetEnvironmentVariable(L"__COMPAT_LAYER", text, 1020);
if (text[0]) {
if (Sxs_CheckCompatLayer_3(text, Setting))
HaveSetting = TRUE;
}
if (! HaveSetting) {
if (Sxs_CheckCompatLayer_2(DosPath, TRUE, text, 1020)) {
if (Sxs_CheckCompatLayer_3(text, Setting))
HaveSetting = TRUE;
}
}
if (! HaveSetting) {
if (Sxs_CheckCompatLayer_2(DosPath, FALSE, text, 1020)) {
if (Sxs_CheckCompatLayer_3(text, Setting))
HaveSetting = TRUE;
}
}
Dll_Free(text);
return HaveSetting;
}
//---------------------------------------------------------------------------
// Sxs_CheckCompatLayer_2
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_CheckCompatLayer_2(
const WCHAR *DosPath, BOOLEAN User, WCHAR *Text, ULONG Length)
{
extern const WCHAR *Key_Registry;
extern const WCHAR *Key_UserCurrent;
UNICODE_STRING objname;
OBJECT_ATTRIBUTES objattrs;
HANDLE handle;
BOOLEAN HaveKey = FALSE;
wcscpy(Text, Key_Registry);
if (User)
wcscat(Text, Key_UserCurrent);
else
wcscat(Text, L"\\machine");
wcscat(Text, L"\\software\\Microsoft\\Windows NT"
L"\\CurrentVersion\\AppCompatFlags\\Layers");
RtlInitUnicodeString(&objname, Text);
InitializeObjectAttributes(
&objattrs, &objname, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (0 == __sys_NtOpenKey(&handle, KEY_READ, &objattrs)) {
RtlInitUnicodeString(&objname, DosPath);
Length *= sizeof(WCHAR);
if (0 == NtQueryValueKey(
handle, &objname, KeyValuePartialInformation,
Text, Length, &Length)) {
KEY_VALUE_PARTIAL_INFORMATION *kvpi =
(KEY_VALUE_PARTIAL_INFORMATION *)Text;
Length = kvpi->DataLength / sizeof(WCHAR);
wmemmove(Text, (WCHAR *)kvpi->Data, Length);
Text[Length] = L'\0';
HaveKey = TRUE;
}
NtClose(handle);
}
return HaveKey;
}
//---------------------------------------------------------------------------
// Sxs_CheckCompatLayer_3
//---------------------------------------------------------------------------
_FX BOOLEAN Sxs_CheckCompatLayer_3(const WCHAR *Text, const WCHAR *Setting)
{
ULONG SettingLen = wcslen(Setting);
const WCHAR *TextPtr = Text;
while (1) {
while (*TextPtr == L' ')
++TextPtr;
if (! *TextPtr)
return FALSE;
if (_wcsnicmp(TextPtr, Setting, SettingLen) == 0
&& ( TextPtr[SettingLen] == L' '
|| TextPtr[SettingLen] == L'\0')) {
return TRUE;
}
while (*TextPtr != L' ') {
if (! *TextPtr)
return FALSE;
++TextPtr;
}
}
return FALSE;
}