From 44db92a8bfc33b6c48b5cb216e81096e2df67e52 Mon Sep 17 00:00:00 2001 From: Pierre LALET <pierre.lalet@cea.fr> Date: Fri, 22 Jan 2016 12:39:29 +0100 Subject: [PATCH] Factorize powershell-related code + introduce VBS fallback --- scapy/arch/windows/__init__.py | 151 +++++++++++++++++---------------- 1 file changed, 79 insertions(+), 72 deletions(-) diff --git a/scapy/arch/windows/__init__.py b/scapy/arch/windows/__init__.py index 9e48f749..eb26736f 100755 --- a/scapy/arch/windows/__init__.py +++ b/scapy/arch/windows/__init__.py @@ -7,9 +7,12 @@ Customizations needed to support Microsoft Windows. """ +from __future__ import with_statement import os,re,sys,socket,time, itertools import subprocess as sp from glob import glob +import tempfile + from scapy.config import conf,ConfClass from scapy.error import Scapy_Exception,log_loading,log_runtime from scapy.utils import atol, itom, inet_aton, inet_ntoa, PcapReader @@ -40,6 +43,55 @@ from scapy.arch.pcapdnet import * LOOPBACK_NAME="lo0" WINDOWS = True +def _exec_query_ps(cmd, fields): + """Execute a PowerShell query""" + ### XXX NOT TESTED AT ALL, WILL NOT WORK + ps = sp.Popen([conf.prog.powershell] + cmd + + ['|', 'select %s' % ', '.join(fields), '|', 'fl'], + stdout=sp.PIPE, + universal_newlines=True) + while True: + line = [ps.stdout.readline().split(':', 1)[1].strip() for _ in fields] + if not line[0]: + break + yield line + +def _exec_query_vbs(cmd, fields): + """Execute a query using VBS. Currently only Get-WmiObject queries + are supported. + + """ + assert len(cmd) == 2 and cmd[0] == "Get-WmiObject" + tmpfile = tempfile.NamedTemporaryFile(suffix=".vbs", delete=False) + tmpfile.write("""Set wmi = GetObject("winmgmts:") +Set lines = wmi.InstancesOf("%s") +For Each line in lines + %s +Next +""" % (cmd[1], "\n ".join("WScript.Echo line.%s" % fld for fld in fields))) + tmpfile.close() + ps = sp.Popen([conf.prog.cscript, tmpfile.name], + stdout=sp.PIPE, + universal_newlines=True) + for _ in xrange(3): + # skip 3 first lines + ps.stdout.readline() + while True: + line = [ps.stdout.readline().strip() for _ in fields] + if not line[0]: + break + yield line + os.unlink(tmpfile.name) + +def exec_query(cmd, fields): + """Execute a system query using PowerShell if it is available, and + using VBS/cscript as a fallback. + + """ + if conf.prog.powershell is None: + return _exec_query_vbs(cmd, fields) + return _exec_query_ps(cmd, fields) + def _where(filename, dirs=[], env="PATH"): """Find file in current dir or system path""" @@ -83,6 +135,8 @@ class WinProgPath(ConfClass): powershell = win_find_exe("powershell", installsubdir="System32\\WindowsPowerShell", env="SystemRoot") + cscript = win_find_exe("cscript", installsubdir="System32", + env="SystemRoot") conf.prog = WinProgPath() @@ -97,56 +151,26 @@ def is_interface_valid(iface): def get_windows_if_list(): if platform.release()=="post2008Server" or platform.release()=="8": # This works only starting from Windows 8/2012 and up. For older Windows another solution is needed - ps = sp.Popen([conf.prog.powershell, 'Get-NetAdapter', '|', 'select Name, InterfaceIndex, InterfaceDescription, InterfaceGuid, MacAddress', '|', 'fl'], stdout = sp.PIPE, universal_newlines = True) + query = exec_query(['Get-NetAdapter'], + ['Name', 'InterfaceIndex', 'InterfaceDescription', + 'InterfaceGuid', 'MacAddress']) else: - ps = sp.Popen([conf.prog.powershell, 'Get-WmiObject', 'Win32_NetworkAdapter', '|', 'select Name, InterfaceIndex, InterfaceDescription, GUID, MacAddress', '|', 'fl'], stdout = sp.PIPE, universal_newlines = True) - #no solution implemented for xp + query = exec_query(['Get-WmiObject', 'Win32_NetworkAdapter'], + ['Name', 'InterfaceIndex', 'InterfaceDescription', + 'GUID', 'MacAddress']) + return [ + iface for iface in + (dict(zip(['name', 'win_index', 'description', 'guid', 'mac'], line)) + for line in query) + if is_interface_valid(iface) + ] - stdout, stdin = ps.communicate() - current_interface = None - interface_list = [] - for i in stdout.split('\n'): - if not i.strip(): - continue - if i.find(':')<0: - continue - name, value = [ j.strip() for j in i.split(':',1) ] - if name == 'Name': - if current_interface and is_interface_valid(current_interface): - interface_list.append(current_interface) - current_interface = {} - current_interface['name'] = value - elif name == 'InterfaceIndex': - current_interface['win_index'] = int(value) - elif name == 'InterfaceDescription': - current_interface['description'] = value - elif name == 'InterfaceGuid': - current_interface['guid'] = value - elif name == 'GUID': - current_interface['guid'] = value - elif name == 'MacAddress': - current_interface['mac'] = ':'.join([ j for j in value.split('-')]) - if current_interface and is_interface_valid(current_interface): - interface_list.append(current_interface) - - return interface_list def get_ip_from_name(ifname, v6=False): - ps = sp.Popen([conf.prog.powershell, 'Get-WmiObject', 'Win32_NetworkAdapterConfiguration', '|', 'select Description, IPAddress', '|', 'fl'], stdout = sp.PIPE, universal_newlines = True) - stdout, stdin = ps.communicate() - selected=False - for i in stdout.split('\n'): - if not i.strip(): - continue - if i.find(':')<0: - continue - name, value = [ j.strip() for j in i.split(':',1) ] - if name=="Description" and value.strip()==ifname.strip(): - selected=True - elif selected: - if v6: - return value.split(",",1)[1].strip('{}').strip() - else: - return value.split(",",1)[0].strip('{}').strip() + for descr, ipadrr in exec_query(['Get-WmiObject', + 'Win32_NetworkAdapterConfiguration'], + ['Description', 'IPAddress']): + if descr == ifname.strip(): + return ipaddr.split(",", 1)[v6].strip('{}').strip() class NetworkInterface(object): """A network interface of your local host""" @@ -285,32 +309,14 @@ get_if_raw_hwaddr = pcapdnet.get_if_raw_hwaddr def read_routes_7(): routes=[] - ps = sp.Popen([conf.prog.powershell, 'Get-WmiObject', 'win32_IP4RouteTable', '|', 'select Name,Mask,NextHop,InterfaceIndex', '|', 'fl'], stdout = sp.PIPE, universal_newlines = True) - stdout, stdin = ps.communicate() - dest=None - mask=None - gw=None - ifIndex=None - for i in stdout.split('\n'): - if not i.strip(): - continue - if i.find(':')<0: + for line in exec_query(['Get-WmiObject', 'win32_IP4RouteTable'], + ['Name', 'Mask', 'NextHop', 'InterfaceIndex']): + try: + iface = devname_from_index(int(line[3])) + except ValueError: continue - name, value = [ j.strip().lower() for j in i.split(':',1) ] - if name=="name": - dest=atol(value) - elif name=="mask": - mask=atol(value) - elif name=="nexthop": - gw=value - elif name=="interfaceindex": - ifIndex=value - try: - iface = devname_from_index(int(ifIndex)) - except ValueError: - continue - addr = ifaces[iface].ip - routes.append((dest, mask, gw, iface, addr)) + routes.append((atol(line[0]), atol(line[1]), line[2], iface, + ifaces[iface].ip)) return routes def read_routes(): @@ -328,6 +334,7 @@ def read_routes(): return routes def read_routes_post2008(): + # XXX TODO: FIX THIS XXX routes = [] if_index = '(\d+)' dest = '(\d+\.\d+\.\d+\.\d+)/(\d+)' -- GitLab