This is a technical deep-dive based on a post I originally wrote on my company blog. I wanted to share the C# implementation details here for fellow Windows devs.
We’ve all seen them. IT admins grab a popular one-click Windows hardening script off the web and push it across a fleet of office PCs, just to tick boxes for a security audit.
The intent is reasonable enough. The outcome, more often than not, is a mess.
A few days later, finance is complaining that their network printer stopped working, and an old internal ERP client can no longer talk to its database. The worst part? Most of these scripts only know how to disable and block. They ship with no real rollback logic at all. The admin ends up manually rebuilding Windows on affected machines.
If your hardening tool does not include a reliable, tested rollback mechanism, it is not really a security tool. It’s a liability waiting to break production.
Why Most Open-Source Hardening Scripts Are Risky
Windows hardening touches deep OS internals: registry keys, filesystem ACLs, system services, and firewall rules.
Most open-source scripts are little more than a long sequence of reg add and sc config commands. They may successfully close a known attack surface, but they ignore a simple reality: every endpoint runs a unique environment.
The script disables SMBv1, but the site still has an older network printer that relies on the SMBv1 protocol. It locks down a critical registry path, and suddenly Windows Update or a line-of-business application crashes.
The Hard Truth About Rollbacks
When building WinSystemHarden, we spent nearly half our development time on the rollback engine alone.
Rollback is not as simple as flipping a toggle back. Here is what it actually requires:
1. Registry & Services (the simpler part)
If we disable the Remote Registry service, rolling back means restoring its original startup state and starting it again. We log every original value and the exact reverse command for each change we make.
2. Firewall Rules (requires precision)
When we add rules to block ports like 445 or 135, rollback cannot just flush the entire firewall policy. We target and delete only the specific rules our tool created, by name.
3. ACL Permissions (the highest-risk area)
This is where many tools break systems. To block tampering, we can restrict write access on sensitive paths such as C:\Windows\System32\config or the hosts file.
If a naive rollback tries to fix permissions by blindly adding Everyone:(W) via icacls, it can destroy the original permission inheritance — and in the worst case, leave Windows unbootable.
Our approach avoids ad-hoc permission commands entirely. Before applying any hardening change, the tool captures the full ACL tree and saves it as an XML snapshot. On rollback, we import that snapshot and restore permissions exactly as they were.
Here is the actual C# logic we use to back up the ACLs via PowerShell:
private string BackupAcl(string targetPath, string backupFileName)
{
string backupPath = Path.Combine(_aclBackupDir, backupFileName);
string safeTargetPath = targetPath.Replace("'", "''");
string safeBackupPath = backupPath.Replace("'", "''");
string psCmd =
$"$acl = Get-Acl -LiteralPath '{safeTargetPath}'; " +
$"$acl | Export-Clixml -LiteralPath '{safeBackupPath}' -Force";
int exitCode = RunPowerShell(psCmd, 60);
return (exitCode == 0 && File.Exists(backupPath)) ? backupPath : "";
}
And to restore it, we simply reverse the process using Import-Clixml and Set-Acl. This is the only safe way we’ve found to guarantee that a rollback won't break the OS.
4. The bcdedit WOW64 Trap
Configuring DEP requires bcdedit.exe. But if your app is 32-bit running on 64-bit Windows, accessing System32\bcdedit.exe triggers file system redirection. The OS silently reroutes the call to SysWOW64, where bcdedit.exe does not exist, and the command fails.
Our tool detects this condition and explicitly calls C:\Windows\SysNative\bcdedit.exe to bypass the redirection:
if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess)
{
string sysNative = Path.Combine(systemRoot, "SysNative");
string sysNativePath = Path.Combine(sysNative, "bcdedit.exe");
if (File.Exists(sysNativePath)) return sysNativePath;
}
// Fallback to default System32 path if needed
Skip this check, and users click Harden while nothing actually takes effect.
Time-Point Rollbacks — Not Just Single Undo Actions
Many tools only let you undo one isolated setting. WinSystemHarden works with batch, time-stamped rollback snapshots.
Every hardening run creates a snapshot tagged with a timestamp. When a user finds that a hardening session broke their workflow, they do not need to comb through lengthy logs to revert individual tweaks. They just select the snapshot from the earlier run and trigger rollback. The tool reverses every change from that session, in the correct reverse order.
Try a Hardening Tool That Won’t Break Your PCs
We built WinSystemHarden to make local Windows hardening safer. It is completely free, with no feature limits.
No accounts required, no cloud telemetry or sync. It includes 29 practical hardening rules aligned with CIS and NSA security guidance. And if something breaks your workflow, the one-click rollback is always available.
Top comments (2)
the SysNative check is the one people forget. another way out is shipping the tool as a 64-bit process (Prefer32Bit false), then the redirect never kicks in.
q on the ACL snapshot: does it include the owner and SACL too? reading the SACL with AccessControlSections.All needs SeSecurityPrivilege, so it's easy to end up restoring only the DACL
Thanks Mehdi.
On Prefer32Bit false, building as a pure x64 process is definitely the cleanest way to avoid redirection entirely. I kept the binary as 32-bit to stay compatible with older systems, which is why the SysNative check is the necessary fallback here.
Regarding the ACL snapshot, I double-checked my code, and as you suspected, I'm using the basic Get-Acl and Export-Clixml approach. It only serializes the DACL and Owner, with no logic to read the SACL or enable SeSecurityPrivilege. That's definitely an area for future optimization.
For a hardening tool targeting individual users, I believe DACL and Owner already cover the core requirement of blocking unauthorized write/delete access. However, your point about enterprise compliance and full auditing is spot on. If I expand in that direction, I'll definitely need to dig into AccessControlSections.All and the privilege requirements.