MHeads
MHeads

Reputation: 387

Editing binary Registry key

i'm trying to programmatically configure some options in Internet Explorer like :

  1. Allowing ActiveX Filtering
  2. Allowing Scripting
  3. etc..

They are all stored in the registry so I can easily edit them with.

public void EditKey(String keyPath, String keyName, Int32 newValue)
    {
        using (RegistryKey key = Registry.CurrentUser.OpenSubKey(keyPath, true))
        {
            if (key != null)
                key.SetValue(keyName, newValue, RegistryValueKind.DWord);
        }
    }

Here is my problem :

I need to add a website into the Tools -> Compatibility View Settings in Internet Explorer.

After some research, I saw that this list of websites is stored in :

HKEY_CURRENT_USER \ Software \ Microsoft \ Internet Explorer \ BrowserEmulation \ ClearableListData \ UserFilter.

The problem is that this key is a binary key so it's a little bit hard to, first of all decode what's in there and to edit it

I see that there is a delimiter between each stored website :

binary key

You clearly sees that the website : 123.com and 456.com is in the list. I need to add a website to that list but here comme the fact that the delimiter seems to randomly changed.

I build a predefined delimiter with my wanted website so it look like so :

private void ReadBinaryKey()
    {
        byte[] newWebsite = new byte []
        {
            0x0C,0x00,0x00,0x00,0xA8,0x82,0x8F,0x0D,
            0xC1,0x57,0xCE,0x01,0x01,0x00,0x00,0x00,
            0x08,0x00,0x32,0x00,0x30,0x00,0x32,0x00,
            0x30,0x00,0x2E,0x00,0x6E,0x00,0x65,0x00,
            0x74,0x00
        };

        using (RegistryKey key = Registry.CurrentUser.OpenSubKey(PATH_CVS, true))
        {
            if (key != null)
            {
                var value = (byte[])key.GetValue("UserFilter");

                // need to set my value here key.SetValue("UserFilter", newWebSite)
            }
        }        
    }

I don't tried this out cause I already know that it will not work at all. The problem is the randomly delimiter. Is there an other way to proceed my needs? Any help will be appreciated.

Thanks.

Upvotes: 2

Views: 5796

Answers (3)

Brian Cyr
Brian Cyr

Reputation: 33

Here is how I read this data:

Bytes  Description
00-07  Header (Appears to be constant "41,1f,00,00,53,08,ad,ba")
08-11  Int64 Total # of entries in the list
12-15  Int64 Total # of bytes to follow including this number. (DataLen + 4)
16-19  Int64 Version (seems to always be 1)
20-??  Repeating entries.

Entry Format
Bytes  Description
00-03  Int64   Entry Number  (Increments for each entry)
04-07  Int64   Entry Header (Seems to be constant at 12 (0xC))
08-11  Int64   Unknown - Checksum?
12-15  Int64   Unknown - Timestamp?
16-19  Int64   Unknown - Always 1
20-21  Int32   Length of data to follow  (an entry of abc.com would be 7)
22-??  Unicode Chars for the website/address

Upvotes: 0

Birol İnci
Birol İnci

Reputation: 81

here is the code that works. I added some code to the code that Ryoichi Fukushima create. main difference I made is I added count of domain to the byte array. I tested it in IE11, IE10.

private const string CLEARABLE_LIST_DATA = @"Software\Microsoft\Internet Explorer\BrowserEmulation\ClearableListData";
    private const string USERFILTER = "UserFilter";

    private static string[] GetDomains()
    {
        string[] domains;

        using (Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(CLEARABLE_LIST_DATA))
        {
            byte[] filter = regkey.GetValue(USERFILTER) as byte[];
            domains = GetDomains(filter);
        }

        return domains;
    }

    /* IT'S DANGER!! */
    // You shouldn't call until it becomes completely obvious that UNKNOWN parameter is meaning.
    private static void AddUserFilter(string domain)
    {
        string[] domains = GetDomains();
        foreach (string item in domains)
        {
            if (item==domain)
            {
                return;
            }
        }

        using (Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(CLEARABLE_LIST_DATA))
        {
            byte[] filter = regkey.GetValue(USERFILTER) as byte[];
            if(filter==null) filter=new byte[0];
            byte[] newReg = GetAddedValue(domain, filter);

            regkey.SetValue(USERFILTER, newReg, Microsoft.Win32.RegistryValueKind.Binary);
        }
    }

    private static void RemoveUserFilter(string domain)
    {
        using (Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(CLEARABLE_LIST_DATA))
        {
            byte[] filter = regkey.GetValue(USERFILTER) as byte[];
            byte[] newReg = GetRemovedValue(domain, filter);

            if (GetDomains(newReg).Length == 0)
                regkey.DeleteValue(USERFILTER);
            else
                regkey.SetValue(USERFILTER, newReg, Microsoft.Win32.RegistryValueKind.Binary);
        }
    }

    private static byte[] GetFilter()
    {
        byte[] filter;
        using (Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(CLEARABLE_LIST_DATA))
        {
            filter = regkey.GetValue(USERFILTER) as byte[];
        }
        return filter;
    }

    private static string[] GetDomains(byte[] filter)
    {
        List<string> domains = new List<string>();

        int length;
        int offset_filter = 24;
        int totalSize = filter.Length;

        while (offset_filter < totalSize)
        {
            length = BitConverter.ToUInt16(filter, offset_filter + 16);
            domains.Add(System.Text.Encoding.Unicode.GetString(filter, 16 + 2 + offset_filter, length * 2));
            offset_filter += 16 + 2 + length * 2;
        }

        return domains.ToArray();
    }

    private static byte[] GetAddedValue(string domain, byte[] filter)
    {
        byte[] SEPARATOR = new byte[] { 0x0C, 0x00, 0x00, 0x00 };
        byte[] CONSTANT = new byte[] { 0x01, 0x00, 0x00, 0x00 };
        byte[] UNKNOWN = BitConverter.GetBytes(DateTime.Now.ToBinary());

        List<byte> newReg = new List<byte>();
        byte[] binDomain = System.Text.Encoding.Unicode.GetBytes(domain);

        newReg.AddRange(filter);
        newReg.AddRange(SEPARATOR);
        /************************************************************************************************/
        newReg.AddRange(UNKNOWN); // IT'S IRRESPONSIBLE!!  Setting 0x00 is preferable to adding DateTime
        /************************************************************************************************/
        newReg.AddRange(CONSTANT);
        newReg.AddRange(BitConverter.GetBytes((UInt16)domain.Length));
        newReg.AddRange(binDomain);

        byte[] newSize = BitConverter.GetBytes((UInt16)(newReg.Count - 12));
        newReg[12] = newSize[0];
        newReg[13] = newSize[1];

        string[] domains = GetDomains();
        byte[] newCount = BitConverter.GetBytes((UInt16)(domains.Length + 1));
        newReg[8] = newCount[0];
        newReg[9] = newCount[1];

        newReg[20] = newCount[0];
        newReg[21] = newCount[1];

        return newReg.ToArray();
    }

    private static byte[] GetRemovedValue(string domain, byte[] filter)
    {
        byte[] newReg;
        int length;
        int offset_filter = 24;
        int offset_newReg = 0;
        int totalSize = filter.Length;

        newReg = new byte[totalSize];
        Array.Copy(filter, 0, newReg, 0, offset_filter);
        offset_newReg += offset_filter;

        while (offset_filter < totalSize)
        {
            length = BitConverter.ToUInt16(filter, offset_filter + 16);
            if (domain != System.Text.Encoding.Unicode.GetString(filter, offset_filter + 16 + 2, length * 2))
            {
                Array.Copy(filter, offset_filter, newReg, offset_newReg, 16 + 2 + length * 2);
                offset_newReg += 16 + 2 + length * 2;
            }
            offset_filter += 16 + 2 + length * 2;
        }
        Array.Resize(ref newReg, offset_newReg);
        byte[] newSize = BitConverter.GetBytes((UInt16)(offset_newReg - 12));
        newReg[12] = newSize[0];
        newReg[13] = newSize[1];

        return newReg;
    }

Upvotes: 1

Ryoichi Fukushima
Ryoichi Fukushima

Reputation: 1

MAYBE...

0x00-0x0B : header
0x0C-0x0D : "TOTAL BYTES-12" (UInt16)
0x0E-0x17 : constant A
0x18-0x1B : separator
0x1C-0x23 : UNKNOWN(id? NOT registered datetime...)
0x24-0x27 : constant B
0x28-0x29 : length of target domain(UInt16, ex. example.com is 0x0B,0x00)
0x2A-     : target domain (UNICODE)
[repeat separator...target domain]

SAMPLE...

private const string CLEARABLE_LIST_DATA = @"Software\Microsoft\Internet Explorer\BrowserEmulation\ClearableListData";
private const string USERFILTER = "UserFilter";

private static string[] GetDomains()
{
    string[] domains;

    using (Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(CLEARABLE_LIST_DATA))
    {
        byte[] filter = regkey.GetValue(USERFILTER) as byte[];
        domains = GetDomains(filter);
    }

    return domains;
}

/* IT'S DANGER!! */
// You shouldn't call until it becomes completely obvious that UNKNOWN parameter is meaning.
private static void AddUserFilter(string domain)
{
    using (Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(CLEARABLE_LIST_DATA))
    {
        byte[] filter = regkey.GetValue(USERFILTER) as byte[];
        byte[] newReg = GetAddedValue(domain, filter);

        regkey.SetValue(USERFILTER, newReg, Microsoft.Win32.RegistryValueKind.Binary);
    }
}

private static void RemoveUserFilter(string domain)
{
    using (Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(CLEARABLE_LIST_DATA))
    {
        byte[] filter = regkey.GetValue(USERFILTER) as byte[];
        byte[] newReg = GetRemovedValue(domain, filter);

        if (GetDomains(newReg).Length == 0)
            regkey.DeleteValue(USERFILTER);
        else
            regkey.SetValue(USERFILTER, newReg, Microsoft.Win32.RegistryValueKind.Binary);
    }
}

private static byte[] GetFilter()
{
    byte[] filter;
    using (Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(CLEARABLE_LIST_DATA))
    {
        filter = regkey.GetValue(USERFILTER) as byte[];
    }
    return filter;
}

private static string[] GetDomains(byte[] filter)
{
    List<string> domains = new List<string>();

    int length;
    int offset_filter = 24;
    int totalSize = filter.Length;

    while (offset_filter < totalSize)
    {
        length = BitConverter.ToUInt16(filter, offset_filter + 16);
        domains.Add(System.Text.Encoding.Unicode.GetString(filter, 16 + 2 + offset_filter, length * 2));
        offset_filter += 16 + 2 + length * 2;
    }

    return domains.ToArray();
}

private static byte[] GetAddedValue(string domain, byte[] filter)
{
    byte[] SEPARATOR = new byte[] { 0x0C, 0x00, 0x00, 0x00 };
    byte[] CONSTANT = new byte[] { 0x01, 0x00, 0x00, 0x00 };
    byte[] UNKNOWN = BitConverter.GetBytes(DateTime.Now.ToBinary());

    List<byte> newReg = new List<byte>();
    byte[] binDomain = System.Text.Encoding.Unicode.GetBytes(domain);

    newReg.AddRange(filter);
    newReg.AddRange(SEPARATOR);
    /************************************************************************************************/
    newReg.AddRange(UNKNOWN); // IT'S IRRESPONSIBLE!!  Setting 0x00 is preferable to adding DateTime
    /************************************************************************************************/
    newReg.AddRange(CONSTANT);
    newReg.AddRange(BitConverter.GetBytes((UInt16)domain.Length));
    newReg.AddRange(binDomain);

    byte[] newSize = BitConverter.GetBytes((UInt16)(newReg.Count - 12));
    newReg[12] = newSize[0];
    newReg[13] = newSize[1];

    return newReg.ToArray();
}

private static byte[] GetRemovedValue(string domain, byte[] filter)
{
    byte[] newReg;
    int length;
    int offset_filter = 24;
    int offset_newReg = 0;
    int totalSize = filter.Length;

    newReg = new byte[totalSize];
    Array.Copy(filter, 0, newReg, 0, offset_filter);
    offset_newReg += offset_filter;

    while (offset_filter < totalSize)
    {
        length = BitConverter.ToUInt16(filter, offset_filter + 16);
        if (domain != System.Text.Encoding.Unicode.GetString(filter, offset_filter + 16 + 2, length * 2))
        {
            Array.Copy(filter, offset_filter, newReg, offset_newReg, 16 + 2 + length * 2);
            offset_newReg += 16 + 2 + length * 2;
        }
        offset_filter += 16 + 2 + length * 2;
    }
    Array.Resize(ref newReg, offset_newReg);
    byte[] newSize = BitConverter.GetBytes((UInt16)(offset_newReg - 12));
    newReg[12] = newSize[0];
    newReg[13] = newSize[1];

    return newReg;
}

Upvotes: 0

Related Questions