Open a JobObject created in a service from a user session process - windows

I have a windows service that creates a JobObject that i need to keep alive as long as the machine is turned on - the goal is to manage a few user session processes that can terminate/start at any time with this JobObject. I am creating it in a service to make sure the process is running at startup, and that it can't be killed by regular users.
However, i don't seem to be able to open a handle to this JobObject from the user session, I always get an access denied (5) error, despite going as far as creating it with a NULL DACL.
I have found a somewhat related question here: Open an Event object created by my service from my application, but for me, even with the NULL DACL, when asking for a JOB_OBJECT_ASSIGN_PROCESS right, i get access denied (asking for SYNCHRONIZE works for example).
The service code:
PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(psd, TRUE, NULL, FALSE);
SECURITY_ATTRIBUTES secAttr= {0};
secAttr.nLength = sizeof(secAttr);
secAttr.bInheritHandle = false;
secAttr.lpSecurityDescriptor = psd;
hJobObject = CreateJobObject(&secAttr, SCL_JOBOBJECTNAME);
LocalFree(psd);
The user session code:
hJobObject = OpenJobObject(JOB_OBJECT_ASSIGN_PROCESS, FALSE, SCL_JOBOBJECTNAME);
if (hJobObject == NULL)
{
DWORD wError = GetLastError();
printf("Error: %d\n", wError); // this always pops 5
return 1;
}
Any ideas? As a test, i tried spawning a user session process from within the service, and assign the JobObject via the service code, and that worked,.. so i'm fairly certain its related to security settings i am missing, despite the NULL DACL.

if you create Job in service - this object by default will be have WinSystemLabelSid label SID: S-1-16-16384 - System Mandatory Level. (i just check this) so you need not only set Dacl but Sacl too. for example:
ULONG cb = MAX_SID_SIZE;
PSID LowLabelSid = (PSID)alloca(MAX_SID_SIZE);
if (CreateWellKnownSid(WinLowLabelSid, 0, LowLabelSid, &cb))
{
PACL Sacl = (PACL)alloca(cb += sizeof(ACL) + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK));
InitializeAcl(Sacl, cb, ACL_REVISION);
if (AddMandatoryAce(Sacl, ACL_REVISION, 0, 0, LowLabelSid))
{
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
SetSecurityDescriptorSacl(&sd, TRUE, Sacl, FALSE);
SECURITY_ATTRIBUTES sa= { sizeof(sa), &sd, FALSE };
if (HANDLE hJob = CreateJobObject(&sa, L"Global\\{58BFC6DB-BE93-4cdb-919C-4C713ACB5A32}"))
{
CloseHandle(hJob);
}
}
}

Related

Need to give read-write access to the .log file which is created by other windows user through VC++ application

I have application in VC++. Which is creating test.log file when it launch and modify log file after session end of application.
My issue is Lets take two normal windows user test1 and test2 both do not have administrator rights.
1] when i login windfows using test1 user and launch my application. when application session end after 10 min if user do not make any operation. When application ends i am creating datalog.log file in "C:\ProgramData\MyApplication\datalog.log" location.
2] I logout windows test1 user
3]I login test2 user on same windows and run my application, This time when session ends, my application get crashed with error message as follows:
Problem signature: Problem Event Name: BEX Application
Name: MyApplication.exe Application Version: 1.0.0.0 Application
Timestamp: 5d60cf28 Fault Module Name: ucrtbase.DLL Fault Module
Version: 10.0.10240.16390 Fault Module Timestamp: 55a5bf73
Exception Offset: 0007c3b4 Exception Code: c0000417 Exception
Data: 00000000 OS Version: 6.1.7601.2.1.0.256.48
To solve this i implemented following function
void SetFilePermission(LPCTSTR FileName)
{
PSID pEveryoneSID = NULL;
PACL pACL = NULL;
EXPLICIT_ACCESS ea[1];
SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
// Create a well-known SID for the Everyone group.
AllocateAndInitializeSid(&SIDAuthWorld, 1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pEveryoneSID);
// Initialize an EXPLICIT_ACCESS structure for an ACE.
ZeroMemory(&ea, 1 * sizeof(EXPLICIT_ACCESS));
ea[0].grfAccessPermissions = 0xFFFFFFFF;
ea[0].grfAccessMode = GRANT_ACCESS;
ea[0].grfInheritance = NO_INHERITANCE;
ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID;
// Create a new ACL that contains the new ACEs.
SetEntriesInAcl(1, ea, NULL, &pACL);
// Initialize a security descriptor.
PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
// Add the ACL to the security descriptor.
SetSecurityDescriptorDacl(pSD,
TRUE, // bDaclPresent flag
pACL,
FALSE); // not a default DACL
//Change the security attributes
SetFileSecurity(FileName, DACL_SECURITY_INFORMATION, pSD);
if (pEveryoneSID)
FreeSid(pEveryoneSID);
if (pACL)
LocalFree(pACL);
if (pSD)
LocalFree(pSD);
}
which is called from following
SetFilePermission(FileName);
stream = fopen( FileName, "a" );
//LOG
//fprintf( stream, "%s\n", s );
fprintf( stream, "%s %s\n", buff, s );
//LOG
fclose( stream );
while debugging i application crashed without any message at fprintf( stream, "%s %s\n", buff, s ); this line.
When i try to modify file manually it gives access rights permission message.
My need is to give read/writer access rights to the datalog.log file regardless of users login on windows and user who created the file.
Operating system is windows 7

OpenMutex fails in process opened with CreateProcessAsUser

I've been banging my head on this for days, and I must have read every page on the Internet even remotely related, but I still can't find an answer. Help!
Here's the scenario: In Windows 7, I have a process running under an admin user account (not a service). It creates a global named mutex, which is later used in a child process running under a regular user account. No matter what I do, or what ACLs I put on the mutex, the child process keeps returning Access Denied when trying to get the handle.
I've distilled my code down into a test app just to experiment with the process and mutex parts, and I found something surprising: if I call OpenMutex from the user app without first creating the mutex, I would expect a Not Found error but I still get Access Denied. However, if I launch the user app from Explorer instead (shift-right-click, Run as different user...), I get the expected behavior. I also noticed that the user app has a plain blocky window border rather than the normal Windows theme when launched from the admin app.
So my guess is that there's something wrong with how I'm launching the user app, but I just can't see what I'm missing.
Here are the relevant parts:
bool CUserTest::LogInUser()
{
if ((m_hUserToken == NULL) && !LogonUser(TEST_USER_NAME, L".", TEST_USER_PASS, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &m_hUserToken))
{
CloseHandle(m_hUserToken);
m_hUserToken = NULL;
}
return (m_hUserToken != NULL);
}
bool CUserTest::LaunchTestApp()
{
PROCESS_INFORMATION ProcInfo;
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(si);
si.lpDesktop = L"winsta0\\default";
wchar_t wszCmdLine[MAX_PATH + 1] = { 0 };
wcscpy(wszCmdLine, L"UserTestClient.exe");
bool bSuccess = false;
LPVOID pEnv;
PROFILEINFO sProfileInfo;
ZeroMemory(&sProfileInfo, sizeof(PROFILEINFO));
sProfileInfo.dwSize = sizeof(PROFILEINFO);
sProfileInfo.lpUserName = TEST_USER_NAME;
if (LoadUserProfile(m_hUserToken, &sProfileInfo))
{
if (ImpersonateLoggedOnUser(m_hUserToken))
{
if (CreateEnvironmentBlock(&pEnv, m_hUserToken, FALSE))
{
bSuccess = CreateProcessAsUser(
m_hUserToken,
NULL,
wszCmdLine,
NULL, // ProcessAttributes
NULL, // ThreadAttributes
FALSE, // InheritHandles
CREATE_UNICODE_ENVIRONMENT, // CreationFlags
pEnv, // Environment
NULL, // CurrentDirectory
&si,
&ProcInfo); // ProcessInformation
DestroyEnvironmentBlock(pEnv);
}
RevertToSelf();
}
UnloadUserProfile(m_hUserToken, sProfileInfo.hProfile);
}
if (bSuccess)
{
CloseHandle(ProcInfo.hThread);
CloseHandle(ProcInfo.hProcess);
}
return bSuccess;
}
I never could get the CreateProcessAsUser call to work correctly, but I finally got it working using CreateProcessWithLogonW instead. The trick was to set si.lpDesktop to NULL rather than "winsta0\default", contrary to everything I'd read up to this point.

How can I add customized strings to the messages displayed by shutdown screen in Windows 7?

How can I add custom text to shutdown screen, like those messages that show when Windows is installing updates before shutting down? For example, you have a backup script that is executed on shutdown, and you want to inform about the progress of the backup just like Windows does when installing updates. Is there any command line tool for that, or some code library, or even something in Windows API?
Note that this is not about how to shutdown a computer, and it is not about whatever way to display a message there in shutdown screen, such as console applications or message boxes. This is not about customizing existing messages either, and it is not about any shutdown dialog that shows before shutdown screen and allows the user to cancel the shutdown or proceed without waiting for the programs to terminate.
This is about understanding how Windows implements the displaying of those messages the way they are displayed there in shutdown, and how to add new messages to be displayed, preferably with progress information. To be clear, below is a screenshot.
There is a function WmsgPostNotifyMessage in wmsgapi.dll which is displaying this message. Undocumented though, but shouldn't be a problem to use.
Here is a C++ code that can shutdown the computer with message.
#include <windows.h>
#pragma comment( lib, "advapi32.lib" )
BOOL MySystemShutdown( LPTSTR lpMsg )
{
HANDLE hToken; // handle to process token
TOKEN_PRIVILEGES tkp; // pointer to token structure
BOOL fResult; // system shutdown flag
// Get the current process token handle so we can get shutdown
// privilege.
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return FALSE;
// Get the LUID for shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
&tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
if (GetLastError() != ERROR_SUCCESS)
return FALSE;
// Display the shutdown dialog box and start the countdown.
fResult = InitiateSystemShutdown(
NULL, // shut down local computer
lpMsg, // message for user
30, // time-out period, in seconds
FALSE, // ask user to close apps
TRUE); // reboot after shutdown
if (!fResult)
return FALSE;
// Disable shutdown privilege.
tkp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
return TRUE;
}

MiniFilter driver. Filter attaching problems

I'm developing a miniFilter driver and took the Microsoft's SwapBuffers
miniFilter as example.
An InstaceSetup routin by default is attaching to all volumes. But I don't want
to attach to all of them, only to some choosen...
I tried to set "NULL" instead of "InstanceSetup" in "FLT_REGISTRATION
FilterRegistration" and then to call "FltAttachVolume" in the "DriverEntry"
routin. I've done the following:
PFLT_VOLUME vol;
UNICODE_STRING vname;
....
RtlInitUnicodeString(&vname, L"E:\");
FltGetVolumeFromName(gFilterHandle, &vname, &vol);
...
FltAttachVolume(gFilterHandle, vol, NULL, NULL);
...
When i tried to call FltAttachVolume with the "NULL" 3-d parameter
(PCUNICODE_STRING InstanceName) i received a
"STATUS_FLT_INSTANCE_NAME_COLLISION" error.
If i call FltAttachVolume with a "NOT NULL" 3-d parameter, such as a
"UniqueInstaceName" it returns me "-2145452013".
I'm receiving the same errors, when i,m trying to attach a volume, using a
FilterAttach routine from my User application, like this:
...
driver.driverName = L"swapBuffers";
...
LPCWSTR vname = L"F:\";
...
FilterAttach(driver.driverName, vname, NULL, NULL, NULL);
With "NULL" 3-d parameter (LPCWSTR lpInstanceName):
"ERROR_FLT_INSTANCE_NAME_COLLISION"
With "NOT-NULL": "-2145452013".
In MiniSpy miniFilter there is a User application, and the routine FilterAttach
is used. I tried to call this routine in my application the same way - no
results.
Finally, i changed the swapBuffers inf-file:
there was no DefaultInstance parameter, i set it: "SwapBuffers - Top
Instance".
also i copied this from the MiniSpy inf-file:
[MiniFilter.AddRegistry]
HKR,"Instances","DefaultInstance",0x00000000,%DefaultInstance%
HKR,"Instances\"%Instance1.Name%,"Altitude",0x00000000,%Instance1.Altitude%
HKR,"Instances\"%Instance1.Name%,"Flags",0x00010001,%Instance1.Flags%
HKR,"Instances\"%Instance2.Name%,"Altitude",0x00000000,%Instance2.Altitude%
HKR,"Instances\"%Instance2.Name%,"Flags",0x00010001,%Instance2.Flags%
HKR,"Instances\"%Instance3.Name%,"Altitude",0x00000000,%Instance3.Altitude%
HKR,"Instances\"%Instance3.Name%,"Flags",0x00010001,%Instance3.Flags%
.............
Instance1.Name = "SwapBuffers - Middle Instance"
Instance1.Altitude = "370000"
Instance1.Flags = 0x1 ; Suppress automatic attachments
Instance2.Name = "SwapBuffers - Bottom Instance"
Instance2.Altitude = "361000"
Instance2.Flags = 0x1 ; Suppress automatic attachments
Instance3.Name = "SwapBuffers - Top Instance"
Instance3.Altitude = "385100"
Instance3.Flags = 0x1 ; Suppress automatic attachments
changing the flags to 0x1 to suppress automatic attachments.
And only installing my SwapBuffers miniFilter through this Inf file, i received
"STATUS_SUCCESS" from FltAttachVolume routine in my driver. But it isn't really
attaching to the disk...
What am i doing wrong?
Thanks.
Instance1.Flags = 0x1
That is fine.
I have somewhat similar code and that works fine.
status = FltRegisterFilter( DriverObject,
&FilterRegistration,
&gFilterHandle );
FLT_ASSERT( NT_SUCCESS( status ) );
if (NT_SUCCESS( status )) {
PSECURITY_DESCRIPTOR sd;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING uniString;
status = FltBuildDefaultSecurityDescriptor(&sd,
FLT_PORT_ALL_ACCESS);
if (!NT_SUCCESS(status)) {
return status;
}
RtlInitUnicodeString(&uniString, PORT_NAME);
InitializeObjectAttributes(&oa,
&uniString,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
sd);
status = FltCreateCommunicationPort(gFilterHandle,
&gServerPort,
&oa,
NULL,
Connect,
Disconnect,
Message,
1);
FltFreeSecurityDescriptor(sd);
BREAK_HERE(); // DbgBreak() macro
//
// Start filtering i/o
//
status = FltStartFiltering(gFilterHandle);
if (!NT_SUCCESS(status)) {
FltUnregisterFilter(gFilterHandle);
}
else {
RtlInitUnicodeString(&uniString, L"\\Device\\HarddiskVolume1");
PFLT_VOLUME vol;
FltGetVolumeFromName(gFilterHandle, &uniString, &vol);
status = FltAttachVolume(gFilterHandle, vol, NULL, NULL);
// status == 0x0 at that point and the mini filter is attached to the Volume
}
}
I normally attach to all volumes but I wanted to try attaching to a single volume and it works fine.

Create Process with FS Virtualization Enabled

With UAC disabled, I need to create a process with the same characteristics as the process created with UAC enabled - basically I'm emulating process creation with UAC enabled.
My only roadblock is virtualization. The sample code below should create an instance of notedpad at medium IL with virtualization enabled. In actuality, it creates an instance of notepad at medium IL with virtualization disabled. I'm not entirely sure why the virtualization token is being ignored. Any ideas?
BOOL bRet;
HANDLE hToken;
HANDLE hNewToken;
// Notepad is used as an example
WCHAR wszProcessName[MAX_PATH] =
L"C:\\Windows\\System32\\Notepad.exe";
// Medium integrity SID
WCHAR wszIntegritySid[20] = L"S-1-16-8192";
PSID pIntegritySid = NULL;
DWORD EnableVirtualization = 1;
TOKEN_MANDATORY_LABEL TIL = {0};
PROCESS_INFORMATION ProcInfo = {0};
STARTUPINFO StartupInfo = {0};
ULONG ExitCode = 0;
if (OpenProcessToken(GetCurrentProcess(),MAXIMUM_ALLOWED, &hToken))
{
if (DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL,
SecurityImpersonation, TokenPrimary, &hNewToken))
{
if (ConvertStringSidToSid(wszIntegritySid, &pIntegritySid))
{
TIL.Label.Attributes = SE_GROUP_INTEGRITY;
TIL.Label.Sid = pIntegritySid;
// Set the process integrity level
if (SetTokenInformation(hNewToken, TokenIntegrityLevel, &TIL,
sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid)))
{
// Enable FS Virtualization
if (SetTokenInformation(hNewToken, TokenVirtualizationEnabled,
&EnableVirtualization, sizeof(EnableVirtualization)))
{
// Create the new process at Low integrity
bRet = CreateProcessAsUser(hNewToken, NULL,
wszProcessName, NULL, NULL, FALSE,
0, NULL, NULL, &StartupInfo, &ProcInfo);
}
}
LocalFree(pIntegritySid);
}
CloseHandle(hNewToken);
}
CloseHandle(hToken);
}
So, I was approaching this incorrectly - fs virtualization is not what I want. To emulate UAC, as described above, its necessary to create a restricted token with the administrators group disabled and use that token to create the process.
The reason that this doesn't work, is that the SetTokenInformation call to turn on virtualisation is working on the primary token created for CreateProcessAsUser. What's needed is an access token for the actual process. This can be obtained by creating the process with the CreationFlag CREATE_SUSPENDED, and calling OpenProcessToken with the process handle from ProcInfo. Use SetTokenInformation on that token to enable virtualisation, and then ResumeThread to run the process.

Resources