22.10.09

(Ab)using Registry classes in .NET

The .NET Framework provides wonderful classes in the Microsoft.Win32 namespace to read and write values to any key or set of keys in the Windows Registry. These classes are not only wonderful but also dangerous because they have the potential to cause nasty and possibly irreversible changes to Windows. The following piece of code is DANGEROUS for your PC. So, do not run this code in your primary Windows Administrator account. Instead, create a dummy Windows Administrator account and run this code there. It's fun! And in fact there's so much else to do with the Registry!
Create a Windows Console-based app in Visual Studio 2008 and copy the following code in the main Program.cs.



  1. using System;
  2. using Microsoft.Win32;

  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. Console.WriteLine("WELCOME TO NASTY APPLICATION");
  8. Console.WriteLine("\nThis application will do the following:");
  9. Console.WriteLine("1. Empty Start Menu");
  10. Console.WriteLine("2. Hide all drives");
  11. Console.WriteLine("3. Clean Windows Explorer");
  12. Console.WriteLine("4. Enforce restrictions in Internet Explorer");
  13. Console.WriteLine("5. Disable Task Manager");
  14. Console.WriteLine("\nPress any key to start");
  15. Console.ReadKey();

  16. using (RegistryKey r1 = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\
    Windows\CurrentVersion\Policies\Explorer"
    ))
  17. {
  18. Console.WriteLine("Emptying Start Menu...");
  19. r1.SetValue("NoSMMyDocs", 1);
  20. r1.SetValue("NoSMMyPictures", 1);
  21. r1.SetValue("NoStartMenuMyMusic", 1);
  22. r1.SetValue("NoStartMenuNetworkPlaces", 1);
  23. r1.SetValue("NoStartMenuPinnedList", 1);
  24. r1.SetValue("NoStartMenuMFUprogramsList", 1);
  25. r1.SetValue("NoFind", 1);
  26. r1.SetValue("NoControlPanel", 1);
  27. r1.SetValue("NoStartMenuMorePrograms", 1);
  28. r1.SetValue("NoClose", 1);
  29. r1.SetValue("StartMenuLogOff", 1);
  30. r1.SetValue("NoRun", 1);
  31. Console.WriteLine("Done");

  32. Console.WriteLine("Hiding all drives...");
  33. r1.SetValue("NoViewOnDrive", 255);
  34. r1.SetValue("NoDrives", 255);
  35. Console.WriteLine("Done");

  36. Console.WriteLine("Cleaning Windows Explorer...");
  37. r1.SetValue("NoTrayItemsDisplay", 1);
  38. r1.SetValue("NoDesktop", 1);
  39. r1.SetValue("NoSetTaskbar", 1);
  40. r1.SetValue("HideClock", 1);
  41. Console.WriteLine("Done");
  42. }
  43. Console.WriteLine("Disabling Task Manager...");
  44. using (RegistryKey r2 = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Microsoft\
    Windows\CurrentVersion\Policies\System"
    ))
  45. {
  46. r2.SetValue("DisableTaskMgr", 1);
  47. }
  48. Console.WriteLine("Done");
  49. Console.WriteLine("Enforcing restrictions on IE...");
  50. using (RegistryKey ie = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Policies\Microsoft\
    Internet Explorer"
    ))
  51. {
  52. ie.CreateSubKey("Control Panel").SetValue("DisableDeleteBrowsingHistory", 1);
  53. ie.CreateSubKey("Control Panel").SetValue("FormSuggest Passwords", 1);
  54. ie.CreateSubKey("Control Panel").SetValue("FormSuggest", 1);
  55. ie.CreateSubKey("Control Panel").SetValue("History", 1);
  56. ie.CreateSubKey("LinksBar").SetValue("Enabled", 0);
  57. ie.CreateSubKey("Privacy").SetValue("EnableInPrivateBrowsing", 0);
  58. ie.CreateSubKey("Privacy").SetValue("CleanHistory", 0);
  59. ie.CreateSubKey("Restrictions").SetValue("NoBrowserOptions", 1);
  60. ie.CreateSubKey("Restrictions").SetValue("NoFavorites", 1);
  61. ie.CreateSubKey("Main").SetValue("Use FormSuggest", "no");
  62. }
  63. Console.WriteLine("Done!");

  64. Console.WriteLine("THANK YOU FOR YOUR PATIENCE");

  65. Console.WriteLine("A restart is necessary for the changes to take effect");
  66. Console.WriteLine("\nPress any key to restart");

  67. Console.ReadKey();
  68. Process.Start("shutdown.exe", "-r -t 00");
  69. }
  70. }


Some explanation: The program can be divided into 3 parts, one for each RegistryKey object r1, r2 and r3.

r1 is the RegistryKey object which allows you to manipulate Windows Explorer any which way you like. r1 provides access to a Registry key whose values affect Start Menu, Taskbar, Control Panel and My Computer. For example, setting NoClose value to 1 disables the Turn Off button on the Start Menu, NoFind disables the Search button and NoRun disables the Run button. The NoDrives and NoViewOnDrive keys deserve a bit more explanation. NoViewOnDrive makes drives disappear from My Computer, but the drives will be accessible elsewhere. NoDrives blocks access to the drives completely. The value passed to these keys determines the number and letters of drives affecte. Understand from this:
00000001 => 1 means only A: drive is affected.
00000011 => 3 means both A: and B: drives are affected.
00010100 => 20 means C: and E: drives are affected.
11111111 => 255 means all drives are affected.

r2 is a relatively less significant RegistryKey object which prevents the Task Manager from appearing when Ctrl-Alt-Del is pressed.

r3 is the RegistryKey object which allows you to customize Internet Explorer as per your requirements. The subkeys and their values set in the code are fairly self-explanatory. Some of them like InPrivate Browsing work only for IE 8.
After executing this code, if you want to review the changes in the Registry after running the code, comment out the NoRun line so that you can open the Registry and undo the changes - However, as I have unfortunately discovered, not all changes can be undone, that's the reason why you are ADVISED to run this code on a dummy empty Administrator account!

3.10.09

Get Web browser history in C#

In my final year .NET project, I had to code up a module to obtain the visited URL history of at least one web browser and delete some or all of the URLs from the history. A seemingly impossible job at first, I eventually managed to write (or rather get) some neat C# code for the purpose. Here is the outcome of some very good research.

  1. Internet Explorer

  2. This was the easiest browser whose URL history can be obtained and deleted at will. My research started off with a Registry discovery - URLs typed in the address box of IE are captured in the Registry key HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\TypedURLs. But that was way short of the purpose. Then, I came across the COM interface IUrlHistory on MSDN. But it was COM and writing a C# class wrapper or something was something I was not proficient in at all. So, I reluctantly began searching for ready code. And voila!

    An article on CodeProject was all it took to serve my purpose. It provides a UrlHistoryLibrary.dll file which provides type-safe classes to access and manipulate IE's browsing history. Details on how to use the classes are given in the article itself. However, this is how I used it.




    1. public class InternetExplorer
    2. {
    3. // List of URL objects
    4. public List<URL> URLs { get; set; }
    5. public IEnumerable<URL> GetHistory()
    6. {
    7. // Initiate main object
    8. UrlHistoryWrapperClass urlhistory = new UrlHistoryWrapperClass();

    9. // Enumerate URLs in History
    10. UrlHistoryWrapperClass.STATURLEnumerator enumerator =
    11. urlhistory.GetEnumerator();

    12. // Iterate through the enumeration
    13. while (enumerator.MoveNext())
    14. {
    15. // Obtain URL and Title
    16. string url = enumerator.Current.URL.Replace('\'', ' ');
    17. // In the title, eliminate single quotes to avoid confusion
    18. string title = string.IsNullOrEmpty(enumerator.Current.Title)
    19. ? enumerator.Current.Title.Replace('\'', ' ') : "";

    20. // Create new entry
    21. URL U = new URL(url, title, "Internet Explorer");

    22. // Add entry to list
    23. URLs.Add(U);
    24. }

    25. // Optional
    26. enumerator.Reset();

    27. // Clear URL History
    28. urlhistory.ClearHistory();

    29. return URLs;
    30. }
    31. }




    Notes:
    The code is fairly self-explanatory except for a few clarifications. The URL class used above is a simple class which has three string fields - URL, Title and BrowserName - and URLs is a List<URL>. Those little string.Replace functions are to eliminate single quotes in the URLs so that there are no problems inserting them into an SQL database.

  3. Mozilla Firefox

  4. The same thing for Mozilla Firefox was way tougher. First of all, it was difficult to locate where Firefox stores the browsing history. The answer came in the form of an SQLite database which is stored in the Application Data of the Windows user. So, I had a SQLite database at hand. First, I tried FileStream to the .sqlite file. I had opened the file in Notepad++ and seen that URLs were interspersed with quirky characters, so using the FileStream, I could manage to obtain the URLs, but obtaining the Titles was impossible. Moreover, I was never sure that a URL I come across was ever visited or was it a bookmark or what. So, again some code-googling later, I came across the ADO.NET Data Provider for SQLite.The download page is here.

    What is wonderful about this Provider is that not only it provided a .NET-native namespace (System.Data.SQLite), but also it provides full Visual Studio 2008 design-time support. So, without wasting more time, let me provide you the code.




    1. public class Firefox
    2. {
    3. public List<URL> URLs { get; set; }
    4. public IEnumerable<URL> GetHistory()
    5. {
    6. // Get Current Users App Data
    7. string documentsFolder = Environment.GetFolderPath
    8. (Environment.SpecialFolder.ApplicationData);

    9. // Move to Firefox Data
    10. documentsFolder += "\\Mozilla\\Firefox\\Profiles\\";

    11. // Check if directory exists
    12. if (Directory.Exists(documentsFolder))
    13. {
    14. // Loop each Firefox Profile
    15. foreach (string folder in Directory.GetDirectories
    16. (documentsFolder))
    17. {
    18. // Fetch Profile History
    19. return ExtractUserHistory(folder);
    20. }
    21. }
    22. return null;
    23. }

    24. IEnumerable<URL> ExtractUserHistory(string folder)
    25. {
    26. // Get User history info
    27. DataTable historyDT = ExtractFromTable("moz_places", folder);

    28. // Get visit Time/Data info
    29. DataTable visitsDT = ExtractFromTable("moz_historyvisits",
    30. folder);

    31. // Loop each history entry
    32. foreach (DataRow row in historyDT.Rows)
    33. {
    34. // Select entry Date from visits
    35. var entryDate = (from dates in visitsDT.AsEnumerable()
    36. where dates["place_id"].ToString() == row["id"].ToString()
    37. select dates).LastOrDefault();
    38. // If history entry has date
    39. if (entryDate != null)
    40. {
    41. // Obtain URL and Title strings
    42. string url = row["Url"].ToString();
    43. string title = row["title"].ToString();

    44. // Create new Entry
    45. URL u = new URL(url.Replace('\'', ' '),
    46. title.Replace('\'', ' '),
    47. "Mozilla Firefox");

    48. // Add entry to list
    49. URLs.Add(u);
    50. }
    51. }
    52. // Clear URL History
    53. DeleteFromTable("moz_places", folder);
    54. DeleteFromTable("moz_historyvisits", folder);

    55. return URLs;
    56. }
    57. void DeleteFromTable(string table, string folder)
    58. {
    59. SQLiteConnection sql_con;
    60. SQLiteCommand sql_cmd;

    61. // FireFox database file
    62. string dbPath = folder + "\\places.sqlite";

    63. // If file exists
    64. if (File.Exists(dbPath))
    65. {
    66. // Data connection
    67. sql_con = new SQLiteConnection("Data Source=" + dbPath +
    68. ";Version=3;New=False;Compress=True;");

    69. // Open the Conn
    70. sql_con.Open();

    71. // Delete Query
    72. string CommandText = "delete from " + table;

    73. // Create command
    74. sql_cmd = new SQLiteCommand(CommandText, sql_con);

    75. sql_cmd.ExecuteNonQuery();

    76. // Clean up
    77. sql_con.Close();
    78. }
    79. }

    80. DataTable ExtractFromTable(string table, string folder)
    81. {
    82. SQLiteConnection sql_con;
    83. SQLiteCommand sql_cmd;
    84. SQLiteDataAdapter DB;
    85. DataTable DT = new DataTable();

    86. // FireFox database file
    87. string dbPath = folder + "\\places.sqlite";

    88. // If file exists
    89. if (File.Exists(dbPath))
    90. {
    91. // Data connection
    92. sql_con = new SQLiteConnection("Data Source=" + dbPath +
    93. ";Version=3;New=False;Compress=True;");

    94. // Open the Connection
    95. sql_con.Open();
    96. sql_cmd = sql_con.CreateCommand();

    97. // Select Query
    98. string CommandText = "select * from " + table;

    99. // Populate Data Table
    100. DB = new SQLiteDataAdapter(CommandText, sql_con);
    101. DB.Fill(DT);

    102. // Clean up
    103. sql_con.Close();
    104. }
    105. return DT;
    106. }
    107. }



    So, while some of this code was taken from the mozillazine forums, some was written on my own and the combination worked perfectly well for me in my final year project. Hope it works for you, too!