Created
March 17, 2018 13:23
-
-
Save rosberglinhares/239547aadfe08cf60f11025ffb3fc969 to your computer and use it in GitHub Desktop.
PowerShell script to change the type of the passed services to 'Own Process'. In this way, it is possible to check how much memory is specifically allocated to each service.
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
<# | |
.SYNOPSIS | |
Enables privileges in the access token of the current process. This allows the process to perform system-level actions that it could not previously. | |
This code was adapted from the following link: https://msdn.microsoft.com/en-us/library/windows/desktop/aa446619(v=vs.85).aspx. | |
.PARAMETER Privilege | |
Specifies, as a string array, the privileges to be enabled. More information about privileges can be found at | |
https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx. | |
.NOTES | |
Author: Author: Rosberg Linhares ([email protected]) | |
Date: March 16, 2018 | |
#> | |
param ( | |
[parameter(Mandatory=$true)] | |
[ValidateSet('SeAssignPrimaryTokenPrivilege', 'SeAuditPrivilege', 'SeBackupPrivilege', 'SeChangeNotifyPrivilege', 'SeCreateGlobalPrivilege', 'SeCreatePagefilePrivilege', | |
'SeCreatePermanentPrivilege', 'SeCreateSymbolicLinkPrivilege', 'SeCreateTokenPrivilege', 'SeDebugPrivilege', 'SeEnableDelegationPrivilege', 'SeImpersonatePrivilege', | |
'SeIncreaseBasePriorityPrivilege', 'SeIncreaseQuotaPrivilege', 'SeIncreaseWorkingSetPrivilege', 'SeLoadDriverPrivilege', 'SeLockMemoryPrivilege', | |
'SeMachineAccountPrivilege', 'SeManageVolumePrivilege', 'SeProfileSingleProcessPrivilege', 'SeRelabelPrivilege', 'SeRemoteShutdownPrivilege', 'SeRestorePrivilege', | |
'SeSecurityPrivilege', 'SeShutdownPrivilege', 'SeSyncAgentPrivilege', 'SeSystemEnvironmentPrivilege', 'SeSystemProfilePrivilege', 'SeSystemtimePrivilege', | |
'SeTakeOwnershipPrivilege', 'SeTcbPrivilege', 'SeTimeZonePrivilege', 'SeTrustedCredManAccessPrivilege', 'SeUndockPrivilege', 'SeUnsolicitedInputPrivilege')] | |
[string[]] $Privilege | |
) | |
$ErrorActionPreference = 'Stop' # Stops executing on error instead of silent continue. | |
Set-StrictMode -Version Latest # Enforces coding rules in expressions, scripts, and script blocks. Uninitialized variables are not permitted. | |
$winApiAdvApi32Code = @' | |
using System; | |
using System.Runtime.InteropServices; | |
namespace WinApi | |
{ | |
public class AdvApi32 | |
{ | |
// https://www.pinvoke.net/default.aspx/Structures/TOKEN_PRIVILEGES.html | |
public const UInt32 SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001; | |
public const UInt32 SE_PRIVILEGE_ENABLED = 0x00000002; | |
public const UInt32 SE_PRIVILEGE_REMOVED = 0x00000004; | |
public const UInt32 SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000; | |
public const int MAX_PRIVILEGES = 10; | |
// https://www.pinvoke.net/default.aspx/advapi32/AdjustTokenPrivileges.html | |
[StructLayout(LayoutKind.Sequential)] | |
public struct LUID | |
{ | |
public Int32 LowPart; | |
public UInt32 HighPart; | |
} | |
// https://www.pinvoke.net/default.aspx/Structures/LUID_AND_ATTRIBUTES.html | |
[StructLayout(LayoutKind.Sequential, Pack = 4)] | |
public struct LUID_AND_ATTRIBUTES | |
{ | |
public LUID Luid; | |
public UInt32 Attributes; | |
} | |
// https://www.pinvoke.net/default.aspx/Structures/TOKEN_PRIVILEGES.html | |
public struct TOKEN_PRIVILEGES | |
{ | |
public UInt32 PrivilegeCount; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst=MAX_PRIVILEGES)] | |
public LUID_AND_ATTRIBUTES [] Privileges; | |
} | |
// https://www.pinvoke.net/default.aspx/advapi32/OpenProcessToken.html | |
[DllImport("advapi32.dll", SetLastError=true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static extern bool OpenProcessToken(IntPtr ProcessHandle, | |
UInt32 DesiredAccess, out IntPtr TokenHandle); | |
// https://www.pinvoke.net/default.aspx/advapi32/LookupPrivilegeValue.html | |
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Auto)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, | |
out LUID lpLuid); | |
// https://www.pinvoke.net/default.aspx/advapi32/AdjustTokenPrivileges.html | |
[DllImport("advapi32.dll", SetLastError=true)] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, | |
[MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges, | |
ref TOKEN_PRIVILEGES NewState, | |
UInt32 Zero, | |
IntPtr Null1, | |
IntPtr Null2); | |
} | |
} | |
'@ | |
$winApiKernel32Code = @' | |
using System; | |
using System.Security; | |
using System.Runtime.InteropServices; | |
using System.Runtime.ConstrainedExecution; | |
namespace WinApi | |
{ | |
public class Kernel32 | |
{ | |
// https://www.pinvoke.net/default.aspx/Constants/WINERROR.html | |
public const int ERROR_SUCCESS = 0; | |
public const int ERROR_NOT_ALL_ASSIGNED = 1300; | |
// https://www.pinvoke.net/default.aspx/kernel32/CloseHandle.html | |
[DllImport("kernel32.dll", SetLastError=true)] | |
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] | |
[SuppressUnmanagedCodeSecurity] | |
[return: MarshalAs(UnmanagedType.Bool)] | |
public static extern bool CloseHandle(IntPtr hObject); | |
} | |
} | |
'@ | |
Add-Type -TypeDefinition $winApiAdvApi32Code | |
Add-Type -TypeDefinition $winApiKernel32Code | |
function Throw-WinApiError([int] $Win32ErrorCode, [string] $FunctionName) | |
{ | |
$errorMessage = [ComponentModel.Win32Exception]$Win32ErrorCode | |
throw "Error executing $($FunctionName): $errorMessage" | |
} | |
$processHandle = (Get-Process -Id $PID).Handle | |
$tokenHandle = 0 | |
if (![WinApi.AdvApi32]::OpenProcessToken($processHandle, [Security.Principal.TokenAccessLevels]::AdjustPrivileges, [ref] $tokenHandle)) | |
{ | |
Throw-WinApiError ([Runtime.InteropServices.Marshal]::GetLastWin32Error()) 'OpenProcessToken' | |
} | |
try | |
{ | |
$tokenPrivileges = New-Object WinApi.AdvApi32+TOKEN_PRIVILEGES | |
$tokenPrivileges.PrivilegeCount = $Privilege.Count | |
$tokenPrivileges.Privileges = [WinApi.AdvApi32+LUID_AND_ATTRIBUTES[]]::New([WinApi.AdvApi32]::MAX_PRIVILEGES) | |
for ($index = 0; $index -le $Privilege.Count - 1; $index++) | |
{ | |
$privilegeLocallyUniqueId = New-Object WinApi.AdvApi32+LUID | |
if (![WinApi.AdvApi32]::LookupPrivilegeValue($null, $Privilege[$index], [ref] $privilegeLocallyUniqueId)) | |
{ | |
Throw-WinApiError ([Runtime.InteropServices.Marshal]::GetLastWin32Error()) 'LookupPrivilegeValue' | |
} | |
$locallyUniqueIdAndAttr = New-Object WinApi.AdvApi32+LUID_AND_ATTRIBUTES | |
$locallyUniqueIdAndAttr.Luid = $privilegeLocallyUniqueId | |
$locallyUniqueIdAndAttr.Attributes = [WinApi.AdvApi32]::SE_PRIVILEGE_ENABLED | |
$tokenPrivileges.Privileges[$index] = $locallyUniqueIdAndAttr | |
} | |
if (![WinApi.AdvApi32]::AdjustTokenPrivileges($tokenHandle, $false, [ref] $tokenPrivileges, 0, [IntPtr]::Zero, [IntPtr]::Zero)) | |
{ | |
Throw-WinApiError ([Runtime.InteropServices.Marshal]::GetLastWin32Error()) 'AdjustTokenPrivileges' | |
} | |
else | |
{ | |
$successErrorCode = [Runtime.InteropServices.Marshal]::GetLastWin32Error() | |
if ($successErrorCode -eq [WinApi.Kernel32]::ERROR_NOT_ALL_ASSIGNED) | |
{ | |
throw 'The token does not have one or more of the specified privileges.' | |
} | |
} | |
} | |
finally | |
{ | |
if (![WinApi.Kernel32]::CloseHandle($tokenHandle)) | |
{ | |
Throw-WinApiError ([Runtime.InteropServices.Marshal]::GetLastWin32Error()) 'CloseHandle' | |
} | |
} |
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
<# | |
.SYNOPSIS | |
Changes the type of the passed services to 'Own Process'. In this way, it is possible to check how much memory is specifically allocated to each service. | |
After this cmdlet is used, it is necessary to restart the machine to see the results. | |
.NOTES | |
Author: Rosberg Linhares ([email protected]) | |
Date: March 16, 2018 | |
#> | |
param ( | |
[parameter(Mandatory=$true)] | |
[string[]] $ServiceName | |
) | |
$ErrorActionPreference = 'Stop' # Stops executing on error instead of silent continue. | |
Set-StrictMode -Version Latest # Enforces coding rules in expressions, scripts, and script blocks. Uninitialized variables are not permitted. | |
New-Variable ConstChangeServiceTypeOwnProcess -Option ReadOnly -Value 16 -Force | |
New-Variable ConstChangeServiceReturnSuccess -Option ReadOnly -Value 0 -Force | |
New-Variable ConstWindowsRegistryServiceRelativePathFormat -Option ReadOnly -Value 'SYSTEM\CurrentControlSet\services\{0}' -Force | |
New-Variable ConstEnablePrivilegeScriptFilePath -Option ReadOnly -Value (Join-Path $PSScriptRoot 'Enable-Privilege.ps1') -Force | |
function Set-ServiceTypeToOwnProcess([string] $ServiceName) | |
{ | |
function Set-ServiceTypeToOwnProcessByCim($Win32Service) | |
{ | |
$serviceFullName = "$($Win32Service.Name) - $($Win32Service.DisplayName)" | |
Write-Verbose "[$serviceFullName] Changing type via Cim" | |
$result = $Win32Service | Invoke-CimMethod -MethodName 'Change' -Arguments @{ ServiceType = $ConstChangeServiceTypeOwnProcess } -Verbose:$false | |
if ($result.ReturnValue -eq $ConstChangeServiceReturnSuccess) | |
{ | |
Write-Verbose "[$serviceFullName] Changed to Own Process successfully" | |
return $true | |
} | |
else | |
{ | |
Write-Warning "[$serviceFullName] Failed to change service to Own Process via Cim. Return value = $($result.ReturnValue)" | |
return $false | |
} | |
} | |
function Set-ServiceTypeToOwnProcessByWindowsRegistry($Win32Service) | |
{ | |
$serviceFullName = "$($Win32Service.Name) - $($Win32Service.DisplayName)" | |
Write-Verbose "[$serviceFullName] Changing type via Windows Registry" | |
try | |
{ | |
$registryServicePath = "HKLM:\$($ConstWindowsRegistryServiceRelativePathFormat -f $ServiceName)" | |
Set-ItemProperty -Path $registryServicePath -Name 'Type' -Value $ConstChangeServiceTypeOwnProcess | |
Write-Verbose "[$serviceFullName] Service changed to Own Process successfully" | |
return $true | |
} | |
catch | |
{ | |
Write-Warning "[$serviceFullName] Failed to change service to Own Process via Windows Registry. Error message = $($_.Exception.Message)" | |
return $false | |
} | |
} | |
function Grant-FullControlRightsOnServiceRegistryKeyToCurrentUser($Win32Service) | |
{ | |
$serviceFullName = "$($Win32Service.Name) - $($Win32Service.DisplayName)" | |
Write-Verbose "[$serviceFullName] Granting full control rights on the service registry key" | |
try | |
{ | |
# SeTakeOwnershipPrivilege: Necessary to change the current owner of a registry key | |
# SeRestorePrivilege: Necessary to restore the owner to 'NT AUTHORITY\SYSTEM' | |
& $ConstEnablePrivilegeScriptFilePath -Privilege SeTakeOwnershipPrivilege, SeRestorePrivilege | |
$registryServiceRelativePath = $ConstWindowsRegistryServiceRelativePathFormat -f $ServiceName | |
$registryKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($registryServiceRelativePath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [Security.AccessControl.RegistryRights]::TakeOwnership) | |
try | |
{ | |
$accessControl = $registryKey.GetAccessControl() | |
$currentUser = [Security.Principal.NTAccount][Security.Principal.WindowsIdentity]::GetCurrent().Name | |
$previousOwner = [Security.Principal.NTAccount]$accessControl.Owner | |
# It is necessary to change the current owner for modifying access rights on the key | |
$accessControl.SetOwner($currentUser) | |
$registryKey.SetAccessControl($accessControl) | |
# Add FullControl rights to the current user | |
$accessRule = New-Object System.Security.AccessControl.RegistryAccessRule($currentUser, [Security.AccessControl.RegistryRights]::FullControl, [Security.AccessControl.AccessControlType]::Allow) | |
$accessControl.SetAccessRule($accessRule) | |
$registryKey.SetAccessControl($accessControl) | |
# Restore the previous owner | |
$accessControl.SetOwner($previousOwner) | |
$registryKey.SetAccessControl($accessControl) | |
} | |
finally | |
{ | |
$registryKey.Dispose() | |
} | |
Write-Verbose "[$serviceFullName] Full control rights granted on the service registry key successfully" | |
return $true | |
} | |
catch | |
{ | |
Write-Warning "[$serviceFullName] Failed to grant full control rights on the service registry key. Error message = $($_.Exception.Message)" | |
return $false | |
} | |
} | |
$win32Service = Get-CimInstance -ClassName Win32_Service -Filter "Name = '$ServiceName'" -Verbose:$false | |
if ($win32Service) | |
{ | |
if (!(Set-ServiceTypeToOwnProcessByCim $win32Service)) | |
{ | |
if (!(Set-ServiceTypeToOwnProcessByWindowsRegistry $win32Service)) | |
{ | |
if (Grant-FullControlRightsOnServiceRegistryKeyToCurrentUser $win32Service) | |
{ | |
Set-ServiceTypeToOwnProcessByWindowsRegistry $win32Service | Out-Null | |
} | |
} | |
} | |
} | |
else | |
{ | |
Write-Warning "[$ServiceName] Service not found" | |
} | |
} | |
$ServiceName | ForEach-Object { Set-ServiceTypeToOwnProcess $_ } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment