Windows registry PermissionError

Eryk Sun eryksun at gmail.com
Thu May 12 23:42:25 EDT 2022


On 5/12/22, Mike Dewhirst <miked at dewhirst.com.au> wrote:
>
>              access=wr.KEY_ALL_ACCESS + wr.KEY_WRITE,

The access parameter is a bit mask of access rights that combine via
bitwise OR (|), not via arithmetic addition.

KEY_ALL_ACCESS (0x000F_003F) is a superset of KEY_WRITE (0x0002_0006):

    KEY_WRITE = (
        READ_CONTROL           | # 0x0002_0000
        KEY_SET_VALUE          | # 0x0000_0002
        KEY_CREATE_SUB_KEY     | # 0x0000_0004
    )                            # 0x0002_0006

    KEY_ALL_ACCESS = (
        DELETE                 | # 0x0001_0000
        READ_CONTROL           | # 0x0002_0000
        WRITE_DAC              | # 0x0004_0000
        WRITE_OWNER            | # 0x0008_0000
        KEY_QUERY_VALUE        | # 0x0000_0001
        KEY_SET_VALUE          | # 0x0000_0002
        KEY_CREATE_SUB_KEY     | # 0x0000_0004
        KEY_ENUMERATE_SUB_KEYS | # 0x0000_0008
        KEY_NOTIFY             | # 0x0000_0010
        KEY_CREATE_LINK        | # 0x0000_0020
    )                            # 0x000F_003F

The result of the arithmetic addition `KEY_ALL_ACCESS + KEY_WRITE` is
0x0011_0045, which is wrong and meaningless. Registry key objects do
not support SYNCHRONIZE (0x0010_0000) access; DELETE (0x0001_0000)
access isn't needed; 0x0000_0040 is not a supported key right;
KEY_CREATE_SUB_KEY (0x0000_0004) access isn't needed; and
KEY_QUERY_VALUE (0x0000_0001) isn't sufficient.

You should limit the requested access to the specific access rights
that are required for querying and setting values in the key:

    access=(wr.KEY_QUERY_VALUE | wr.KEY_SET_VALUE)

>     def setvalue(self, vname, value):
>        return wr.SetValueEx(self.select(), vname, 0, 1, value)

You shouldn't hard code the value of the data type constant. Use
wr.REG_SZ instead of 1.

The return value of self.select() is a winreg PyHKEY object that wraps
the OS handle for the key object. You're relying on implicit closing
of this handle based on referencing counting. It's cleaner to use it
in a `with` statement, as you would for a file object returned by
open(). For example:

    with self.select() as hkey:
        wr.SetValueEx(hkey, vname, 0, wr.REG_SZ, value)

>      lmregistry = Registry(
>          hkey=wr.HKEY_LOCAL_MACHINE,
>          sub_key="SOFTWARE\WOW6432Node\XXX Technology\AppName",

You really shouldn't open the "WOW6432Node" key directly. It is an
implementation detail of the WOW64 subsystem that runs 32-bit
applications on a 64-bit system. If you need to operate on the
registry keys of 32-bit applications from a native 64-bit process,
open the normal path using the access right KEY_WOW64_32KEY
(0x0000_0200). For example:

    hkey = wr.HKEY_LOCAL_MACHINE
    subkey = r"SOFTWARE\XXX Technology\AppName"
    access = (
        wr.KEY_QUERY_VALUE |
        wr.KEY_SET_VALUE |
        wr.KEY_WOW64_32KEY
    )

Typically you'd first try opening the path without either
KEY_WOW64_32KEY or KEY_WOW64_64KEY. The default view matches the
current process.

https://docs.microsoft.com/en-us/windows/win32/winprog64/accessing-an-alternate-registry-view

Remember to escape the backslash separators in string literals of key
paths, or use raw string literals as I used in the above example.


More information about the Python-list mailing list