├── README.md ├── log-monkey.png ├── sysdiagnose-appconduit.py ├── sysdiagnose-appupdates.py ├── sysdiagnose-mobileactivation.py ├── sysdiagnose-mobilebackup.py ├── sysdiagnose-mobilecontainermanager.py ├── sysdiagnose-net-ext-cache.py ├── sysdiagnose-networkinterfaces.py ├── sysdiagnose-networkprefs.py ├── sysdiagnose-sys.py ├── sysdiagnose-uuid2path.py ├── sysdiagnose-wifi-icloud.py ├── sysdiagnose-wifi-kml.py ├── sysdiagnose-wifi-net.py └── sysdiagnose-wifi-plist.py /README.md: -------------------------------------------------------------------------------- 1 | # iOS_sysdiagnose_forensic_scripts 2 | 3 |
4 |

5 | Picture of Apple Log Loving Monkey 7 |
8 | 9 | iOS devices have the ability to create numerous logs containing forensically useful information. 10 | These logs may contain volatile information which should be collected ASAP during forensic processing. 11 | 12 | Mattia Epifani (Github: mattiaepi , [Twitter: @mattiaep](https://twitter.com/mattiaep)) , Heather Mahalik (Github: hmahalik , [Twitter: @HeatherMahalik](https://twitter.com/HeatherMahalik)) and [@Cheeky4n6monkey](https://twitter.com/cheeky4n6monkey) have written a document describing their initial research into these logs. This document is freely available from: 13 |

https://www.for585.com/sysdiagnose

14 | 15 |

Big Thankyous to Peter Maaswinkel and Pranav Anand for their additional testing and document review.

16 |

Thanks also to David Durvaux (ddurvaux) for sharing his script - sysdiagnose-appupdates.py

17 |

Thanks to Silvia Spallarossa for her testing of the scripts and bug fixes for sysdiagnose-networkinterfaces.py.

18 | 19 | It is strongly suggested that interested forensic monkeys first read the document BEFORE attempting to use these scripts. 20 | The document details the various iOS logs available, methods of generating and collecting those logs and how to use these scripts to extract forensically interesting information from them. 21 | 22 | These scripts were written for Python3 (tested under Ubuntu 16.04 and macOS X Mojave) using test data from various iOS12 devices. They do not require any third party Python libaries. 23 |
24 | 25 | Here is a usage summary of the available scripts: 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
NameDescriptionOutputUsage Example
sysdiagnose-sys.pyExtracts OS info from logs/SystemVersion/SystemVersion.plistCommand linepython3 sysdiagnose-sys.py -i SystemVersion.plist
sysdiagnose-networkprefs.pyExtracts hostnames from logs/Networking/preferences.plistCommand linepython3 sysdiagnose-networkprefs.py -i preferences.plist
sysdiagnose-networkinterfaces.pyExtracts network config info from logs/Networking/NetworkInterfaces.plistCommand linepython3 sysdiagnose-networkinterfaces.py -i NetworkInterfaces.plist
sysdiagnose-mobilecontainermanager.pyExtracts uninstall info from logs/MobileContainerManager/containermanagerd.log.0Command linepython3 sysdiagnose-mobilecontainermanager.py -i containermanagerd.log.0
sysdiagnose-mobilebackup.pyExtracts backup info from logs/MobileBackup/com.apple.MobileBackup.plistCommand linepython3 sysdiagnose-mobilebackup.py -i com.apple.MobileBackup.plist
sysdiagnose-mobileactivation.pyMobile Activation Startup and Upgrade info from logs/MobileActivation/mobileactivationd.log.*Command linepython3 sysdiagnose-mobileactivation.py -i mobileactivation.log
sysdiagnose-wifi-plist.pyExtracts Wi-Fi network values from WiFi/com.apple.wifi.plist
Use -t option for TSV output file 41 |
Command line and TSVpython3 sysdiagnose-wifi-plist.py -i com.apple.wifi.plist -t
sysdiagnose-wifi-icloud.pyExtracts Wi-Fi network values from WiFi/ICLOUD.apple.wifid.plist
Use -t option for TSV output file
Command line and TSVpython3 sysdiagnose-wifi-icloud.py -i ICLOUD.apple.wifid.plist -t
sysdiagnose-wifi-net.pyExtracts Wi-Fi network names to categorized TSV files from WiFi/wifi *.logTSV filespython3 sysdiagnose-wifi-net.py -i wifi-buf.log
sysdiagnose-wifi-kml.pyExtracts Wi-Fi geolocation values and creates a KML from wifi*.logKMLpython3 sysdiagnose-wifi-kml.py -i wifi-buf.log
sysdiagnose-uuid2path.pyExtracts GUID and path info from logs/tailspindb/UUIDToBinaryLocationsCommand line (comma separated)python3 sysdiagnose-uuid2path.py -i UUIDToBinaryLocations
sysdiagnose-net-ext-cache.pyExtracts app name & GUID info from logs/Networking/com.apple.networkextension.cache.plist
Use -v option to print GUID info
Command linepython3 sysdiagnose-net-ext-cache.py -i com.apple.networkextension.cache.plist -v
sysdiagnose-appconduit.pyExtracts connection info from logs/AppConduit/AppConduit.log.*Command linepython3 sysdiagnose-appconduit.py -i AppConduit.log
sysdiagnose-appupdates.pyExtracts update info from logs/appinstallation/AppUpdates.sqlite.db.*Command linepython3 sysdiagnose-appupdates.py -i AppUpdates.sqlitedb
58 | 59 | -------------------------------------------------------------------------------- /log-monkey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheeky4n6monkey/iOS_sysdiagnose_forensic_scripts/21df9a41e026a61768561df2fb229506c92a1413/log-monkey.png -------------------------------------------------------------------------------- /sysdiagnose-appconduit.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print connection info from logs/AppConduit/AppConduit.log.* 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | 10 | version_string = "sysdiagnose-appconduit.py v2019-05-10 Version 1.0" 11 | 12 | if sys.version_info[0] < 3: 13 | print("Must be using Python 3! Exiting ...") 14 | exit(-1) 15 | 16 | print("Running " + version_string + "\n") 17 | 18 | usage = "\n%prog -i inputfile\n" 19 | 20 | parser = OptionParser(usage=usage) 21 | parser.add_option("-i", dest="inputfile", 22 | action="store", type="string", 23 | help="logs/AppConduit/AppConduit.log.* To Be Searched") 24 | (options, args) = parser.parse_args() 25 | 26 | #no arguments given by user, print help and exit 27 | if len(sys.argv) == 1: 28 | parser.print_help() 29 | exit(-1) 30 | 31 | linecount = 0 32 | connectedcount = 0 33 | resumecount = 0 34 | reunioncount = 0 35 | disconnectedcount = 0 36 | suspendcount = 0 37 | 38 | with open(options.inputfile, 'r') as fp: 39 | data = fp.readlines() 40 | 41 | for line in data: 42 | linecount += 1 43 | 44 | if '[ACXCompanionSyncConnectionManager devicesAreNowConnected:]: Device' in line: 45 | connectedcount += 1 46 | #print("\n" + line) 47 | txts = line.split() 48 | #print(txts, linecount) 49 | #print(len(txts)) 50 | if(len(txts) > 10): 51 | dayofweek = txts[0] 52 | month = txts[1] 53 | day = txts[2] 54 | time = txts[3] 55 | year = txts[4] 56 | device = txts[11] 57 | print(day + " " + month + " " + year + " " + time + " - " + device + " Now Connected [line " + str(linecount) + "]") 58 | else: 59 | #malformed message ... ignore 60 | print("\nMalformed devicesAreNowConnected entry at line "+str(linecount)+"\n") 61 | 62 | 63 | if '[ACXInstallQueue reachabilityChangedForDevice:]_block_invoke: Resuming because' in line: 64 | resumecount += 1 65 | #print("\n" + line) 66 | txts = line.split() 67 | #print(txts, linecount) 68 | #print(len(txts)) 69 | if(len(txts) > 11): 70 | dayofweek = txts[0] 71 | month = txts[1] 72 | day = txts[2] 73 | time = txts[3] 74 | year = txts[4] 75 | device = txts[12] 76 | print(day + " " + month + " " + year + " " + time + " - " + device + " Resuming [line " + str(linecount) + "]") 77 | else: 78 | #malformed message ... ignore 79 | print("\nMalformed Resuming entry at line "+str(linecount)+"\n") 80 | 81 | 82 | if '[ACXCompanionSyncConnection performReunionSyncWithReason:]_block_invoke: Starting reunion sync because ' in line: 83 | reunioncount += 1 84 | #print("\n" + line) 85 | txts = line.split() 86 | #print(txts, linecount) 87 | #print(len(txts)) 88 | if(len(txts) > 14): 89 | dayofweek = txts[0] 90 | month = txts[1] 91 | day = txts[2] 92 | time = txts[3] 93 | year = txts[4] 94 | device = txts[15] 95 | print(day + " " + month + " " + year + " " + time + " - " + device + " Starting Reunion Sync [line " + str(linecount) + "]") 96 | else: 97 | #malformed message ... ignore 98 | print("\nMalformed Sync entry at line "+str(linecount)+"\n") 99 | 100 | 101 | if '[ACXCompanionSyncConnectionManager devicesAreNoLongerConnected:]: Device' in line: 102 | disconnectedcount += 1 103 | #print("\n" + line) 104 | txts = line.split() 105 | #print(txts, linecount) 106 | #print(len(txts)) 107 | if(len(txts) > 10): 108 | dayofweek = txts[0] 109 | month = txts[1] 110 | day = txts[2] 111 | time = txts[3] 112 | year = txts[4] 113 | device = txts[11] 114 | print(day + " " + month + " " + year + " " + time + " - " + device + " Disconnected [line " + str(linecount) + "]") 115 | else: 116 | #malformed message ... ignore 117 | print("\nMalformed devicesAreNoLongerConnected entry at line "+str(linecount)+"\n") 118 | 119 | if '[ACXInstallQueue reachabilityChangedForDevice:]_block_invoke: Suspending because' in line: 120 | suspendcount += 1 121 | #print("\n" + line) 122 | txts = line.split() 123 | #print(txts, linecount) 124 | #print(len(txts)) 125 | if(len(txts) > 11): 126 | dayofweek = txts[0] 127 | month = txts[1] 128 | day = txts[2] 129 | time = txts[3] 130 | year = txts[4] 131 | device = txts[12] 132 | print(day + " " + month + " " + year + " " + time + " - " + device + " Suspending [line " + str(linecount) + "]") 133 | else: 134 | #malformed message ... ignore 135 | print("\nMalformed Suspending entry at line "+str(linecount)+"\n") 136 | 137 | 138 | print("\nFound " + str(connectedcount) + " Now Connected entries") 139 | print("Found " + str(resumecount) + " Resuming entries") 140 | print("Found " + str(reunioncount) + " Starting Reunion Sync entries") 141 | print("Found " + str(disconnectedcount) + " Disconnected entries") 142 | print("Found " + str(suspendcount) + " Suspending entries\n") 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /sysdiagnose-appupdates.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print connection info from logs/appinstallation/AppUpdates.sqlite.db 5 | # Author: david@autopsit.org 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import time 10 | import datetime 11 | import sqlite3 12 | 13 | version_string = "sysdiagnose-appupdates.py v2019-10-02 Version 1.0" 14 | 15 | if sys.version_info[0] < 3: 16 | print("Must be using Python 3! Exiting ...") 17 | exit(-1) 18 | 19 | print("Running " + version_string + "\n") 20 | 21 | usage = "\n%prog -i inputfile\n" 22 | 23 | parser = OptionParser(usage=usage) 24 | parser.add_option("-i", dest="inputfile", 25 | action="store", type="string", 26 | help="logs/appinstallation/AppUpdates.sqlite.db to be parsed") 27 | (options, args) = parser.parse_args() 28 | 29 | #no arguments given by user, print help and exit 30 | if len(sys.argv) == 1: 31 | parser.print_help() 32 | exit(-1) 33 | 34 | try: 35 | appinstalldb = sqlite3.connect(options.inputfile) 36 | cursor = appinstalldb.cursor() 37 | print("pid\tbundle_id\tinstall_date(UTC)\ttimestamp(UTC)") 38 | for row in cursor.execute("SELECT pid, bundle_id, install_date, timestamp FROM app_updates"): 39 | [pid, bundle_id, install_date, timestamp] = row 40 | if (install_date is not None): 41 | # convert "install_date" from Cocoa EPOCH -> UTC 42 | epoch = install_date + 978307200 # difference between COCOA and UNIX epoch is 978307200 seconds 43 | utctime = datetime.datetime.utcfromtimestamp(epoch) 44 | else: 45 | utctime = "NULL" 46 | if (timestamp is not None): 47 | # convert "timestamp" from Unix EPOCH -> UTC 48 | utctimestamp = datetime.datetime.utcfromtimestamp(timestamp) 49 | else: 50 | utctimestamp = "NULL" 51 | 52 | print("%s\t%s\t%s\t%s" % (pid, bundle_id, utctime, utctimestamp)) 53 | except: 54 | print("AN UNHANDLED ERROR OCCURRED AND THE DB WAS NOT PARSED") 55 | 56 | 57 | 58 | # That's all folks ;) 59 | 60 | -------------------------------------------------------------------------------- /sysdiagnose-mobileactivation.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print Mobile Activation Startup and Upgrade info from logs/MobileActivation/mobileactivationd.log.* 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | 10 | version_string = "sysdiagnose-mobileactivation.py v2019-05-10 Version 1.0" 11 | 12 | if sys.version_info[0] < 3: 13 | print("Must be using Python 3! Exiting ...") 14 | exit(-1) 15 | 16 | print("Running " + version_string + "\n") 17 | 18 | usage = "\n%prog -i inputfile\n" 19 | 20 | parser = OptionParser(usage=usage) 21 | parser.add_option("-i", dest="inputfile", 22 | action="store", type="string", 23 | help="logs/MobileActivation/mobileactivationd.log.* To Be Searched") 24 | (options, args) = parser.parse_args() 25 | 26 | #no arguments given by user, print help and exit 27 | if len(sys.argv) == 1: 28 | parser.print_help() 29 | exit(-1) 30 | 31 | linecount = 0 32 | hitcount = 0 33 | activationcount = 0 34 | with open(options.inputfile, 'r') as fp: 35 | data = fp.readlines() 36 | 37 | for line in data: 38 | linecount += 1 39 | 40 | if 'perform_data_migration' in line: 41 | hitcount += 1 42 | #print("\n" + line) 43 | txts = line.split() 44 | #print(txts, linecount) 45 | #print(len(txts)) 46 | dayofweek = txts[0] 47 | month = txts[1] 48 | day = txts[2] 49 | time = txts[3] 50 | year = txts[4] 51 | frombuild = txts[12] 52 | tobuild = txts[14] 53 | print("\n" + day + " " + month + " " + year + " " + time + " Upgraded from " + frombuild + " to " + tobuild + " [line " + str(linecount) + "]") 54 | 55 | 56 | if 'MA: main: ____________________ Mobile Activation Startup _____________________' in line: 57 | activationcount += 1 58 | #print("\n" + line) 59 | txts = line.split() 60 | #print(txts, linecount) 61 | #print(len(txts)) 62 | dayofweek = txts[0] 63 | month = txts[1] 64 | day = txts[2] 65 | time = txts[3] 66 | year = txts[4] 67 | print("\n" + day + " " + month + " " + year + " " + time + " Mobile Activation Startup " + " [line " + str(linecount) + "]") 68 | 69 | if 'MA: main: build_version:' in line: 70 | #print("\n" + line) 71 | txts = line.split() 72 | #print(txts, linecount) 73 | #print(len(txts)) 74 | dayofweek = txts[0] 75 | month = txts[1] 76 | day = txts[2] 77 | time = txts[3] 78 | year = txts[4] 79 | buildver = txts[11] 80 | print(day + " " + month + " " + year + " " + time + " Mobile Activation Build Version = " + buildver) 81 | 82 | if 'MA: main: hardware_model:' in line: 83 | #print("\n" + line) 84 | txts = line.split() 85 | #print(txts, linecount) 86 | #print(len(txts)) 87 | dayofweek = txts[0] 88 | month = txts[1] 89 | day = txts[2] 90 | time = txts[3] 91 | year = txts[4] 92 | hwmodel = txts[11] 93 | print(day + " " + month + " " + year + " " + time + " Mobile Activation Hardware Model = " + hwmodel) 94 | 95 | if 'MA: main: product_type:' in line: 96 | #print("\n" + line) 97 | txts = line.split() 98 | #print(txts, linecount) 99 | #print(len(txts)) 100 | dayofweek = txts[0] 101 | month = txts[1] 102 | day = txts[2] 103 | time = txts[3] 104 | year = txts[4] 105 | prod = txts[11] 106 | print(day + " " + month + " " + year + " " + time + " Mobile Activation Product Type = " + prod) 107 | 108 | if 'MA: main: device_class:' in line: 109 | #print("\n" + line) 110 | txts = line.split() 111 | #print(txts, linecount) 112 | #print(len(txts)) 113 | dayofweek = txts[0] 114 | month = txts[1] 115 | day = txts[2] 116 | time = txts[3] 117 | year = txts[4] 118 | devclass = txts[11] 119 | print(day + " " + month + " " + year + " " + time + " Mobile Activation Device Class = " + devclass) 120 | 121 | print("\nFound " + str(hitcount) + " Upgrade entries") 122 | 123 | print("Found " + str(activationcount) + " Mobile Activation Startup entries\n") 124 | 125 | -------------------------------------------------------------------------------- /sysdiagnose-mobilebackup.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the values from logs/MobileBackup/com.apple.MobileBackup.plist 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import plistlib 10 | 11 | #import pprint 12 | 13 | version_string = "sysdiagnose-mobilebackup.py v2019-05-10 Version 1.0" 14 | 15 | if sys.version_info[0] < 3: 16 | print("Must be using Python 3! Exiting ...") 17 | exit(-1) 18 | 19 | 20 | usage = "\n%prog -i inputfile\n" 21 | 22 | parser = OptionParser(usage=usage) 23 | parser.add_option("-i", dest="inputfile", 24 | action="store", type="string", 25 | help="logs/MobileBackup/com.apple.MobileBackup.plist To Be Searched") 26 | (options, args) = parser.parse_args() 27 | 28 | #no arguments given by user, print help and exit 29 | if len(sys.argv) == 1: 30 | parser.print_help() 31 | exit(-1) 32 | 33 | print("Running " + version_string + "\n") 34 | 35 | with open(options.inputfile, 'rb') as fp: 36 | pl = plistlib.load(fp) 37 | #pprint.pprint(pl) 38 | #print(pl.keys()) 39 | 40 | if 'BackupStateInfo' in pl.keys(): 41 | for key, val in pl["BackupStateInfo"].items(): 42 | #print("key = " + str(key) + ", val = " + str(val)) 43 | if key == 'date': 44 | print("BackupStateInfo Date = " + str(val)) 45 | if key == 'isCloud': 46 | print("BackupStateInfo isCloud = " + str(val)) 47 | 48 | if 'RestoreInfo' in pl.keys(): 49 | for key, val in pl["RestoreInfo"].items(): 50 | if key == 'RestoreDate': 51 | print("RestoreInfo Date = " + str(val)) 52 | if key == 'BackupBuildVersion': 53 | print("RestoreInfo BackupBuildVersion = " + str(val)) 54 | if key == 'DeviceBuildVersion': 55 | print("RestoreInfo DeviceBuildVersion = " + str(val)) 56 | if key == 'WasCloudRestore': 57 | print("RestoreInfo WasCloudRestore = " + str(val)) 58 | 59 | 60 | -------------------------------------------------------------------------------- /sysdiagnose-mobilecontainermanager.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print uninstall infor from logs/MobileContainerManager/containermanagerd.log.0 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | 10 | version_string = "sysdiagnose-mobilecontainermanager.py v2019-05-10 Version 1.0" 11 | 12 | if sys.version_info[0] < 3: 13 | print("Must be using Python 3! Exiting ...") 14 | exit(-1) 15 | 16 | print("Running " + version_string + "\n") 17 | 18 | usage = "\n%prog -i inputfile\n" 19 | 20 | parser = OptionParser(usage=usage) 21 | parser.add_option("-i", dest="inputfile", 22 | action="store", type="string", 23 | help="logs/MobileContainerManager/containermanagerd.log.0 To Be Searched") 24 | (options, args) = parser.parse_args() 25 | 26 | #no arguments given by user, print help and exit 27 | if len(sys.argv) == 1: 28 | parser.print_help() 29 | exit(-1) 30 | 31 | linecount = 0 32 | hitcount = 0 33 | with open(options.inputfile, 'r') as fp: 34 | data = fp.readlines() 35 | 36 | for line in data: 37 | linecount += 1 38 | 39 | if '[MCMGroupManager _removeGroupContainersIfNeededforUser:groupContainerClass:identifiers:referenceCounts:]: Last reference to group container' in line: 40 | hitcount += 1 41 | #print("\n" + line) 42 | txts = line.split() 43 | #print(txts, linecount) 44 | #print(len(txts)) 45 | dayofweek = txts[0] 46 | month = txts[1] 47 | day = txts[2] 48 | time = txts[3] 49 | year = txts[4] 50 | group = txts[15] 51 | print(day + " " + month + " " + year + " " + time + " Removed " + group + " [line " + str(linecount) + "]") 52 | 53 | print("\nFound " + str(hitcount) + " group removal entries\n") 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /sysdiagnose-net-ext-cache.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the values from logs/Networking/com.apple.networkextension.cache.plist 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import plistlib 10 | 11 | #import pprint 12 | 13 | version_string = "sysdiagnose-net-ext-cache.py v2019-05-10 Version 1.0" 14 | 15 | if sys.version_info[0] < 3: 16 | print("Must be using Python 3! Exiting ...") 17 | exit(-1) 18 | 19 | 20 | usage = "\n%prog -i inputfile\n" 21 | 22 | parser = OptionParser(usage=usage) 23 | parser.add_option("-i", dest="inputfile", 24 | action="store", type="string", 25 | help="logs/Networking/com.apple.networkextension.cache.plist To Be Searched") 26 | parser.add_option("-v", dest="verbose", 27 | action="store_true", default=False, 28 | help="Print GUIDs as well as app names") 29 | (options, args) = parser.parse_args() 30 | 31 | #no arguments given by user, print help and exit 32 | if len(sys.argv) == 1: 33 | parser.print_help() 34 | exit(-1) 35 | 36 | print("Running " + version_string + "\n") 37 | 38 | count = 0 39 | with open(options.inputfile, 'rb') as fp: 40 | pl = plistlib.load(fp) 41 | #pprint.pprint(pl) 42 | #print(pl.keys()) 43 | 44 | if 'app-rules' in pl.keys(): 45 | for key, list1 in pl["app-rules"].items(): 46 | count += 1 47 | if (options.verbose): 48 | print(str(key) + " = " + ', '.join(list1)) # verbose with GUIDs 49 | else: 50 | print(str(key)) # just app names 51 | 52 | print("\n" + str(count) + " cache entries retrieved\n") 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /sysdiagnose-networkinterfaces.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the values from logs/Networking/NetworkInterfaces.plist 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import plistlib 10 | 11 | version_string = "sysdiagnose-networkinterfaces.py v2019-11-08 Version 1.0" 12 | 13 | if sys.version_info[0] < 3: 14 | print("Must be using Python 3! Exiting ...") 15 | exit(-1) 16 | 17 | print("Running " + version_string + "\n") 18 | 19 | usage = "\n%prog -i inputfile\n" 20 | 21 | parser = OptionParser(usage=usage) 22 | parser.add_option("-i", dest="inputfile", 23 | action="store", type="string", 24 | help="logs/Networking/NetworkInterfaces.plist To Be Searched") 25 | (options, args) = parser.parse_args() 26 | 27 | with open(options.inputfile, 'rb') as fp: 28 | pl = plistlib.load(fp) 29 | if 'Interfaces' in pl.keys(): 30 | #print(pl["Interfaces"]) 31 | #print(type(pl["Interfaces"])) = dict 32 | 33 | for dictn in pl['Interfaces']: 34 | print("==================================") 35 | print("BSD Name = " + dictn['BSD Name']) 36 | if 'Active' in dictn.keys(): 37 | print("Active = " + str(dictn['Active'])) 38 | if 'IOMACAddress' in dictn.keys(): 39 | #print("IOMACAddress = " + str(dictn['IOMACAddress'])) # dictn['IOMACAddress'] = bytes type 40 | print("IOMACAddress = " + dictn['IOMACAddress'].hex()) # string type 41 | if 'IOPathMatch' in dictn.keys(): 42 | print("IOPathMatch = " + dictn['IOPathMatch']) 43 | 44 | for key, val in dictn['SCNetworkInterfaceInfo'].items(): 45 | if key == 'UserDefinedName': 46 | print("UserDefinedName = " + val) 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /sysdiagnose-networkprefs.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the values from /logs/Networking/preferences.plist 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import plistlib 10 | 11 | version_string = "sysdiagnose-networkprefs.py v2019-05-10 Version 1.0" 12 | 13 | if sys.version_info[0] < 3: 14 | print("Must be using Python 3! Exiting ...") 15 | exit(-1) 16 | 17 | print("Running " + version_string + "\n") 18 | 19 | usage = "\n%prog -i inputfile\n" 20 | 21 | parser = OptionParser(usage=usage) 22 | parser.add_option("-i", dest="inputfile", 23 | action="store", type="string", 24 | help="/logs/Networking/preferences.plist To Be Searched") 25 | (options, args) = parser.parse_args() 26 | 27 | with open(options.inputfile, 'rb') as fp: 28 | pl = plistlib.load(fp) 29 | #print(pl.keys()) # dict_keys(['CurrentSet', 'System', 'Sets', 'NetworkServices']) 30 | 31 | if 'System' in pl.keys(): 32 | #print(pl["System"]) 33 | #print(type(pl["System"])) = dict 34 | if 'System' in pl["System"].keys(): 35 | for key, val in pl["System"].items(): 36 | if key == 'System': 37 | print("System ComputerName = " + val["ComputerName"]) # System/System/ComputerName 38 | print("System HostName = " + val["HostName"]) # System/System/HostName 39 | if key == 'Network': 40 | for key2, val2 in val["HostNames"].items(): 41 | print("Network LocalHostName = " + val2) # for each System/Network/HostNames/LocalHostName 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /sysdiagnose-sys.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the values from /logs/SystemVersion/SystemVersion.plist 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import plistlib 10 | 11 | version_string = "sysdiagnose-sys.py v2019-05-10 Version 1.0" 12 | 13 | if sys.version_info[0] < 3: 14 | print("Must be using Python 3! Exiting ...") 15 | exit(-1) 16 | 17 | print("Running " + version_string + "\n") 18 | 19 | usage = "\n%prog -i inputfile\n" 20 | 21 | parser = OptionParser(usage=usage) 22 | parser.add_option("-i", dest="inputfile", 23 | action="store", type="string", 24 | help="/logs/SystemVersion/SystemVersion.plist To Be Searched") 25 | (options, args) = parser.parse_args() 26 | 27 | with open(options.inputfile, 'rb') as fp: 28 | pl = plistlib.load(fp) 29 | print("ProductName = " + pl["ProductName"]) 30 | print("ProductVersion = " + pl["ProductVersion"]) 31 | print("ProductBuildVersion = " + pl["ProductBuildVersion"]) 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /sysdiagnose-uuid2path.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the values from logs/tailspindb/UUIDToBinaryLocations (XML plist) 5 | # Uses Python3's plistlib 6 | # Author: cheeky4n6monkey@gmail.com 7 | 8 | import sys 9 | from optparse import OptionParser 10 | import plistlib 11 | import pprint 12 | 13 | version_string = "sysdiagnose-uuid2path.py v2019-05-10 Version 1.0" 14 | 15 | if sys.version_info[0] < 3: 16 | print("Must be using Python 3! Exiting ...") 17 | exit(-1) 18 | 19 | usage = "\n%prog -i inputfile\n" 20 | 21 | parser = OptionParser(usage=usage) 22 | parser.add_option("-i", dest="inputfile", 23 | action="store", type="string", 24 | help="logs/tailspindb/UUIDToBinaryLocations plist To Be Printed") 25 | (options, args) = parser.parse_args() 26 | 27 | #no arguments given by user, print help and exit 28 | if len(sys.argv) == 1: 29 | parser.print_help() 30 | exit(-1) 31 | 32 | print("Running " + version_string + "\n") 33 | 34 | with open(options.inputfile, 'rb') as fp: 35 | pl = plistlib.load(fp) 36 | for key, val in pl.items(): 37 | print(str(key) + ", " + str(val)) 38 | 39 | print("\n" + str(len(pl.keys())) + " GUIDs found\n") 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /sysdiagnose-wifi-icloud.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the values from WiFi/ICLOUD_com.apple.wifid.plist 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import plistlib 10 | 11 | version_string = "sysdiagnose-wifi-icloud.py v2019-05-10 Version 1.0" 12 | 13 | if sys.version_info[0] < 3: 14 | print("Must be using Python 3! Exiting ...") 15 | exit(-1) 16 | 17 | print("Running " + version_string + "\n") 18 | 19 | usage = "\n%prog -i inputfile\n" 20 | 21 | parser = OptionParser(usage=usage) 22 | parser.add_option("-i", dest="inputfile", 23 | action="store", type="string", 24 | help="WiFi/ICLOUD_com.apple.wifid.plist To Be Searched") 25 | parser.add_option("-t", dest="outputtsv", 26 | action="store_true", default=False, 27 | help="Write TSV output file called sysdiagnose-wifi-icloud-output.TSV") 28 | (options, args) = parser.parse_args() 29 | 30 | netlist = [] 31 | 32 | with open(options.inputfile, 'rb') as fp: 33 | pl = plistlib.load(fp) 34 | if 'values' in pl.keys(): 35 | name = "" 36 | timestamp ="" 37 | bssid = "" 38 | ssid = "" 39 | addedat = "" 40 | addedby = "" 41 | enabled = "" 42 | for key, val in pl['values'].items(): # values contains an entry for each wifi net 43 | print("==================================") 44 | print("Name = " + key) 45 | name = key 46 | 47 | if type(val) == dict: 48 | for key2, val2 in val.items(): 49 | if key2 == 'timestamp': 50 | print("timestamp = " + str(val2)) 51 | timestamp = str(val2) 52 | 53 | if key2 == 'value': 54 | if type(val2) == dict: 55 | for key3, val3 in val2.items(): 56 | if key3 == 'BSSID': 57 | print("BSSID = " + str(val3)) 58 | bssid = str(val3) 59 | if key3 == 'SSID_STR': 60 | print("SSID_STR = " + str(val3)) 61 | ssid = str(val3) 62 | if key3 == 'added_at': 63 | print("added_at = " + str(val3)) 64 | addedat = str(val3) 65 | if key3 == 'added_by': 66 | print("added_by = " + str(val3)) 67 | addedby = str(val3) 68 | if key3 == 'enabled': 69 | print("enabled = " + str(val3)) 70 | enabled = str(val3) 71 | 72 | netlist.append((name, timestamp, bssid, ssid, addedat, addedby, enabled)) 73 | 74 | print("\nRetrieved " + str(len(pl['values'].keys())) + " wifi entries\n") 75 | 76 | 77 | if (options.outputtsv): 78 | with open("sysdiagnose-wifi-icloud-output.TSV", 'w') as wp: 79 | wp.write("NAME\tTIMESTAMP\tBSSID\tSSID\tADDEDAT\tADDEDBY\tENABLED\n") # header 80 | for name, timestamp, bssid, ssid, addedat, addedby, enabled in netlist: 81 | wp.write(name+"\t"+timestamp+"\t"+bssid+"\t"+ssid+"\t"+addedat+"\t"+addedby+"\t"+enabled+"\n") 82 | 83 | print("Also outputted to sysdiagnose-wifi-icloud-output.TSV\n") 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /sysdiagnose-wifi-kml.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the geolocation values from WiFi/wifi*.log 5 | # and log locations to output KML 6 | # Author: cheeky4n6monkey@gmail.com 7 | 8 | #import os 9 | import sys 10 | from optparse import OptionParser 11 | import tarfile 12 | 13 | version_string = "sysdiagnose-wifi-kml.py v2019-05-10 Version 1.0" 14 | 15 | if sys.version_info[0] < 3: 16 | print("Must be using Python 3! Exiting ...") 17 | exit(-1) 18 | 19 | print("Running " + version_string + "\n") 20 | 21 | usage = "\n%prog -i inputfile\n" 22 | 23 | parser = OptionParser(usage=usage) 24 | parser.add_option("-i", dest="inputfile", 25 | action="store", type="string", 26 | help="WiFi/wifi*.log To Be Searched") 27 | (options, args) = parser.parse_args() 28 | 29 | #no arguments given by user, print help and exit 30 | if len(sys.argv) == 1: 31 | parser.print_help() 32 | exit(-1) 33 | 34 | linecount = 0 35 | ignorecount = 0 36 | updatecount = 0 37 | geotagcount = 0 38 | callbackcount = 0 39 | localecallbackcount = 0 40 | checklocalecount = 0 41 | networktranscount = 0 42 | wifimanagercount = 0 43 | wificurrentlocation = 0 44 | 45 | locations = [] 46 | scanlocations = [] 47 | geolocations = [] 48 | callbacklocations = [] 49 | localecallbacklocations = [] 50 | checklocalelocations = [] 51 | networktranslocations = [] 52 | copylocations = [] 53 | 54 | #print(options.inputfile[0:-4]) # = wifi-buf-04-26-2019__16:00:52.768.log 55 | 56 | if options.inputfile.endswith('.tgz'): # eg wifi-buf-04-26-2019__16:00:52.768.log.tgz 57 | # untar file first to current directory 58 | # tarfile.open currently Throws InvalidHeader error! 59 | with tarfile.open(options.inputfile, 'r:gz') as t: 60 | t.extractall('./') 61 | 62 | # does not get here due to exception ... todo 63 | 64 | # readfile = ass-ume extracted name is same as input name minus the .tgz 65 | with open(options.inputfile[0:-4], 'r') as fp: 66 | data = fp.readlines() 67 | # TODO: Implement processing when given zip file 68 | ''' 69 | for line in data: 70 | if 'didUpdateLocations:' in line: 71 | count += 1 72 | print(line) 73 | ''' 74 | else: # ass-ume input file has been untarred already and is plaintext 75 | with open(options.inputfile, 'r') as fp: 76 | data = fp.readlines() 77 | 78 | for line in data: 79 | linecount += 1 80 | 81 | if 'didUpdateLocations: latitude' in line: 82 | #print("\n" + line) 83 | txts = line.split() 84 | #print(txts, linecount) 85 | #print(len(txts)) 86 | 87 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 88 | if len(txts) > 8: # latitude is the 4th field but check we have all fields before parsing 89 | updatecount += 1 90 | date = txts[0] 91 | time = txts[1] 92 | llat = txts[4][9:-1] # strip trailing "," and leading "latitude=" 93 | llg = txts[5][10:] # strip leading "longitude=" 94 | acc = txts[6][9:] # strip leading "Accuracy=" 95 | tinterval = txts[7][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 96 | src = txts[8][7:] # strip leading "source=" 97 | #print("didUpdateLocations dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 98 | locations.append(("didUpdateLocations", linecount, updatecount, date, time, llat, llg, acc, tinterval, src)) 99 | else: 100 | #wrong number of fields (eg missing date) ... skip hit completely 101 | print("\nERROR - didUpdateLocations = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 102 | ignorecount += 1 103 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 104 | if len(txts) > 7: # latitude is the 4th field but check we have all fields before parsing 105 | updatecount += 1 106 | date = txts[0] 107 | time = txts[1] 108 | llat = txts[3][9:-1] # strip trailing "," and leading "latitude=" 109 | llg = txts[4][10:] # strip leading "longitude=" 110 | acc = txts[5][9:] # strip leading "Accuracy=" 111 | tinterval = txts[6][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 112 | src = txts[7][7:] # strip leading "source=" 113 | # print("didUpdateLocations dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 114 | locations.append(("didUpdateLocations", linecount, updatecount, date, time, llat, llg, acc, tinterval, src)) 115 | else: 116 | #wrong number of fields (eg missing date) ... skip hit completely 117 | print("\nERROR - didUpdateLocations = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 118 | ignorecount += 1 119 | 120 | elif '__WiFiManagerGeoTagNetwork: latitude' in line: 121 | #print("\n" + line) 122 | txts = line.split() 123 | #print(txts, linecount) 124 | #print(len(txts)) 125 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 126 | if len(txts) > 8: # latitude is the 4th field but check we have all fields before parsing 127 | geotagcount += 1 128 | date = txts[0] 129 | time = txts[1] 130 | llat = txts[4][9:-1] # strip trailing "," and leading "latitude=" 131 | llg = txts[5][10:] # strip leading "longitude=" 132 | acc = txts[6][9:] # strip leading "Accuracy=" 133 | tinterval = txts[7][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 134 | src = txts[8][7:] # strip leading "source=" 135 | #print("__WiFiManagerGeoTagNetwork dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 136 | geolocations.append(("__WiFiManagerGeoTagNetwork", linecount, geotagcount, date, time, llat, llg, acc, tinterval, src)) 137 | else: 138 | #wrong number of fields (eg missing date) ... skip hit completely 139 | print("\nERROR - __WiFiManagerGeoTagNetwork = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 140 | ignorecount += 1 141 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 142 | if len(txts) > 7: # latitude is the 4th field but check we have all fields before parsing 143 | geotagcount += 1 144 | date = txts[0] 145 | time = txts[1] 146 | llat = txts[3][9:-1] # strip trailing "," and leading "latitude=" 147 | llg = txts[4][10:] # strip leading "longitude=" 148 | acc = txts[5][9:] # strip leading "Accuracy=" 149 | tinterval = txts[6][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 150 | src = txts[7][7:] # strip leading "source=" 151 | # print("__WiFiManagerGeoTagNetwork dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 152 | geolocations.append(("__WiFiManagerGeoTagNetwork", linecount, geotagcount, date, time, llat, llg, acc, tinterval, src)) 153 | else: 154 | #wrong number of fields (eg missing date) ... skip hit completely 155 | print("\nERROR - __WiFiManagerGeoTagNetwork = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 156 | ignorecount += 1 157 | 158 | elif '__WiFiManagerLocationManagerCallback: latitude' in line: 159 | #print("\n" + line) 160 | txts = line.split() 161 | #print(txts, linecount) 162 | #print(len(txts)) 163 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 164 | if len(txts) > 8: # latitude is the 4th field but check we have all fields before parsing 165 | callbackcount += 1 166 | date = txts[0] 167 | time = txts[1] 168 | llat = txts[4][9:-1] # strip trailing "," and leading "latitude=" 169 | llg = txts[5][10:] # strip leading "longitude=" 170 | acc = txts[6][9:] # strip leading "Accuracy=" 171 | tinterval = txts[7][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 172 | src = txts[8][7:] # strip leading "source=" 173 | #print("__WiFiManagerLocationManagerCallback dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 174 | callbacklocations.append(("__WiFiManagerLocationManagerCallback", linecount, callbackcount, date, time, llat, llg, acc, tinterval, src)) 175 | else: 176 | #wrong number of fields (eg missing date) ... skip hit completely 177 | print("\nERROR - __WiFiManagerLocationManagerCallback = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 178 | ignorecount += 1 179 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 180 | if len(txts) > 7: # latitude is the 4th field but check we have all fields before parsing 181 | callbackcount += 1 182 | date = txts[0] 183 | time = txts[1] 184 | llat = txts[3][9:-1] # strip trailing "," and leading "latitude=" 185 | llg = txts[4][10:] # strip leading "longitude=" 186 | acc = txts[5][9:] # strip leading "Accuracy=" 187 | tinterval = txts[6][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 188 | src = txts[7][7:] # strip leading "source=" 189 | # print("__WiFiManagerLocationManagerCallback dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 190 | callbacklocations.append(("__WiFiManagerLocationManagerCallback", linecount, callbackcount, date, time, llat, llg, acc, tinterval, src)) 191 | else: 192 | #wrong number of fields (eg missing date) ... skip hit completely 193 | print("\nERROR - __WiFiManagerLocationManagerCallback = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 194 | ignorecount += 1 195 | 196 | elif '__WiFiLocaleManagerLocationManagerCallback: latitude' in line: 197 | #print("\n" + line) 198 | txts = line.split() 199 | #print(txts, linecount) 200 | #print(len(txts)) 201 | 202 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 203 | # Note: current logs may not contain an location for this 204 | if len(txts) > 8: # latitude is the 4th field but check we have all fields before parsing 205 | localecallbackcount += 1 206 | date = txts[0] 207 | time = txts[1] 208 | llat = txts[4][9:-1] # strip trailing "," and leading "latitude=" 209 | llg = txts[5][10:] # strip leading "longitude=" 210 | acc = txts[6][9:] # strip leading "Accuracy=" 211 | tinterval = txts[7][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 212 | src = txts[8][7:] # strip leading "source=" 213 | #print("__WiFiLocaleManagerLocationManagerCallback dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 214 | localecallbacklocations.append(("__WiFiLocaleManagerLocationManagerCallback", linecount, localecallbackcount, date, time, llat, llg, acc, tinterval, src)) 215 | else: 216 | #wrong number of fields (eg missing date) ... skip hit completely 217 | print("\nERROR - __WiFiLocaleManagerLocationManagerCallback = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 218 | ignorecount += 1 219 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 220 | if len(txts) > 7: # latitude is the 4th field but check we have all fields before parsing 221 | localecallbackcount += 1 222 | date = txts[0] 223 | time = txts[1] 224 | llat = txts[3][9:-1] # strip trailing "," and leading "latitude=" 225 | llg = txts[4][10:] # strip leading "longitude=" 226 | acc = txts[5][9:] # strip leading "Accuracy=" 227 | tinterval = txts[6][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 228 | src = txts[7][7:] # strip leading "source=" 229 | # print("__WiFiLocaleManagerLocationManagerCallback dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 230 | localecallbacklocations.append(("__WiFiLocaleManagerLocationManagerCallback", linecount, localecallbackcount, date, time, llat, llg, acc, tinterval, src)) 231 | else: 232 | #wrong number of fields (eg missing date) ... skip hit completely 233 | print("\nERROR - __WiFiLocaleManagerLocationManagerCallback = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 234 | ignorecount += 1 235 | 236 | elif 'WiFiLocaleManagerCheckLocale: latitude' in line: 237 | #print("\n" + line) 238 | txts = line.split() 239 | #print(txts, linecount) 240 | #print(len(txts)) 241 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 242 | # Note: current logs may not contain an entry for this 243 | if len(txts) > 8: # latitude is the 4th field but check we have all fields before parsing 244 | checklocalecount += 1 245 | date = txts[0] 246 | time = txts[1] 247 | llat = txts[4][9:-1] # strip trailing "," and leading "latitude=" 248 | llg = txts[5][10:] # strip leading "longitude=" 249 | acc = txts[6][9:] # strip leading "Accuracy=" 250 | tinterval = txts[7][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 251 | src = txts[8][7:] # strip leading "source=" 252 | #print("WiFiLocaleManagerCheckLocale dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 253 | checklocalelocations.append(("WiFiLocaleManagerCheckLocale", linecount, checklocalecount, date, time, llat, llg, acc, tinterval, src)) 254 | else: 255 | #wrong number of fields (eg missing date) ... skip hit completely 256 | print("\nERROR - WiFiLocaleManagerCheckLocale = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 257 | ignorecount += 1 258 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 259 | if len(txts) > 7: # latitude is the 4th field but check we have all fields before parsing 260 | checklocalecount += 1 261 | date = txts[0] 262 | time = txts[1] 263 | llat = txts[3][9:-1] # strip trailing "," and leading "latitude=" 264 | llg = txts[4][10:] # strip leading "longitude=" 265 | acc = txts[5][9:] # strip leading "Accuracy=" 266 | tinterval = txts[6][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 267 | src = txts[7][7:] # strip leading "source=" 268 | # print("WiFiLocaleManagerCheckLocale dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 269 | checklocalelocations.append(("WiFiLocaleManagerCheckLocale", linecount, checklocalecount, date, time, llat, llg, acc, tinterval, src)) 270 | else: 271 | #wrong number of fields (eg missing date) ... skip hit completely 272 | print("\nERROR - WiFiLocaleManagerCheckLocale = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 273 | ignorecount += 1 274 | 275 | elif '__WiFiDeviceManagerAttemptNetworkTransition: latitude' in line: 276 | #print("\n" + line) 277 | txts = line.split() 278 | #print(txts, linecount) 279 | #print(len(txts)) 280 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 281 | # Note: current logs may not contain an entry for this 282 | if len(txts) > 8: # latitude is the 4th field but check we have all fields before parsing 283 | networktranscount += 1 284 | date = txts[0] 285 | time = txts[1] 286 | llat = txts[4][9:-1] # strip trailing "," and leading "latitude=" 287 | llg = txts[5][10:] # strip leading "longitude=" 288 | acc = txts[6][9:] # strip leading "Accuracy=" 289 | tinterval = txts[7][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 290 | src = txts[8][7:] # strip leading "source=" 291 | #print("__WiFiDeviceManagerAttemptNetworkTransition dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 292 | networktranslocations.append(("__WiFiDeviceManagerAttemptNetworkTransition", linecount, networktranscount, date, time, llat, llg, acc, tinterval, src)) 293 | else: 294 | #wrong number of fields (eg missing date) ... skip hit completely 295 | print("\nERROR - __WiFiDeviceManagerAttemptNetworkTransition = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 296 | ignorecount += 1 297 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 298 | if len(txts) > 7: # latitude is the 4th field but check we have all fields before parsing 299 | networktranscount += 1 300 | date = txts[0] 301 | time = txts[1] 302 | llat = txts[3][9:-1] # strip trailing "," and leading "latitude=" 303 | llg = txts[4][10:] # strip leading "longitude=" 304 | acc = txts[5][9:] # strip leading "Accuracy=" 305 | tinterval = txts[6][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 306 | src = txts[7][7:] # strip leading "source=" 307 | # print("__WiFiDeviceManagerAttemptNetworkTransition dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + ", line = " + str(linecount)) 308 | networktranslocations.append(("__WiFiDeviceManagerAttemptNetworkTransition", linecount, networktranscount, date, time, llat, llg, acc, tinterval, src)) 309 | else: 310 | #wrong number of fields (eg missing date) ... skip hit completely 311 | print("\nERROR - __WiFiDeviceManagerAttemptNetworkTransition = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 312 | ignorecount += 1 313 | 314 | elif '__WiFiDeviceManagerScanPreviousNetworkChannel: latitude' in line: 315 | #print("\n" + line) 316 | txts = line.split() 317 | #print(txts, str(linecount)) 318 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 319 | if len(txts) > 8: # latitude is the 4th field but check we have all fields before parsing 320 | wifimanagercount += 1 321 | date = txts[0] 322 | time = txts[1] 323 | llat = txts[4][9:-1] # strip trailing "," and leading "latitude=" 324 | llg = txts[5][10:] # strip leading "longitude=" 325 | acc = txts[6][9:] # strip leading "Accuracy=" 326 | tinterval = txts[7][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 327 | src = txts[8][7:] # strip leading "source=" 328 | #print("__WiFiDeviceManagerScanPreviousNetworkChannel dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + " line = " + str(linecount)) 329 | scanlocations.append(("__WiFiDeviceManagerScanPreviousNetworkChannel", linecount, wifimanagercount, date, time, llat, llg, acc, tinterval, src)) 330 | else: 331 | #wrong number of fields (eg missing date) ... skip hit completely 332 | print("\nERROR - __WiFiDeviceManagerScanPreviousNetworkChannel = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 333 | ignorecount += 1 334 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 335 | if len(txts) > 7: # latitude is the 4th field but check we have all fields before parsing 336 | wifimanagercount += 1 337 | date = txts[0] 338 | time = txts[1] 339 | llat = txts[3][9:-1] # strip trailing "," and leading "latitude=" 340 | llg = txts[4][10:] # strip leading "longitude=" 341 | acc = txts[5][9:] # strip leading "Accuracy=" 342 | tinterval = txts[6][21:-4] # strip leading "timeIntervalSinceNow=" and trailing "secs" 343 | src = txts[7][7:] # strip leading "source=" 344 | # print("__WiFiDeviceManagerScanPreviousNetworkChannel dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + " int = " + tinterval + " src = " + src + " line = " + str(linecount)) 345 | scanlocations.append(("__WiFiDeviceManagerScanPreviousNetworkChannel", linecount, wifimanagercount, date, time, llat, llg, acc, tinterval, src)) 346 | else: 347 | #wrong number of fields (eg missing date) ... skip hit completely 348 | print("\nERROR - __WiFiDeviceManagerScanPreviousNetworkChannel = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 349 | ignorecount += 1 350 | 351 | elif 'WiFiManagerCopyCurrentLocation: currentLocation' in line: 352 | #print("\n" + line) 353 | txts = line.split() 354 | #print(txts, str(linecount)) 355 | #print(len(txts)) 356 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 357 | # Note: current logs may not contain an entry for this 358 | if len(txts) > 16: # currentLocation pair is the 4th field but check we have all fields before parsing 359 | wificurrentlocation += 1 360 | date = txts[0] 361 | time = txts[1] 362 | llat, llg = txts[4][17:-1].split(',') # currentLocation:<+44.38199906,+9.06126224> => +44.38199906,+9.06126224 363 | acc = txts[5] + txts[5][:-1] # combine into +/-1433.02 364 | speed = txts[8] # speed m/s 365 | course = txts[12][:-1] # course 366 | atdate = txts[14] # @date 367 | attime = txts[15] + " " + txts[16] # @time AM/PM 368 | tz = ' '.join(txts[17:]) # ass-ume remainder is timezone. each word is an item in a list so need to join 369 | #print(tz) 370 | #print("WiFiManagerCopyCurrentLocation dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + \ 371 | #" spd = " + speed + " course = " + course + " atdate = " + atdate + " attime = " + attime +\ 372 | #" " + tz + " line = " + str(linecount)) 373 | # use a separate locations list because of the additional stored values (speed, course etc) 374 | copylocations.append(("WiFiManagerCopyCurrentLocation", linecount, wificurrentlocation, date, time, llat, llg, acc, speed, course, atdate, attime, tz, src)) 375 | else: 376 | #wrong number of fields (eg missing date) ... skip hit completely 377 | print("\nERROR - WiFiManagerCopyCurrentLocation = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 378 | ignorecount += 1 379 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 380 | if len(txts) > 15: # currentLocation pair is the 4th field but check we have all fields before parsing 381 | wificurrentlocation += 1 382 | date = txts[0] 383 | time = txts[1] 384 | llat, llg = txts[3][17:-1].split(',') # currentLocation:<+44.38199906,+9.06126224> => +44.38199906,+9.06126224 385 | acc = txts[4] + txts[5][:-1] # combine into +/-1433.02 386 | speed = txts[7] # speed m/s 387 | course = txts[11][:-1] # course 388 | atdate = txts[13] # @date 389 | attime = txts[14] + " " + txts[15] # @time AM/PM 390 | tz = ' '.join(txts[16:]) # ass-ume remainder is timezone. each word is an item in a list so need to join 391 | #print(tz) 392 | # print("WiFiManagerCopyCurrentLocation dt = " + date + " " + time + " llat = " + llat + " llg = " + llg + " acc = " + acc + \ 393 | # " spd = " + speed + " course = " + course + " atdate = " + atdate + " attime = " + attime +\ 394 | # " " + tz + " line = " + str(linecount)) 395 | # use a separate locations list because of the additional stored values (speed, course etc) 396 | copylocations.append(("WiFiManagerCopyCurrentLocation", linecount, wificurrentlocation, date, time, llat, llg, acc, speed, course, atdate, attime, tz, src)) 397 | else: 398 | #wrong number of fields (eg missing date) ... skip hit completely 399 | print("\nERROR - WiFiManagerCopyCurrentLocation = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 400 | ignorecount += 1 401 | elif 'latitude' in line: # we get here, something is wrong 402 | ignorecount += 1 403 | print("\n\n**** WARNING: Unexpected format for log entry - Ignoring ... ****") 404 | print(line + " from line = " + str(linecount) + "\n") # malfomed line is ... 405 | 406 | 407 | print("\n\n=====================================================") 408 | print("\nFound " + str(updatecount) + " valid didUpdateLocation instances in " + options.inputfile) 409 | print("\nFound " + str(geotagcount) + " valid __WiFiManagerGeoTagNetwork instances in " + options.inputfile) 410 | print("\nFound " + str(callbackcount) + " valid __WiFiManagerLocationManagerCallback instances in " + options.inputfile) 411 | print("\nFound " + str(localecallbackcount) + " valid __WiFiLocaleManagerLocationManagerCallback instances in " + options.inputfile) 412 | print("\nFound " + str(checklocalecount) + " valid WiFiLocaleManagerCheckLocale instances in " + options.inputfile) 413 | print("\nFound " + str(networktranscount) + " valid __WiFiDeviceManagerAttemptNetworkTransition instances in " + options.inputfile) 414 | print("\nFound " + str(wifimanagercount) + " valid __WiFiDeviceManagerScanPreviousNetworkChannel instances in " + options.inputfile) 415 | print("\nFound " + str(wificurrentlocation) + " valid WiFiManagerCopyCurrentLocation instances in " + options.inputfile) 416 | print("\n=====================================================") 417 | 418 | if (len(locations)+len(copylocations)+len(scanlocations)+len(geolocations)+len(callbacklocations)+len(localecallbacklocations)+\ 419 | len(checklocalelocations) + len(networktranslocations) > 0): 420 | f = open("wifi-buf-locations.kml", "w") 421 | f.write("\n") 422 | f.write("\n") 423 | f.write("") 424 | f.write("\n" + options.inputfile + "1\n") 425 | f.write("didUpdateLocation0\n") 426 | for name, linecount, groupcount, date, time, llat, llg, acc, tinterval, src in locations: # yellow dot 427 | f.write("\n\n") 428 | f.write("\n") 429 | f.write("" + name + str(groupcount) + "\n") 430 | f.write(" " + name + " " + str(groupcount) + "\nlat = " + llat + ", long = " + llg + "\n" + date + " " + time + "\naccuracy = " + acc + "\nsource = " + src + "\n\nfile = " + options.inputfile + "\nline = " + str(linecount) + "\n") 431 | f.write("" + llg + ", " + llat + "\n") 432 | f.write("") 433 | f.write("\n") 434 | f.write("__WiFiManagerGeoTagNetwork0\n") 435 | for name, linecount, groupcount, date, time, llat, llg, acc, tinterval, src in geolocations: # blue pushpin 436 | f.write("\n\n") 437 | f.write("" + name + str(groupcount) + "\n") 438 | f.write("\n") 439 | f.write(" " + name + " " + str(groupcount) + "\nlat = " + llat + ", long = " + llg + "\n" + date + " " + time + "\naccuracy = " + acc + "\nsource = " + src + "\n\nfile = " + options.inputfile + "\nline = " + str(linecount) + "\n") 440 | f.write("" + llg + ", " + llat + "\n") 441 | f.write("") 442 | f.write("\n") 443 | f.write("__WiFiManagerLocationManagerCallback0\n") 444 | for name, linecount, groupcount, date, time, llat, llg, acc, tinterval, src in callbacklocations: # pink pushpin 445 | f.write("\n\n") 446 | f.write("" + name + str(groupcount) + "\n") 447 | f.write("\n") 448 | f.write(" " + name + " " + str(groupcount) + "\nlat = " + llat + ", long = " + llg + "\n" + date + " " + time + "\naccuracy = " + acc + "\nsource = " + src + "\n\nfile = " + options.inputfile + "\nline = " + str(linecount) + "\n") 449 | f.write("" + llg + ", " + llat + "\n") 450 | f.write("") 451 | f.write("\n") 452 | f.write("__WiFiLocaleManagerLocationManagerCallback0\n") 453 | for name, linecount, groupcount, date, time, llat, llg, acc, tinterval, src in localecallbacklocations: # purple pushpin 454 | f.write("\n\n") 455 | f.write("" + name + str(groupcount) + "\n") 456 | f.write("\n") 457 | f.write(" " + name + " " + str(groupcount) + "\nlat = " + llat + ", long = " + llg + "\n" + date + " " + time + "\naccuracy = " + acc + "\nsource = " + src + "\n\nfile = " + options.inputfile + "\nline = " + str(linecount) + "\n") 458 | f.write("" + llg + ", " + llat + "\n") 459 | f.write("") 460 | f.write("\n") 461 | f.write("WiFiLocaleManagerCheckLocale0\n") 462 | for name, linecount, groupcount, date, time, llat, llg, acc, tinterval, src in checklocalelocations: # light blue pushpin 463 | f.write("\n\n") 464 | f.write("" + name + str(groupcount) + "\n") 465 | f.write("\n") 466 | f.write(" " + name + " " + str(groupcount) + "\nlat = " + llat + ", long = " + llg + "\n" + date + " " + time + "\naccuracy = " + acc + "\nsource = " + src + "\n\nfile = " + options.inputfile + "\nline = " + str(linecount) + "\n") 467 | f.write("" + llg + ", " + llat + "\n") 468 | f.write("") 469 | f.write("\n") 470 | f.write("__WiFiDeviceManagerAttemptNetworkTransition0\n") 471 | for name, linecount, groupcount, date, time, llat, llg, acc, tinterval, src in networktranslocations: # white pushpin 472 | f.write("\n\n") 473 | f.write("" + name + str(groupcount) + "\n") 474 | f.write("\n") 475 | f.write(" " + name + " " + str(groupcount) + "\nlat = " + llat + ", long = " + llg + "\n" + date + " " + time + "\naccuracy = " + acc + "\nsource = " + src + "\n\nfile = " + options.inputfile + "\nline = " + str(linecount) + "\n") 476 | f.write("" + llg + ", " + llat + "\n") 477 | f.write("") 478 | f.write("\n") 479 | f.write("__WiFiDeviceManagerScanPreviousNetworkChannel0\n") 480 | for name, linecount, groupcount, date, time, llat, llg, acc, tinterval, src in scanlocations: # green pushpin 481 | f.write("\n\n") 482 | f.write("" + name + str(groupcount) + "\n") 483 | f.write("\n") 484 | f.write(" " + name + " " + str(groupcount) + "\nlat = " + llat + ", long = " + llg + "\n" + date + " " + time + "\naccuracy = " + acc + "\nsource = " + src + "\n\nfile = " + options.inputfile + "\nline = " + str(linecount) + "\n") 485 | f.write("" + llg + ", " + llat + "\n") 486 | f.write("") 487 | f.write("\n") 488 | f.write("WiFiManagerCopyCurrentLocation0\n") 489 | for name, linecount, groupcount, date, time, llat, llg, acc, speed, course, atdate, attime, tz, src in copylocations: # red tinted white pushpin 490 | f.write("\n\n") 491 | f.write("" + name + str(groupcount) + "\n") 492 | f.write("\n") 493 | f.write(" " + name + " " + str(groupcount) + "\nlat = " + llat + ", long = " + llg + "\n" + date + " " + time + "\naccuracy = " + acc + \ 494 | "\nspeed = " + speed + "\ncourse = " + course + "\nat " + atdate + " " + attime + " " + tz + "\nsource = " + src + "\n\nfile = " + options.inputfile + "\nline = " + str(linecount) + "\n") 495 | f.write("" + llg + ", " + llat + "\n") 496 | f.write("") 497 | f.write("\n") 498 | f.write("\n\n") 499 | f.write("\n") 500 | f.close() 501 | 502 | print("\nLogged "+ str(len(locations) + len(geolocations) + len(callbacklocations) +\ 503 | len(localecallbacklocations) + len(checklocalelocations) + len(networktranslocations) + \ 504 | len(scanlocations) + len(copylocations)) + " locations to wifi-buf-locations.kml output file\n") 505 | print("Ignored " + str(ignorecount) + " malformed log entries\n") 506 | 507 | 508 | 509 | -------------------------------------------------------------------------------- /sysdiagnose-wifi-net.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the Network names (and log to TSV) from WiFi/wifi*.log 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import tarfile 10 | import re 11 | import shlex 12 | 13 | version_string = "sysdiagnose-wifi-net.py v2019-05-10 Version 1.0" 14 | 15 | if sys.version_info[0] < 3: 16 | print("Must be using Python 3! Exiting ...") 17 | exit(-1) 18 | 19 | #no arguments given by user, print help and exit 20 | if len(sys.argv) == 1: 21 | parser.print_help() 22 | exit(-1) 23 | 24 | print("Running " + version_string + "\n") 25 | 26 | usage = "\n%prog -i inputfile\n" 27 | 28 | parser = OptionParser(usage=usage) 29 | parser.add_option("-i", dest="inputfile", 30 | action="store", type="string", 31 | help="WiFi/wifi*.log To Be Searched") 32 | (options, args) = parser.parse_args() 33 | 34 | linecount = 0 35 | ignorecount = 0 36 | filterednetworkscount = 0 37 | channelsfoundcount = 0 38 | backgroundscancount = 0 39 | MRUnetworkscount = 0 40 | ppmattachedcount = 0 41 | alreadyattachedcount = 0 42 | 43 | filterednetworks = [] 44 | channelsfound = [] 45 | backgroundscan = [] 46 | MRUnetworks = [] 47 | ppmattached = [] 48 | alreadyattached = [] 49 | 50 | #print(options.inputfile[0:-4]) # = wifi-buf-04-26-2019__16:00:52.768.log 51 | 52 | if options.inputfile.endswith('.tgz'): # eg wifi-buf-04-26-2019__16:00:52.768.log.tgz 53 | # untar file first to current directory 54 | # tarfile.open Throws InvalidHeader error! 55 | with tarfile.open(options.inputfile, 'r:gz') as t: 56 | t.extractall('./') 57 | # does not get here due to exception ... todo 58 | 59 | # readfile = ass-ume extracted name is same as input name minus the .tgz 60 | with open(options.inputfile[0:-4], 'r') as fp: 61 | data = fp.readlines() 62 | # TODO: Implement processing when given zip file 63 | 64 | else: # ass-ume input file has been untarred already and is plaintext 65 | with open(options.inputfile, 'r') as fp: 66 | data = fp.readlines() 67 | 68 | for line in data: 69 | linecount += 1 70 | 71 | if 'AJScan: Filtered networks -' in line: 72 | #print("\n" + line) 73 | txts = line.split() 74 | #print(txts, str(linecount)) 75 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 76 | if len(txts) > 7: # 7th field is first network name (after "AJScan: Filtered networks -") 77 | filterednetworkscount += 1 78 | date = txts[0] 79 | time = txts[1] 80 | networks = txts[7:-1] # skip last item "..." 81 | #print("$$$ Filtered Networks found = " + ' '.join(networks) + ", line = " + str(linecount)) 82 | for net in networks: # each network gets own entry 83 | filterednetworks.append((date, time, net, linecount)) 84 | else: 85 | #wrong number of fields (eg missing date) ... skip hit completely 86 | print("\nERROR - Filtered Networks = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 87 | ignorecount += 1 88 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 89 | if len(txts) > 6: # 7th field is first network name (after "AJScan: Filtered networks -") 90 | filterednetworkscount += 1 91 | date = txts[0] 92 | time = txts[1] 93 | networks = txts[6:-1] # skip last item "..." 94 | #print("$$$ Filtered Networks found = " + ' '.join(networks) + ", line = " + str(linecount)) 95 | for net in networks: # each network gets own entry 96 | filterednetworks.append((date, time, net, linecount)) 97 | else: 98 | #wrong number of fields (eg missing date) ... skip hit completely 99 | print("\nERROR - Filtered Networks = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 100 | ignorecount += 1 101 | 102 | if 'Scanning 2Ghz Channels found:' in line: 103 | #print("\n" + line) 104 | txts = line.split() 105 | #print(txts, str(linecount)) 106 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 107 | # Can be empty ... 108 | if len(txts) > 7: # there is something after the "Scanning 2Ghz Channels found:" 109 | channelsfoundcount += 1 110 | date = txts[0] 111 | time = txts[1] 112 | networks = ' '.join(txts[7:]) 113 | networks2 = networks.split(', ') # parse comma seperated string list 114 | #print("@@@ Scanning Channels found: " + ' '.join(networks2) + ", line = " + str(linecount)) 115 | for net in networks2: # each network gets own entry 116 | channelsfound.append((date, time, net, linecount)) 117 | else: 118 | #wrong number of fields (eg missing date) ... skip hit completely 119 | print("\nERROR - Scanning Channels = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 120 | ignorecount += 1 121 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 122 | # Can be empty ... 123 | if len(txts) > 6: # there is something after the "Scanning 2Ghz Channels found:" 124 | channelsfoundcount += 1 125 | date = txts[0] 126 | time = txts[1] 127 | networks = ' '.join(txts[6:]) 128 | networks2 = networks.split(', ') # parse comma seperated string list 129 | #print("@@@ Scanning Channels found: " + ' '.join(networks2) + ", line = " + str(linecount)) 130 | for net in networks2: # each network gets own entry 131 | channelsfound.append((date, time, net, linecount)) 132 | else: 133 | #wrong number of fields (eg missing date) ... skip hit completely 134 | print("\nERROR - Scanning Channels = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 135 | ignorecount += 1 136 | 137 | if 'Preparing background scan request for ' in line: 138 | #print("\n" + line) 139 | txts = line.split() 140 | #print(txts, str(linecount)) 141 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 142 | if len(txts) > 7: # 7th field should contain network name 143 | backgroundscancount += 1 144 | date = txts[0] 145 | time = txts[1] 146 | 147 | result = re.search('Preparing background scan request for (.*) on channels:', line) 148 | #print(result) 149 | if (result is None): # search for 2nd variant 150 | result = re.search('Preparing background scan request for (.*) Background Scan Caching is Enabled', line) 151 | if (result is not None): 152 | networks = result.group(1) # group all network names together via regex 153 | networks2 = shlex.split(networks) # split which is "" friendly. It won't break up quoted phrases that have spaces 154 | 155 | #print("!!! Background Scan networks found " + ' '.join(networks2) + ", line = " + str(linecount)) 156 | for net in networks2: # each network gets own entry 157 | backgroundscan.append((date, time, net, linecount)) 158 | else: 159 | #wrong number of fields (eg missing date) ... skip hit completely 160 | print("\nERROR - background scan request = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 161 | ignorecount += 1 162 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 163 | if len(txts) > 6: # 7th field should contain network name 164 | backgroundscancount += 1 165 | date = txts[0] 166 | time = txts[1] 167 | 168 | result = re.search('Preparing background scan request for (.*) on channels:', line) 169 | #print(result) 170 | if (result is None): # search for 2nd variant 171 | result = re.search('Preparing background scan request for (.*) Background Scan Caching is Enabled', line) 172 | if (result is not None): 173 | networks = result.group(1) # group all network names together via regex 174 | networks2 = shlex.split(networks) # split which is "" friendly. It won't break up quoted phrases that have spaces 175 | 176 | #print("!!! Background Scan networks found " + ' '.join(networks2) + ", line = " + str(linecount)) 177 | for net in networks2: # each network gets own entry 178 | backgroundscan.append((date, time, net, linecount)) 179 | else: 180 | #wrong number of fields (eg missing date) ... skip hit completely 181 | print("\nERROR - background scan request = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 182 | ignorecount += 1 183 | 184 | if 'Scanning for MRU Networks:' in line: 185 | #print("\n" + line) 186 | txts = line.split() 187 | #print(txts, str(linecount)) 188 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 189 | if len(txts) > 7: # 7th field should contain network name 190 | MRUnetworkscount += 1 191 | date = txts[0] 192 | time = txts[1] 193 | # time can be 3/18/2019 6:40:17.341 Scanning for MRU Networks: 194 | # or 1/07/2019 19:12:36.354 Scanning for MRU Networks: 195 | tlength = len(time) # should be 11 or 12 196 | mru = line.split(' ')# double spaces between networks eg "BLAH" on channels: 1 "BLAH2" on channels: 2 197 | #print(mru) 198 | #print("mru len = " + str(len(mru))) 199 | 200 | if (tlength == 11): 201 | # mru = [' 1/19/2019', '8:46:40.818 Scanning for MRU Networks:', '"Marriott_GUEST" on channels: 136 48 \n'] 202 | if len(mru) > 2: # has to be something after "Scanning for MRU Networks:" 203 | #print("### MRU networks found: " + ', '.join(mru[2:]) + ", line = " + str(linecount)) 204 | for m in mru[2:]: 205 | MRUnetworks.append((date, time, m.rstrip(), linecount)) 206 | 207 | if (tlength == 12): 208 | # mru = [' 1/07/2019 19:11:57.026 Scanning for MRU Networks:', '"AndroidAP" on channels: 1', '"Vodafone" on channels: 36', '"*WIFI-AIRPORT" on channels: 60 40 \n'] 209 | if len(mru) > 1: # has to be something after "Scanning for MRU Networks:" 210 | #print("### MRU networks found: " + ', '.join(mru[1:]) + ", line = " + str(linecount)) 211 | for m in mru[1:]: 212 | MRUnetworks.append((date, time, m.rstrip(), linecount)) 213 | else: 214 | #wrong number of fields (eg missing date) ... skip hit completely 215 | print("\nERROR - MRU networks = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 216 | ignorecount += 1 217 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 218 | if len(txts) > 6: # 7th field should contain network name 219 | MRUnetworkscount += 1 220 | date = txts[0] 221 | time = txts[1] 222 | # time can be 3/18/2019 6:40:17.341 Scanning for MRU Networks: 223 | # or 1/07/2019 19:12:36.354 Scanning for MRU Networks: 224 | tlength = len(time) # should be 11 or 12 225 | mru = line.split(' ')# double spaces between networks eg "BLAH" on channels: 1 "BLAH2" on channels: 2 226 | #print(mru) 227 | #print("mru len = " + str(len(mru))) 228 | 229 | if (tlength == 11): 230 | # mru = [' 1/19/2019', '8:46:40.818 Scanning for MRU Networks:', '"Marriott_GUEST" on channels: 136 48 \n'] 231 | if len(mru) > 2: # has to be something after "Scanning for MRU Networks:" 232 | #print("### MRU networks found: " + ', '.join(mru[2:]) + ", line = " + str(linecount)) 233 | for m in mru[2:]: 234 | MRUnetworks.append((date, time, m.rstrip(), linecount)) 235 | 236 | if (tlength == 12): 237 | # mru = [' 1/07/2019 19:11:57.026 Scanning for MRU Networks:', '"AndroidAP" on channels: 1', '"Vodafone" on channels: 36', '"*WIFI-AIRPORT" on channels: 60 40 \n'] 238 | if len(mru) > 1: # has to be something after "Scanning for MRU Networks:" 239 | #print("### MRU networks found: " + ', '.join(mru[1:]) + ", line = " + str(linecount)) 240 | for m in mru[1:]: 241 | MRUnetworks.append((date, time, m.rstrip(), linecount)) 242 | else: 243 | #wrong number of fields (eg missing date) ... skip hit completely 244 | print("\nERROR - MRU networks = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 245 | ignorecount += 1 246 | 247 | if '__WiFiDeviceManagerReleasePpmResource: PPM attached - still connected to ' in line: 248 | #print("\n" + line) 249 | txts = line.split() 250 | #print(txts, str(linecount)) 251 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 252 | if len(txts) > 10: 253 | ppmattachedcount += 1 254 | date = txts[0] 255 | time = txts[1] 256 | net = txts[10:] # Assuming only one entry 257 | #print("$$$ PPM attached networks found = " + ' '.join(net).rstrip('.') + ", line = " + str(linecount)) 258 | ppmattached.append((date, time, ' '.join(net).rstrip('.'), linecount)) # net has . at end 259 | else: 260 | #wrong number of fields (eg missing date) ... skip hit completely 261 | print("\nERROR - PPM attached networks = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 262 | ignorecount += 1 263 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 264 | if len(txts) > 9: 265 | ppmattachedcount += 1 266 | date = txts[0] 267 | time = txts[1] 268 | net = txts[9:] # Assuming only one entry 269 | #print("$$$ PPM attached networks found = " + ' '.join(net).rstrip('.') + ", line = " + str(linecount)) 270 | ppmattached.append((date, time, ' '.join(net).rstrip('.'), linecount)) # net has . at end 271 | else: 272 | #wrong number of fields (eg missing date) ... skip hit completely 273 | print("\nERROR - PPM attached networks = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 274 | ignorecount += 1 275 | 276 | if '__WiFiDeviceManagerAutoAssociate: Already connected to ' in line: 277 | #print("\n" + line) 278 | txts = line.split() 279 | #print(txts, str(linecount)) 280 | if ':' in line: # current log format has extra : text after date/time eg "wifi-mm-dd-yyyy__hh[separator]mm[separator]ss.sss.log" 281 | if len(txts) > 7: 282 | alreadyattachedcount += 1 283 | date = txts[0] 284 | time = txts[1] 285 | net = txts[7:] # Assuming only one entry 286 | #print("$$$ Already attached networks found = " + ' '.join(net).rstrip('.') + ", line = " + str(linecount)) 287 | alreadyattached.append((date, time, ' '.join(net).rstrip('.'), linecount)) # net has . at end 288 | else: 289 | #wrong number of fields (eg missing date) ... skip hit completely 290 | print("\nERROR - Already attached networks = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 291 | ignorecount += 1 292 | 293 | else: #archived log format eg WiFiManager/wifi-buf-mm-dd-yyyy__hh-mm-ss.sss.log 294 | if len(txts) > 6: 295 | alreadyattachedcount += 1 296 | date = txts[0] 297 | time = txts[1] 298 | net = txts[6:] # Assuming only one entry 299 | #print("$$$ Already attached networks found = " + ' '.join(net).rstrip('.') + ", line = " + str(linecount)) 300 | alreadyattached.append((date, time, ' '.join(net).rstrip('.'), linecount)) # net has . at end 301 | else: 302 | #wrong number of fields (eg missing date) ... skip hit completely 303 | print("\nERROR - Already attached networks = Wrong Number of fields in file (line = " + str(linecount) + ") - Ignoring ...\n") 304 | ignorecount += 1 305 | 306 | print("\n\n=====================================================") 307 | 308 | print("\nFound " + str(filterednetworkscount) + " filtered network messages in " + options.inputfile) 309 | print("\nFound " + str(channelsfoundcount) + " found channel messages in " + options.inputfile) 310 | print("\nFound " + str(backgroundscancount) + " background scan channel messages in " + options.inputfile) 311 | print("\nFound " + str(MRUnetworkscount) + " MRU network messages in " + options.inputfile) 312 | print("\nFound " + str(ppmattachedcount) + " PPM attached still connected messages in " + options.inputfile) 313 | print("\nFound " + str(alreadyattachedcount) + " already attached still connected messages in " + options.inputfile) 314 | print("\n=====================================================\n") 315 | 316 | if filterednetworkscount > 0: 317 | f_filtered = open("wifi-buf-net_filtered.TSV", "w") 318 | f_filtered.write("DATE\tTIME\tTYPE\tNETWORK\tLINE\tLOGFILE\n") 319 | 320 | for date, time, net, linecount in filterednetworks: 321 | f_filtered.write(date + "\t" + time + "\tFilteredNetworks\t" + net +"\t" + str(linecount) + "\t" + options.inputfile + "\n") 322 | f_filtered.close() 323 | print("Logged "+ str(len(filterednetworks)) + " FilteredNetworks to wifi-buf-net_filtered.TSV output file\n") 324 | 325 | if channelsfoundcount > 0: 326 | f_channel = open("wifi-buf-net_channels.TSV", "w") 327 | f_channel.write("DATE\tTIME\tTYPE\tNETWORK\tLINE\tLOGFILE\n") 328 | 329 | for date, time, net, linecount in channelsfound: 330 | f_channel.write(date + "\t" + time + "\tFoundChannels\t" + net +"\t" + str(linecount) + "\t" + options.inputfile + "\n") 331 | f_channel.close() 332 | print("Logged "+ str(len(channelsfound)) + " FoundChannels to wifi-buf-net_channels.TSV output file\n") 333 | 334 | if backgroundscancount > 0: 335 | f_bgscan = open("wifi-buf-net_bgscan.TSV", "w") 336 | f_bgscan.write("DATE\tTIME\tTYPE\tNETWORK\tLINE\tLOGFILE\n") 337 | 338 | for date, time, net, linecount in backgroundscan: 339 | f_bgscan.write(date + "\t" + time + "\tBGScans\t" + net +"\t" + str(linecount) + "\t" + options.inputfile + "\n") 340 | f_bgscan.close() 341 | print("Logged "+ str(len(backgroundscan)) + " BGScans to wifi-buf-net_bgscan.TSV output file\n") 342 | 343 | if MRUnetworkscount > 0: 344 | f_mru = open("wifi-buf-net_mru.TSV", "w") 345 | f_mru.write("DATE\tTIME\tTYPE\tNETWORK\tLINE\tLOGFILE\n") 346 | 347 | for date, time, m, linecount in MRUnetworks: 348 | f_mru.write(date + "\t" + time + "\tMRUs\t" + m +"\t" + str(linecount) + "\t" + options.inputfile + "\n") 349 | 350 | f_mru.close() 351 | print("Logged "+ str(len(MRUnetworks)) + " MRUs to wifi-buf-net_mru.TSV output file\n") 352 | 353 | if ppmattachedcount > 0: 354 | f_mru = open("wifi-buf-net_ppmattached.TSV", "w") 355 | f_mru.write("DATE\tTIME\tTYPE\tNETWORK\tLINE\tLOGFILE\n") 356 | 357 | for date, time, m, linecount in ppmattached: 358 | f_mru.write(date + "\t" + time + "\tPPMAttached\t" + m +"\t" + str(linecount) + "\t" + options.inputfile + "\n") 359 | 360 | f_mru.close() 361 | print("Logged "+ str(len(ppmattached)) + " PPMAttached to wifi-buf-net_ppmattached.TSV output file\n") 362 | 363 | if alreadyattachedcount > 0: 364 | f_mru = open("wifi-buf-net_alreadyattached.TSV", "w") 365 | f_mru.write("DATE\tTIME\tTYPE\tNETWORK\tLINE\tLOGFILE\n") 366 | 367 | for date, time, m, linecount in alreadyattached: 368 | f_mru.write(date + "\t" + time + "\tAlreadyAttached\t" + m +"\t" + str(linecount) + "\t" + options.inputfile + "\n") 369 | 370 | f_mru.close() 371 | print("Logged "+ str(len(alreadyattached)) + " AlreadyAttached to wifi-buf-net_alreadyattached.TSV output file\n") 372 | 373 | print("=====================================================\n") 374 | print("Ignored " + str(ignorecount) + " malformed entries") 375 | print("Exiting ...\n") 376 | 377 | 378 | 379 | -------------------------------------------------------------------------------- /sysdiagnose-wifi-plist.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | # For Python3 4 | # Script to print the values from WiFi/com.apple.wifi.plist or WiFi/preferences.plist 5 | # Author: cheeky4n6monkey@gmail.com 6 | 7 | import sys 8 | from optparse import OptionParser 9 | import plistlib 10 | 11 | #import pprint 12 | 13 | version_string = "sysdiagnose-wifi-plist.py v2019-10-24 Version 1.0" 14 | 15 | if sys.version_info[0] < 3: 16 | print("Must be using Python 3! Exiting ...") 17 | exit(-1) 18 | 19 | 20 | usage = "\n%prog -i inputfile\n" 21 | 22 | parser = OptionParser(usage=usage) 23 | parser.add_option("-i", dest="inputfile", 24 | action="store", type="string", 25 | help="WiFi/com.apple.wifi.plist or WiFi/preferences.plist To Be Searched") 26 | parser.add_option("-t", dest="outputtsv", 27 | action="store_true", default=False, 28 | help="Write TSV output file called sysdiagnose-wifi-plist-output.TSV") 29 | (options, args) = parser.parse_args() 30 | 31 | #no arguments given by user, print help and exit 32 | if len(sys.argv) == 1: 33 | parser.print_help() 34 | exit(-1) 35 | 36 | print("Running " + version_string + "\n") 37 | 38 | outputlist = [] 39 | with open(options.inputfile, 'rb', ) as fp: 40 | pl = plistlib.load(fp) 41 | #pprint.pprint(pl) 42 | #print(pl.keys()) 43 | 44 | if 'List of known networks' in pl.keys(): 45 | for dic in pl['List of known networks']: # list of dicts 46 | #print(item) 47 | print("=============================") 48 | print("SSID_STR = " + dic['SSID_STR']) 49 | ssid = dic['SSID_STR'] 50 | bssid = "" 51 | if 'BSSID' in dic.keys(): 52 | print("BSSID = " + dic['BSSID']) 53 | bssid = dic['BSSID'] 54 | 55 | netusage = "" 56 | if 'networkUsage' in dic.keys(): 57 | print("networkUsage = " + str(dic['networkUsage'])) 58 | netusage = str(dic['networkUsage']) 59 | 60 | countrycode = "" 61 | if '80211D_IE' in dic.keys(): 62 | #print(type(dic['80211D_IE'])) # dict 63 | for key2, val2 in dic['80211D_IE'].items(): 64 | if key2 == 'IE_KEY_80211D_COUNTRY_CODE': 65 | print("IE_KEY_80211D_COUNTRY_CODE = " + val2) 66 | countrycode = val2 67 | 68 | devname = "" 69 | mfr = "" 70 | serialnum = "" 71 | modelname = "" 72 | if 'WPS_PROB_RESP_IE' in dic.keys(): 73 | for key3, val3 in dic['WPS_PROB_RESP_IE'].items(): 74 | 75 | if key3 == 'IE_KEY_WPS_DEV_NAME': 76 | print("IE_KEY_WPS_DEV_NAME = " + val3) 77 | devname = val3 78 | if key3 == 'IE_KEY_WPS_MANUFACTURER': 79 | print("IE_KEY_WPS_MANUFACTURER = " + val3) 80 | mfr = val3 81 | if key3 == 'IE_KEY_WPS_SERIAL_NUM': 82 | print("IE_KEY_WPS_SERIAL_NUM = " + val3) 83 | serialnum = val3 84 | #serialnum = "testserial" 85 | if key3 == 'IE_KEY_WPS_MODEL_NAME': 86 | print("IE_KEY_WPS_MODEL_NAME = " + val3) 87 | modelname = val3 88 | #modelname = "testmodel" 89 | 90 | lastjoined = "" 91 | if 'lastJoined' in dic.keys(): 92 | print("lastJoined = " + str(dic['lastJoined'])) 93 | lastjoined = str(dic['lastJoined']) 94 | lastautojoined = "" 95 | if 'lastAutoJoined' in dic.keys(): 96 | print("lastAutoJoined = " + str(dic['lastAutoJoined'])) 97 | lastautojoined = str(dic['lastAutoJoined']) 98 | enabled = "" 99 | if 'enabled' in dic.keys(): 100 | enabled = str(dic['enabled']) 101 | print("enabled = " + str(dic['enabled'])) 102 | print("=============================\n") 103 | 104 | outputlist.append((ssid, bssid, netusage, countrycode, devname, mfr, serialnum, modelname, lastjoined, lastautojoined, enabled)) 105 | 106 | 107 | if (options.outputtsv): 108 | with open("sysdiagnose-wifi-plist-output.TSV", 'w') as wp: 109 | wp.write("SSID\tBSSID\tNETUSAGE\tCOUNTRYCODE\tDEVICENAME\tMANUFACTURER\tSERIALNUM\tMODELNAME\tLASTJOINED\tLASTAUTOJOINED\tENABLED\n") # header 110 | for ssid, bssid, netusage, countrycode, devname, mfr, serialnum, modelname, lastjoined, lastautojoined, enabled in outputlist: 111 | wp.write(ssid+"\t"+bssid+"\t"+netusage+"\t"+countrycode+"\t"+devname+"\t"+mfr+"\t"+serialnum+"\t"+modelname+"\t"+lastjoined+"\t"+lastautojoined+"\t"+enabled+"\n") 112 | 113 | print("Also outputted to sysdiagnose-wifi-plist-output.TSV\n") 114 | 115 | --------------------------------------------------------------------------------