def dcm_discovery(args): """ Scans for diagnostics support by sending session control against different arbitration IDs. :param: args: A namespace containing min and max """ min_id = int_from_str_base(args.min) max_id = int_from_str_base(args.max) with CanActions() as can_wrap: print("Starting diagnostics service discovery") def response_analyser_wrapper(arb_id): print "\rSending diagnostics Tester Present to 0x{0:04x}".format(arb_id), stdout.flush() def response_analyser(msg): # Catch both ok and negative response if msg.data[1] in [0x50, 0x7F]: print("\nFound diagnostics at arbitration ID 0x{0:04x}, " "reply at 0x{1:04x}".format(arb_id, msg.arbitration_id)) can_wrap.bruteforce_stop() return response_analyser def none_found(s): print("\nDiagnostics service could not be found: {0}".format(s)) # Message to bruteforce - [length, session control, default session] message = insert_message_length([0x10, 0x01]) can_wrap.bruteforce_arbitration_id(message, response_analyser_wrapper, min_id=min_id, max_id=max_id, callback_end=none_found)
def dcm_discovery(args): """ Scans for diagnostics support by sending session control against different arbitration IDs. :param: args: A namespace containing min and max """ min_id = int_from_str_base(args.min) max_id = int_from_str_base(args.max) no_stop = args.nostop class Diagnostics: found = False with CanActions() as can_wrap: print("Starting diagnostics service discovery") def response_analyser_wrapper(arb_id): print "\rSending Diagnostic Session Control to 0x{0:04x}".format( arb_id), stdout.flush() def response_analyser(msg): # Catch both ok and negative response if len(msg.data) >= 2 and msg.data[1] in [0x50, 0x7F]: Diagnostics.found = True print( "\nFound diagnostics at arbitration ID 0x{0:04x}, " "reply at 0x{1:04x}".format(arb_id, msg.arbitration_id)) if no_stop == False: can_wrap.bruteforce_stop() return response_analyser def discovery_finished(s): if Diagnostics.found: print("\n{0}".format(s)) else: print( "\nDiagnostics service could not be found: {0}".format(s)) # Message to bruteforce - [length, session control, default session] message = insert_message_length([0x10, 0x01]) can_wrap.bruteforce_arbitration_id(message, response_analyser_wrapper, min_id=min_id, max_id=max_id, callback_end=discovery_finished)
def subfunc_discovery(args): """ Scans for subfunctions of a given service. :param args: A namespace containing src, dst, service, show and i """ send_arb_id = int_from_str_base(args.src) rcv_arb_id = int_from_str_base(args.dst) service_id = int_from_str_base(args.service) show_data = args.show bruteforce_indices = args.i # Sanity checks all_valid = True for i in bruteforce_indices: if not 2 <= i <= 7: print( "Invalid bruteforce index '{0}' - must be in range 2-7".format( i)) all_valid = False if not all_valid: return with CanActions(arb_id=send_arb_id) as can_wrap: found_sub_functions = [] print("Starting DCM sub-function discovery") def response_analyser_wrapper(data): print("\rProbing sub-function 0x{0:02x} data {1} (found: {2})". format(service_id, data, len(found_sub_functions)), end="") stdout.flush() def response_analyser(msg): if msg.arbitration_id != rcv_arb_id: return # Response queued - do not handle if msg.data[:4] == [0x03, 0x7f, service_id, 0x78]: can_wrap.current_delay = 1.0 return # Catch ok status elif msg.data[1] - 0x40 == service_id or \ (msg.data[1] == 0x7F and msg.data[3] not in [0x11, 0x12, 0x31, 0x78]): found_sub_functions.append((data, [msg])) elif msg.data[0] == 0x10: # If response takes up multiple frames can_wrap.current_delay = 1.0 found_sub_functions.append((data, [msg])) if show_data: # Cool, give me the rest can_wrap.send([0x30]) else: # Fine, but I don't want the remaining data can_wrap.send([0x32]) elif show_data and msg.data[0] & 0xF0 == 0x20: # Parts following a 0x30 in multiple frame response (keep waiting) can_wrap.current_delay = 1.0 found_sub_functions[-1][1].append(msg) else: # We got an answer - no reason to keep waiting can_wrap.current_delay = 0.0 return response_analyser def finished(s): print("\nDone: {0}".format(s)) try: # Message to bruteforce - [length, session control, default session] message = insert_message_length([service_id, 0x00, 0x00]) can_wrap.bruteforce_data_new(message, bruteforce_indices=bruteforce_indices, callback=response_analyser_wrapper, callback_done=finished) can_wrap.notifier.listeners = [] finally: # Print found functions if len(found_sub_functions) > 0: print("\n\nFound sub-functions for service 0x{0:02x} ({1}):\n". format( service_id, DCM_SERVICE_NAMES.get(service_id, "Unknown service"))) for (sub_function, msgs) in found_sub_functions: print("Sub-function {0}".format(" ".join(sub_function))) if show_data: for message in msgs: print(" {0}".format(message)) else: print("\n\nNo sub-functions were found")
def dcm_discovery(args): """ Scans for diagnostics support by sending session control against different arbitration IDs. :param: args: A namespace containing min and max """ min_id = int_from_str_base(args.min) max_id = int_from_str_base(args.max) no_stop = args.nostop blacklist = [int_from_str_base(b) for b in args.blacklist] valid_responses = [0x50, 0x7F] def scan_arbitration_ids_to_blacklist(scan_duration): print("Scanning for arbitration IDs to blacklist (-autoblacklist)") ids_to_blacklist = set() def response_handler(msg): if msg.data[1] in valid_responses: ids_to_blacklist.add(msg.arbitration_id) with CanActions() as can_actions: # Listen for matches can_actions.add_listener(response_handler) for i in range(scan_duration, 0, -1): print("\r Scanning... {0} seconds left, {1} found".format( i - 1, len(ids_to_blacklist)), end="") stdout.flush() time.sleep(1) print("") can_actions.clear_listeners() # Add found matches to blacklist for arb_id in ids_to_blacklist: blacklist.append(arb_id) # Perform automatic blacklist scanning if args.autoblacklist > 0: scan_arbitration_ids_to_blacklist(args.autoblacklist) class Diagnostics: found = False with CanActions() as can_wrap: print("Starting diagnostics service discovery") def response_analyser_wrapper(arb_id): print("\rSending Diagnostic Session Control to 0x{0:04x}".format( arb_id), end="") stdout.flush() def response_analyser(msg): # Ignore blacklisted arbitration IDs if msg.arbitration_id in blacklist: return # Catch both ok and negative response if len(msg.data) >= 2 and msg.data[1] in valid_responses: Diagnostics.found = True print("\nFound diagnostics at arbitration ID 0x{0:04x}, " "reply at 0x{1:04x}".format(arb_id, msg.arbitration_id)) if not no_stop: can_wrap.bruteforce_stop() return response_analyser def discovery_finished(s): if Diagnostics.found: print("\n{0}".format(s)) else: print( "\nDiagnostics service could not be found: {0}".format(s)) # Message to bruteforce - [length, session control, default session] message = insert_message_length([0x10, 0x01]) can_wrap.bruteforce_arbitration_id(message, response_analyser_wrapper, min_id=min_id, max_id=max_id, callback_end=discovery_finished)
def subfunc_discovery(args): """ Scans for subfunctions of a given service. :param args: A namespace containing src, dst, service, show and i """ send_arb_id = int_from_str_base(args.src) rcv_arb_id = int_from_str_base(args.dst) service_id = int_from_str_base(args.service) show_data = args.show bruteforce_indices = args.i with CanActions(arb_id=send_arb_id) as can_wrap: found_sub_functions = [] print("Starting DCM sub-function discovery") def response_analyser_wrapper(data): print "\rProbing sub-function 0x{0:02x} data {1} (found: {2})".format( service_id, data, len(found_sub_functions)), stdout.flush() def response_analyser(msg): if msg.arbitration_id != rcv_arb_id: return # Response queued - do not handle if msg.data[:4] == [0x03, 0x7f, service_id, 0x78]: can_wrap.current_delay = 1.0 return # Catch ok status elif msg.data[1]-0x40 == service_id or\ (msg.data[1] == 0x7F and msg.data[3] not in [0x11, 0x12, 0x31, 0x78]): # TODO - more? found_sub_functions.append((data, [msg])) elif msg.data[0] == 0x10: # If response takes up multiple frames can_wrap.current_delay = 1.0 found_sub_functions.append((data, [msg])) if show_data: # Cool, give me the rest can_wrap.send([0x30]) else: # Fine, but I don't want the remaining data can_wrap.send([0x32]) elif show_data and msg.data[0] & 0xF0 == 0x20: # Parts following a 0x30 in multiple frame response (keep waiting) can_wrap.current_delay = 1.0 found_sub_functions[-1][1].append(msg) else: # We've got an answer - no reason to keep waiting can_wrap.current_delay = 0.0 return response_analyser def finished(s): print("\nDone: {0}".format(s)) try: # Message to bruteforce - [length, session control, default session] message = insert_message_length([service_id, 0x00, 0x00]) can_wrap.bruteforce_data_new(message, bruteforce_indices=bruteforce_indices, callback=response_analyser_wrapper, callback_end=finished) can_wrap.notifier.listeners = [] finally: # Print found functions if len(found_sub_functions) > 0: print("\n\nFound sub-functions for service 0x{0:02x} ({1}):\n".format( service_id, DCM_SERVICE_NAMES.get(service_id, "Unknown service"))) for (sub_function, msgs) in found_sub_functions: print("Sub-function {0}".format(" ".join(sub_function))) if show_data: for msg in msgs: print(" {0}".format(msg)) else: print("\n\nNo sub-functions were found")