前言

在制作视频嗅探工具的时候是需要开启系统网络代理模式的,开启代理模式有两种方式,一种是手动开启,另一种可以通过程序来开启代理模式,windows上开启代理模式是通过修改注册表来实现了,今天就给大家介绍下python内置模块winreg来修改注册表。注册表这个东西大家可能都不是很熟悉,因为我们平时用到的少;但是它是Windows的核心,很多软件的启动和日志记录什么的都包含在里面,可以说它是一个大型的数据库也不为过,今天我们就来看看Python是如何操作注册表的吧。

认识注册表

进入系统注册表的方法多种多样,最常见的就是运行窗口输入命令“regedit”,即可进入注册表:

注册表

注册表中的几个菜单分别对应机器的根目录登陆的用户信息和本地机器信息以及用户信息和本地配置信息等。

python内置模块winreg

在Python中就有这么一个神奇的模块,它可以用来操作注册表。它就是-----"winreg",一个Python自带的操作注册表的模块。

导入winreg模块

import winreg

winreg常量

"winreg"总有很多有用的方法,基本上就是操作注册表中的键值,我们挑几个重要的来说说。首先我们来了解下"winreg"中的各个常量:

  1. HKEY_ 常量
winreg.HKEY_CLASSES_ROOT     #存储应用和shell的信息
winreg.HKEY_CURRENT_USER     #当前用户自定义的信息
winreg.HKEY_LOCAL_MACHINE    #计算机系统所有的信息
winreg.HKEY_USERS            #所有用户信息
winreg.HKEY_PERFORMANCE_DATA #性能数据
winreg.HKEY_CURRENT_CONFIG   #本地计算机系统的硬件配置文件
winreg.HKEY_DYN_DATA         #windows98后的版本无法使用
  1. 访问权限
winreg.KEY_ALL_ACCESS           #所有权限
winreg.KEY_WRITE                #可写
winreg.KEY_READ                 #可读
winreg.KEY_EXECUTE              #可执行相当于
KEY_READwinreg.KEY_QUERY_VALUE          #查询注册表键值
winreg.KEY_SET_VALUE            #创建、删除或设置一组注册表值
winreg.KEY_CREATE_SUB_KEY       #创建一个注册表子项的注册表键
winreg.KEY_ENUMERATE_SUB_KEYS   #枚举注册表子项所需的注册表键
winreg.KEY_NOTIFY               #修改注册表键时的提示
winreg.KEY_CREATE_LINK          #创建一个链接,预留给系统用
  1. 64位或32位系统具体应用
winreg.KEY_WOW64_64KEY  #在64位Windows应用程序应该运行在64位注册表视图
winreg.KEY_WOW64_32KEY  #在64位Windows应用程序应该运行在32位注册表视图
  1. 值类型
winreg.REG_BINARY                  #任何形式的二进制数据
winreg.REG_DWORD                   #32位的数
winreg.REG_DWORD_LITTLE_ENDIAN     #32位的数字在低位优先的格式,相当于
REG_DWORDwinreg.REG_DWORD_BIG_ENDIAN        #32位的数字在高位优先的格式winreg.REG_EXPAND_SZ               #以null结尾的字符串包含环境变量的引用(% %)
winreg.REG_LINK                    #Unicode符号链接
winreg.REG_MULTI_SZ                #一个以null结尾的字符串序列,由两个空字符结束
winreg.REG_NONE                    #没有定义的值类型
winreg.REG_QWORD                   #64位的数
winreg.REG_QWORD_LITTLE_ENDIAN         #在低位优先一个64位的数字格式,相当于REG_QWORD
winreg.REG_RESOURCE_LIST               #设备驱动器资源列表
winreg.REG_FULL_RESOURCE_DESCRIPTOR    #硬件设置
winreg.REG_RESOURCE_REQUIREMENTS_LIST  #硬件资源列表
winreg.REG_SZ                          #一个以null结尾的字符串

winreg相关操作

winreg远程操作计算机注册表

reg=winreg.ConnectRegistry('\\计算机名',winreg.HKEY_LOCAL_MACHINE)#返回值是所开打键的句柄
#第一个参数是指远程计算机名,第二个参数是指注册表中的键,如HKEY_LOCAL_MACHINE,它是winreg中的常量。

不过我们在这里要注意的是,如果远程注册表没有系统管理员权限,是无法正常访问注册表的。所以我们先要判断下它的访问权限。这里就要用到我们之前讲的"ctypes"模块中的判断用户是否是管理员用户的方法了。

import ctypes
import sys
def admin():
    aa=ctypes.windll.shell32.IsUserAnAdmin()
    return aa
if admin()==1: #有管理员权限可打开远程注册表
    winreg.ConnectRegistry('\\计算机名',winreg.HKEY_LOCAL_MACHINE)
else:
    if sys.version_info[0]==3: #python版本是3以上的版本
        ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
    else: #python2 版本
        ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)

winreg关闭连接注册表

连接之后我们不想用了,就要随手把它给关闭了,也很简单,只要拿到打开注册表的句柄,就可以关闭了。

winreg.CloseKey(reg)

图片

可以看到句柄的值不一样。

其实还有一种方法,就是利用注册处理对象的方法来关闭。

reg.Close()

注册对象还支持上下文和分离处理对象周期:

reg.detach() #返回一个整数,记录当前对象的生命周期,如果关闭注册句柄对象,那么则为0

winreg打开注册表键

#打开指定的键,返回一个处理对象
winreg.OpenKey(key, sub_key, reserved=0, access=winreg.KEY_READ)
winreg.OpenKeyEx(key, sub_key, reserved=0, access=winreg.KEY_READ)
#key:HKEY_ 常量
#sub_key:指定键的子键
#reserved:一个保留的证书,必须是零。默认值为零
#access:访问权限

winreg创建新的注册表键

winreg.CreateKey(key,sub_key)
winreg.CreateKeyEx(key,sub_key,reserved=0,access=winreg.KEY_WRITE)
#key:HKEY_ 常量
#sub_key:指定键的子键
#reserved:一个保留的证书,必须是零。默认值为零
#access:访问权限

图片

winreg删除注册表中指定的键

winreg.DeleteKey( key,sub_key) #不能删除带有子项的键
winreg.DeleteKeyEx(key,sub_key,reserved=0,access=winreg.KEY_WOW64_64KEY)#不能删除带有子项的键
winreg.DeleteValue(key, value)#从某个注册键中删除一个命名值项
#用法与上面相同,只是结果是删除罢了

图片

可以看到”cnm“已经被删除了。如果键不存在,删除会报错。

winreg枚举注册表键

winreg.EnumKey(key,index) #枚举打开的注册表键的子键,并返回一个字符串
winreg.EnumValue(key,index)#枚举打开的注册表键值,并返回一个元组
#index:一个整数,用于标识所获取键的索引

图片

winreg刷新注册表键

winreg.FlushKey(key)  #同步某个键的所有属性写入注册表

winreg读取注册表

winreg.LoadKey(key,sub_key,file_name)#file_name:读取注册表的数据的文件名

winreg查找注册表键

winreg.QueryInfoKey(key) #返回一个3元素元组的键的信息
winreg.QueryValue(key,sub_key) #用一个字符串来检索一个键的值
winreg.QueryValueEx(key,value_name) #检索与开放权限的注册表键相关联的指定值的数据类型和名称

图片

winreg 保存注册表键

winreg.SaveKey(key, file_name) #保存指定的键和所有指定文件的注册表子项

winreg启用禁用注册表

winreg.DisableReflectionKey(key) #禁用
winreg.EnableReflectionKey(key)  #启用

winreg 反射状态是否禁用

winreg.QueryReflectionKey(key) #结果为True 则表示禁用

winreg在指定键上关联值

winreg.SetValue(key, sub_key, type, value) #添加键和值
winreg.SetValueEx(key,value_name,reserved,type,value)#将数据存储在一个开放的注册表键值字段
#value_name:该字符串名称的注册表子键
#type:值类型
#value:子键的键值

图片

图片

可以看出它们的区别,而且前者值类型只能指定为“winreg.REG_SZ”,而后者什么类型都可以。

winreg 寻找应用程序的位置并打开

前面我们介绍了"winreg"几乎所有的方法,现在我们就来具体做一个应用练练手,就拿我们的360安全卫士为例,我们尝试着通过注册表先找到它的位置然后打开它。那么接下来小编开始表演了:

1).定位360安全卫士的注册表项:

1)).打开系统注册表编辑器,然后进行搜索关键字:

图片

2)).定位到注册表路径

图片

2).打开注册表键

通过我们找到的子键然后对其进行查找操作,得到处理对象的句柄“reg”

reg=winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\360安全卫士")

3).找到应用的绝对路径并打印

通过数值名称找到数值数据,

path=winreg.QueryValueEx(reg,'DisplayIcon')

这样就找到了这个应用的绝对路径了,返回值是一个元祖,我们使用索引访问:

path[0]

图片

可以看到我们已经成功打印出了我们要找的应用程序的绝对路径了,接下来就可以愉快的打开它了。打开的方法多种多样,什么“os”,“subprocess”,"ctypes","pywin32",一大堆的方法,不过小编还是觉得“os”最方便。

os.popen(path[0])

图片

最后别忘了关闭对象处理句柄哦。

#两种方法都可以关闭
winreg.CloseKey(reg)
reg.Close()

winreg开启关闭系统网络代理模式案例

代码如下:

import winreg
import ctypes


KEY_ProxyEnable = "ProxyEnable"
KEY_ProxyServer = "ProxyServer"
KEY_ProxyOverride = "ProxyOverride"
KEY_XPATH = "Software\Microsoft\Windows\CurrentVersion\Internet Settings"

#设置刷新
internet_option_refresh = 37
internet_option_settings_changed = 39

def win_start_proxy(proxyIp, ignore_ip = '*<-loopback>'):
    try:
        hKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, KEY_XPATH, 0, winreg.KEY_ALL_ACCESS)
        winreg.SetValueEx(hKey, KEY_ProxyEnable, 0, winreg.REG_DWORD, 1)
        winreg.SetValueEx(hKey, KEY_ProxyServer, 0, winreg.REG_SZ, proxyIp)
        winreg.SetValueEx(hKey, KEY_ProxyOverride, 0, winreg.REG_SZ, ignore_ip)
        winreg.CloseKey(hKey)
        hKey.Close()
    except Exception as e:
        print(e)
    #刷新
    internet_set_option = ctypes.windll.Wininet.InternetSetOptionW
    internet_set_option(0, internet_option_refresh, 0, 0)
    internet_set_option(0, internet_option_settings_changed, 0, 0)
    print('开启系统代理模式:', proxyIp)
    print('当前嗅探模式状态:', win_proxy_status())

def win_disable_proxy():
    try:
        hKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, KEY_XPATH, 0, winreg.KEY_ALL_ACCESS)
        winreg.SetValueEx(hKey, KEY_ProxyEnable, 0, winreg.REG_DWORD, 0)
        winreg.SetValueEx(hKey, KEY_ProxyServer, 0, winreg.REG_SZ, '')
        winreg.SetValueEx(hKey, KEY_ProxyOverride, 0, winreg.REG_SZ, '')
        winreg.CloseKey(hKey)
        hKey.Close()
    except Exception as e:
        print(e)
    #刷新
    internet_set_option = ctypes.windll.Wininet.InternetSetOptionW
    internet_set_option(0, internet_option_refresh, 0, 0)
    internet_set_option(0, internet_option_settings_changed, 0, 0)
    print('关闭代理模式')
    print('当前嗅探模式状态:', win_proxy_status())

def win_set_proxy_override(ignore_ip = '<-loopback>'):
    '''
    设置系统忽略代理地址
    '''
    try:
        hKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, KEY_XPATH, 0, winreg.KEY_ALL_ACCESS)
        winreg.SetValueEx(hKey, KEY_ProxyOverride, 0, winreg.REG_SZ, ignore_ip)
        winreg.CloseKey(hKey)
        hKey.Close()
    except Exception as e:
        print(e)

# 获取当前代理状态
def win_proxy_status():
    hKey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, KEY_XPATH, 0, winreg.KEY_READ)
    retVal = winreg.QueryValueEx(hKey, KEY_ProxyEnable)
    winreg.CloseKey(hKey)
    hKey.Close()
    return int(retVal[0])==1



if __name__ == "__main__":

    if win_proxy_status():
        win_disable_proxy()
        print('关闭代理')
    else:
        win_start_proxy('127.0.0.1:8000')
        print('打开代理')

    print(win_proxy_status())

总结

winreg提供了比较完善的操作windows注册表的相关接口,通过winreg基本上都可以实现你想要的操作。