if we run elevated process (by admin user) - it have not elevated linked session. (and non elevated process have elevated linked session) you need:
- open process token
- query linked session token for this token via
TokenLinkedToken
- query default dacl for this linked token via
TokenDefaultDacl
- initialize security descriptor with this DACL
code for get default dacl for not elevated session:
ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? 0 : GetLastError();
}
ULONG GetNotElevatedDefaultDacl(PTOKEN_DEFAULT_DACL* DefaultDacl)
{
HANDLE hToken;
ULONG err = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (!err)
{
ULONG cb;
union {
TOKEN_LINKED_TOKEN tlt;
TOKEN_ELEVATION_TYPE tet;
};
err = BOOL_TO_ERROR(GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &cb));
if (!err)
{
if (tet == TokenElevationTypeFull)
{
err = BOOL_TO_ERROR(GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &cb));
}
else
{
err = ERROR_ELEVATION_REQUIRED;
}
}
CloseHandle(hToken);
if (!err)
{
union {
PTOKEN_DEFAULT_DACL p;
PVOID buf;
};
cb = 0x100;
do
{
if (buf = LocalAlloc(0, cb))
{
if (err = BOOL_TO_ERROR(GetTokenInformation(
tlt.LinkedToken, TokenDefaultDacl, buf, cb, &cb)))
{
LocalFree(buf);
}
else
{
*DefaultDacl = p;
}
}
else
{
err = GetLastError();
break;
}
} while (err == ERROR_INSUFFICIENT_BUFFER);
CloseHandle(tlt.LinkedToken);
}
}
return err;
}
and using it (this for any object which take SECURITY_ATTRIBUTES
on create)
PTOKEN_DEFAULT_DACL DefaultDacl;
ULONG err = GetNotElevatedDefaultDacl(&DefaultDacl);
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa = { sizeof(sa), &sd, FALSE };
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
if (!err)
{
SetSecurityDescriptorDacl(&sd, TRUE, DefaultDacl->DefaultDacl, FALSE);
}
HANDLE hObject = CreateMailslot(
L"\\\\?\\Global\\MailSlot\\12345678", 0, MAILSLOT_WAIT_FOREVER, &sa);
if (!err)
{
LocalFree(DefaultDacl);
}
if (hObject)
{
// CheckObjectSD(hObject);
CloseHandle(hObject);
}
if create object(mailslot in this case) from elevated process with default dacl - security DACL will be look like:
T FL AcessMsK Sid
A 00 001F01FF S-1-5-32-544 'Administrators'
A 00 001F01FF S-1-5-18 'SYSTEM'
A 00 001200A9 S-1-5-5-0-x 'LogonSessionId_0_x'
so all access for SYSTEM and Administrators and read+execute access for current Logon Session. as result not elevated process from same logon session have only read access.
if use explicit DACL from not elevated session - result:
T FL AcessMsK Sid
A 00 001F01FF S-1-5-21-a-b-c-d 'SomeUser'
A 00 001F01FF S-1-5-18 'SYSTEM'
A 00 001200A9 S-1-5-5-0-x 'LogonSessionId_0_x'
so all access for SYSTEM and SomeUser and read+execute access for current Logon Session.
note because elevated process have SomeUser as TokenUser he have all access for this object
for check object security descriptor we can use for example next code:
void CheckObjectSD(HANDLE hObject)
{
union {
PSECURITY_DESCRIPTOR psd;
PVOID buf;
};
ULONG cb = 0, rcb = 0x30;
volatile static UCHAR guz;
buf = alloca(guz);
PVOID stack = alloca(guz);
ULONG err;
do
{
if (cb < rcb)
{
cb = (ULONG)((ULONG_PTR)stack - (ULONG_PTR)(buf = alloca(rcb - cb)));
}
if (!(err = BOOL_TO_ERROR(GetKernelObjectSecurity(hObject,
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, psd, cb, &rcb))))
{
PWSTR psz;
if (ConvertSecurityDescriptorToStringSecurityDescriptorW(psd, SDDL_REVISION,
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, &psz, 0))
{
DbgPrint("%S\n", psz);
LocalFree(psz);
}
}
} while (err == ERROR_INSUFFICIENT_BUFFER);
}
if we have not admin user account, elevation was via another user account. elevated process in this case have no more linked session (if we try query linked token we got error - A specified logon session does not exist. It may already have been terminated. ). possible solution here(and in generic case too) in next:
for users process default DACL usually grant GENERIC_ALL
for System and UserSid and GENERIC_READ | GENERIC_EXECUTE
for logon session SID. we can query process token, get it default DACL, found LogonSession SID in DACL and change it access mask to GENERIC_ALL
. this can be done by next code:
ULONG GetDaclForLogonSession(HANDLE hToken, PTOKEN_DEFAULT_DACL* DefaultDacl)
{
ULONG err;
ULONG cb = 0x100;
union {
PTOKEN_DEFAULT_DACL p;
PVOID buf;
};
do
{
if (buf = LocalAlloc(0, cb))
{
if (!(err = BOOL_TO_ERROR(GetTokenInformation(hToken, TokenDefaultDacl, buf, cb, &cb))))
{
err = ERROR_NOT_FOUND;
if (PACL Dacl = p->DefaultDacl)
{
if (USHORT AceCount = Dacl->AceCount)
{
union {
PVOID pv;
PBYTE pb;
PACE_HEADER pah;
PACCESS_ALLOWED_ACE paaa;
};
pv = Dacl + 1;
static const SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
do
{
switch (pah->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
PSID Sid = &paaa->SidStart;
if (*GetSidSubAuthorityCount(Sid) == SECURITY_LOGON_IDS_RID_COUNT &&
*GetSidSubAuthority(Sid, 0) == SECURITY_LOGON_IDS_RID &&
!memcmp(GetSidIdentifierAuthority(Sid), &NtAuth, sizeof(NtAuth)))
{
paaa->Mask = GENERIC_ALL;
*DefaultDacl = p;
return 0;
}
break;
}
pb += pah->AceSize;
} while (--AceCount);
}
}
}
LocalFree(buf);
}
else
{
return GetLastError();
}
} while (err == ERROR_INSUFFICIENT_BUFFER);
return err;
}
ULONG GetDaclForLogonSession(PTOKEN_DEFAULT_DACL* DefaultDacl)
{
HANDLE hToken;
ULONG err = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (!err)
{
err = GetDaclForLogonSession(hToken, DefaultDacl);
CloseHandle(hToken);
}
return err;
}
as result we got DACL
we grant all access to current logon session. usage the same - simply replace call from GetNotElevatedDefaultDacl
to GetDaclForLogonSession
CreateFile
, but want a file, that's not backed by storage on the disk. It's not really clear, what you are asking for. Can you clarify? @πάν: That's not, what the c++ tag is for. From the info: "Use this tag for questions about code (to be) compiled with a C++ compiler." That does not imply, that the tag should be used for C++ specific problems only (although that would probably make for better tag searchability). – IInspectableCreateFile
creates or opens only a File object. NT has 3 types of create calls for the kernel functionIoCreateFile
:CreateFileTypeNone
(i.e.NtCreateFile
system call for a regular file or device),CreateFileTypeNamedPipe
(i.e.NtCreateNamedPipeFile
), andCreateFileTypeMailslot
(i.e.NtCreateMailslotFile
). The latter two use the reservedInternalParameters
to create a server-side named pipe or mailslot. – Eryk SunNtCreateFile
=>IoCreateFile
:CreateFileTypeNone
, which creates a File object that references either a device directly or a file on a device (e.g. a file in a file system or in a device namespace). Named pipes and mailslots are created in rudimentary file systems (e.g. "\Device\NamedPipe\" is listable viaNtQueryDirectoryFile
), in which a file is created by the first server-side File object reference. – Eryk Sun