Registry access exception problem - c#

I'm currently building a registry explorer, mostly because I want to support some much better searching operations. Like 'find all' and regular expressions. One problem I'm facing is that some keys throw a security exception when opening. I HAVE TRIED running the app with administrator priviledges, my user account is an administrator also. I embedded a manifest with "requireAdministrator" requested priviledges. I have also tried setting the ClickOnce security settings to Full trust, which is incompatible with requireAdministrator, or so Visual Studio tells me.... Nothing seems to help with avoiding this exception.
I would just like to iterate over all of the keys. I do not wish to add/delete keys. If a user wishes to delete a key and does not have permission to do so, it would display an error message. I just want to be able to have unrestricted READ access. Is this possible?
FTR: I'm on Win7 x64 and using Vs2010u and project is written in C# on .net 4.0. If regedit is capable of reading all keys even if it doesn't let you edit some of them. It would seem appropriate that we too can make an app to do the same thing. Though I'm finding it very difficult, and there doesn't seem to be any real help on the www. Only link-link circles, yay.
[EDIT]
Here's the code that reads the keys:
private void IterateSubKeys(RegistryKeyModel key) {
var subKeys = key.Key.GetSubKeyNames();
var values = key.Key.GetValueNames();
foreach (var valuename in values) {
try {
var valueKind = key.Key.GetValueKind(valuename);
var value = key.Key.GetValue(valuename);
key.Values.Add(new RegistryValueModel(valuename, value, valueKind));
}
catch { }
}
foreach (var keyname in subKeys) {
try {
var subkey = key.Key.OpenSubKey(
keyname,
RegistryKeyPermissionCheck.ReadSubTree,
RegistryRights.ReadKey);
key.SubKeys.Add(new RegistryKeyModel(subkey));
}
catch { Console.WriteLine("Error reading key: {0}", keyname); }
}
}

This is by design. There are lots of security related keys that can only accessible to the System account. You can't use that account. Regedit can't read these keys either, they are just not visible. Avoiding the expensive exception is going to require pinvoke.

Related

C# WPF - Registry Access not Allowed, even with Administrator Privileges?

I've recently been working on a very nice Registry Editor.
However, certain Registry keys, pointed out below in Regedit, will not show up in my program, as they raise an error of insufficient privileges when opened, and so are caught by error handling and skipped:
Regedit:
My program:
As you can see, the SECURITY key is missing, and the SAM key is not expandable, even though I am running the program with administrator privileges.
This can obviously be fixed by making fake keys and putting them there, and just displaying an empty default value for them, however that isn't a concrete solution, just a way to make it seem to the user as if the issue is solved.
I was wondering if there is a way to fix the issue in a concrete way, or in other words, to receive registry access to those keys?
All they display is an empty default value any way, including the expandable SAM key - it just has a subkey named 'SAM' with an empty default value as well.
However, to the user, it's much better if the program displays exactly as in Regedit, as it means that it's a fully functional piece of software.
Thanks for the help.
Edit (code included):
public static void TreeViewItemExpanded(TreeViewItem sender)
{
if (sender.Items[0] is string)
{
sender.Items.Clear();
RegistryKey expandedKey = (RegistryKey)sender.Tag;
foreach (string key in expandedKey.GetSubKeyNames().OrderBy(x => x)) try { sender.Items.Add(CreateTreeViewItem(expandedKey.OpenSubKey(key))); } catch { }
}
}
private static TreeViewItem CreateTreeViewItem(RegistryKey key)
{
TreeViewItem treeViewItem = new TreeViewItem() { Header = new RegistryEditor_RegistryStructure_TreeView() { Name = Path.GetFileName(key.ToString()) }, Tag = key };
try { if (key.SubKeyCount > 0) treeViewItem.Items.Add("Loading..."); } catch { }
return treeViewItem;
}
You did not supply sample code to your routine, but I have a suspision that you are using a default registry security descriptor.
You can specify a security descriptor for a registry key when you call the RegCreateKeyEx or RegSetKeySecurity function.
When you call the RegOpenKeyEx function, the system checks the requested access rights against the key's security descriptor. If the user does not have the correct access to the registry key, the open operation fails. If an administrator needs access to the key, the solution is to enable the SE_TAKE_OWNERSHIP_NAME privilege and open the registry key with WRITE_OWNER access.
This information is taken from: MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878(v=vs.85).aspx
In C# You should be using the Registery Permission Class
https://msdn.microsoft.com/en-us/library/system.security.permissions.registrypermission(v=vs.110).aspx
A good example of how to handle Registry Permissions can be found here:
https://msdn.microsoft.com/en-us/library/microsoft.win32.registrykey.setaccesscontrol(v=vs.110).aspx
you need enable SE_RESTORE_PRIVILEGE and SE_BACKUP_PRIVILEGE and use RegOpenKeyEx or ZwOpenKeyEx with REG_OPTION_BACKUP_RESTORE flag (but this will be work only begin from Windows 7 and later versions of Windows)
If this flag is set, the function ignores the samDesired parameter and
attempts to open the key with the access required to backup or restore
the key. If the calling thread has the SE_BACKUP_NAME privilege
enabled, the key is opened with the ACCESS_SYSTEM_SECURITY and
KEY_READ access rights. If the calling thread has the SE_RESTORE_NAME
privilege enabled, beginning with Windows Vista, the key is opened
with the ACCESS_SYSTEM_SECURITY, DELETE and KEY_WRITE access rights.
If both privileges are enabled, the key has the combined access rights
for both privileges.
for example
#define LAA(se) {{se},SE_PRIVILEGE_ENABLED|SE_PRIVILEGE_ENABLED_BY_DEFAULT}
#define BEGIN_PRIVILEGES(tp, n) static const struct {ULONG PrivilegeCount;LUID_AND_ATTRIBUTES Privileges[n];} tp = {n,{
#define END_PRIVILEGES }};
ULONG AdjustBackupRestore()
{
HANDLE hToken;
if (OpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
BEGIN_PRIVILEGES(tp, 2)
LAA(SE_RESTORE_PRIVILEGE),
LAA(SE_BACKUP_PRIVILEGE),
END_PRIVILEGES
AdjustTokenPrivileges(hToken, FALSE, (::PTOKEN_PRIVILEGES)&tp, 0, 0, 0);
ULONG err = GetLastError();
CloseHandle(hToken);
return err;
}
return GetLastError();
}
if (!AdjustBackupRestore())//called once on startup
{
HKEY hKey;
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SECURITY\\SAM", REG_OPTION_BACKUP_RESTORE|REG_OPTION_OPEN_LINK, 0, &hKey))
{
RegCloseKey(hKey);
}
}
however for get full power for registry editor/viewer I be use native api

How do I programmatically give ownership of a Registry Key to Administrators?

I ran into a bizarre issue when I upgraded some machines to Windows 10 where incorrect permissions on RuntimeBroker caused problems. I found a solution online that recommended changing permissions (first in the registry, then in DCOM configuration), and I'm trying to write a small .NET application to automate the process.
Presently the owner of the relevant registry keys is NT SERVICE\TrustedInstaller and I'm trying to change it to COMPUTER\Administrators. I have a simple WPF application with the requestedExecutionLevel set to "requireAdministrator," but I'm still running into problems. Here's a snippet of code to illustrate the problem:
using System.Security.AccessControl;
using System.Security.Principal;
using Microsoft.Win32;
namespace PermissionFixer
{
public class Fixer
{
public void Fix()
{
var subKey = Registry.ClassesRoot.OpenSubKey(#"AppID\{9CA88EE3-ACB7-47c8-AFC4-AB702511C276}", true);
if (subKey != null)
{
var admins = new NTAccount("Administrators");
var ac = subKey.GetAccessControl();
ac.SetOwner(admins);
ac.AddAccessRule(new RegistryAccessRule(admins, RegistryRights.FullControl, AccessControlType.Allow));
subKey.SetAccessControl(ac);
}
}
}
}
The trouble is that it doesn't even get past the call to OpenSubKey() before hitting a SecurityException that says "Requested registry access is not allowed." I think that's because Administrators doesn't yet have the access (remember it belongs to TrustedInstaller), but it becomes a bit of a chicken and egg problem. The strange thing is that when I use regedit by hand I am allowed to change the owner to Administrators, and I'm pretty sure my instance of regedit is running as Administrators.
How can I get this working in .NET?
I figured it out, and fortunately it is possible to achieve with the .NET classes. Here is how you have to call OpenSubKey:
var subKey = Registry.ClassesRoot.OpenSubKey(#"AppID\{9CA88EE3-ACB7-47c8-AFC4-AB702511C276}", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.TakeOwnership);
Then you have to nix the call to AddAccessRule()... you can't modify that until you have ownership; and you have to do those two operations in serial. So take ownership first, then re-open the key with different access rights to add the access rule.
EDIT: I discovered today that you must first manipulate the token with which your application is running, by hooking into P/Invoke calls. I found a class called TokenManipulator referenced in another Stack Overflow question. Include that class in your project, and then grant Backup, Restore, and TakeOwnership privileges to your token before calling OpenSubKey. So your method will end up looking something like this:
try
{
TokenManipulator.AddPrivilege("SeRestorePrivilege");
TokenManipulator.AddPrivilege("SeBackupPrivilege");
TokenManipulator.AddPrivilege("SeTakeOwnershipPrivilege");
var subKey = Registry.ClassesRoot.OpenSubKey(#"AppID\{9CA88EE3-ACB7-47c8-AFC4-AB702511C276}", RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.TakeOwnership);
// code to change owner...
}
finally
{
TokenManipulator.RemovePrivilege("SeRestorePrivilege");
TokenManipulator.RemovePrivilege("SeBackupPrivilege");
TokenManipulator.RemovePrivilege("SeTakeOwnershipPrivilege");
}

System.DirectoryServices.AccountManagement.PrincipalContext broken after Windows 10 update

I've been using this little function without any issue for the past few years to validate user credentials. The createPrincipalContext method returns a PrincipalContext with ContextType.Machine and the machine name.
public static bool ValidateCredentials(string username, string password, string domain = null) {
try {
using (var principalContext = createPrincipalContext(username, domain)) {
username = GetLoginInfo(username).Username;
// validate the credentials
if (principalContext.ValidateCredentials(username, password)) {
//once valid check if account is enabled
using (UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, username)) {
return user.Enabled.GetValueOrDefault(false);
}
}
}
} catch (PrincipalOperationException e) {
traceError(e);
} catch (Exception e) {
traceError(e);
}
return false;
}
My development machine automatically updated to the latest version of Windows 10 this recently, and since then, principalContext.ValidateCredentials has been throwing the following exception.
System.IO.FileNotFoundException: The system cannot find the file specified.
Other than the machine update nothing else was changed. I've spend the last few days searching the net for what may have caused the issue.
Does anyone have any experience in identifying what may have been the cause and if possible, a solution?
One final Google before I started rolling back my machine to the previous build and I found this
https://connect.microsoft.com/IE/feedback/details/1904887/windows-10-insider-preview-build-10565
the problem is caused by missing registry entries in HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows NT\CurrentVersion, specifically: RegisteredOwner and RegisteredOrganization
EDIT:
Run the Registry Editor by pressing Windows R and typing regedit.exe. Browse to the location above
Just right click on the CurrentVersion in the Registry Editor and select New > String Value. After you add each entry ( RegisteredOwner and RegisteredOrganization ) edit their values. You can use your username and company name respectively.
Uncheck the Prefer 32-bit checkbox in your project's properties window under the Build tab, it is checked by default - see screenshot. This fixed it for me! Checking the checkbox again will cause the exceptions you describe to re-appear. I'm guessing this will force it to run in 64-bit mode if possible, and therefore use the 64-bit registry path rather than the WOW6432Node registry path and hence it will find the correct keys it needs.
Uncheck 'Prefer 32-bit' screenshot
Try change your build platform target to "AnyCPU", i found that if my platform target is x86, I have this issue!
Why, yet have no idea, seems like win 10 bug!!!

Permission For writing to LOCAL_MACHINE

I made an app that allows windows users to spoof Mac Address .
It works by adding "NetworkAdapter": "00ff00ff00ff" key/value pair to registry of the users selected nic.
The problem is that every time the app tries to make changes to windows registry Windows pop's up a warning dialog, e.g.:
but clicking continue will add the registry values successfully and the app functions normally.
What can i do/or add changes in my code to make the dialog box disappear or can i do it in a better way?
The app requires Admin Privileges
here's the git repo of the app
here's the method:
public void SetMac(string macAddress)
{
const string Name = #"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}";
using (RegistryKey key0 = Registry.LocalMachine.OpenSubKey(Name, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.FullControl))
{
string[] x = key0.GetSubKeyNames();
foreach (string name in x)
{
var var1 = Registry.LocalMachine.OpenSubKey(Name,RegistryKeyPermissionCheck.ReadWriteSubTree,RegistryRights.FullControl);
var v = var1.OpenSubKey(name, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.FullControl);
var z = v.GetValue("DriverDesc");
if (comboBox1.Text == z.ToString() )
{
v.SetValue("NetworkAddress",comboBox2.Text);
MessageBox.Show(z.ToString());
}
v.Close();
var1.Close();
}
key0.Close();
}
}
You need to run your app under elevated privileges, see Requested registry access is not allowed.
The problem here is that the user does not have permission to open the target key for writing. As abatishchev has already suggested, you need to run the application elevated so that the user actually has Administrators group membership when the code is executed.
The reason that this looks like a CAS permission error is a design flaw in the RegistryKey.OpenSubKey method. It ought to throw an UnauthorizedAccessException when the target key cannot be opened for writing due to inadequate user permissions, but it actually throws a SecurityException instead. The problem ends up appearing to be due to insuffience CAS permissions when it is really the user, not the code, that lacks permissions to edit the key.

Get value of registry key C#

I have already looked at existing topics, so please try to refrain from dropping links here.
I want to get the value of a registry key - plain and simple. Here is what I have so far.
Registry:
1) Made a key under
Current_User\Software\Custom_Subkey\Custom_Value\Custom_key\string_value
I am trying to find the string_value
string reg_subKey = "Software\\Custom_Subkey\\Custom_Value";
RegistryKey root = Registry.CurrentUser.CreateSubKey(reg_subKey);
foreach (string keyname in root.GetValueNames())
{
textBox4.AppendText(keyname.ToString() + Environment.NewLine);
// Appends the following data to textBox4 once the foreach is completed:
// Header1
// Header2
// Header3
// Header4
// Header5
// Now I want to get the VALUES of each header:
using (RegistryKey key = root.OpenSubKey(keyname))
{
**// THIS LINE GETS HIGHLIGHTED WITH THE FOLLOWING ERROR:
"Object reference not set to an instance of an object.**"
MessageBox.Show(key.ValueCount.ToString());
}
}
Hopefully this is a simple fix. I look forward to hearing your responses.
Thanks,
Evan
I believe you want root.GetSubKeyNames() in the loop not GetValueNames()
While values is working to get the values I would suggest the following loop:
foreach(string keyname in root.GetSubKeyNames())
{
// use key to get value and set textbox4
using (RegistryKey key = root.OpenSubKey(keyname))
{
MessageBox.Show(key.ValueCount.ToString());
}
}
The OpenSubKey method does not throw an exception if the specified subkey is not found. Instead, it simply returns null. It's your responsibility as a programmer to ensure that the appropriate key was found and opened by checking the return value of the method call.
Thus, my suspicion is that the registry key that you've specified is invalid. Open up Registry Editor (regedt32.exe), and verify that you can find the key in the registry exactly as written.
If you find that the registry key is indeed located exactly where you thought it was, then the problem may be related to the WOW64 subsystem, which allows 64-bit versions of Windows to run 64-bit apps. If the value was written to the registry by a 32-bit program, you won't be able to read it with the above code from a 64-bit program (or vice versa). The simplest way to check this is to change the compilation settings for your project. For example, if you're currently compiling for x86, then change to compiling for x64, or vice versa. Registry redirection may also be getting in your way; this will check for that as well.
I wanted the very same thing and your code helped me, but as you said, it didn't work properly. So, I made some modifications and I think it works fine now! Try this:
//Just make the reference until "custom_subkey", not to the next one ("custom value")
string reg_subKey = "Software\\Custom_Subkey";
RegistryKey root = Registry.CurrentUser.CreateSubKey(reg_subKey);
//Use GetSubKeyNames, instead of GetValueNames, because now you are in a higher level
foreach (string keyname in root.GetSubKeyNames())
{
using (RegistryKey key = root.OpenSubKey(keyname))
{
foreach (string valueName in key.GetValueNames())
{
MessageBox.Show(valueName);
MessageBox.Show(key.GetValue(valueName).ToString() );
}
}
}

Categories

Resources