目录
2.2 python类体系:一切皆对象,对象的访问可通过“可见+拥有”分析
1、缘起
前几天,我有一个设想,想用C语言写出一系列底层访问(获取与操作)WIFI的具体实现,然后封装成库引入到python中来,从技能上完成python和C/C++的连通。设想的施行条件VS2007、SDK、libcap、windump、python我都准备好(N,N,N年前就用过),不过还是在施行前从网上查了一下python操作WIFI现状,发现有个python库ctypes可以直接操作WINAPI,还发现有个pywifi包可以直接使用,于是就先深入一把ctypes,并pip install pywifi,看看这个包怎么样。(除pywifi外当然还有其他有意思的包)。
奔跑吧,兄弟:
pywifi 2020-05-22 15:30:47,918 INFO Get interface: Qualcomm Atheros AR956x Wireless Network Adapter
pywifi 2020-05-22 15:30:47,920 INFO iface 'Qualcomm Atheros AR956x Wireless Network Adapter' scans
pywifi 2020-05-22 15:30:52,935 INFO Scan found 11 networks.
pywifi 2020-05-22 15:30:52,942 INFO ---------------------------------->strProfileName: DXG3F
pywifi 2020-05-22 15:30:52,944 INFO dot11Ssid: DXG3F
pywifi 2020-05-22 15:30:52,947 INFO dot11BssType: dot11_BSS_type_infrastructure
pywifi 2020-05-22 15:30:52,950 INFO uNumberOfBssids: 1
pywifi 2020-05-22 15:30:52,952 INFO Bssids: ['78:eb:14:d4:09:06']
pywifi 2020-05-22 15:30:52,955 INFO sigFre: [(-47, 2472000)]
pywifi 2020-05-22 15:30:52,957 INFO bNetworkConnectable: True
pywifi 2020-05-22 15:30:52,961 INFO wlanNotConnectableReason(if TRUE): 操作成功。
pywifi 2020-05-22 15:30:52,963 INFO uNumberOfPhyTypes: 1
pywifi 2020-05-22 15:30:52,964 INFO dot11PhyTypes:
pywifi 2020-05-22 15:30:52,965 INFO dot11_phy_type_ht
pywifi 2020-05-22 15:30:52,967 INFO bMorePhyTypes: False
pywifi 2020-05-22 15:30:52,968 INFO wlanSignalQuality (-100,-50)-->(0,100): 100
pywifi 2020-05-22 15:30:52,969 INFO bSecurityEnabled: True
pywifi 2020-05-22 15:30:52,971 INFO dot11DefaultAuthAlgorithm: DOT11_AUTH_ALGO_RSNA_PSK
pywifi 2020-05-22 15:30:52,972 INFO dot11DefaultCipherAlgorithm: DOT11_CIPHER_ALGO_CCMP
pywifi 2020-05-22 15:30:52,975 INFO dwFlags: 6
pywifi 2020-05-22 15:30:52,975 INFO dwReserved: 0
pywifi 2020-05-22 15:30:53,074 INFO ---------------------------------->strProfileName: CPS_Hotel
pywifi 2020-05-22 15:30:53,076 INFO dot11Ssid: CPS_Hotel
pywifi 2020-05-22 15:30:53,078 INFO dot11BssType: dot11_BSS_type_infrastructure
pywifi 2020-05-22 15:30:53,080 INFO uNumberOfBssids: 6
pywifi 2020-05-22 15:30:53,084 INFO Bssids: ['00:1b:2f:ae:77:e5', 'c0:3f:0e:82:7f:3e', '00:18:4d:2b:c3:82', 'c0:3f:0e:82:7f:37', '00:24:b2:61:84:0f', '84:1b:5e:7b:b3:90']
pywifi 2020-05-22 15:30:53,086 INFO sigFre: [(-91, 2412000), (-90, 2437000), (-85, 2437000), (-91, 2462000), (-90, 2422000), (-92, 2462000)]
pywifi 2020-05-22 15:30:53,088 INFO bNetworkConnectable: True
pywifi 2020-05-22 15:30:53,091 INFO wlanNotConnectableReason(if TRUE): 操作成功。
pywifi 2020-05-22 15:30:53,094 INFO uNumberOfPhyTypes: 2
pywifi 2020-05-22 15:30:53,096 INFO dot11PhyTypes:
pywifi 2020-05-22 15:30:53,099 INFO dot11_phy_type_erp
pywifi 2020-05-22 15:30:53,101 INFO dot11_phy_type_ht
pywifi 2020-05-22 15:30:53,103 INFO bMorePhyTypes: False
pywifi 2020-05-22 15:30:53,107 INFO wlanSignalQuality (-100,-50)-->(0,100): 30
pywifi 2020-05-22 15:30:53,109 INFO bSecurityEnabled: True
pywifi 2020-05-22 15:30:53,111 INFO dot11DefaultAuthAlgorithm: DOT11_AUTH_ALGO_RSNA_PSK
pywifi 2020-05-22 15:30:53,113 INFO dot11DefaultCipherAlgorithm: DOT11_CIPHER_ALGO_CCMP
pywifi 2020-05-22 15:30:53,115 INFO dwFlags: 0
pywifi 2020-05-22 15:30:53,118 INFO dwReserved: 0
pywifi 2020-05-22 15:30:53,252 INFO ---------------------------------->strProfileName: HUAWEI-421
pywifi 2020-05-22 15:30:53,254 INFO dot11Ssid: HUAWEI-421
pywifi 2020-05-22 15:30:53,257 INFO dot11BssType: dot11_BSS_type_infrastructure
pywifi 2020-05-22 15:30:53,259 INFO uNumberOfBssids: 1
pywifi 2020-05-22 15:30:53,261 INFO Bssids: ['b0:89:00:09:56:fc']
pywifi 2020-05-22 15:30:53,263 INFO sigFre: [(-86, 2462000)]
pywifi 2020-05-22 15:30:53,266 INFO bNetworkConnectable: True
pywifi 2020-05-22 15:30:53,269 INFO wlanNotConnectableReason(if TRUE): 操作成功。
pywifi 2020-05-22 15:30:53,271 INFO uNumberOfPhyTypes: 1
pywifi 2020-05-22 15:30:53,274 INFO dot11PhyTypes:
pywifi 2020-05-22 15:30:53,278 INFO dot11_phy_type_ht
pywifi 2020-05-22 15:30:53,281 INFO bMorePhyTypes: False
pywifi 2020-05-22 15:30:53,283 INFO wlanSignalQuality (-100,-50)-->(0,100): 28
pywifi 2020-05-22 15:30:53,286 INFO bSecurityEnabled: True
pywifi 2020-05-22 15:30:53,289 INFO dot11DefaultAuthAlgorithm: DOT11_AUTH_ALGO_RSNA_PSK
pywifi 2020-05-22 15:30:53,291 INFO dot11DefaultCipherAlgorithm: DOT11_CIPHER_ALGO_CCMP
pywifi 2020-05-22 15:30:53,293 INFO dwFlags: 0
pywifi 2020-05-22 15:30:53,295 INFO dwReserved: 0
pywifi 2020-05-22 15:30:53,298 INFO ---------------------------------->strProfileName: DXG3F
pywifi 2020-05-22 15:30:53,301 INFO dot11Ssid: DXG3F
pywifi 2020-05-22 15:30:53,303 INFO dot11BssType: dot11_BSS_type_infrastructure
pywifi 2020-05-22 15:30:53,305 INFO uNumberOfBssids: 1
pywifi 2020-05-22 15:30:53,308 INFO Bssids: ['78:eb:14:d4:09:06']
pywifi 2020-05-22 15:30:53,310 INFO sigFre: [(-47, 2472000)]
pywifi 2020-05-22 15:30:53,313 INFO bNetworkConnectable: True
pywifi 2020-05-22 15:30:53,316 INFO wlanNotConnectableReason(if TRUE): 操作成功。
pywifi 2020-05-22 15:30:53,318 INFO uNumberOfPhyTypes: 1
pywifi 2020-05-22 15:30:53,320 INFO dot11PhyTypes:
pywifi 2020-05-22 15:30:53,322 INFO dot11_phy_type_ht
pywifi 2020-05-22 15:30:53,325 INFO bMorePhyTypes: False
pywifi 2020-05-22 15:30:53,328 INFO wlanSignalQuality (-100,-50)-->(0,100): 100
pywifi 2020-05-22 15:30:53,330 INFO bSecurityEnabled: True
pywifi 2020-05-22 15:30:53,332 INFO dot11DefaultAuthAlgorithm: DOT11_AUTH_ALGO_RSNA_PSK
pywifi 2020-05-22 15:30:53,334 INFO dot11DefaultCipherAlgorithm: DOT11_CIPHER_ALGO_CCMP
pywifi 2020-05-22 15:30:53,337 INFO dwFlags: 0
pywifi 2020-05-22 15:30:53,340 INFO dwReserved: 0
pywifi 2020-05-22 15:30:53,343 INFO ---------------------------------->strProfileName: ChinaNet-2.4G-439
pywifi 2020-05-22 15:30:53,345 INFO dot11Ssid: ChinaNet-2.4G-439
pywifi 2020-05-22 15:30:53,347 INFO dot11BssType: dot11_BSS_type_infrastructure
pywifi 2020-05-22 15:30:53,350 INFO uNumberOfBssids: 1
pywifi 2020-05-22 15:30:53,352 INFO Bssids: ['b0:ac:d2:0a:2e:12']
pywifi 2020-05-22 15:30:53,354 INFO sigFre: [(-91, 2427000)]
pywifi 2020-05-22 15:30:53,357 INFO bNetworkConnectable: True
pywifi 2020-05-22 15:30:53,360 INFO wlanNotConnectableReason(if TRUE): 操作成功。
pywifi 2020-05-22 15:30:53,363 INFO uNumberOfPhyTypes: 1
pywifi 2020-05-22 15:30:53,365 INFO dot11PhyTypes:
pywifi 2020-05-22 15:30:53,367 INFO dot11_phy_type_ht
pywifi 2020-05-22 15:30:53,369 INFO bMorePhyTypes: False
pywifi 2020-05-22 15:30:53,372 INFO wlanSignalQuality (-100,-50)-->(0,100): 12
pywifi 2020-05-22 15:30:53,375 INFO bSecurityEnabled: True
pywifi 2020-05-22 15:30:53,378 INFO dot11DefaultAuthAlgorithm: DOT11_AUTH_ALGO_RSNA_PSK
pywifi 2020-05-22 15:30:53,380 INFO dot11DefaultCipherAlgorithm: DOT11_CIPHER_ALGO_CCMP
pywifi 2020-05-22 15:30:53,383 INFO dwFlags: 0
pywifi 2020-05-22 15:30:53,385 INFO dwReserved: 0
pywifi 2020-05-22 15:30:53,389 INFO ---------------------------------->strProfileName: A Hide Network
pywifi 2020-05-22 15:30:53,391 INFO dot11Ssid: A Hide Network
pywifi 2020-05-22 15:30:53,393 INFO dot11BssType: dot11_BSS_type_infrastructure
pywifi 2020-05-22 15:30:53,395 INFO uNumberOfBssids: 1
pywifi 2020-05-22 15:30:53,398 INFO Bssids: ['80:3f:5d:5e:24:e3']
pywifi 2020-05-22 15:30:53,401 INFO sigFre: [(-95, 2457000)]
pywifi 2020-05-22 15:30:53,403 INFO bNetworkConnectable: True
pywifi 2020-05-22 15:30:53,406 INFO wlanNotConnectableReason(if TRUE): 操作成功。
pywifi 2020-05-22 15:30:53,408 INFO uNumberOfPhyTypes: 1
pywifi 2020-05-22 15:30:53,411 INFO dot11PhyTypes:
pywifi 2020-05-22 15:30:53,414 INFO dot11_phy_type_ht
pywifi 2020-05-22 15:30:53,417 INFO bMorePhyTypes: False
pywifi 2020-05-22 15:30:53,419 INFO wlanSignalQuality (-100,-50)-->(0,100): 4
pywifi 2020-05-22 15:30:53,423 INFO bSecurityEnabled: True
pywifi 2020-05-22 15:30:53,426 INFO dot11DefaultAuthAlgorithm: DOT11_AUTH_ALGO_RSNA_PSK
pywifi 2020-05-22 15:30:53,428 INFO dot11DefaultCipherAlgorithm: DOT11_CIPHER_ALGO_CCMP
pywifi 2020-05-22 15:30:53,431 INFO dwFlags: 0
pywifi 2020-05-22 15:30:53,433 INFO dwReserved: 0
…
很容易了解到本机WIFI基本状态,以上面列出的最后显示的“A Hide Network ”为例。这是一个隐藏的WIFI网络,即电脑或手机上无法显示WIFI名称的那种,“A Hide Network”是我为了查询的需要而在日志输出语句中加的名称。网络类型是普通WIFI网络(区别于ad-hoc网络),网络中只有一个无线接入点(有可能是无线路由器、手机WIFI、电脑WIFI等),MAC为80:3f:5d:5e:24:e3,信号较弱,2.4G频段;接入点的WIFI物理组件使用802.11n协议,有安全机制,认证采用提前共享密钥的RSNA算法而加密的是CCMP算法,可被其他设备连接(因为是隐藏网络,所以要手动连接)。
别问我是怎么分析地这么头头是道,绝对属于我的是分析,而分析的内容有些是临时查WIN32 API、看无线网络安全基础、以及对一些关键词查字典式地查出的。
同时,也用Qtdesigner做了一个界面(只是引入UI,还没有加入wifi操作代码):
class MainGUI(QtWidgets.QMainWindow,Ui_MainWindow):
def __init__(self, parent = None, flags = Qt.WindowFlags()):
super().__init__(parent, flags)
self.setupUi(self)
def WiFipreconnect(self):pass
def WiFiscan(self,INobj):pass
def WiFiconnect(self,INobj):pass
if __name__=="__main__":
app=QtWidgets.QApplication(sys.argv)
window=MainGUI()
window.show()
try:
sys.exit(app.exec_())
except: pass
如果你也用过pywifi,可能会奇怪之前列出的wifi数据,原程序输出不是这样的,那是因为我已经做了我想要的改动。
在看代码期间,发现一个有趣的问题,原来代码:
片段一:
class Interface:
"""Interface provides methods for manipulating wifi devices."""
"""
For encapsulating OS dependent behavior, we declare _raw_obj here for
storing some common attribute (e.g. name) and os attributes (e.g. dbus
objects for linux)
"""
_raw_obj = {}
_wifi_ctrl = {}
_logger = None
def __init__(self, raw_obj):
self._raw_obj = raw_obj
self._wifi_ctrl = wifiutil.WifiUtil()
self._logger = logging.getLogger('pywifi')
片段二:
class PyWiFi:
"""PyWiFi provides operations to manipulate wifi devices."""
_ifaces = []
_logger = None
def __init__(self):
self._logger = logging.getLogger('pywifi')
def interfaces(self):
"""Collect the available wlan interfaces."""
self._ifaces = []
wifi_ctrl = wifiutil.WifiUtil()
for interface in wifi_ctrl.interfaces():
iface = Interface(interface)
self._ifaces.append(iface)
self._logger.info("Get interface: %s", iface.name())
if not self._ifaces:
self._logger.error("Can't get wifi interface")
return self._ifaces
我不知道pywifi包的发布者本来用意,但很明显,这两个片段都存在类属性与实例属性的设计矛盾。这实际上很容易发现。
这样的矛盾在现有pywifi包的设计架构上,或者说在几百行以内的python代码中不会导致什么很大的漏洞。如果要基于pywifi做进一步开发,则要警惕。
2、群中的一次讨论
2.1 类与子类
2.1.1 从现象说起1:属性成员
与这个设计缺陷相对应的,是那天在群里的一个讨论。讨论的内容简要还原如下(我用的是python 3.6.5):
>>> class parent:
_d={}
def __init__(self):
self._d['a']=0
self._d['b']=0
self._d['c']=0
>>> class A(parent):
def init(self):
self._d['a']=1
self._d['b']=1
self._d['c']=1
>>> class B(parent):
def init(self):
self._d['a']=2
self._d['b']=2
self._d['c']=2
>>> a=A()
>>> b=B()
>>> a.init()
>>> l=[b,a]
>>> for i in l:print(i._d)
{'a': 1, 'b': 1, 'c': 1}
{'a': 1, 'b': 1, 'c': 1}
有群友提问,为什么输出结果都一样?
原因很简单:子类实例对象a和b所谓“继承”来的_d实际上是同一个“外部”(不拥有但可见可访问)对象。
请仔细观察下面经我粗暴标示的属性和方法:
>>> A.__dict__
mappingproxy({'__module__': '__main__', 'init': <function A.init at 0x0000024BF7073D08>, '__doc__': None})
>>> dir(A)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_d', 'init']
>>> a.__dict__
{}
>>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_d', 'init'