Skip to content

Instantly share code, notes, and snippets.

@rohnedwards
Last active August 29, 2015 14:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rohnedwards/ff18e60d41cd1ca44d25 to your computer and use it in GitHub Desktop.
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/
<#
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