I'm using the GetSecurityInfo
funtion to get my own process's Discretional Access Control List (DACL):
PACL oldAcl;
Pointer se;
GetSecurityInfo(GetCurrentProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
null, null, ref oldAcl, nil, ref se);
And then i can use the GetExplicitEntriesFromAcl
to crack open the ACL to get at it's list of Access Control Entries (ACE) inside:
UInt32 nCount;
EXPLICIT_ACCESS[] list;
GetExplicitEntriesFromAcl(oldAcl, ref nCount, ref list);
I can go through the list of three entries on my process:
STACKOVERFLOW\ian (S-1-5-21-6198258843-697258998-2146844275-1109) [SidTypeUser]
NT AUTHORITY\SYSTEM (S-1-5-18) [SidTypeWellKnownGroup]
I now want to go through and update the DACL for the process (which of course i'm allowed to do since i have WRITE_DACL
- and because i'm the Owner, which means i implicitly have WRITE_DACL
).
But i only want to re-write access control entries that apply to "me".
In this case there happen to be three Trustees:
Trustees are presented to us as a TRUSTEE
object (note, not all of which have an SID). I know from experience that i am two of those trustees; but not the third.
Is there a function that i can use to compare "me" against a TRUSTEE
?
Boolean DoIMatchThisTrustee(TRUSTEE trustee)
{
}
No reason. I'm removing PROCESS_VM_READ
, PROCESS_VM_WRITE
, and PROCESS_VM_OPERATION
from myself on my own process.
you actually want check Discretional Access Control List (DACL) for Sids which is "me" - so enabled members of your process token.
To determine whether a SID is enabled in a token we can use CheckTokenMembership
function.
use GetSecurityInfo
not the best choice i think, much better use GetKernelObjectSecurity
here. however you can check and trustees if want ("note, not all of which have an SID" - this is in general case, but in case DACL you will got only TRUSTEE_IS_SID
trustees). code can be next:
void Test()
{
HANDLE hToken, hImpToken;
if (OpenProcessToken(NtCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &hToken))
{
BOOL fOk = DuplicateToken(hToken, ::SecurityIdentification, &hImpToken);
CloseHandle(hToken);
if (fOk)
{
ULONG cb = 0, rcb = 256;
static volatile UCHAR guz = 0;
PVOID stack = alloca(guz);
union {
PVOID buf;
PSECURITY_DESCRIPTOR pSD;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (GetKernelObjectSecurity(NtCurrentProcess(), DACL_SECURITY_INFORMATION, pSD, cb, &rcb))
{
BOOL bPresent, bDefault;
union {
PACL Acl;
PBYTE pb;
PACE_HEADER pah;
PACCESS_ALLOWED_ACE paaa;
};
if (GetSecurityDescriptorDacl(pSD, &bPresent, &Acl, &bDefault) && bPresent && Acl)
{
CheckSidsInAcl(Acl);
if (USHORT AceCount = Acl->AceCount)
{
Acl++;
do
{
if (pah->AceType == ACCESS_ALLOWED_ACE_TYPE)
{
BOOL IsMember;
if (CheckTokenMembership(hImpToken, &paaa->SidStart, &IsMember))
{
PWSTR sz;
if (ConvertSidToStringSid(&paaa->SidStart, &sz))
{
DbgPrint("%x %S\n", IsMember, sz);
LocalFree(sz);
}
}
else
{
GetLastError();
}
}
} while (pb += pah->AceSize, --AceCount);
}
}
break;
}
} while (GetLastError() == ERROR_INSUFFICIENT_BUFFER);
CloseHandle(hImpToken);
}
}
}
I don't think there are any functions to compare nor normalize a TRUSTEE.
The ACEs in a ACL always store a SID (as far as I know) so it is probably safe to assume that the TRUSTEE will be a TRUSTEE_IS_*SID form when you get it from a ACL.
PSID GetSID(const TRUSTEE&t)
{
if (TRUSTEE_IS_SID == t.TrusteeForm) return (PSID) t.ptstrName;
if (TRUSTEE_IS_OBJECTS_AND_SID == t.TrusteeForm) return ((OBJECTS_AND_SID*)t.ptstrName)->pSid;
return NULL;
}
bool DoIMatchThisTrustee(TRUSTEE&t)
{
PSID tsid = GetSID(t);
PSID mysid = GetMySid(); // From process/thread token or somewhere else
return tsid && EqualSid(tsid, mysid);
}
If you don't want to assume then you can use LookupAccountName
on the string forms to get a SID.
If for whatever reason you don't want to lookup any strings you can do things NT4 style and work with the ACL directly. Call GetAce
to enumerate the ACL and use something like this:
PSID GetAllowedSID(const ACE_HEADER&ah)
{
switch(ah.AceType)
{
case ACCESS_ALLOWED_ACE_TYPE: return (PSID) &((ACCESS_ALLOWED_ACE*)&ah)->SidStart;
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE: return (PSID) &((ACCESS_ALLOWED_CALLBACK_ACE*)&ah)->SidStart;
case ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE: return (PSID) &((ACCESS_ALLOWED_CALLBACK_OBJECT_ACE*)&ah)->SidStart;
case ACCESS_ALLOWED_OBJECT_ACE_TYPE: return (PSID) &((ACCESS_ALLOWED_OBJECT_ACE*)&ah)->SidStart;
default: return NULL;
}
}
If you are doing this to increase security you might want to do things the other way around and only allow "NT AUTHORITY\SYSTEM" and "BUILTIN\Administrators" these rights.
Whether or not the logon session is "you" is debatable but you cannot compare the full SID to find out, just the SECURITY_NT_AUTHORITY+SECURITY_LOGON_IDS_RID parts.
RbMm's comment reminded me that i already knew the answer somewhere deep in my brain: CheckTokenMembeship
:
//Get the ACL on the process
PACL oldAcl;
Pointer se;
GetSecurityInfo(GetCurrentProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
null, null, ref oldAcl, nil, ref se); //allocates memory into se, which we must LocalFree later
//oldAcl is a pointer to inside the se blob
//Crack open the ACL, to feast on the entries inside
UInt32 nCount;
EXPLICIT_ACCESS[] list;
GetExplicitEntriesFromAcl(oldAcl, ref nCount, ref list); //allocates memory into list, which we must localFree later
//the flags i want to remove me from having
DWORD removeFlags = PROCESS_VM_READ || PROCESS_VM_WRITE || PROCESS_VM_OPERATION;
//Go through the list, looking for entries that are "me"
for (EXPLICIT_ACCESS ea in list)
{
if (ea.Trustee.TrusteeForm != TRUSTEE_IS_SID)
continue;
BOOL isMember;
CheckTokenMembership(0, PSID(ea.Trustee.ptstrName), out isMember);
if (!isMember)
continue;
//Remove the permissions
ea.grfAccessPermissions = ea.grfAccessPermissions && (!removeFlags);
aclUpdateNeeded = true;
}
//write the new DACL
SetEntriesInAcl(nCount, list, null, out newAcl); //allocates a new acl
SetSecurityInfo(GetCurrentProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
null, null, newAcl, null); //apply the new acl
LocalFree(list); //free the memory allocated by GetExplicitEntriesFromAcl
LocalFree(se); //free the memory allocated by GetSecurityInfo
User contributions licensed under CC BY-SA 3.0