forked from Snoooopy/MetroUnlocker
Initial commit
This commit is contained in:
153
MetroUnlocker/ProductPolicy/ProductPolicy.cs
Normal file
153
MetroUnlocker/ProductPolicy/ProductPolicy.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
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 RegistryValueKind Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return (RegistryValueKind)Header.DataType;
|
||||
}
|
||||
}
|
||||
|
||||
private void NameFromBin(ref byte[] PolicyBlob, int offset)
|
||||
{
|
||||
Name = Encoding.Unicode.GetString(PolicyBlob, offset + Marshal.SizeOf(Header), Header.Name);
|
||||
}
|
||||
|
||||
private void ValFromBin(ref byte[] PolicyBlob, int offset)
|
||||
{
|
||||
int posdata = offset + Marshal.SizeOf(Header) + Header.Name;
|
||||
Bytes = new byte[Header.Data];
|
||||
Array.Copy(PolicyBlob, posdata, Bytes, 0, Header.Data);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
NameFromBin(ref PolicyBlob, offset);
|
||||
ValFromBin(ref PolicyBlob, offset);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case RegistryValueKind.String:
|
||||
return StringValue;
|
||||
case RegistryValueKind.DWord:
|
||||
return DWordValue.ToString();
|
||||
default:
|
||||
return Bytes != null ? BitConverter.ToString(Bytes) : "";
|
||||
}
|
||||
}
|
||||
|
||||
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 };
|
||||
//}
|
||||
}
|
||||
}
|
||||
157
MetroUnlocker/ProductPolicy/ProductPolicyEditor.cs
Normal file
157
MetroUnlocker/ProductPolicy/ProductPolicyEditor.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
82
MetroUnlocker/ProductPolicy/Tools.cs
Normal file
82
MetroUnlocker/ProductPolicy/Tools.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user