Note that absolutely none of this is authoritative or directly based on relevant documentation. It’s mostly what I found and figured out and guessed and (in some cases) made up. Some of it may be wrong or dangerous or lead to disaster or confusion. I am not taking responsibility here for anything, not even spelling. Read and digest at your own peril!

Like services (see Services) processes have security descriptors that contain a DACL.

Processes can be intefered with by users who are not their owners (although this does not work if the processes are owned by the Administrators group). It is sometimes the case that one wants one user (or members of a group) to be able to terminate processes run by other users (for example services that cannot be stopped because of a problem).

If user legrand starts a program, user benoit cannot typically interfere with it:

PS C:\Users\benoit> query session
 SESSIONNAME               USERNAME                 ID  STATE   TYPE        DEVICE
 services                                            0  Disc
>console                   benoit                    1  Active
                           legrand                   3  Disc
 rdp-tcp                                         65536  Listen
PS C:\Users\benoit> Get-Process winver

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    186      13     2308      15432              8836   3 winver


PS C:\Users\benoit> Get-Process winver|Stop-Process
Stop-Process : Cannot stop process "winver (8836)" because of the following error: Access is denied
At line:1 char:20
+ Get-Process winver|Stop-Process
+                    ~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (System.Diagnostics.Process (winver):Process) [Stop-Process], ProcessCommandException
    + FullyQualifiedErrorId : CouldNotStopProcess,Microsoft.PowerShell.Commands.StopProcessCommand

PS C:\Users\benoit> taskkill /im winver.exe
ERROR: The process "winver.exe" with PID 8836 could not be terminated.
Reason: Access is denied.
PS C:\Users\benoit>

Note that user legrand is logged into session 3 and is running the program winver. User benoit tries to terminate winver but cannot, neither using PowerShell’s Stop-Process cmdlet nor using the taskkill program.

But the DACL (discretionary access control list) of the process (running program) can be modified by those who have access to it and by the user who starts it.

This is what the DACL of the process 8836 looks like:

PS C:\> Get-Process winver

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    185      13     2352      15472       0.11   8836   3 winver


PS C:\> & 'C:\Program Files\ABTokenTools\AclEdit.exe'
AclEdit type pathObject [sddl] [D|E]

0       SE_UNKNOWN_OBJECT_TYPE
1       SE_FILE_OBJECT
2       SE_SERVICE
3       SE_PRINTER
4       SE_REGISTRY_KEY
5       SE_LMSHARE
6       SE_KERNEL_OBJECT
7       SE_WINDOW_OBJECT
8       SE_DS_OBJECT
9       SE_DS_OBJECT_ALL
10      SE_PROVIDER_DEFINED_OBJECT
11      SE_WMIGUID_OBJECT
12      SE_REGISTRY_WOW64_32KEY
13      SE_REGISTRY_WOW64_64KEY

Currently supports setting DACLs and owners. Setting an owner might require the appropriate privilege.
Disable or enable inheritance with AclEdit type pathObject sddl D|E.
File, service, printer, registry, and share objects take UNC paths. DS_OBJECT takes X.500 format.
Registry paths start with "CLASSES_ROOT", "CURRENT_USER", "MACHINE", and "USERS". "MACHINE\SOFTWARE" is a key.
"6 pid" will display ACL of process with id pid
"6 \KernelObjects\Session#" will display ACL of session number #.
"7 WinSta0 or 7 Default" will display permissions of the current session's window station 0 or default desktop.

PS C:\> & 'C:\Program Files\ABTokenTools\AclEdit.exe' 6 8836
O:S-1-5-21-344341352-2539047333-2300305637-1005D:(A;;0x1fffff;;;S-1-5-21-344341352-2539047333-2300305637-1005)(A;;0x1fffff;;;SY)(A;;0x121411;;;S-1-5-5-0-36021173)
PS C:\>

Looking the the SDDL output, we see the following:

O:S-1-5-21-344341352-2539047333-2300305637-1005 The owner of the process is user legrand
D: beginning of DACL
(A;;0x1fffff;;;S-1-5-21-344341352-2539047333-2300305637-1005) User legrand has full access
(A;;0x1fffff;;;SY) LocalSystem has full access
(A;;0x121411;;;S-1-5-5-0-36021173) The user’s session has some access

We need the process to start with a different DACL.

To see how this works, we first have to look at how process creation works.

This is the necessary includes and some variables and a function for error reporting. I always include the variables and function in every program. The includes are necessary for process creation and modifying a process security descriptor.

Also note that this program, since it uses wchar.h requires the C runtime library which either needs to be installed separately on the target computer or statically linked:

Properties -> Configuration Properties -> C/C++ -> Code Generation -> Runtime Library: Multi-threaded (/MT)

#include <Windows.h>
#include <AclAPI.h>
#include <sddl.h>
#include <securitybaseapi.h>
#include <wchar.h>

BOOL debug = TRUE; // Error() below will only do something if debug is TRUE.

// Windows APIs give results in various ways, some say true if they work, some give a status number, but GetLastError() will always get the last error.
BOOL ok = TRUE;
DWORD error = 0;
LSTATUS status = 0;

void Error(LPCWSTR sz)
{
	if (!debug) { return; }
	if (!ok || status) { error = GetLastError(); }
	fwprintf(stderr, L"%s\tOK: [%d]\tSTATUS: [%d], Error: [%d]\n", sz, ok, status, error);
	error = 0;
	status = 0;
	ok = TRUE;
}

Then creating a process is not so difficult:

int main()
{
	// need a startup info struct and a process info struct
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	// they need to be initialised with nothing
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));

	// create new process to run winver.exe
	// image path, command line, process attributes, thread attributes, inherit handles, creation flags, environment, directory, startup info address, process info address
	ok = CreateProcess(L"C:\\Windows\\System32\\winver.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
	Error(L"CreateProcess");

	// close handles to process and thread in pi struct
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
}

This simply starts winver.exe literally without any special settings.

User benoit was not able to terminate this process started and owned by user legrand.

Now let’s create a process with a custom DACL. In this case we make the DACL quite ridiculous, we simply allow everything to everyone. (It would be more prudent to read the existing DACL and add to it.)

The process is created suspended so the DACL can be updated before the process is released into the wild.

int main()
{
	// need a startup info struct and a process info struct
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	// they need to be initialised with nothing
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));

	// create new process to run winver.exe
	// image path, command line, process attributes, thread attributes, inherit handles, creation flags, environment, directory, startup info address, process info address
	ok = CreateProcess(L"C:\\Windows\\System32\\winver.exe", NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
	Error(L"CreateProcess");

	// can now set process acl, will simply allow everyone to do everything with it
	PSECURITY_DESCRIPTOR pSD = NULL;
	LPWSTR sddl = L"D:(A;;0x1fffff;;;WD)"; // "WD" (world) is everyone.
	ok = ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, SDDL_REVISION_1, &pSD, NULL);
	Error(L"ConvertStringSecurityDescriptorToSecurityDescriptor");
	BOOL tfDaclPresent = FALSE;
	BOOL tfDaclDefaulted = FALSE;
	PACL pDacl = NULL;
	ok = GetSecurityDescriptorDacl(pSD, &tfDaclPresent, &pDacl, &tfDaclDefaulted);
	Error(L"GetSecurityDescriptorDacl");
	status = SetSecurityInfo(pi.hProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, pDacl, NULL);
	Error(L"SetSecurityInfo");

	// release the process into the wild
	ResumeThread(pi.hThread);

	// close handles to process and thread in pi struct
	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);
}

This results in a process winver.exe with the following (very simple) DACL:

PS C:\> Get-Process winver

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    181      13     2348      15472       0.09   8160   3 winver


PS C:\> & 'C:\Program Files\ABTokenTools\AclEdit.exe' 6 8160
O:S-1-5-21-344341352-2539047333-2300305637-1005D:(A;;0x1fffff;;;WD)
PS C:\>
O:S-1-5-21-344341352-2539047333-2300305637-1005 The owner is still user legrand
D: DACL starts
(A;;0x1fffff;;;WD) Everyone (WD) has full access

And now user benoit can terminate the process, since user benoit is a man of the world:

PS C:\Users\benoit> Get-Process winver

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
-------  ------    -----      -----     ------     --  -- -----------
    182      13     2320      15472       0.09   8160   3 winver


PS C:\Users\benoit> Get-Process winver|Stop-Process

Confirm
Are you sure you want to perform the Stop-Process operation on the following item: winver(8160)?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):
PS C:\Users\benoit> Get-Process winver
Get-Process : Cannot find a process with the name "winver". Verify the process name and call the cmdlet again.
At line:1 char:1
+ Get-Process winver
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (winver:String) [Get-Process], ProcessCommandException
    + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand

PS C:\Users\benoit>

Now, this way of dealing with processes is not particularly simple. For example, you need whomever starts the process to cooperate and configure the DACL correctly. An easier way to deal with allowing a user to stop processes of a certain name via JEA.

Next: Processes JEA