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  }