FuzzTests.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 using System; 5 using System.Diagnostics; 6 using System.Globalization; 7 using System.Resources; 8 using Microsoft.VisualStudio.TestTools.UnitTesting; 9 using Microsoft.Win32; 10 using RegistryPreviewUILib; 11 12 namespace RegistryPreview.FuzzTests 13 { 14 public class FuzzTests 15 { 16 private const string REGISTRYHEADER4 = "regedit4"; 17 private const string REGISTRYHEADER5 = "windows registry editor version 5.00"; 18 private const string KEYIMAGE = "ms-appx:///Assets/RegistryPreview/folder32.png"; 19 private const string DELETEDKEYIMAGE = "ms-appx:///Assets/RegistryPreview/deleted-folder32.png"; 20 21 // Case 1: Fuzz test for CheckKeyLineForBrackets 22 public static void FuzzCheckKeyLineForBrackets(ReadOnlySpan<byte> input) 23 { 24 string registryLine; 25 26 // Simulate registry file content as registryContent 27 var registryContent = GenerateRegistryHeader(input); 28 29 string[] registryLines = registryContent.Split("\r"); 30 31 if (registryLines.Length <= 1) 32 { 33 return; 34 } 35 36 // REG files have to start with one of two headers and it's case-insensitive 37 // The header in the registry file is either REGISTRYHEADER4 or REGISTRYHEADER5 38 registryLine = registryLines[0]; 39 40 // Check if the registry header is valid 41 if (!IsValidRegistryHeader(registryLine)) 42 { 43 return; 44 } 45 46 int index = 1; 47 registryLine = registryLines[index]; // Extract content after the header 48 49 ParseHelper.ProcessRegistryLine(registryLine); 50 if (registryLine.StartsWith("[-", StringComparison.InvariantCulture)) 51 { 52 // remove the - as we won't need it but it will get special treatment in the UI 53 registryLine = registryLine.Remove(1, 1); 54 55 string imageName = DELETEDKEYIMAGE; 56 57 // Fuzz test for the CheckKeyLineForBrackets method 58 ParseHelper.CheckKeyLineForBrackets(ref registryLine, ref imageName); 59 } 60 else if (registryLine.StartsWith('[')) 61 { 62 string imageName = KEYIMAGE; 63 64 // Fuzz test for the CheckKeyLineForBrackets method 65 ParseHelper.CheckKeyLineForBrackets(ref registryLine, ref imageName); 66 } 67 else 68 { 69 return; 70 } 71 } 72 73 // Case 2: Fuzz test for StripFirstAndLast 74 public static void FuzzStripFirstAndLast(ReadOnlySpan<byte> input) 75 { 76 string registryLine; 77 78 var registryContent = GenerateRegistryHeader(input); 79 80 registryContent = registryContent.Replace("\r\n", "\r"); 81 string[] registryLines = registryContent.Split("\r"); 82 83 if (registryLines.Length <= 1) 84 { 85 return; 86 } 87 88 // REG files have to start with one of two headers and it's case-insensitive 89 registryLine = registryLines[0]; 90 91 if (!IsValidRegistryHeader(registryLine)) 92 { 93 return; 94 } 95 96 int index = 1; 97 registryLine = registryLines[index]; 98 99 ParseHelper.ProcessRegistryLine(registryLine); 100 101 if (registryLine.StartsWith("[-", StringComparison.InvariantCulture)) 102 { 103 // remove the - as we won't need it but it will get special treatment in the UI 104 registryLine = registryLine.Remove(1, 1); 105 106 string imageName = DELETEDKEYIMAGE; 107 ParseHelper.CheckKeyLineForBrackets(ref registryLine, ref imageName); 108 109 // Fuzz test for the StripFirstAndLast method 110 registryLine = ParseHelper.StripFirstAndLast(registryLine); 111 } 112 else if (registryLine.StartsWith('[')) 113 { 114 string imageName = KEYIMAGE; 115 ParseHelper.CheckKeyLineForBrackets(ref registryLine, ref imageName); 116 117 // Fuzz test for the StripFirstAndLast method 118 registryLine = ParseHelper.StripFirstAndLast(registryLine); 119 } 120 else if (registryLine.StartsWith('"') && registryLine.EndsWith("=-", StringComparison.InvariantCulture)) 121 { 122 // remove "=-" 123 registryLine = registryLine[..^2]; 124 125 // remove the "'s without removing all of them 126 // Fuzz test for the StripFirstAndLast method 127 registryLine = ParseHelper.StripFirstAndLast(registryLine); 128 } 129 else if (registryLine.StartsWith('"')) 130 { 131 int equal = registryLine.IndexOf('='); 132 if ((equal < 0) || (equal > registryLine.Length - 1)) 133 { 134 // something is very wrong 135 return; 136 } 137 138 // set the name and the value 139 string name = registryLine.Substring(0, equal); 140 141 // trim the whitespace and quotes from the name 142 name = name.Trim(); 143 144 // Fuzz test for the StripFirstAndLast method 145 name = ParseHelper.StripFirstAndLast(name); 146 147 // Clean out any escaped characters in the value, only for the preview 148 name = ParseHelper.StripEscapedCharacters(name); 149 150 // set the value 151 string value = registryLine.Substring(equal + 1); 152 153 // trim the whitespace from the value 154 value = value.Trim(); 155 156 // if the first character is a " then this is a string value, so find the last most " which will avoid comments 157 if (value.StartsWith('"')) 158 { 159 int last = value.LastIndexOf('"'); 160 if (last >= 0) 161 { 162 value = value.Substring(0, last + 1); 163 } 164 } 165 166 if (value.StartsWith('"') && value.EndsWith('"')) 167 { 168 value = ParseHelper.StripFirstAndLast(value); 169 } 170 } 171 else 172 { 173 return; 174 } 175 } 176 177 public static string GenerateRegistryHeader(ReadOnlySpan<byte> input) 178 { 179 string header = new Random().Next(2) == 0 ? REGISTRYHEADER4 : REGISTRYHEADER5; 180 181 string inputText = System.Text.Encoding.UTF8.GetString(input); 182 string registryContent = header + "\r" + inputText; 183 184 return registryContent; 185 } 186 187 private static bool IsValidRegistryHeader(string line) 188 { 189 // Convert the line to lowercase once for comparison 190 switch (line) 191 { 192 case REGISTRYHEADER4: 193 case REGISTRYHEADER5: 194 return true; 195 default: 196 return false; 197 } 198 } 199 } 200 }