C#Winapi-创建一个新的DACL
我正在尝试在用户使用Logonuserexw登录的用户中启动一个过程。
为此,我需要修改WinStation“ Winsta0”和Desktop“ Default”的DACL。 我要做的是使用getCurityInfo获取DACL和安全性描述符(我实际上不需要或使用)。 然后,我两次致电GetAclinformation,以获取有关ACL大小和修订的信息。
ACL_SIZE_INFORMATION aclInfoSizeOut = new ACL_SIZE_INFORMATION();
GetAclInformation(daclWinsta, out aclInfoSizeOut, Marshal.SizeOf(aclInfoSizeOut), ACL_INFORMATION_CLASS.AclSizeInformation);
ACL_REVISION_INFORMATION aclInfoRevisionOut = new ACL_REVISION_INFORMATION();
GetAclInformation(daclWinsta, out aclInfoRevisionOut, Marshal.SizeOf(aclInfoRevisionOut), ACL_INFORMATION_CLASS.AclRevisionInformation);
一旦我拥有数据, 我计算新ACL的要求大小:
int cbNewACL = Convert.ToInt32(aclInfoSizeOut.AclBytesInUse + Marshal.SizeOf(allowedAce) + GetLengthSid(userpSid) - sizeof(UInt32));
然后按 https://web.archive.org/web/2012121231022835/http:/http://support.microsoft.com.com.com/kb/102102 我使用这种新的ACL为新ACL分配了
IntPtr pNewAcl = LocalAlloc(LocalAllocFlags.LPTR, cbNewACL);
它开始混乱的位置我很重要。我无法理解这实际上是如何工作的。 使用localalloc i现在有一个指针,要记忆我指定的大小。 然后,我初始化了应该在该内存块中的新ACL,但是如何?因为一旦我使用以下功能,指针实际上就会重写。有趣的是,每次我调用该功能时,它总是具有相同的值。而Locallloc返回的指针总是不同的。
InitializeAcl(out pNewAcl, cbNewACL, aclInfoRevisionOut.AclRevision);
初始化功能中的PACL被视为 “ [OUT] PACL指向ACL结构的指针,该函数将在调用此功能之前为PACL分配内存。” 我会理解是否将其传递给了该功能的REF,可以知道在何处将ACL定为初始化,但REF根本不会更改它。
另一件事是当我调用initializeacl时,cbnewacl设置为0。这绝对超出了我的脑海。它如何以及为什么会改变价值?
然后,当我调用AddAccessloweredace时,它完全弄乱了我设置的结构,然后才能从现有的Acl-Acl-Acl-Acl-Acl-Acl-Acl-Acl-Acl-Acl-Acl-AcliSizeOut和AclinForeVisionOut获取设置为废话值。例如计数0,使用中的字节78548557(有些数字)。 cbnewacl被更改为1。我不知道为什么这样做。
AddAccessAllowedAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WINSTA_ALL_ACCESS, userpSid);
以下是我的完整代码,它“工作” - 我得到用户的令牌和psid,我查询现有的DACL,我查询DACL的成员并获取他们的字符串SIDS,但仅此而已。我无法创建一个新的DACL。也以我的评论发布。我希望我不要忘记任何签名,因为该代码在VS中比我实际发布的时间更长。
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUserExW(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken,
out IntPtr ppLogonSid,
out IntPtr ppProfileBuffer,
out IntPtr pdwProfileLength,
out QUOTA_LIMITS pQuotaLimits
);
[DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int ConvertSidToStringSidW(
IntPtr SidPtr,
out IntPtr SidString
);
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern int GetSecurityInfo
(
IntPtr handle,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
out IntPtr ppsidOwner,
out IntPtr ppsidGroup,
out IntPtr ppDacl,
out IntPtr ppSacl,
out IntPtr ppSecurityDescriptor
);
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr GetProcessWindowStation();
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern bool GetAclInformation(
IntPtr pAcl,
out ACL_SIZE_INFORMATION pAclInformation,
int nAclInformationLength,
ACL_INFORMATION_CLASS aclInformationClass
);
public struct ACL_SIZE_INFORMATION
{
public uint AceCount;
public uint AclBytesInUse;
public uint AclBytesFree;
}
public struct ACL_REVISION_INFORMATION
{
public int AclRevision;
}
public enum ACL_INFORMATION_CLASS
{
AclRevisionInformation = 1,
AclSizeInformation
}
public struct QUOTA_LIMITS
{
public int PagedPoolLimit;
public int NonPagedPoolLimit;
public int MinimumWorkingSetSize;
public int MaximumWorkingSetSize;
public int PagefileLimit;
public Int64 TimeLimit;
}
ublic struct ACCESS_ALLOWED_ACE
{
public ACE_HEADER Header;
public ACCESS_MASK Mask;
public UInt16 SidStart;
}
ublic enum LocalAllocFlags : uint
{
LHND = 0x0042,
LMEM_FIXED = 0x0000,
LMEM_MOVEABLE = 0x0002,
LMEM_ZEROINIT = 0x0040,
LPTR = 0x0040
}
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalAlloc(LocalAllocFlags flags, int bytes);
DllImport("Advapi32.dll", SetLastError = true)]
public static extern bool InitializeAcl(
out IntPtr pAcl,
int nAclLength,
int dwAclRevision
);
public static extern int AddAccessAllowedAce
(
ref IntPtr pAcl,
/* ACL_REVISION 2
ACL_REVISION_DS 4
*/
int dwAceRevision,
ACCESS_MASK AccessMask,
IntPtr pSid
);
LogonUserExW("XXXXX", "FFFFF", "BBBBB", 2, 0, out IntPtr userToken, out IntPtr userpSid, out IntPtr profileBuffer, out IntPtr profileLength, out QUOTA_LIMITS profQuotaLimits);
ConvertSidToStringSidW(userpSid, out IntPtr ptrSid);
string stringSid = Marshal.PtrToStringUni(ptrSid);
IntPtr winstaHandle = GetProcessWindowStation();
//get security descriptor for the station
int getDescriptorResult = GetSecurityInfo(winstaHandle, SE_OBJECT_TYPE.SE_WINDOW_OBJECT, SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION, out IntPtr owner, out IntPtr group, out IntPtr daclWinsta, out IntPtr Sacl, out IntPtr secDescriptor);
//this actually works but shows different values than ACL_SIZE_INFORMATION and ACL_REVISION_INFORMATION
//maybe DACL is in different structure than ACL struct? could not find any other struct in the documentation
ACL aclStruct = (ACL)Marshal.PtrToStructure(daclWinsta, typeof(ACL));
ACL_SIZE_INFORMATION aclInfoSizeOut = new ACL_SIZE_INFORMATION();
GetAclInformation(daclWinsta, out aclInfoSizeOut, Marshal.SizeOf(aclInfoSizeOut), ACL_INFORMATION_CLASS.AclSizeInformation);
ACL_REVISION_INFORMATION aclInfoRevisionOut = new ACL_REVISION_INFORMATION();
GetAclInformation(daclWinsta, out aclInfoRevisionOut, Marshal.SizeOf(aclInfoRevisionOut), ACL_INFORMATION_CLASS.AclRevisionInformation);
//count:17 bytes:436
//create a new ACL just to get its size for the cbNewACL value
ACCESS_ALLOWED_ACE allowedAce = new ACCESS_ALLOWED_ACE();
int cbNewACL = Convert.ToInt32(aclInfoSizeOut.AclBytesInUse + Marshal.SizeOf(allowedAce) + GetLengthSid(userpSid) - sizeof(UInt32));
//??? for some reason cbNewACL gets cleared after calling InitializeAcl
IntPtr pNewAcl = LocalAlloc(LocalAllocFlags.LPTR, cbNewACL);
InitializeAcl(out pNewAcl, cbNewACL, aclInfoRevisionOut.AclRevision);
//just for test try to add it right away
//AddAccessAllowedAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WINSTA_ALL_ACCESS, userpSid);
//after calling AddAccessAllowedAce the information is structs aclInfoSizeOut and aclInfoRevisionOut gets destroyed
//cbNewAcl gets set to 1
//???
bool newAceAdded = false;
bool userSidAlreadyExists = false;
//copy old ACEs into the new ACL
if (aclInfoSizeOut.AceCount != 0)
{
int indexInNewAcl = 0;
for (int i=0;i<aclInfoSizeOut.AceCount;i++)
{
//get ace and add it to the new ACL
GetAce(daclWinsta, i, out IntPtr existingAce);
if (existingAce != IntPtr.Zero)
{
//get ace header from the ACE pointer to identify the ACE type
//get first 4 bytes from the pointer starting at 0 since ACE_HEADER struct is of size 4
//once we have it in the byte array, create a GC handle with the bytes - this allocates them in a managed memory
//then read it to the structure using Marshal.PtrToStructure
ACE_HEADER aceHeader = new ACE_HEADER();
byte[] aceHeaderBytes = new byte[Marshal.SizeOf(aceHeader)];
Marshal.Copy(existingAce, aceHeaderBytes, 0, aceHeaderBytes.Length);
GCHandle aceHeaderBytesHandle = GCHandle.Alloc(aceHeaderBytes, GCHandleType.Pinned);
try
{
aceHeader = (ACE_HEADER)Marshal.PtrToStructure(aceHeaderBytesHandle.AddrOfPinnedObject(), typeof(ACE_HEADER));
switch (aceHeader.AceType)
{
case 0:
case 1:
//0 allowed - ACCESS_ALLOWED_ACE, 1 denied - ACCESS_DENIED_ACE
//the two have the same members definied in their structure.
//the declaration below is not explicitly needed in our case, but might be useful for some other things
//ACCESS_ALLOWED_ACE existingDeniedAllowedACE = (ACCESS_ALLOWED_ACE)Marshal.PtrToStructure(existingAce, typeof(ACCESS_ALLOWED_ACE));
//0 and 1 in this context are together in one clause since they are definied by the same members in the same order, thus allowing us
//to get SidStart from the same offset from the ACE IntPtr
//GUESSING: SidStart starts at 8th byte in the struct, therefore an offset of 8 bytes - size of ACE_HEADER and ACCESS_MASK (Uint16)
//if for example the ACE type would be definied by more members with SidStart at the end, we would have to calculate the offset by
//the sum of all members except for SidStart
IntPtr sidPtrInAce = IntPtr.Zero;
try
{
sidPtrInAce = IntPtr.Add(existingAce, 8);
ConvertSidToStringSidW(sidPtrInAce, out IntPtr pSidStringInAce);
if (pSidStringInAce == IntPtr.Zero) { throw new Exception("failed to get pSidString"); }
string sidStringInAce = Marshal.PtrToStringUni(pSidStringInAce);
Console.WriteLine(sidStringInAce);
if (sidStringInAce == stringSid) { userSidAlreadyExists = true; }
} catch { }
break;
}
if (userSidAlreadyExists) { break; }
//if the ACE was not added AND the processing ACE is not NON-INHERITED DENIED and is not DENIED for Object AND is not Enable for Object
//then add our ADE to ensure it is in the correct order
//Windows 2000 and later ACE ordering in ACL:
//Non-Inherited -> Inherited
//withing each of the two groups the ACEs are also in the following order
//Disable for the object
//Disable for the subject of the object
//Enable for the object
//Enable for the subject of the object
//So basically if we hit anything but NON-Inherited disable for the object, NON-Inherited Disable for the subject of the object and NON-Inherited Enable for the object
//then we should add our ACE - this will ensure correct order
//^ could not figure out how to distinguish between Enable for the object and Enable for the subject of the object
//instead, add the ACE the moment we find an inherited ACE
if (!newAceAdded && isAceInherited(aceHeader.AceFlags))
{
//AddAccessAllowedAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WINSTA_ALL_ACCESS, userpSid);
newAceAdded = true;
//indexInNewAcl++;
}
//AddAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, indexInNewAcl, existingAce, aceHeader.AceSize);
indexInNewAcl++;
}
catch (Exception ex)
{
aceHeaderBytesHandle.Free();
}
} else
{
Console.WriteLine("failed obtaining existing ACE in ACL. quitting"); Console.Read(); return;
}
}
}
if (userSidAlreadyExists) { Console.WriteLine("user already exists in the ACL. quit"); Console.Read(); return; }
if (!newAceAdded && !userSidAlreadyExists)
{
//we did not hit an inherited ACE - probably none exists in the ACL OR AceCount was 0 - no going through ACEs
//therefore user was not added
//AddAccessAllowedAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WINSTA_ALL_ACCESS, userpSid);
newAceAdded = true;
}
if (!newAceAdded)
{
Console.WriteLine("failed to add new ACE. quit"); Console.Read(); return;
}
CloseHandle(userToken);
LocalFree(userpSid);
Console.WriteLine("ready to quit");
Console.Read();
I am trying to launch a process in a context of a user that I log on using LogonUserExW.
In order to do that, I need to modify DACL of Winstation "Winsta0" and Desktop "Default".
What I do is get the DACL and Security Descriptor (which I don't actually need nor use) using GetSecurityInfo.
Then I call GetAclInformation twice to get information about the size and revision of the ACL.
ACL_SIZE_INFORMATION aclInfoSizeOut = new ACL_SIZE_INFORMATION();
GetAclInformation(daclWinsta, out aclInfoSizeOut, Marshal.SizeOf(aclInfoSizeOut), ACL_INFORMATION_CLASS.AclSizeInformation);
ACL_REVISION_INFORMATION aclInfoRevisionOut = new ACL_REVISION_INFORMATION();
GetAclInformation(daclWinsta, out aclInfoRevisionOut, Marshal.SizeOf(aclInfoRevisionOut), ACL_INFORMATION_CLASS.AclRevisionInformation);
Once I have the data,
I calculate the required size of the new ACL:
int cbNewACL = Convert.ToInt32(aclInfoSizeOut.AclBytesInUse + Marshal.SizeOf(allowedAce) + GetLengthSid(userpSid) - sizeof(UInt32));
Then as per https://web.archive.org/web/20121231022835/http://support.microsoft.com/kb/102102 I allocate memory for the new ACL using
IntPtr pNewAcl = LocalAlloc(LocalAllocFlags.LPTR, cbNewACL);
This is where it starts getting confusing for me BIG time. I fail to understand how this actually works.
Using the LocalAlloc I now have a pointer to a memory of the size I specified.
Then I initialize the new ACL which is supposed to be in that memory block, BUT how? Because the pointer is actually rewritten once I use the function below. Interestingly enough, it always has the same value every time I call the function. Whereas the pointer returned by Locallloc is always different.
InitializeAcl(out pNewAcl, cbNewACL, aclInfoRevisionOut.AclRevision);
The pAcl in InitializeAcl function is defnied as
"[out] pAcl A pointer to an ACL structure to be initialized by this function. Allocate memory for pAcl before calling this function."
I would understand if it was passed as REF for the function to know where to actually initialize the ACL, but REF doesn't change it at all.
Another thing is when I call the InitializeAcl, the cbNewAcl gets set to 0. This goes absolutely beyond my head. How and why does it change the value?
Then when I call AddAccessAllowedAce it completely messes up the structures I have set before I get the data from the existing ACL- aclInfoSizeOut and aclInfoRevisionOut which get set to nonsense values. Such as count 0, bytes in use 78548557 (some high number). And cbNewAcl gets changed to 1. I have no idea why it does that.
AddAccessAllowedAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WINSTA_ALL_ACCESS, userpSid);
Below is my full code which "works" - I get the user's token and psid, I query the existing DACL, I query the members of the DACL and get their string SIDs, but that is about it. I can't create a new DACL. Posting it with my comments as well. I hope I did not forget any signatures as the code is a bit longer in VS than what I am actually posting.
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUserExW(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken,
out IntPtr ppLogonSid,
out IntPtr ppProfileBuffer,
out IntPtr pdwProfileLength,
out QUOTA_LIMITS pQuotaLimits
);
[DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern int ConvertSidToStringSidW(
IntPtr SidPtr,
out IntPtr SidString
);
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern int GetSecurityInfo
(
IntPtr handle,
SE_OBJECT_TYPE ObjectType,
SECURITY_INFORMATION SecurityInfo,
out IntPtr ppsidOwner,
out IntPtr ppsidGroup,
out IntPtr ppDacl,
out IntPtr ppSacl,
out IntPtr ppSecurityDescriptor
);
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr GetProcessWindowStation();
[DllImport("Advapi32.dll", SetLastError = true)]
public static extern bool GetAclInformation(
IntPtr pAcl,
out ACL_SIZE_INFORMATION pAclInformation,
int nAclInformationLength,
ACL_INFORMATION_CLASS aclInformationClass
);
public struct ACL_SIZE_INFORMATION
{
public uint AceCount;
public uint AclBytesInUse;
public uint AclBytesFree;
}
public struct ACL_REVISION_INFORMATION
{
public int AclRevision;
}
public enum ACL_INFORMATION_CLASS
{
AclRevisionInformation = 1,
AclSizeInformation
}
public struct QUOTA_LIMITS
{
public int PagedPoolLimit;
public int NonPagedPoolLimit;
public int MinimumWorkingSetSize;
public int MaximumWorkingSetSize;
public int PagefileLimit;
public Int64 TimeLimit;
}
ublic struct ACCESS_ALLOWED_ACE
{
public ACE_HEADER Header;
public ACCESS_MASK Mask;
public UInt16 SidStart;
}
ublic enum LocalAllocFlags : uint
{
LHND = 0x0042,
LMEM_FIXED = 0x0000,
LMEM_MOVEABLE = 0x0002,
LMEM_ZEROINIT = 0x0040,
LPTR = 0x0040
}
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern IntPtr LocalAlloc(LocalAllocFlags flags, int bytes);
DllImport("Advapi32.dll", SetLastError = true)]
public static extern bool InitializeAcl(
out IntPtr pAcl,
int nAclLength,
int dwAclRevision
);
public static extern int AddAccessAllowedAce
(
ref IntPtr pAcl,
/* ACL_REVISION 2
ACL_REVISION_DS 4
*/
int dwAceRevision,
ACCESS_MASK AccessMask,
IntPtr pSid
);
LogonUserExW("XXXXX", "FFFFF", "BBBBB", 2, 0, out IntPtr userToken, out IntPtr userpSid, out IntPtr profileBuffer, out IntPtr profileLength, out QUOTA_LIMITS profQuotaLimits);
ConvertSidToStringSidW(userpSid, out IntPtr ptrSid);
string stringSid = Marshal.PtrToStringUni(ptrSid);
IntPtr winstaHandle = GetProcessWindowStation();
//get security descriptor for the station
int getDescriptorResult = GetSecurityInfo(winstaHandle, SE_OBJECT_TYPE.SE_WINDOW_OBJECT, SECURITY_INFORMATION.DACL_SECURITY_INFORMATION | SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION, out IntPtr owner, out IntPtr group, out IntPtr daclWinsta, out IntPtr Sacl, out IntPtr secDescriptor);
//this actually works but shows different values than ACL_SIZE_INFORMATION and ACL_REVISION_INFORMATION
//maybe DACL is in different structure than ACL struct? could not find any other struct in the documentation
ACL aclStruct = (ACL)Marshal.PtrToStructure(daclWinsta, typeof(ACL));
ACL_SIZE_INFORMATION aclInfoSizeOut = new ACL_SIZE_INFORMATION();
GetAclInformation(daclWinsta, out aclInfoSizeOut, Marshal.SizeOf(aclInfoSizeOut), ACL_INFORMATION_CLASS.AclSizeInformation);
ACL_REVISION_INFORMATION aclInfoRevisionOut = new ACL_REVISION_INFORMATION();
GetAclInformation(daclWinsta, out aclInfoRevisionOut, Marshal.SizeOf(aclInfoRevisionOut), ACL_INFORMATION_CLASS.AclRevisionInformation);
//count:17 bytes:436
//create a new ACL just to get its size for the cbNewACL value
ACCESS_ALLOWED_ACE allowedAce = new ACCESS_ALLOWED_ACE();
int cbNewACL = Convert.ToInt32(aclInfoSizeOut.AclBytesInUse + Marshal.SizeOf(allowedAce) + GetLengthSid(userpSid) - sizeof(UInt32));
//??? for some reason cbNewACL gets cleared after calling InitializeAcl
IntPtr pNewAcl = LocalAlloc(LocalAllocFlags.LPTR, cbNewACL);
InitializeAcl(out pNewAcl, cbNewACL, aclInfoRevisionOut.AclRevision);
//just for test try to add it right away
//AddAccessAllowedAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WINSTA_ALL_ACCESS, userpSid);
//after calling AddAccessAllowedAce the information is structs aclInfoSizeOut and aclInfoRevisionOut gets destroyed
//cbNewAcl gets set to 1
//???
bool newAceAdded = false;
bool userSidAlreadyExists = false;
//copy old ACEs into the new ACL
if (aclInfoSizeOut.AceCount != 0)
{
int indexInNewAcl = 0;
for (int i=0;i<aclInfoSizeOut.AceCount;i++)
{
//get ace and add it to the new ACL
GetAce(daclWinsta, i, out IntPtr existingAce);
if (existingAce != IntPtr.Zero)
{
//get ace header from the ACE pointer to identify the ACE type
//get first 4 bytes from the pointer starting at 0 since ACE_HEADER struct is of size 4
//once we have it in the byte array, create a GC handle with the bytes - this allocates them in a managed memory
//then read it to the structure using Marshal.PtrToStructure
ACE_HEADER aceHeader = new ACE_HEADER();
byte[] aceHeaderBytes = new byte[Marshal.SizeOf(aceHeader)];
Marshal.Copy(existingAce, aceHeaderBytes, 0, aceHeaderBytes.Length);
GCHandle aceHeaderBytesHandle = GCHandle.Alloc(aceHeaderBytes, GCHandleType.Pinned);
try
{
aceHeader = (ACE_HEADER)Marshal.PtrToStructure(aceHeaderBytesHandle.AddrOfPinnedObject(), typeof(ACE_HEADER));
switch (aceHeader.AceType)
{
case 0:
case 1:
//0 allowed - ACCESS_ALLOWED_ACE, 1 denied - ACCESS_DENIED_ACE
//the two have the same members definied in their structure.
//the declaration below is not explicitly needed in our case, but might be useful for some other things
//ACCESS_ALLOWED_ACE existingDeniedAllowedACE = (ACCESS_ALLOWED_ACE)Marshal.PtrToStructure(existingAce, typeof(ACCESS_ALLOWED_ACE));
//0 and 1 in this context are together in one clause since they are definied by the same members in the same order, thus allowing us
//to get SidStart from the same offset from the ACE IntPtr
//GUESSING: SidStart starts at 8th byte in the struct, therefore an offset of 8 bytes - size of ACE_HEADER and ACCESS_MASK (Uint16)
//if for example the ACE type would be definied by more members with SidStart at the end, we would have to calculate the offset by
//the sum of all members except for SidStart
IntPtr sidPtrInAce = IntPtr.Zero;
try
{
sidPtrInAce = IntPtr.Add(existingAce, 8);
ConvertSidToStringSidW(sidPtrInAce, out IntPtr pSidStringInAce);
if (pSidStringInAce == IntPtr.Zero) { throw new Exception("failed to get pSidString"); }
string sidStringInAce = Marshal.PtrToStringUni(pSidStringInAce);
Console.WriteLine(sidStringInAce);
if (sidStringInAce == stringSid) { userSidAlreadyExists = true; }
} catch { }
break;
}
if (userSidAlreadyExists) { break; }
//if the ACE was not added AND the processing ACE is not NON-INHERITED DENIED and is not DENIED for Object AND is not Enable for Object
//then add our ADE to ensure it is in the correct order
//Windows 2000 and later ACE ordering in ACL:
//Non-Inherited -> Inherited
//withing each of the two groups the ACEs are also in the following order
//Disable for the object
//Disable for the subject of the object
//Enable for the object
//Enable for the subject of the object
//So basically if we hit anything but NON-Inherited disable for the object, NON-Inherited Disable for the subject of the object and NON-Inherited Enable for the object
//then we should add our ACE - this will ensure correct order
//^ could not figure out how to distinguish between Enable for the object and Enable for the subject of the object
//instead, add the ACE the moment we find an inherited ACE
if (!newAceAdded && isAceInherited(aceHeader.AceFlags))
{
//AddAccessAllowedAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WINSTA_ALL_ACCESS, userpSid);
newAceAdded = true;
//indexInNewAcl++;
}
//AddAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, indexInNewAcl, existingAce, aceHeader.AceSize);
indexInNewAcl++;
}
catch (Exception ex)
{
aceHeaderBytesHandle.Free();
}
} else
{
Console.WriteLine("failed obtaining existing ACE in ACL. quitting"); Console.Read(); return;
}
}
}
if (userSidAlreadyExists) { Console.WriteLine("user already exists in the ACL. quit"); Console.Read(); return; }
if (!newAceAdded && !userSidAlreadyExists)
{
//we did not hit an inherited ACE - probably none exists in the ACL OR AceCount was 0 - no going through ACEs
//therefore user was not added
//AddAccessAllowedAce(ref pNewAcl, aclInfoRevisionOut.AclRevision, ACCESS_MASK.READ_CONTROL | ACCESS_MASK.WINSTA_ALL_ACCESS, userpSid);
newAceAdded = true;
}
if (!newAceAdded)
{
Console.WriteLine("failed to add new ACE. quit"); Console.Read(); return;
}
CloseHandle(userToken);
LocalFree(userpSid);
Console.WriteLine("ready to quit");
Console.Read();
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据塞尔文的评论:
问题是初始签名。它不是输出的,而是在INTPTR指向的地址中初始化的ACL的功能。
除此之外,我还必须更改addace和addaccessloweredace签名-Ref intptr pacl jur in intptr。
As per Selvin's comment:
The problem was with InitializeAcl signature. It is not out, but in and the function initialized the acl in the address pointed by the IntPtr.
In addition to that, I had to change AddAce and AddAccessAllowedAce signatures as well - ref IntPtr pAcl to just in IntPtr.