Last active
August 29, 2015 14:26
-
-
Save rohnedwards/ff18e60d41cd1ca44d25 to your computer and use it in GitHub Desktop.
Demo code for using QueryServiceObjectSecurity() Win32 call from PowerShell. Created in response to a comment from here: https://rohnspowershellblog.wordpress.com/2013/03/19/viewing-service-acls/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
NOTE: I think you have to run this as an admin b/c ServiceHandle seems to | |
be null when not elevated. Also, this can't be used to get the SACL | |
(ServiceHandle probably isn't opened with that access requested, and | |
this code doesn't do privilege modifications). If you really want to | |
get around these problems, you can probably use reflection to get at | |
the GetServiceHandle() private method on the ServiceController | |
instance. That might work as a non-elevated user... | |
#> | |
# P/Invoke code: | |
Add-Type @" | |
using System; | |
using System.Runtime.InteropServices; | |
using System.Security.AccessControl; | |
namespace Custom { | |
public class ServiceSecurity { | |
[DllImport("advapi32.dll", SetLastError=true)] | |
static extern bool QueryServiceObjectSecurity( | |
SafeHandle serviceHandle, | |
SecurityInfos secInfo, | |
byte[] lpSecDesrBuf, | |
int bufSize, | |
out uint bufSizeNeeded | |
); | |
public static CommonSecurityDescriptor GetAccessControl(System.ServiceProcess.ServiceController service) { | |
return GetAccessControl(service, AccessControlSections.Owner | AccessControlSections.Group | AccessControlSections.Access); | |
} | |
public static CommonSecurityDescriptor GetAccessControl(System.ServiceProcess.ServiceController service, AccessControlSections includeSections) { | |
// Figure out SecurityInfos based on includeSections | |
SecurityInfos securityInfos = 0; | |
if ((includeSections & AccessControlSections.Owner) != 0) { | |
securityInfos |= SecurityInfos.Owner; | |
} | |
if ((includeSections & AccessControlSections.Group) != 0) { | |
securityInfos |= SecurityInfos.Group; | |
} | |
if ((includeSections & AccessControlSections.Access) != 0) { | |
securityInfos |= SecurityInfos.DiscretionaryAcl; | |
} | |
// This won't work unless you enable SeSecurityPrivilege... | |
if ((includeSections & AccessControlSections.Audit) != 0) { | |
securityInfos |= SecurityInfos.SystemAcl; | |
} | |
try { | |
bool result; | |
uint sdSize; | |
int lastErrorCode; | |
result = QueryServiceObjectSecurity( | |
service.ServiceHandle, | |
securityInfos, | |
null, | |
0, | |
out sdSize | |
); | |
// At this point, result should be false, and the last error code should be 122 | |
lastErrorCode = Marshal.GetLastWin32Error(); | |
if (lastErrorCode != 122) { throw new System.ComponentModel.Win32Exception(lastErrorCode); } | |
byte[] binarySD = new byte[sdSize]; | |
// Call again: | |
result = QueryServiceObjectSecurity( | |
service.ServiceHandle, | |
securityInfos, | |
binarySD, | |
binarySD.Length, | |
out sdSize | |
); | |
lastErrorCode = Marshal.GetLastWin32Error(); | |
// Call didn't work! | |
if (result != true) { | |
throw new System.ComponentModel.Win32Exception(lastErrorCode); | |
} | |
return new CommonSecurityDescriptor( | |
false, | |
false, | |
binarySD, | |
0 | |
); | |
} | |
catch (Exception e) { | |
// You could add more info here... | |
throw e; | |
} | |
} | |
} | |
} | |
"@ -ReferencedAssemblies System.ServiceProcess | |
# Example using it: | |
[Custom.ServiceSecurity]::GetAccessControl("bits") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment