@grumple Whenever the script needs to be updated I post it at the top of the first post and I post it here in the thread, or somebody else does first. If I get a report of a vulnerability with the script, I fix it and post an update. If an upgrade creates an x:\windows.old folder the script should be run again because the \windows folder has been replaced so previously locked files aren't locked anymore; however, the LockFiles task will rename or lock the required system files so it should be mostly okay since rempl and update assistant most likely won't be included in a feature update anyway. I can say that right now with v2.7.2 of the script, if you run Sledgehammer and close it, I have a 100% certainty that Microsoft can't override it. Using the script normally, doing updates manually, I'm about 99.999% sure Microsoft can't override it.
I'm still using v2.7.0 on Windows 10 1909, and it's working effectively after monthly updates through August. But I wouldn't trust Sledgehammer versions before 2.7.2 for Windows 10 2004. As FAQ C4 says about Windows Feature Updates in the Readme file, ". . . always use the latest version of the script."
Snippet tries to keep original owner when run recursively by design and that will spew an error when it cannot add permissions, but then it will retry, this time after taking ownership, so if you base your conclusion only on the script output, you might be wrong. Did you actually check the permissions in the registry after running #2 as-is? Chances are high you will see Everyone denied on each and every key. In any case, this is not the right thread for an extended discussion about reg_own
Anyway, there is one situation where reg_own fails to set permissions without intermediate call: - Exclusive own by TrustedInstaller, with just read permissions defined for System and Administrators So the snippet is denied change permissions since it runs under Administrators account by default (powershell) Simple fix is to first add FullControl for Administrators and then do your initial operation. Better fix is to first add FullControl for a surrogate account (as to not override built-in Administrators), do your initial operations, then remove the surrogate account. Example Code: Path : Microsoft.PowerShell.Core\Registry::HKLM\SOFTWARE\SomeKey Owner : NT SERVICE\TrustedInstaller Group : NT SERVICE\TrustedInstaller Access : NT AUTHORITY\SYSTEM Allow -2147483648 NT AUTHORITY\SYSTEM Allow ReadKey BUILTIN\Administrators Allow -2147483648 BUILTIN\Administrators Allow ReadKey BUILTIN\Users Allow ReadKey BUILTIN\Users Allow -2147483648 NT SERVICE\TrustedInstaller Allow FullControl NT SERVICE\TrustedInstaller Allow 268435456 APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow -2147483648 APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow ReadKey To just change somevalue and keep everything as is (sneaky), could call the snippet like this: Code: :: 1. first make sure we have permissions to make changes by using the surrogate admin group S-1-5-114 call :reg_own "HKLM\SOFTWARE\SomeKey" all S-1-5-114 "" Allow "FullControl" :: 2. do our thing reg add "HKLM\SOFTWARE\SomeKey" /f /v somevalue /d snippetrullz :: could now add any permissions without getting access denied errors (commented below) rem call :reg_own "HKLM\SOFTWARE\SomeKey" all S-1-5-18 "" Deny "FullControl" reg add "HKLM\SOFTWARE\SomeKey\More" /f /v othervalue /d 1 /t reg_dword :: 3. once done, remove surrogate admin group - the original Administrators remains unchanged call :reg_own "HKLM\SOFTWARE\SomeKey" none S-1-5-114 "" This is probably the GOLD showcase usage for my reg_own snippet adjusting any values without leaving changed permissions and changed ownership behind, something much harder to do in regedit and other tools when processing keys recursively...
Well the last example was meant for the standard use case of changing a value that was locked by the OS, while your use case is different. Denying permissions works absolutely fine for a specific key, but when doing it recursively we need to be smart about it, as you can end up with "put the cart before the horses" situation - effectively denying yourself making further permission changes to subkeys. So, never use FullControl when setting deny permissions recursively. WriteKey will also deny "Read Control" so don't use that either. Instead, just deny all write permissions explicitly: "SetValue,CreateSubkey,CreateLink,Delete,ChangePermissions,TakeOwnership" So for your use case, this should work: Code: @echo off &title reg_own deny experiment :::: Ask for elevation passing any batch arguments (don't care for passing user or ti here since we deny write for everyone) set _=call "%~f0" %*® query HKU\S-1-5-19>nul 2>nul||(powershell -nop -c start cmd -args '/d/x/q/r',$env:_ -verb runas & exit) :::: 1. make sure we have permissions to make changes by adding S-1-1-0 (Everyone) recursively REM call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-1-0 "" Allow "FullControl" :::: 2. do our thing with the above registry key - if not doing anything to it 1. is not needed and only doing 3. is enough to lock key :::: 3. deny write for S-1-1-0 (Everyone) and set owner to S-1-2-3 (dummy) - must be last and use explicit write when recursively set VO=verbose-output :: now silent by default, only lists rights if VO is defined; to undefine: set "VO=" set write="SetValue,CreateSubkey,CreateLink,Delete,ChangePermissions,TakeOwnership" call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-1-0 S-1-2-3 Deny %write% ECHO: ECHO: ECHO Your key is now locked and it's safe to update windows ECHO: pause exit/b :reg_own #key [optional] all user owner access permission : call :reg_own "HKCU\My" "" S-1-5-32-545 S-1-5-18 Allow FullControl powershell -nop -c $A='%~1','%~2','%~3','%~4','%~5','%~6';iex(([io.file]::ReadAllText('%~f0')-split':Own1\:.*')[1])&exit/b:Own1: $D1=[IO.IODescriptionAttribute].Module.GetType('System.Diagnostics.Process').GetMethods(42) |? {$_.Name -eq 'SetPrivilege'} 'SeSecurityPrivilege','SeTakeOwnershipPrivilege','SeBackupPrivilege','SeRestorePrivilege' |% {$D1.Invoke($null, @("$_",2))} $path=$A[0]; $rk=$path-split'\\',2; $HK=gi -lit Registry::$($rk[0]) -fo; $s=$A[1]; $sps=[Security.Principal.SecurityIdentifier] $u=($A[2],'S-1-5-32-544')[!$A[2]];$o=($A[3],$u)[!$A[3]];$w=$u,$o |% {new-object $sps($_)}; $old=!$A[3];$own=!$old; $y=$s-eq'all' $rar=new-object Security.AccessControl.RegistryAccessRule( $w[0], ($A[5],'FullControl')[!$A[5]], 1, 0, ($A[4],'Allow')[!$A[4]] ) $x=$s-eq'none'; function Own1($k){$t=$HK.OpenSubKey($k,2,'TakeOwnership'); 0,4 |% {try{$o=$t.GetAccessControl($_)}catch{$old=0}} if($old){$own=1;$w[1]=$o.GetOwner($sps)};$o.SetOwner($w[0]);$t.SetAccessControl($o); $c=$HK.OpenSubKey($k,2,'ChangePermissions') $p=$c.GetAccessControl(2);if($y){$p.SetAccessRuleProtection(1,1)};$p.ResetAccessRule($rar);if($x){$p.RemoveAccessRuleAll($rar)} $c.SetAccessControl($p);if($own){$o.SetOwner($w[1]);$t.SetAccessControl($o)};if($s){$subkeys=$HK.OpenSubKey($k).GetSubKeyNames() foreach($n in $subkeys){Own1 "$k\$n"}}};Own1 $rk[1];if($env:VO){get-acl Registry::$path|fl} #:Own1: lean & mean snippet by AveYo ::-_-:: Could instead Allow FullControl for Everyone, then Allow just ReadKey for specific accounts, and finally remove Everyone: Code: @echo off &title reg_own readkey only experiment :::: Define TI sid (TrustedInstaller) for /f "tokens=3" %%a in ('sc.exe showsid TrustedInstaller') do set TI=%%a >nul :::: Define USER sid before asking for elevation since it gets replaced for limited accounts set _=call "%~f0" %* &if "%USER%"=="" for /f "tokens=2" %%u in ('whoami /user /fo list') do set USER=%%u :::: Ask for elevation passing USER and any batch arguments - ps also enables debug priviledge unlike vbs reg query HKU\S-1-5-19>nul 2>nul||(powershell -nop -c start cmd -args '/d/x/q/rset USER=%USER%^&',$env:_ -verb runas &exit) :::: 1. make sure we have permissions to make changes by adding S-1-1-0 (Everyone) recursively call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-1-0 "" Allow "FullControl" :::: 2. only allow ReadKey for S-1-5-32-544 (Administrators), S-1-5-18 (SYSTEM) and %TI% (TrustedInstaller) to prevent OS changes call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-5-32-544 "" Allow ReadKey call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-5-18 "" Allow ReadKey call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all %TI% "" Allow ReadKey :::: Cleanup previous experiment with S-1-5-114 (surrogate admins group) call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" none S-1-5-114 "" set VO=verbose-output :: snippet now silent by default, will only lists rights if VO is defined; to undefine: set "VO=" :::: 3.a either remove S-1-1-0 (Everyone) and set owner to S-1-2-3 (dummy) - here preferred over using global deny but both are fine call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" none S-1-1-0 S-1-2-3 :::: 3.b or deny write for S-1-1-0 (Everyone) - must be last and should use explicit write when run recursively, not FUllControl REM set write="SetValue,CreateSubkey,CreateLink,Delete,ChangePermissions,TakeOwnership" REM call :reg_own "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Appx\AppxAllUserStore\InboxApplications" all S-1-1-0 S-1-2-3 Deny %write% ECHO: ECHO: ECHO Your key is now locked and it's safe to update windows ECHO: pause exit/b :reg_own #key [optional] all user owner access permission : call :reg_own "HKCU\My" "" S-1-5-32-545 S-1-5-18 Allow FullControl powershell -nop -c $A='%~1','%~2','%~3','%~4','%~5','%~6';iex(([io.file]::ReadAllText('%~f0')-split':Own1\:.*')[1])&exit/b:Own1: $D1=[IO.IODescriptionAttribute].Module.GetType('System.Diagnostics.Process').GetMethods(42) |? {$_.Name -eq 'SetPrivilege'} 'SeSecurityPrivilege','SeTakeOwnershipPrivilege','SeBackupPrivilege','SeRestorePrivilege' |% {$D1.Invoke($null, @("$_",2))} $path=$A[0]; $rk=$path-split'\\',2; $HK=gi -lit Registry::$($rk[0]) -fo; $s=$A[1]; $sps=[Security.Principal.SecurityIdentifier] $u=($A[2],'S-1-5-32-544')[!$A[2]];$o=($A[3],$u)[!$A[3]];$w=$u,$o |% {new-object $sps($_)}; $old=!$A[3];$own=!$old; $y=$s-eq'all' $rar=new-object Security.AccessControl.RegistryAccessRule( $w[0], ($A[5],'FullControl')[!$A[5]], 1, 0, ($A[4],'Allow')[!$A[4]] ) $x=$s-eq'none'; function Own1($k){$t=$HK.OpenSubKey($k,2,'TakeOwnership'); 0,4 |% {try{$o=$t.GetAccessControl($_)}catch{$old=0}} if($old){$own=1;$w[1]=$o.GetOwner($sps)};$o.SetOwner($w[0]);$t.SetAccessControl($o); $c=$HK.OpenSubKey($k,2,'ChangePermissions') $p=$c.GetAccessControl(2);if($y){$p.SetAccessRuleProtection(1,1)};$p.ResetAccessRule($rar);if($x){$p.RemoveAccessRuleAll($rar)} $c.SetAccessControl($p);if($own){$o.SetOwner($w[1]);$t.SetAccessControl($o)};if($s){$subkeys=$HK.OpenSubKey($k).GetSubKeyNames() foreach($n in $subkeys){Own1 "$k\$n"}}};Own1 $rk[1];if($env:VO){get-acl Registry::$path|fl} #:Own1: lean & mean snippet by AveYo ::-_-:: So you see, the snippet is quite versatile, it's just that I haven't given good directions One improvement would be doing recursiveness in reverse, but that would bloat the 12-lines snippet and it's not really needed if planning changes like above.
Part of giving good directions is having bright students! I'm finding out that I really didn't know as much as I thought I did about OS privilege manipulation. I think understanding and managing permissions is crucial if you're trying to gain control of an online system. I feel honored that you've taken as much time as you have to expand my knowledge bubble a bit further. So thank you for taking me through some more examples. I feel like I'm getting closer to understanding the power and versatility of the snippet tool. The several examples you've shared with the embedded explanations are very helpful for me to grasp the logic of the reg-own tool. When I was playing around with reg-own in my earlier tests, I accidentally managed to do something really cool. Unfortunately, I didn't notice right away and I then couldn't duplicate the steps I took.The "cool thing" I accidentally did is what you purposefully demonstrated in the second script "reg_own readkey only experiment" Thanks! I like how "set VO=verbose-output" (if($env:VO)) makes this script more end-user friendly. If I understood DOS scripting better, I could grasp what you're doing differently when you "Define TI sid (TrustedInstaller)" to also "enable debug privilege unlike vbs" I can see there is a difference with your earlier script, but ... yeah ... One comment on utility of the"%write%" parameters used in the first script "reg_own deny experiment" The list of parameters assigned to %write% (which match the parameters you used in "reg_own snippet usage - mdl TrustedInstaller example #2") is possibly enough to lock down some keys and maybe even locks down most keys. However, with "InboxApplications", only denying "FullControl" works to stop Windows from accessing the "child-keys" and provisioning System Application packages. If you're interested in how Windows uses the "InboxApplications" key then take a look at post #5587 by @GodHand.
I see I have multiple alerts in this thread but there's way too much information to try to sift through as to what is being requested. Please summarize what I'm specifically being tagged for, in particular in connection with said comment: For the record I have never withheld any information I have asserted as knowing with complete certainty. Moreover, I do not make posts that give any definitive source of information while also withholding specific details that directly pertain to said information.
Quick question (off the topic of the last couple of pages/posts). Once you trigger the Sledgehammer script and go through the process and get to the Wumgr window, there is an entry (if memory serves me) to do the updates offline. Does that mean that it's possible to download the updates (via the Windows 10 Forums site) and then have Wumgr install the already downloaded updates from there?
Offline mode in WuMgr uses the wsusscn2.cab catalog from Microsoft to determine required patches. It's called offline because the scanning does not use Windows Update. Downloading the catalog and updates still requires being online, however. Advantage: Will probably work even if Windows Update is slightly out of order. Disadvantage: Does only contain B releases, not Previews. Edit: Check out the meaning of the box "Download and update manually". This might be more like what you desire.
Carlos, thanks for the reply. I have enough issues with the B releases (I'm assuming that those are the "released to the public" releases) so I think I'll stay away from the "Preview" releases, which I believe are released to the MS guinea pigs, I mean beta testers group I'll check out the "Download and update manually" to see how that works.