Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 19c8cf4

Browse files
committed
first untested version of Recall hardening #131
1 parent 0a94fb7 commit 19c8cf4

File tree

4 files changed

+211
-1
lines changed

4 files changed

+211
-1
lines changed

global_vars.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ var hardenSubjectsForPrivilegedUsers = append(hardenSubjectsForUnprivilegedUsers
4949
LibreOfficeBlockUntrustedRefererLinks,
5050
LibreOfficeUpdateCheck,
5151
LibreOfficeDisableUpdateLink,
52+
Recall,
5253
}...)
5354

5455
var expertConfig map[string]bool

recall_feature.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Hardentools
2+
// Copyright (C) 2017-2025 Security Without Borders
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package main
18+
19+
// Enable Recall Feature:
20+
// Enable-WindowsOptionalFeature -Online -FeatureName "Recall"
21+
// Disable and Remove Recall Feature:
22+
// Disable-WindowsOptionalFeature -Online -FeatureName "Recall" -Remove
23+
// Get Status:
24+
// Get-WindowsOptionalFeature -Online -FeatureName "Recall"
25+
// More details here:
26+
// - https://learn.microsoft.com/en-us/windows/client-management/manage-recall
27+
28+
import (
29+
"errors"
30+
"fmt"
31+
"strings"
32+
)
33+
34+
// RecallStruct ist the struct for HardenInterface implementation.
35+
type RecallStruct struct {
36+
shortName string
37+
longName string
38+
description string
39+
hardenByDefault bool
40+
}
41+
42+
// Recall contains Names for Recall Feature implementation of hardenInterface.
43+
var Recall = &RecallStruct{
44+
shortName: "Recall Windows Feature",
45+
longName: "Recall Windows Feature",
46+
description: `Recall Windows Feature`,
47+
hardenByDefault: false,
48+
}
49+
50+
var featureName = "recall"
51+
52+
// Harden method.
53+
func (recall RecallStruct) Harden(harden bool) error {
54+
psString := ""
55+
if harden {
56+
// save state
57+
if recall.IsHardened() {
58+
saveHardenState(featureName, "disabled")
59+
} else {
60+
saveHardenState(featureName, "enabled")
61+
}
62+
63+
// set Powershell-Command
64+
psString = fmt.Sprintf("Disable-WindowsOptionalFeature -Online -FeatureName \"Recall\" -Remove")
65+
} else {
66+
savedState, err := getSavedHardenState(featureName)
67+
if err != nil {
68+
// probably no saved state found, so will not restore
69+
Info.Println("Recall: No saved state found, so will not restore")
70+
return errors.New("No saved state found for Recall, so will not restore")
71+
}
72+
73+
if savedState != "enabled" {
74+
Info.Println("Recall: Was not in enabled state before hardening, so will not restore")
75+
return errors.New("Recall was not enabled before hardening, so will not restore")
76+
}
77+
78+
// set Powershell-Command
79+
psString = fmt.Sprintf("Enable-WindowsOptionalFeature -Online -FeatureName \"Recall\"")
80+
}
81+
82+
Info.Printf("Recall: Executing Powershell.exe with command \"%s\"", psString)
83+
out, err := executeCommand("PowerShell.exe", "-noprofile", "-Command", psString)
84+
if err != nil {
85+
Info.Printf("ERROR: Recall: Executing Powershell.exe with command \"%s\" failed", psString)
86+
Info.Printf("ERROR: Recall: Powershell Output was: %s", out)
87+
return errors.New("Executing powershell command " + psString + " failed")
88+
}
89+
90+
isHardened := recall.IsHardened()
91+
if harden {
92+
if !isHardened {
93+
Info.Print("Recall: Hardening seems to have failed")
94+
showInfoDialog("Recall has not been disabled!")
95+
return errors.New("Recall has not been disabled")
96+
}
97+
} else {
98+
if isHardened {
99+
Info.Print("Recall: Reenabling seems to have failed")
100+
showInfoDialog("Recall has not been enabled!")
101+
return errors.New("Recall has not been enabled")
102+
}
103+
// Delete savedState in hardentools registry key
104+
deleteSavedHardenState(featureName)
105+
}
106+
107+
Info.Println("Recall: Process successfull")
108+
109+
return nil
110+
}
111+
112+
// IsHardened checks if Recall is already hardened.
113+
func (recall RecallStruct) IsHardened() bool {
114+
psStringTest := "Get-WindowsOptionalFeature -Online -FeatureName \"Recall\" | Select-Object -ExpandProperty State"
115+
Info.Printf("Recall: Executing Powershell.exe with command \"%s\"", psStringTest)
116+
out, err := executeCommand("PowerShell.exe", "-noprofile", "-Command", psStringTest)
117+
if err != nil {
118+
Info.Printf("ERROR: Recall: Executing Powershell.exe with command \"%s\" failed", psStringTest)
119+
Info.Printf("ERROR: Recall: Powershell Output was: %s", out)
120+
return false
121+
}
122+
123+
Info.Printf("Recall: Powershell output for test of status was:\n%s", out)
124+
out = strings.ReplaceAll(out, "\r\n", "")
125+
// Output should start with "Disabled", e.g. it should be "DisabledWithPayloadRemoved"
126+
if strings.HasPrefix(out, "Disabled") {
127+
Info.Print("Recall: Is hardened")
128+
return true
129+
} else {
130+
Info.Print("Recall: Not hardened")
131+
return false
132+
}
133+
}
134+
135+
// Name returns Name.
136+
func (recall RecallStruct) Name() string {
137+
return recall.shortName
138+
}
139+
140+
// LongName returns Long Name.
141+
func (recall RecallStruct) LongName() string {
142+
return recall.longName
143+
}
144+
145+
// Description returns description.
146+
func (recall RecallStruct) Description() string {
147+
return recall.description
148+
}
149+
150+
// HardenByDefault returns if subject should be hardened by default.
151+
func (recall RecallStruct) HardenByDefault() bool {
152+
return recall.hardenByDefault
153+
}

registry_utils.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,3 +624,59 @@ func restoreSavedRegistryKeys() error {
624624

625625
return err
626626
}
627+
628+
// saveHardenState is a helper method for saving non-registry-based harden status
629+
func saveHardenState(feature, stateToSafe string) error {
630+
// Open hardentools root key.
631+
hardentoolsKey, _, err := registry.CreateKey(registry.CURRENT_USER,
632+
hardentoolsKeyPath, registry.ALL_ACCESS)
633+
if err != nil {
634+
return err
635+
}
636+
defer hardentoolsKey.Close()
637+
638+
// save value
639+
Trace.Println("Saving value for feature: " + feature + " with " + stateToSafe)
640+
err = hardentoolsKey.SetStringValue("SavedStateNonReg_"+feature, stateToSafe)
641+
if err != nil {
642+
Info.Println("Could not save state due to error: " + err.Error())
643+
}
644+
645+
return nil
646+
}
647+
648+
// getSavedHardenState is a helper method for saving non-registry-based harden status
649+
func getSavedHardenState(feature string) (savedState string, err error) {
650+
// Open hardentools root key.
651+
hardentoolsKey, err := registry.OpenKey(registry.CURRENT_USER, hardentoolsKeyPath, registry.QUERY_VALUE)
652+
if err != nil {
653+
return "", err
654+
}
655+
defer hardentoolsKey.Close()
656+
657+
// Open registry key.
658+
savedState, _, err = hardentoolsKey.GetStringValue("SavedStateNonReg_" + feature)
659+
if err != nil {
660+
Trace.Println("Could not retrieve saved state for feature " + feature + " due to error: " + err.Error())
661+
return "", err
662+
} else {
663+
Trace.Println("Retreived saved state for feature " + feature + ":" + savedState)
664+
return savedState, nil
665+
}
666+
}
667+
668+
func deleteSavedHardenState(feature string) error {
669+
// Open hardentools root key.
670+
hardentoolsKey, err := registry.OpenKey(registry.CURRENT_USER, hardentoolsKeyPath, registry.QUERY_VALUE)
671+
if err != nil {
672+
return err
673+
}
674+
defer hardentoolsKey.Close()
675+
676+
err = hardentoolsKey.DeleteValue("SavedStateNonReg_" + feature)
677+
if err != nil {
678+
Info.Printf("Could not delete saved state for feature %s due to error %s",
679+
feature, err.Error())
680+
}
681+
return err
682+
}

windows_asr.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ var actionsArrayHardended = []bool{true, true, true, true, true, true, true,
6262
var actionsArrayNotHardended = []bool{false, false, false, false, false, false,
6363
false, false, false, false, false, false, false, false, false}
6464

65-
// WindowsASRStruct ist the struct for HardenInterface implementation.
65+
// WindowsASRStruct is the struct for HardenInterface implementation.
6666
type WindowsASRStruct struct {
6767
shortName string
6868
longName string

0 commit comments

Comments
 (0)