示例#1
0
def auth_scan(u, auth_range, key_func=None, delay=None):
    log.debug('Starting auth scan for range: {}'.format(auth_range))
    u.c.placeCanBookmark('auth_scan({}, key_func={}, delay={})'.format(auth_range, key_func, delay))
    auth_levels = {}
    for i in auth_range:  
        if key_func:
            key = ''
        else:
            key = key_func(i)

        log.detail('Trying auth level {}: key \'{}\''.format(i, key))
        u.c.placeCanBookmark('SecurityAccess({}, {})'.format(i, repr(key)))

        resp = try_auth(u, i, key)
        if resp is not None:
            log.debug('auth {}: {}'.format(i, resp))
            if 'resp' in resp:
                log.msg('SECURITY {}: {}'.format(i, resp['resp'].encode('hex')))
            else:
                log.msg('SECURITY {}: {}'.format(i, err_str(resp['err'])))
            auth_levels[i] = resp

        if delay:
            time.sleep(delay)

    return auth_levels
示例#2
0
    def auth_scan(self, auth_range, rescan=False):
        arb, resp, ext = self._addr
        u = self._scancls(self.c,
                          arb,
                          resp,
                          extflag=ext,
                          verbose=False,
                          timeout=self._timeout)
        u.StartTesterPresent(request_response=False)

        for sess in self._sessions:
            if sess != 1 and \
                    ('auth' not in self._sessions[sess] or \
                    len(self._sessions[sess]['auth']) == 0 or rescan):
                log.msg('{} session {} starting auth scan'.format(
                    self._addr, sess))
                with utils.new_session(u, sess,
                                       self._sessions[sess]['prereqs'], True):
                    # Pass the get_key() function in the UDS scan class through
                    results = utils.auth_scan(u,
                                              auth_range,
                                              lambda x: u.get_key(sess, x),
                                              delay=self._delay)

                    if 'auth' in self._sessions[sess]:
                        self._sessions[sess]['auth'].update(results)
                    else:
                        self._sessions[sess]['auth'] = results
示例#3
0
def did_read_scan(u, did_range, delay=None):
    log.debug('Starting DID read scan for range: {}'.format(did_range))
    u.c.placeCanBookmark('did_read_scan({}, delay={})'.format(
        did_range, delay))
    dids = {}
    for i in did_range:
        log.detail('Trying DID read {}'.format(hex(i)))
        u.c.placeCanBookmark('ReadDID({})'.format(hex(i)))
        resp = try_read_did(u, i)

        if resp is not None:
            log.debug('DID {}: {}'.format(hex(i), resp))
            if 'resp' in resp:
                printable_did = ''.join([
                    x if x in string.printable else ''
                    for x in resp['resp'][3:]
                ])
                log.msg('DID {}: {} ({})'.format(did_str(i), resp['resp'],
                                                 printable_did))
            else:
                log.msg('DID {}: ERR {}'.format(did_str(i),
                                                err_str(resp['err'])))
            dids[i] = resp

        if delay:
            time.sleep(delay)

    return dids
示例#4
0
    def session_scan(self,
                     session_range,
                     rescan=False,
                     rescan_did_range=None,
                     recursive_scan=True):
        arb, resp, ext = self._addr
        # Unfortunately session scanning (and the later DID scanning) is more
        # reliable with the standard 3 second timeout
        u = self._scancls(self.c,
                          arb,
                          resp,
                          extflag=ext,
                          verbose=False,
                          timeout=3.0)

        log.msg('{} starting session scan'.format(self._addr))

        # Only scan for new sessions if the session list consists only of session 1
        if len(self._sessions) == 1:
            new_sessions = utils.session_scan(u,
                                              session_range,
                                              delay=self._delay,
                                              recursive_scan=recursive_scan)
            self._sessions.update(new_sessions)

        # For each session that was found, go through the list of DIDs and
        # identify which DIDs can be read in this session
        for sess in self._sessions:
            if sess != 1 and 'resp' in self._sessions[sess] and (rescan or \
                    'dids' not in self._sessions[sess] or len(self._sessions[sess]['dids']) == 0):
                try:
                    with utils.new_session(u, sess,
                                           self._sessions[sess]['prereqs'],
                                           True):
                        log.debug('{} session {} ({}) re-reading DIDs'.format(
                            self._addr, sess, self._sessions[sess]['prereqs']))

                        self._sessions[sess]['dids'] = {}
                        # If rescan is set do a full DID scan instead of the short
                        # scan of only existing DIDs
                        if rescan:
                            results = utils.did_read_scan(u,
                                                          rescan_did_range,
                                                          delay=self._delay)
                            self._sessions[sess]['dids'].update(results)
                        else:
                            valid_did_range = [
                                d for d in self._sessions[1]['dids']
                            ]
                            results = utils.did_read_scan(u,
                                                          valid_did_range,
                                                          delay=self._delay)
                            self._sessions[sess]['dids'].update(results)
                except NegativeResponseException as e:
                    log.error(
                        'Failed to enter session {} ({}) to re-scan DIDs, try again later: {}'
                        .format(sess, self._sessions[sess]['prereqs'], e))
示例#5
0
 def did_read_scan(self, did_range, rescan=False):
     # Only do a scan if we don't already have data, unless rescan is set
     if not self._sessions[1]['dids'] or rescan:
         arb, resp, ext = self._addr
         log.msg('{} starting DID scan'.format(self._addr))
         # The DID scan is more reliable using the standard UDS timeout
         # because of the length of time that block transfers can take
         u = self._scancls(self.c,
                           arb,
                           resp,
                           extflag=ext,
                           verbose=False,
                           timeout=3.0)
         self._sessions[1]['dids'].update(
             utils.did_read_scan(u, did_range, delay=self._delay))
示例#6
0
 def did_write_scan(self, did_range, rescan=False):
     # Only do a scan if we don't already have data, unless rescan is set
     if not self._sessions[1]['write_dids'] or rescan:
         # Attempt to write an empty array, which probably won't succeed?
         # but if it does we're pretty screwed.
         arb, resp, ext = self._addr
         log.msg('{} starting DID write scan'.format(self._addr))
         u = self._scancls(self.c,
                           arb,
                           resp,
                           extflag=ext,
                           verbose=False,
                           timeout=self._timeout)
         self._write_dids.update(
             utils.did_write_scan(u, did_range, b'', delay=self._delay))
示例#7
0
def did_write_scan(u, did_range, write_data, delay=None):
    log.debug('Starting DID write scan for range: {}'.format(did_range))
    u.c.placeCanBookmark('did_write_scan({}, write_data={}, delay={})'.format(did_range, write_data, delay))
    dids = {}
    for i in did_range:  
        log.detail('Trying DID write {}'.format(hex(i)))
        u.c.placeCanBookmark('WriteDID({})'.format(hex(i)))
        resp = try_write_did(u, i, write_data)
        if resp is not None:
            log.detail('DID {}: {}'.format(hex(i), resp))
            if 'resp' in resp:
                log.msg('DID {}: {}'.format(did_str(i), resp['resp'].encode('hex')))
            else:
                log.msg('DID {}: {}'.format(did_str(i), err_str(resp['err'])))
            dids[i] = resp

        if delay:
            time.sleep(delay)

    return dids
示例#8
0
def log_and_save(results, note):
    log.msg(note)
    results['notes'][results['start_time']] += '\n' + note
示例#9
0
    def key_length_scan(self, len_range, rescan=False):
        log.msg('{} starting key/seed length scan {}'.format(
            self._addr, len_range))
        self.c.placeCanBookmark('canmap key_length_scan({}, delay={})'.format(
            len_range, self._delay))

        arb, resp, ext = self._addr
        u = self._scancls(self.c,
                          arb,
                          resp,
                          extflag=ext,
                          verbose=False,
                          timeout=self._timeout)
        u.StartTesterPresent(request_response=False)

        # I can't think of a good way to turn this into a more generic utility
        # function
        for sess in self._sessions:
            # Skip session 1
            if sess == 1:
                continue

            with utils.new_session(u, sess, True):
                for lvl in self._sessions[sess]['auth']:
                    if not self._found_key_len(sess, lvl) or rescan:
                        # TODO: For now, we delete the old scan data, not sure how
                        # best to track to new vs. old key key scans otherwise
                        self._sessions[sess]['auth'][lvl] = {'seeds': []}
                        log.msg(
                            '{} session {} auth {} starting key length scan'.
                            format(self._addr, sess, lvl))
                        for keylen in len_range:
                            key = '\x00' * keylen
                            log.detail(
                                'Trying session {}, auth {}, key \'{}\''.
                                format(sess, lvl, key))
                            self.c.placeCanBookmark(
                                'SecurityAccess({}, {})'.format(
                                    sess, repr(key)))
                            resp = self._try_key(u, lvl, key)
                            self._sessions[sess]['auth'][lvl].update(resp)

                            self._sessions[sess]['auth'][lvl]['seeds'].append(
                                dict(u.seed))

                            if 'resp' in resp:
                                # Get the key attempted from the recorded seed data
                                # in case the scanning class modified it
                                log.msg(
                                    'Session {}, auth {} key found! secret {} (seed {})'
                                    .format(sess, lvl, repr(u.seed['secret']),
                                            repr(u.seed['seed'])))
                                break
                            elif resp['err'] == 0x35:
                                log.debug(
                                    'Session {}, auth {} length found! {} (seed {})'
                                    .format(sess, lvl, len(u.seed['secret']),
                                            repr(u.seed['seed'])))
                                break

        if self._delay:
            time.sleep(self._delay)

        # Ensure tester present is not being sent anymore
        u.StopTesterPresent()
示例#10
0
def try_session_scan(u, session_range, prereq_sessions, found_sessions, delay=None, recursive_scan=True, try_ecu_reset=True, try_sess_ctrl_reset=True):
    log.debug('Starting session scan for range: {}'.format(session_range))
    u.c.placeCanBookmark('session_scan({}, delay={})'.format(session_range, delay))
    sessions = {}
    for i in session_range:  
        # If this session matches any one of the prereqs, or one of the
        # sessions already found, skip it
        if i in prereq_sessions or i in found_sessions:
            continue

        log.detail('Trying session {}'.format(i))
        u.c.placeCanBookmark('DiagnosticSessionControl({})'.format(i))

        # Enter any required preq sessions
        try:
            for prereq in prereq_sessions:
                enter_session(u, prereq)
        except uds.NegativeResponseException as e:
            # 0x7f:'ServiceNotSupportedInActiveSession'
            if e.neg_code == 0x7f:
                log.detail('SESSION ({}): Can\'t enter prereqs, stopping session scan'.format(prereq_sessions))
                return sessions
            else:
                raise e

        resp = try_session(u, i)
        if resp is not None:
            resp['prereqs'] = list(prereq_sessions)
            log.debug('session {}: {}'.format(i, resp))
            if 'resp' in resp:
                log.msg('SESSION {}: {} ({})'.format(i, resp['resp'].encode('hex'), prereq_sessions))
            else:
                log.msg('SESSION {}: {} ({})'.format(i, err_str(resp['err']), prereq_sessions))
            sessions[i] = resp

        # Only bother with this if a successful response was received
        if resp and 'resp' in resp:
            if try_ecu_reset:
                try:
                    u.EcuReset()

                    # Small delay to allow for the reset to complete
                    time.sleep(0.2)
                except uds.NegativeResponseException as e:
                    # 0x11:'ServiceNotSupported'
                    # 0x22:'ConditionsNotCorrect'
                    if e.neg_code in [0x11, 0x22]:
                        try_ecu_reset = False
            elif try_sess_ctrl_reset:
                try:
                    # Try just changing back to session 1
                    new_session(u, 1)
                except uds.NegativeResponseException as e:
                    # The default method to try returning to session 1 is EcuReset, if
                    # EcuReset doesn't work (or isn't enabled), then try using the
                    # DiagnosticSessionControl message to return to session 1, if that
                    # doesn't work then we can't attempt recursive session scanning
                    try_sess_ctrl_reset = False

        # Extra delay between attempts if configured
        if delay:
            time.sleep(delay)

    # For each session found re-scan for new sessions that can be entered from
    # those, but only if we have a valid reset method:
    if recursive_scan and (try_ecu_reset or try_sess_ctrl_reset):
        subsessions = {}
        for sess in sessions:
            # Only attempt this with sessions that we got a successful response 
            # for
            if 'msg' in sessions['sess']:
                log.debug('Scanning for sessions from session {} ({})'.format(sess, prereq_sessions))
                prereqs = prereq_sessions + [sess]
                subsessions.update(try_session_scan(u, session_range, prereqs, sessions.keys(),
                    delay=delay, recursive_scan=recursive_scan,
                    try_ecu_reset=try_ecu_reset, try_sess_ctrl_reset=try_sess_ctrl_reset))
        sessions.update(subsessions)

    return sessions
示例#11
0
def ecu_session_scan(c, arb_id_range, ext=0, session=1, udscls=None, timeout=3.0, delay=None, verbose_flag=False):
    scan_type = ''
    if ext:
        scan_type = ' ext'

    if udscls is None:
        udscls = UDS

    log.debug('Starting{} Session ECU scan for range: {}'.format(scan_type, arb_id_range))
    c.placeCanBookmark('ecu_session_scan({}, ext={}, session={}, timeout={}, delay={})'.format(
        arb_id_range, ext, session, timeout, delay))

    ecus = []
    possible_ecus = []
    for i in arb_id_range:  
        if ext and i == uds.ARBID_CONSTS['29bit']['tester']:
            # Skip i == 0xF1 because in that case the sender and receiver IDs 
            # are the same
            log.detail('Skipping 0xF1 in ext ECU scan: invalid ECU address')
            continue
        elif ext == False and i > uds.ARBID_CONSTS['11bit']['max_req_id']:
            # For non-extended scans the valid range goes from 0x00 to 0xFF, but 
            # stop the scan at 0xf7 because at that time the response is the 
            # largest possible valid value
            log.detail('Stopping std ECU scan at 0xF7: last valid ECU address')
            break

        arb_id, resp_id = gen_arbids(i, ext)

        addr = ECUAddress(arb_id, resp_id, ext)
        u = udscls(c, addr.tx_arbid, addr.rx_arbid, extflag=addr.extflag, verbose=verbose_flag, timeout=timeout)
        log.detail('Trying {}'.format(addr))
        try:
            start_index = u.c.getCanMsgCount()
            with new_session(u, session) as msg:
                if msg is not None:
                    log.debug('{} session {}: {}'.format(addr, session, repr(msg)))
                    log.msg('found {}'.format(addr))

                    ecus.append(addr)
                else:
                    tx_msg, responses = find_possible_resp(u, start_index, arb_id,
                            uds.SVC_DIAGNOSTICS_SESSION_CONTROL, session, timeout)
                    if responses:
                        log.warn('Possible non-standard responses for {} found:'.format(addr))
                        rx_arbid, msg = possible_match
                        log.warn('{}: {}'.format(hex(rx_arbid), msg.encode('hex')))
                        possible_ecus.append(ECUAddress(arb_id, rx_arbid, ext))
        except uds.NegativeResponseException as e:
            log.debug('{} session {}: {}'.format(addr, session, e))
            log.msg('found {}'.format(addr))

            # If a negative response happened, that means an ECU is present 
            # to respond at this address.
            ecus.append(addr)

        if delay:
            time.sleep(delay)

    # Double check any non-standard responses that were found
    for addr in possible_ecus:  
        u = udscls(c, addr.tx_arbid, addr.rx_arbid, extflag=addr.extflag,
                verbose=verbose_flag, timeout=timeout)
        log.detail('Trying {}'.format(addr))
        try:
            with new_session(u, sess) as msg:
                if msg is not None:
                    log.debug('{} session {}: {}'.format(addr, sess, repr(msg)))
                    log.msg('found {}'.format(addr))
                    ecus.append(addr)
        except uds.NegativeResponseException as e:
            log.debug('{} session {}: {}'.format(addr, sess, e))
            log.msg('found {}'.format(addr))

            # If a negative response happened, that means an ECU is present 
            # to respond at this address.
            ecus.append(addr)

        if delay:
            time.sleep(delay)

    return ecus
示例#12
0
def ecu_session_scan(c,
                     arb_id_range,
                     ext=0,
                     session=1,
                     udscls=None,
                     timeout=3.0,
                     delay=None,
                     verbose_flag=False):
    scan_type = ''
    if ext:
        scan_type = ' ext'

    if udscls is None:
        udscls = UDS

    log.debug('Starting{} Session ECU scan for range: {}'.format(
        scan_type, arb_id_range))
    c.placeCanBookmark(
        'ecu_session_scan({}, ext={}, session={}, timeout={}, delay={})'.
        format(arb_id_range, ext, session, timeout, delay))

    ecus = []
    possible_ecus = []
    for i in arb_id_range:
        tester_id = uds.ARBID_CONSTS[ext]['tester']
        if i == tester_id:
            # Skip i == 0xF1 because in that case the sender and receiver IDs
            # are the same
            log.detail(
                'Skipping {} in ext ECU scan: invalid ECU address'.format(
                    hex(tester_id)))
            continue

        arb_id, resp_id = gen_arbids(i, ext)
        addr = ECUAddress(arb_id, resp_id, ext)
        log.detail('Trying {}'.format(addr))

        try:
            start_index = u.c.getCanMsgCount()
            with new_session(u, session) as msg:
                if msg is not None:
                    log.debug('{} session {}: {}'.format(
                        addr, session, repr(msg)))
                    log.msg('found {}'.format(addr))

                    ecus.append(addr)
                else:
                    tx_msg, responses = find_possible_resp(
                        u, start_index, arb_id,
                        uds.SVC_DIAGNOSTICS_SESSION_CONTROL, session, timeout)
                    if responses:
                        log.warn(
                            'Possible non-standard responses for {} found:'.
                            format(hex(addr.tx_arbid)))
                        for rx_arbid, msg in responses:
                            log.warn('{}: {}'.format(hex(rx_arbid), msg.hex()))
                        possible_ecus.append(ECUAddress(arb_id, rx_arbid, ext))
        except uds.NegativeResponseException as e:
            log.debug('{} session {}: {}'.format(addr, session, e))
            log.msg('found {}'.format(addr))

            # If a negative response happened, that means an ECU is present
            # to respond at this address.
            ecus.append(addr)

        if delay:
            time.sleep(delay)

    # Double check any non-standard responses that were found
    if possible_ecus:
        log.detail('Retrying possible non-standard ECU addresses')
    for addr in possible_ecus:
        # if the TX ID is the OBD2 request ID, skip it
        if addr.tx_arbid == uds.ARBID_CONSTS[addr.extflag]['obd2_broadcast']:
            log.detail('Skipping OBD2 broadcast address ECU {}'.format(addr))
            continue

        u = udscls(c,
                   addr.tx_arbid,
                   addr.rx_arbid,
                   extflag=addr.extflag,
                   verbose=verbose_flag,
                   timeout=timeout)
        log.detail('Trying {}'.format(addr))
        try:
            with new_session(u, sess) as msg:
                if msg is not None:
                    log.debug('{} session {}: {}'.format(
                        addr, sess, repr(msg)))
                    log.msg('found {}'.format(addr))
                    ecus.append(addr)
        except uds.NegativeResponseException as e:
            log.debug('{} session {}: {}'.format(addr, sess, e))
            log.msg('found {}'.format(addr))

            # If a negative response happened, that means an ECU is present
            # to respond at this address.
            ecus.append(addr)

        if delay:
            time.sleep(delay)

    return ecus