Archived
1
1

First release build.

This commit is contained in:
Mona Lassa
2025-05-22 01:31:03 +02:00
parent ec55169d57
commit f90695dfda
30 changed files with 499 additions and 1389 deletions

View File

@@ -7,57 +7,20 @@ using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace MetroUnlocker.ProductPolicy
{
//public struct ProductPolicyData
//{
// public string String;
// public byte[] Bytes;
// public uint DWord;
//};
class ProductPolicy
{
public bool Modified { get; set; }
public ProductPolicyValue Header { get; set; }
public string Name { get; set; }
//private ProductPolicyData _data;
//public ProductPolicyData Data
//{
// get { return _data; }
// set { _data = value; }
//}
public byte[] Bytes { get; set; }
public string StringValue
{
get
{
return Encoding.Unicode.GetString(Bytes);
}
set {
Bytes = Encoding.Unicode.GetBytes(value);
}
}
public uint DWordValue
{
get
{
return BitConverter.ToUInt32(Bytes, 0);
}
set
{
Bytes = BitConverter.GetBytes(value);
}
}
public string StringValue { get { return Encoding.Unicode.GetString(Bytes); } }
public uint DWordValue { get { return BitConverter.ToUInt32(Bytes, 0); } }
public RegistryValueKind Type
{
get
{
return (RegistryValueKind)Header.DataType;
}
get { return (RegistryValueKind)Header.DataType; }
}
private void NameFromBin(ref byte[] PolicyBlob, int offset)
@@ -74,12 +37,10 @@ namespace MetroUnlocker.ProductPolicy
public void FromBin(ref byte[] PolicyBlob, int offset)
{
Header = Tools.BytesToStruct<ProductPolicyValue>(PolicyBlob, typeof(ProductPolicyValue), offset);
if ((Header.Data + Header.Name + Marshal.SizeOf(Header)) > Header.Size ||
(offset + Header.Size) > PolicyBlob.Length)
{
throw new Exception("Invalid _data Header format");
}
Header = ProductPolicyReader.BytesToStruct<ProductPolicyValue>(PolicyBlob, offset);
if ((Header.Data + Header.Name + Marshal.SizeOf(Header)) > Header.Size || (offset + Header.Size) > PolicyBlob.Length)
throw new Exception("Invalid data Header format");
NameFromBin(ref PolicyBlob, offset);
ValFromBin(ref PolicyBlob, offset);
}
@@ -97,57 +58,6 @@ namespace MetroUnlocker.ProductPolicy
}
}
public int Size()
{
//switch (Type)
//{
// case RegistryValueKind.String:
// return StringValue.Length * 2;
// case RegistryValueKind.DWord:
// return 4;
// default:
// return Bytes.Length;
//}
return Bytes.Length;
}
//public byte[] ToBinary()
//{
// switch (Type)
// {
// case RegistryValueKind.String:
// return Encoding.Unicode.GetBytes(_data.String);
// case RegistryValueKind.DWord:
// return Tools.StructToBytes(DWordVq);
// default:
// return Bytes;
// }
//}
public byte[] ToBin()
{
ProductPolicyValue value = new ProductPolicyValue();
value.Name = (UInt16)(2 * Name.Length);
value.Data = (UInt16)Size();
int datablocksize = Marshal.SizeOf(Header) + value.Name + value.Data;
int suffixLength = 4 - (datablocksize % 4);
value.Size = (UInt16)(Marshal.SizeOf(Header) + value.Name + value.Data + suffixLength);
value.DataType = Header.DataType;
value.Unknown1 = Header.Unknown1;
value.Unknown2 = Header.Unknown2;
byte[] bytes = Tools.StructToBytes(value);
Tools.AppendBytes(ref bytes, Encoding.Unicode.GetBytes(Name));
Tools.AppendBytes(ref bytes, Bytes);
Tools.PaddingAppend(ref bytes, suffixLength);
return bytes;
}
// I would like to not split the data into dword and string on parsing but on getting.
//public void SetDWordValue(uint value)
//{
// Data = new ProductPolicyData { DWord = value };
//}
public int Size() { return Bytes.Length; }
}
}

View File

@@ -1,157 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
using System.Runtime.InteropServices;
namespace MetroUnlocker.ProductPolicy
{
public struct ProductPolicyHeader
{
public UInt32 Size, DataSize, EndMarker, Unknown1, Unknown2;
}
public struct ProductPolicyValue
{
public UInt16 Size, Name, DataType, Data;
public UInt32 Unknown1, Unknown2;
}
public enum PolicyState : uint
{
Disabled = 0,
Enabled = 1,
Unknown
}
class ProductPolicyEditor
{
public List<ProductPolicy> PolicyValues { get; set; }
public ProductPolicyHeader Header;
private byte[] _policyBytes;
private byte[] _productPolicyBlobSuffix;
const string ProductOptionsKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions";
public ProductPolicyEditor()
{
_policyBytes = GetPolicyBlob();
PolicyValues = FromBinary();
}
public bool Save()
{
return SetPolicyBlob(ToBin());
}
private static byte[] GetPolicyBlob()
{
return (byte[])Registry.GetValue(ProductOptionsKey, "ProductPolicy", null);
}
private static bool SetPolicyBlob(byte[] bytes)
{
Registry.SetValue(ProductOptionsKey, "ProductPolicy", bytes);
Thread.Sleep(1000);
return Tools.ArraysEqual(GetPolicyBlob(), bytes);
}
public List<ProductPolicy> FromBinary()
{
return FromBinary(_policyBytes);
}
public List<ProductPolicy> FromBinary(byte[] policyBlob)
{
var header = Tools.BytesToStruct<ProductPolicyHeader>(policyBlob, typeof(ProductPolicyHeader));
if (header.Size < policyBlob.Length || (header.DataSize + Marshal.SizeOf(header) + header.EndMarker) != header.Size)
throw new Exception("Invalid Header format");
int pos = Marshal.SizeOf(header);
int pos_end = pos + (int)header.DataSize;
PolicyValues = new List<ProductPolicy>();
while (pos < pos_end)
{
ProductPolicy pv = new ProductPolicy();
pv.FromBin(ref policyBlob, pos);
PolicyValues.Add(pv);
pos += pv.Header.Size;
}
if (pos < header.Size)
{
_productPolicyBlobSuffix = new byte[policyBlob.Length - pos];
Array.Copy(policyBlob, pos, _productPolicyBlobSuffix, 0, _productPolicyBlobSuffix.Length);
}
else
{
_productPolicyBlobSuffix = null;
}
return PolicyValues;
}
public byte[] ToBin()
{
int headerSize = Marshal.SizeOf(Header);
byte[] policyBlob = new byte[headerSize];
foreach (ProductPolicy v in PolicyValues)
Tools.AppendBytes(ref policyBlob, v.ToBin());
Tools.AppendBytes(ref policyBlob, _productPolicyBlobSuffix);
Header.Size = (UInt32)policyBlob.Length;
Header.EndMarker = (UInt32)_productPolicyBlobSuffix.Length;
Header.DataSize = (UInt32)(Header.Size - Header.EndMarker - headerSize);
Array.Copy(Tools.StructToBytes(Header), 0, policyBlob, 0, headerSize);
return policyBlob;
}
public ProductPolicy GetPolicyWithName(string name)
{
return PolicyValues.Find(value => value.Name == name);
}
public PolicyState GetPolicyStateByName(string name)
{
ProductPolicy policy = GetPolicyWithName(name);
if (policy.Type == RegistryValueKind.DWord)
{
if (policy.DWordValue == 0)
return PolicyState.Disabled;
else if (policy.DWordValue == 1)
return PolicyState.Enabled;
}
return PolicyState.Unknown;
}
public bool SetPolicyStateByName(string name, PolicyState state)
{
ProductPolicy policy = GetPolicyWithName(name);
if (policy.Type == RegistryValueKind.DWord)
{
switch (state)
{
case PolicyState.Disabled:
policy.DWordValue = 0;
break;
case PolicyState.Enabled:
policy.DWordValue = 1;
break;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace MetroUnlocker.ProductPolicy
{
public struct ProductPolicyHeader
{
public UInt32 Size, DataSize, EndMarker, Unknown1, Unknown2;
}
public struct ProductPolicyValue
{
public UInt16 Size, Name, DataType, Data;
public UInt32 Unknown1, Unknown2;
}
public enum PolicyState : uint
{
Disabled = 0,
Enabled = 1,
Unknown
}
class ProductPolicyReader
{
public List<ProductPolicy> PolicyValues { get; set; }
const string ProductOptionsKey = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions";
public ProductPolicyReader()
{
PolicyValues = FromBinary(GetPolicyBlob());
}
private static byte[] GetPolicyBlob()
{
return (byte[])Registry.GetValue(ProductOptionsKey, "ProductPolicy", null);
}
static public T BytesToStruct<T>(byte[] bytes, int offset = 0)
{
int size = Marshal.SizeOf(typeof(T));
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.Copy(bytes, offset, buffer, size);
return (T)Marshal.PtrToStructure(buffer, typeof(T));
}
finally { Marshal.FreeHGlobal(buffer); }
}
public List<ProductPolicy> FromBinary(byte[] policyBlob)
{
var header = BytesToStruct<ProductPolicyHeader>(policyBlob);
if (header.Size < policyBlob.Length || (header.DataSize + Marshal.SizeOf(header) + header.EndMarker) != header.Size)
throw new Exception("Invalid Header format");
int position = Marshal.SizeOf(header);
int end = position + (int)header.DataSize;
PolicyValues = new List<ProductPolicy>();
while (position < end)
{
ProductPolicy policy = new ProductPolicy();
policy.FromBin(ref policyBlob, position);
PolicyValues.Add(policy);
position += policy.Header.Size;
}
return PolicyValues;
}
public ProductPolicy GetPolicyWithName(string name)
{
return PolicyValues.Find(value => value.Name == name);
}
public PolicyState GetPolicyStateByName(string name)
{
ProductPolicy policy = GetPolicyWithName(name);
if (policy.Type == RegistryValueKind.DWord)
{
if (policy.DWordValue == 0)
return PolicyState.Disabled;
else if (policy.DWordValue == 1)
return PolicyState.Enabled;
}
return PolicyState.Unknown;
}
}
}

View File

@@ -1,82 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace MetroUnlocker.ProductPolicy
{
class Tools
{
public static void AppendBytes(ref byte[] b1, byte[] b2)
{
int length = b1.Length;
Array.Resize(ref b1, length + b2.Length);
Array.Copy(b2, 0, b1, length, b2.Length);
}
static public T BytesToStruct<T>(byte[] bytes, Type type, int offset = 0)
{
int size = Marshal.SizeOf(type);
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.Copy(bytes, offset, buffer, size);
return (T)Marshal.PtrToStructure(buffer, type);
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
static public byte[] StructToBytes(object structObject)
{
int size = Marshal.SizeOf(structObject);
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(structObject, buffer, false);
byte[] bytes = new byte[size];
Marshal.Copy(buffer, bytes, 0, size);
return bytes;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
public static void PaddingAppend(ref byte[] b1, int paddinglen)
{
if (paddinglen > 0)
{
int l = b1.Length;
Array.Resize(ref b1, b1.Length + paddinglen);
for (; l < b1.Length; l++)
b1[l] = 0;
}
}
static public bool ArraysEqual(Array a1, Array a2)
{
if (a1 == a2)
return true;
if (a1 == null || a2 == null)
return false;
if (a1.Length != a2.Length)
return false;
System.Collections.IList list1 = a1, list2 = a2; //error CS0305: Using the generic type 'System.Collections.Generic.IList<T>' requires '1' type arguments
for (int i = 0; i < a1.Length; i++)
{
if (!Object.Equals(list1[i], list2[i])) //error CS0021: Cannot apply indexing with [] to an expression of type 'IList'(x2)
return false;
}
return true;
}
}
}