Skip to content

Commit

Permalink
Proper feature persistence, minor bugfixes
Browse files Browse the repository at this point in the history
  • Loading branch information
thebookisclosed committed Apr 9, 2020
1 parent 47d3a1c commit 3ba9d5a
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 53 deletions.
8 changes: 4 additions & 4 deletions ViVe/FeatureConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ public int Group
{
get { return _group; }
set {
if (value > 15)
throw new ArgumentException("Group must not be more than 15");
if (value > 14)
throw new ArgumentException("Group must not be more than 14");
_group = value;
}
}
Expand All @@ -44,8 +44,8 @@ public FeatureEnabledState EnabledState
get { return _enabledState; }
set
{
if ((int)value > 3)
throw new ArgumentException("EnabledState must not be more than 3");
if ((int)value > 2)
throw new ArgumentException("EnabledState must not be more than 2");
_enabledState = value;
}
}
Expand Down
16 changes: 16 additions & 0 deletions ViVe/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,21 @@ int subscriptionCount
public static extern int RtlNotifyFeatureUsage(
byte[] buffer
);

[DllImport("ntdll.dll")]
public static extern int RtlSetSystemBootStatus(
int infoClass,
ref int state,
int stateSize,
IntPtr output
);

[DllImport("ntdll.dll")]
public static extern int RtlGetSystemBootStatus(
int infoClass,
ref int state,
int stateSize,
IntPtr output
);
}
}
16 changes: 16 additions & 0 deletions ViVe/RtlDataHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,21 @@ public static byte[] SerializeFeatureUsageReport(FeatureUsageReport report)
}
return retArray;
}

private static uint SwapBytes(uint x)
{
x = (x >> 16) | (x << 16);
return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
}

private static uint RotateRight32(uint value, int shift)
{
return (value >> shift) | (value << (32 - shift));
}

public static uint GetObfuscatedFeatureId(uint featureId)
{
return RotateRight32(SwapBytes(featureId ^ 0x74161A4E) ^ 0x8FB23D4F, -1) ^ 0x833EA8FF;
}
}
}
131 changes: 124 additions & 7 deletions ViVe/RtlFeatureManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

namespace Albacore.ViVe
Expand Down Expand Up @@ -119,19 +121,19 @@ public static uint QueryFeatureConfigurationChangeStamp()
return NativeMethods.RtlQueryFeatureConfigurationChangeStamp();
}

public static int SetFeatureConfigurations(List<FeatureConfiguration> configurations)
public static int SetLiveFeatureConfigurations(List<FeatureConfiguration> configurations)
{
uint dummy = 0;
return SetFeatureConfigurations(configurations, FeatureConfigurationSection.Runtime, ref dummy);
return SetLiveFeatureConfigurations(configurations, FeatureConfigurationSection.Runtime, ref dummy);
}

public static int SetFeatureConfigurations(List<FeatureConfiguration> configurations, FeatureConfigurationSection section)
public static int SetLiveFeatureConfigurations(List<FeatureConfiguration> configurations, FeatureConfigurationSection section)
{
uint dummy = 0;
return SetFeatureConfigurations(configurations, section, ref dummy);
return SetLiveFeatureConfigurations(configurations, section, ref dummy);
}

public static int SetFeatureConfigurations(List<FeatureConfiguration> configurations, FeatureConfigurationSection section, ref uint changeStamp)
public static int SetLiveFeatureConfigurations(List<FeatureConfiguration> configurations, FeatureConfigurationSection section, ref uint changeStamp)
{
return NativeMethods.RtlSetFeatureConfigurations(ref changeStamp, section, RtlDataHelpers.SerializeFeatureConfigurations(configurations), configurations.Count);
}
Expand Down Expand Up @@ -185,12 +187,12 @@ public static List<FeatureUsageSubscription> QueryFeatureUsageSubscriptions()
return allSubscriptions;
}

public static int AddFeatureUsageSubscriptions(List<FeatureUsageSubscription> subscriptions)
public static int AddLiveFeatureUsageSubscriptions(List<FeatureUsageSubscription> subscriptions)
{
return NativeMethods.RtlSubscribeForFeatureUsageNotification(RtlDataHelpers.SerializeFeatureUsageSubscriptions(subscriptions), subscriptions.Count);
}

public static int RemoveFeatureUsageSubscriptions(List<FeatureUsageSubscription> subscriptions)
public static int RemoveLiveFeatureUsageSubscriptions(List<FeatureUsageSubscription> subscriptions)
{
return NativeMethods.RtlUnsubscribeFromFeatureUsageNotifications(RtlDataHelpers.SerializeFeatureUsageSubscriptions(subscriptions), subscriptions.Count);
}
Expand All @@ -199,5 +201,120 @@ public static int NotifyFeatureUsage(FeatureUsageReport report)
{
return NativeMethods.RtlNotifyFeatureUsage(RtlDataHelpers.SerializeFeatureUsageReport(report));
}

public static int SetBootFeatureConfigurationState(ref int state)
{
return NativeMethods.RtlSetSystemBootStatus(17, ref state, sizeof(int), IntPtr.Zero);
}

public static int GetBootFeatureConfigurationState(ref int state)
{
return NativeMethods.RtlGetSystemBootStatus(17, ref state, sizeof(int), IntPtr.Zero);
}

public static bool SetBootFeatureConfigurations(List<FeatureConfiguration> configurations)
{
try
{
foreach (var config in configurations)
{
uint obfuscatedId = RtlDataHelpers.GetObfuscatedFeatureId(config.FeatureId);
var obfuscatedKey = $@"SYSTEM\CurrentControlSet\Control\FeatureManagement\Overrides\{config.Group}\{obfuscatedId}";
if (config.Action == FeatureConfigurationAction.Delete)
Registry.LocalMachine.DeleteSubKeyTree(obfuscatedKey, false);
else
{
using (var rKey = Registry.LocalMachine.CreateSubKey(obfuscatedKey))
{
if ((config.Action & FeatureConfigurationAction.UpdateEnabledState) == FeatureConfigurationAction.UpdateEnabledState)
{
rKey.SetValue("EnabledState", (int)config.EnabledState);
rKey.SetValue("EnabledStateOptions", config.EnabledStateOptions);
}
if ((config.Action & FeatureConfigurationAction.UpdateVariant) == FeatureConfigurationAction.UpdateVariant)
{
rKey.SetValue("Variant", config.Variant);
rKey.SetValue("VariantPayload", config.VariantPayload);
rKey.SetValue("VariantPayloadKind", config.VariantPayloadKind);
}
}
}
}
return true;
} catch { return false; }
}

public static bool RemoveBootFeatureConfigurations(List<FeatureConfiguration> configurations)
{
try
{
foreach (var config in configurations)
{
uint obfuscatedId = RtlDataHelpers.GetObfuscatedFeatureId(config.FeatureId);
Registry.LocalMachine.DeleteSubKeyTree($@"SYSTEM\CurrentControlSet\Control\FeatureManagement\Overrides\{config.Group}\{obfuscatedId}", false);
}
return true;
}
catch { return false; }
}

public static bool AddBootFeatureUsageSubscriptions(List<FeatureUsageSubscription> subscriptions)
{
try
{
foreach (var sub in subscriptions)
{
uint obfuscatedId = RtlDataHelpers.GetObfuscatedFeatureId(sub.FeatureId);
using (var rKey = Registry.LocalMachine.CreateSubKey($@"SYSTEM\CurrentControlSet\Control\FeatureManagement\UsageSubscriptions\{obfuscatedId}\{{{Guid.NewGuid()}}}"))
{
rKey.SetValue("ReportingKind", (int)sub.ReportingKind);
rKey.SetValue("ReportingOptions", (int)sub.ReportingOptions);
rKey.SetValue("ReportingTarget", BitConverter.GetBytes(sub.ReportingTarget));
}
}
return true;
}
catch { return false; }
}

public static bool RemoveBootFeatureUsageSubscriptions(List<FeatureUsageSubscription> subscriptions)
{
try
{
string[] bootSubs;
using (var rKey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Control\FeatureManagement\UsageSubscriptions"))
bootSubs = rKey.GetSubKeyNames();
foreach (var sub in subscriptions)
{
var obfuscatedKey = RtlDataHelpers.GetObfuscatedFeatureId(sub.FeatureId).ToString();
if (bootSubs.Contains(obfuscatedKey))
{
bool isEmpty = false;
obfuscatedKey = @"SYSTEM\CurrentControlSet\Control\FeatureManagement\UsageSubscriptions\" + obfuscatedKey;
using (var sKey = Registry.LocalMachine.OpenSubKey(obfuscatedKey, true))
{
foreach (var subGuid in sKey.GetSubKeyNames())
{
bool toRemove = false;
using (var gKey = sKey.OpenSubKey(subGuid))
{
if ((int)gKey.GetValue("ReportingKind") == sub.ReportingKind &&
(int)gKey.GetValue("ReportingOptions") == sub.ReportingOptions &&
BitConverter.ToUInt64((byte[])gKey.GetValue("ReportingTarget"), 0) == sub.ReportingTarget)
toRemove = true;
}
if (toRemove)
sKey.DeleteSubKeyTree(subGuid, false);
}
isEmpty = sKey.SubKeyCount == 0;
}
if (isEmpty)
Registry.LocalMachine.DeleteSubKeyTree(obfuscatedKey, false);
}
}
return true;
}
catch { return false; }
}
}
}

0 comments on commit 3ba9d5a

Please sign in to comment.