diff options
| author | 2019-10-24 12:27:31 +0530 | |
|---|---|---|
| committer | 2019-10-24 12:44:37 +0530 | |
| commit | 5175c7927f8c5551d2b572cde902ec7ac2c24cdb (patch) | |
| tree | 7c3aeebf77dc1fa2f4ac88dee1f1cd022045a55e | |
| parent | 5a888f68d54f2b0c9a5a81b94433124a6d9485f5 (diff) | |
Add tool for live btsnoop logging with Frontline BT sniffer (FTS)
* This script supports Bluetooth Virtual Sniffing via Live Import
feature of Frontline Bluetooth Sniffer(FTS).
* It uses APIs from LiveImportAPI.dll in FTS path to communicate
with FTS sniffer and inject HCI packets for live HCI sniffing
| -rw-r--r-- | system/tools/scripts/btsnoop_live.py | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/system/tools/scripts/btsnoop_live.py b/system/tools/scripts/btsnoop_live.py new file mode 100644 index 0000000000..4e145ffea3 --- /dev/null +++ b/system/tools/scripts/btsnoop_live.py @@ -0,0 +1,297 @@ +#!/usr/bin/env python3 +############################################################################################################### +# +# Copyright (C) 2019 Motorola Mobility LLC +# +# Redistribution and use in source and binary forms, with or without modification, are permitted provided that +# the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the +# following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and +# the following disclaimer in the documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or +# promote products derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################################################### +############################################################################################################### +# +# Bluetooth Virtual Sniffing for Android +# +# This script supports Bluetooth Virtual Sniffing via Live Import Feature of Frontline Bluetooth Sniffer(FTS) +# +# It extracts the HCI packets from Snoop logs and redirect it to FTS for live HCI sniffing. +# +# It uses liveimport.ini and LiveImportAPI.dll from FTS path to communicate with FTS sniffer software. +# +# It works on both Windows and Ubuntu. For Ubuntu, both FTS and Python should be installed on Wine. +# +# FTS_INI_PATH & FTS_DLL_PATH should be set to absolute path of liveimport.ini and LiveImportAPI.dll of FTS +# +# Example below - This may change per machine per FTS version in Windows vs Ubuntu (Wine), set accordingly. +# For Windows +# FTS_INI_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 13.2\\' +# FTS_DLL_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 13.2\\Executables\\Core\\' +# +# For Ubuntu - FTS path recognized by Wine (not Ubuntu path) +# FTS_INI_PATH = 'C:\\Program Files\\Frontline Test System II\\Frontline 13.2\\' +# FTS_DLL_PATH = 'C:\\Program Files\\Frontline Test System II\\Frontline 13.2\\Executables\\Core\\' +# +############################################################################################################### + +import os +import platform +import socket +import struct +import subprocess +import sys +import time +if sys.version_info[0] >= 3: + import configparser +else: + import ConfigParser as configparser + +from calendar import timegm +from ctypes import byref, c_bool, c_longlong, CDLL +from _ctypes import FreeLibrary +from datetime import datetime + + +# Update below to right path corresponding to your machine, FTS version and OS used. +FTS_INI_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 15.12\\' +FTS_DLL_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 15.12\\Executables\\Core\\' + + +iniName = 'liveimport.ini' +if (platform.architecture()[0] == '32bit'): + dllName = 'LiveImportAPI.dll' +else: + dllName = 'LiveImportAPI_x64.dll' + +launchFtsCmd = '\"'+FTS_DLL_PATH + 'fts.exe\"' + ' \"/ComProbe Protocol Analysis System=Generic\"' + ' \"/oemkey=Virtual\"' + +# Unix Epoch delta since 01/01/1970 +FILETIME_EPOCH_DELTA = 116444736000000000 +HUNDREDS_OF_NANOSECONDS = 10000000 + +HOST = 'localhost' +PORT = 8872 +SNOOP_ID = 16 +SNOOP_HDR = 24 + + +def get_file_time(): + """ + Obtain current time in file time format for display + """ + date_time = datetime.now() + file_time = FILETIME_EPOCH_DELTA + (timegm(date_time.timetuple()) * HUNDREDS_OF_NANOSECONDS) + file_time = file_time + (date_time.microsecond * 10) + return file_time + + +def get_connection_string(): + """ + Read ConnectionString from liveimport.ini + """ + config = configparser.ConfigParser() + config.read(FTS_INI_PATH + iniName) + try: + conn_str = config.get('General', 'ConnectionString') + except (configparser.NoSectionError, configparser.NoOptionError): + return None + + return conn_str + + +def get_configuration_string(): + """ + Read Configuration string from liveimport.ini + """ + config_str = '' + config = configparser.ConfigParser() + config.read(FTS_INI_PATH + iniName) + try: + config_items = config.items('Configuration') + except (configparser.NoSectionError, configparser.NoOptionError): + return None + + if config_items is not None: + for item in config_items: + key, value = item + config_str += ("%s=%s\n" % (key, value)) + return config_str + else: + return None + +def check_live_import_connection(live_import): + """ + Launch FTS app in Virtual Sniffing Mode + Check if FTS App is ready to start receiving the data. + If not, wait until 1 min and exit if FTS didn't start. + """ + is_connection_running = c_bool() + count = 0 + + status = live_import.IsAppReady(byref(is_connection_running)) + if (is_connection_running.value == True): + print ("FTS is already launched, Start capture if not already started") + return True + + print("Launching FTS Virtual Sniffing") + try: + ftsProcess = subprocess.Popen((launchFtsCmd), stdout=subprocess.PIPE) + except: + print("Error in Launching FTS.. exiting") + return False + + while (is_connection_running.value == False and count < 12): + status = live_import.IsAppReady(byref(is_connection_running)) + if (status < 0): + print("Live Import Internal Error %d" %(status)) + return False + if (is_connection_running.value == False): + print("Waiting for 5 sec.. Open FTS Virtual Sniffing") + time.sleep(5) + count += 1 + if (is_connection_running.value == True): + print ("FTS is ready to receive the data, Start capture now") + return True + else: + print("FTS Virtual Sniffing didn't start until 1 min.. exiting") + return False + + +def init_live_import(conn_str, config_str): + """ + Load DLL and Initialize the LiveImport module for FTS. + """ + success = c_bool() + try: + live_import = CDLL(FTS_DLL_PATH + dllName) + except: + return None + + if live_import is None: + print("Error: Path to LiveImportAPI.dll is incorrect.. exiting"); + return None + + print(dllName + " loaded successfully") + result = live_import.InitializeLiveImport(conn_str.encode('ascii', 'ignore'), + config_str.encode('ascii', 'ignore'), + byref(success)) + if (result < 0): + print("Live Import Init failed") + return None + else: + print("Live Import Init success") + return live_import + + +def release_live_import(live_import): + """ + Cleanup and exit live import module. + """ + if live_import is not None: + live_import.ReleaseLiveImport() + FreeLibrary(live_import._handle) + + +def main(): + + print("Bluetooth Virtual Sniffing for Fluoride") + connection_str = get_connection_string() + if connection_str is None: + print("Error: path to liveimport.ini is incorrect.. exiting") + exit(0) + + configuration_str = get_configuration_string() + if configuration_str is None: + print("Error: path to liveimport.ini is incorrect.. exiting") + exit(0) + + live_import = init_live_import(connection_str, configuration_str) + if live_import is None: + print("Error: Path to LiveImportAPI.dll is incorrect.. exiting") + exit(0) + + if (check_live_import_connection(live_import) == False): + release_live_import(live_import) + exit(0) + + # Wait until the forward socket is ready + print("Waiting until adb is ready") + os.system('adb wait-for-device forward tcp:8872 tcp:8872') + + btsnoop_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + btsnoop_sock.connect((HOST, PORT)) + snoop_id = btsnoop_sock.recv(SNOOP_ID) + if not snoop_id.startswith(b"btsnoop"): + print("Error: Snoop ID wasn't received.. exiting") + release_live_import(live_import) + exit(0) + + while True: + try: + snoop_hdr = btsnoop_sock.recv(SNOOP_HDR) + if snoop_hdr is not None: + try: + olen, ilen, flags = struct.unpack(">LLL", snoop_hdr[0:12]) + except struct.error: + print("Error: Invalid data", repr(snoop_hdr)) + continue + + file_time = get_file_time() + timestamp = c_longlong(file_time) + + snoop_data = b'' + while (len(snoop_data) < olen): + data_frag = btsnoop_sock.recv(olen - len(snoop_data)) + if data_frag is not None: + snoop_data += data_frag + + print ("Bytes received %d Olen %d ilen %d flags %d" % (len(snoop_data), olen, ilen, flags)) + packet_type = struct.unpack(">B", snoop_data[0:1])[0] + if packet_type == 1: + drf = 1 + isend = 0 + elif packet_type == 2: + drf = 2 + if (flags & 0x01): + isend = 1 + else: + isend = 0 + elif packet_type == 3: + drf = 4 + if (flags & 0x01): + isend = 1 + else: + isend = 0 + elif packet_type == 4: + drf = 8 + isend = 1 + + result = live_import.SendFrame(olen-1, olen-1, snoop_data[1:olen], drf, isend, timestamp) + if (result < 0): + print("Send frame failed") + except KeyboardInterrupt: + print("Cleanup and exit") + release_live_import(live_import) + btsnoop_sock.close() + exit(0) + + +if __name__ == '__main__': + main() + |