Exemple #1
0
def GMLAN_InitDiagnostics(sock, broadcast_socket=None, timeout=None, verbose=None, retry=0):  # noqa: E501
    # type: (ISOTPSocket, Optional[ISOTPSocket], Optional[int], Optional[bool], int) -> bool  # noqa: E501
    """ Send messages to put an ECU into diagnostic/programming state.

    :param sock: socket for communication.
    :param broadcast_socket: socket for broadcasting. If provided some message
                             will be sent as broadcast. Recommended when used
                             on a network with several ECUs.
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param verbose: set verbosity level
    :param retry: number of retries in case of failure.
    :return: True on success else False
    """
    # Helper function
    def _send_and_check_response(sock, req, timeout, verbose):
        # type: (ISOTPSocket, Packet, Optional[int], Optional[bool]) -> bool
        if verbose:
            print("Sending %s" % repr(req))
        resp = sock.sr1(req, timeout=timeout, verbose=False)
        return _check_response(resp, verbose)

    if verbose is None:
        verbose = conf.verb > 0
    retry = abs(retry)

    while retry >= 0:
        retry -= 1

        # DisableNormalCommunication
        p = GMLAN(service="DisableNormalCommunication")
        if broadcast_socket is None:
            if not _send_and_check_response(sock, p, timeout, verbose):
                continue
        else:
            if verbose:
                print("Sending %s as broadcast" % repr(p))
            broadcast_socket.send(p)
        time.sleep(0.05)

        # ReportProgrammedState
        p = GMLAN(service="ReportProgrammingState")
        if not _send_and_check_response(sock, p, timeout, verbose):
            continue
        # ProgrammingMode requestProgramming
        p = GMLAN() / GMLAN_PM(subfunction="requestProgrammingMode")
        if not _send_and_check_response(sock, p, timeout, verbose):
            continue
        time.sleep(0.05)

        # InitiateProgramming enableProgramming
        # No response expected
        p = GMLAN() / GMLAN_PM(subfunction="enableProgrammingMode")
        if verbose:
            print("Sending %s" % repr(p))
        sock.send(p)
        time.sleep(0.05)
        return True
    return False
Exemple #2
0
def GMLAN_InitDiagnostics(sock,
                          broadcastsocket=None,
                          timeout=None,
                          verbose=None,
                          retry=0):
    """Send messages to put an ECU into an diagnostic/programming state.

    Args:
        sock:       socket to send the message on.
        broadcast:  socket for broadcasting. If provided some message will be
                    sent as broadcast. Recommended when used on a network with
                    several ECUs.
        timeout:    timeout for sending, receiving or sniffing packages.
        verbose:    set verbosity level
        retry:      number of retries in case of failure.

    Returns true on success.
    """
    if verbose is None:
        verbose = conf.verb
    retry = abs(retry)

    while retry >= 0:
        retry -= 1

        # DisableNormalCommunication
        p = GMLAN(service="DisableNormalCommunication")
        if broadcastsocket is None:
            if not _send_and_check_response(sock, p, timeout, verbose):
                continue
        else:
            if verbose:
                print("Sending %s as broadcast" % repr(p))
            broadcastsocket.send(p)
        time.sleep(0.05)

        # ReportProgrammedState
        p = GMLAN(service="ReportProgrammingState")
        if not _send_and_check_response(sock, p, timeout, verbose):
            continue
        # ProgrammingMode requestProgramming
        p = GMLAN() / GMLAN_PM(subfunction="requestProgrammingMode")
        if not _send_and_check_response(sock, p, timeout, verbose):
            continue
        time.sleep(0.05)

        # InitiateProgramming enableProgramming
        # No response expected
        p = GMLAN() / GMLAN_PM(subfunction="enableProgrammingMode")
        if verbose:
            print("Sending %s" % repr(p))
        sock.send(p)
        time.sleep(0.05)
        return True
    return False
Exemple #3
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     scan_range = kwargs.pop("scan_range", range(0x100))
     rdbi_enumerator = kwargs.pop("rdbi_enumerator", None)
     if rdbi_enumerator is None:
         return (GMLAN() / GMLAN_WDBI(dataIdentifier=x) for x in scan_range)
     elif isinstance(rdbi_enumerator, GMLAN_RDBIEnumerator):
         return (GMLAN() / GMLAN_WDBI(dataIdentifier=t.resp.dataIdentifier,
                                      dataRecord=bytes(t.resp)[2:])
                 for t in rdbi_enumerator.filtered_results
                 if t.resp.service != 0x7f and len(bytes(t.resp)) >= 2)
     else:
         raise Scapy_Exception("rdbi_enumerator has to be an instance "
                               "of GMLAN_RDBIEnumerator")
Exemple #4
0
    def execute(self, socket, state, timeout=1, execution_time=1200, **kwargs):
        # type: (_SocketUnion, EcuState, int, int, Any) -> None
        supported = GMLAN_InitDiagnostics(cast(SuperSocket, socket),
                                          timeout=20,
                                          verbose=kwargs.get("debug", False))
        # TODO: Refactor result storage
        if supported:
            self._store_result(state,
                               GMLAN() / GMLAN_PM(), GMLAN(service=0xE5))
        else:
            self._store_result(
                state,
                GMLAN() / GMLAN_PM(),
                GMLAN() / GMLAN_NR(returnCode=0x11, requestServiceId=0xA5))

        self._state_completed[state] = True
Exemple #5
0
def GMLAN_TransferData(sock,
                       addr,
                       payload,
                       maxmsglen=None,
                       timeout=None,
                       verbose=None,
                       retry=0):  # noqa: E501
    # type: (ISOTPSocket, int, bytes, Optional[int], Optional[int], Optional[bool], int) -> bool  # noqa: E501
    """ Send TransferData message.

    Usually used after calling RequestDownload.

    :param sock: socket to send the message on.
    :param addr: destination memory address on the ECU.
    :param payload: data to be sent.
    :param maxmsglen: maximum length of a single iso-tp message.
                      default: maximum length
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param verbose: set verbosity level.
    :param retry: number of retries in case of failure.
    :return: True on success.
    """
    if verbose is None:
        verbose = conf.verb > 0

    retry = abs(retry)
    startretry = retry

    scheme = conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme']
    if addr < 0 or addr >= 2**(8 * scheme):
        warning("Error: Invalid address %s for scheme %s", hex(addr),
                str(scheme))
        return False

    # max size of dataRecord according to gmlan protocol
    if maxmsglen is None or maxmsglen <= 0 or maxmsglen > (4093 - scheme):
        maxmsglen = (4093 - scheme)

    maxmsglen = cast(int, maxmsglen)

    for i in range(0, len(payload), maxmsglen):
        retry = startretry
        while True:
            if len(payload[i:]) > maxmsglen:
                transdata = payload[i:i + maxmsglen]
            else:
                transdata = payload[i:]
            pkt = GMLAN() / GMLAN_TD(startingAddress=addr + i,
                                     dataRecord=transdata)
            resp = sock.sr1(pkt, timeout=timeout, verbose=0)
            if _check_response(resp, verbose):
                break
            retry -= 1
            if retry >= 0:
                if verbose:
                    print("Retrying..")
            else:
                return False

    return True
Exemple #6
0
def GMLAN_RequestDownload(sock, length, timeout=None, verbose=None, retry=0):
    """Send RequestDownload message.

    Usually used before calling TransferData.

    Args:
        sock:       socket to send the message on.
        length:     value for the message's parameter 'unCompressedMemorySize'.
        timeout:    timeout for sending, receiving or sniffing packages.
        verbose:    set verbosity level.
        retry:      number of retries in case of failure.

    Returns true on success.
    """
    if verbose is None:
        verbose = conf.verb
    retry = abs(retry)

    while retry >= 0:
        # RequestDownload
        pkt = GMLAN() / GMLAN_RD(memorySize=length)
        resp = sock.sr1(pkt, timeout=timeout, verbose=0)
        if _check_response(resp, verbose):
            return True
        retry -= 1
        if retry >= 0 and verbose:
            print("Retrying..")
    return False
Exemple #7
0
def GMLAN_RequestDownload(sock, length, timeout=None, verbose=None, retry=0):
    # type: (SuperSocket, int, Optional[int], Optional[bool], int) -> bool
    """ Send RequestDownload message.

        Usually used before calling TransferData.

    :param sock: socket to send the message on.
    :param length: value for the message's parameter 'unCompressedMemorySize'.
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param verbose: set verbosity level.
    :param retry: number of retries in case of failure.
    :return: True on success
    """
    if verbose is None:
        verbose = conf.verb > 0
    retry = abs(retry)

    while retry >= 0:
        # RequestDownload
        pkt = GMLAN() / GMLAN_RD(memorySize=length)
        resp = sock.sr1(pkt, timeout=timeout, verbose=0)
        if _check_response(resp, verbose):
            return True
        retry -= 1
        if retry >= 0 and verbose:
            print("Retrying..")
    return False
Exemple #8
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     services = set(x & ~0x40 for x in range(0x100))
     services.remove(0x10)  # Remove InitiateDiagnosticOperation service
     services.remove(0x3E)  # Remove TesterPresent service
     services.remove(0xa5)  # Remove ProgrammingMode service
     services.remove(0x34)  # Remove RequestDownload
     return (GMLAN(service=x) for x in services)
Exemple #9
0
    def __init__(self, sock, pkt=GMLAN(service="TesterPresent"), interval=2):
        """ Thread to send TesterPresent messages packets periodically

        Args:
            sock: socket where packet is sent periodically
            pkt: packet to send
            interval: interval between two packets
        """
        PeriodicSenderThread.__init__(self, sock, pkt, interval)
Exemple #10
0
    def get_key_pkt(seed, keyfunction, level=1):
        # type: (Packet, Callable[[int], int], int) -> Optional[Packet]
        try:
            s = seed.securitySeed
        except AttributeError:
            return None

        return cast(Packet, GMLAN() / GMLAN_SA(subfunction=level + 1,
                                               securityKey=keyfunction(s)))
Exemple #11
0
    def __init__(self, sock, pkt=GMLAN(service="TesterPresent"), interval=2):
        # type: (SuperSocket, Packet, int) -> None
        """ Thread to send GMLAN TesterPresent packets periodically

        :param sock: socket where packet is sent periodically
        :param pkt: packet to send
        :param interval: interval between two packets
        """
        PeriodicSenderThread.__init__(self, sock, pkt, interval)
Exemple #12
0
 def enter_diagnostic_session(socket):
     # type: (_SocketUnion) -> bool
     ans = socket.sr1(
         GMLAN() / GMLAN_IDO(subfunction=2), timeout=5, verbose=False)
     if ans is not None and ans.service == 0x7f:
         log_interactive.debug(
             "[-] InitiateDiagnosticOperation received negative response!\n"
             "%s", repr(ans))
     return ans is not None and ans.service != 0x7f
Exemple #13
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     scan_range = kwargs.pop("scan_range", range(0x1ff))
     temp = conf.contribs["GMLAN"]['GMLAN_ECU_AddressingScheme']
     # Shift operations to eliminate addresses not aligned to 4
     max_addr = (2**(temp * 8) - 1) >> 2
     addresses = (random.randint(0, max_addr) << 2 for _ in scan_range)
     return (GMLAN() / GMLAN_TD(subfunction=0, startingAddress=x)
             for x in addresses)
Exemple #14
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     self.probe_width = kwargs.pop("probe_width", self.probe_width)
     self.random_probes_len = \
         kwargs.pop("random_probes_len", self.random_probes_len)
     self.sequential_probes_len = \
         kwargs.pop("sequential_probes_len", self.sequential_probes_len)
     addresses = random.sample(
         range(0, self.highest_possible_addr, self.probe_width),
         self.random_probes_len)
     scan_range = kwargs.pop("scan_range", addresses)
     return (GMLAN() /
             GMLAN_RMBA(memoryAddress=x, memorySize=self.probe_width)
             for x in scan_range)
Exemple #15
0
    def enter(socket,  # type: _SocketUnion
              configuration,  # type: AutomotiveTestCaseExecutorConfiguration
              kwargs  # type: Dict[str, Any]
              ):
        # type: (...) -> bool
        if configuration.unittest:
            configuration["tps"] = None
            socket.sr1(GMLAN(service=0x3E), timeout=0.1, verbose=False)
            return True

        GMLAN_TPEnumerator.cleanup(socket, configuration)
        configuration["tps"] = GMLAN_TesterPresentSender(
            cast(SuperSocket, socket))
        configuration["tps"].start()
        return True
Exemple #16
0
def GMLAN_ReadMemoryByAddress(
        sock,  # type: SuperSocket
        addr,  # type: int
        length,  # type: int
        timeout=None,  # type: Optional[int]
        verbose=None,  # type: Optional[bool]
        retry=0  # type: int
):
    # type: (...) -> Optional[bytes]
    """ Read data from ECU memory.

    :param sock: socket to send the data on.
    :param addr: source memory address on the ECU.
    :param length: bytes to read.
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param verbose: set verbosity level.
    :param retry: number of retries in case of failure.
    :return: bytes red or None
    """
    if verbose is None:
        verbose = conf.verb > 0
    retry = abs(retry)

    scheme = conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme']
    if addr < 0 or addr >= 2**(8 * scheme):
        warning("Error: Invalid address %s for scheme %s", hex(addr),
                str(scheme))
        return None

    # max size of dataRecord according to gmlan protocol
    if length <= 0 or length > (4094 - scheme):
        warning(
            "Error: Invalid length %s for scheme %s. "
            "Choose between 0x1 and %s", hex(length), str(scheme),
            hex(4094 - scheme))
        return None

    while retry >= 0:
        # RequestDownload
        pkt = GMLAN() / GMLAN_RMBA(memoryAddress=addr, memorySize=length)
        resp = sock.sr1(pkt, timeout=timeout, verbose=0)
        if _check_response(resp, verbose):
            return cast(Packet, resp).dataRecord
        retry -= 1
        if retry >= 0 and verbose:
            print("Retrying..")
    return None
Exemple #17
0
def GMLAN_ReadMemoryByAddress(sock,
                              addr,
                              length,
                              timeout=None,
                              verbose=None,
                              retry=0):
    """Read data from ECU memory.

    Args:
        sock:       socket to send the data on.
        addr:       source memory address on the ECU.
        length:     bytes to read
        timeout:    timeout for sending, receiving or sniffing packages.
        verbose:    set verbosity level.
        retry:      number of retries in case of failure.

    Returns the bytes read.
    """
    if verbose is None:
        verbose = conf.verb
    retry = abs(retry)

    scheme = conf.contribs['GMLAN']['GMLAN_ECU_AddressingScheme']
    if addr < 0 or addr >= 2**(8 * scheme):
        warning("Error: Invalid address %s for scheme %s", hex(addr),
                str(scheme))
        return None

    # max size of dataRecord according to gmlan protocol
    if length <= 0 or length > (4094 - scheme):
        warning(
            "Error: Invalid length %s for scheme %s. "
            "Choose between 0x1 and %s", hex(length), str(scheme),
            hex(4094 - scheme))
        return None

    while retry >= 0:
        # RequestDownload
        pkt = GMLAN() / GMLAN_RMBA(memoryAddress=addr, memorySize=length)
        resp = sock.sr1(pkt, timeout=timeout, verbose=0)
        if _check_response(resp, verbose):
            return resp.dataRecord
        retry -= 1
        if retry >= 0 and verbose:
            print("Retrying..")
    return None
Exemple #18
0
    def get_seed_pkt(sock, level=1):
        # type: (_SocketUnion, int) -> Optional[Packet]
        req = GMLAN() / GMLAN_SA(subfunction=level)
        for _ in range(10):
            seed = sock.sr1(req, timeout=5, verbose=False)
            if seed is None:
                return None
            elif seed.service == 0x7f and \
                    GMLAN_Enumerator._get_negative_response_code(seed) != 0x37:
                log_interactive.info("Security access no seed! NR: %s",
                                     repr(seed))
                return None

            elif seed.service == 0x7f and \
                    GMLAN_Enumerator._get_negative_response_code(seed) == 0x37:
                log_interactive.info("Security access retry to get seed")
                time.sleep(10)
                continue
            else:
                return seed
        return None
Exemple #19
0
def GMLAN_GetSecurityAccess(sock, key_function, level=1, timeout=None, verbose=None, retry=0):  # noqa: E501
    # type: (ISOTPSocket, Callable[[int], int], int, Optional[int], Optional[bool], int) -> bool  # noqa: E501
    """ Authenticate on ECU. Implements Seey-Key procedure.

    :param sock: socket to send the message on.
    :param key_function: function implementing the key algorithm.
    :param level: level of access
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param verbose: set verbosity level
    :param retry: number of retries in case of failure.
    :return: True on success.
    """
    if verbose is None:
        verbose = conf.verb > 0
    retry = abs(retry)

    if key_function is None:
        return False

    if level % 2 == 0:
        warning("Parameter Error: Level must be an odd number.")
        return False

    while retry >= 0:
        retry -= 1

        request = GMLAN() / GMLAN_SA(subfunction=level)
        if verbose:
            print("Requesting seed..")
        resp = sock.sr1(request, timeout=timeout, verbose=0)
        if not _check_response(resp, verbose):
            if verbose:
                print("Negative Response.")
            continue

        seed = resp.securitySeed
        if seed == 0:
            if verbose:
                print("ECU security already unlocked. (seed is 0x0000)")
            return True

        keypkt = GMLAN() / GMLAN_SA(subfunction=level + 1,
                                    securityKey=key_function(seed))
        if verbose:
            print("Responding with key..")
        resp = sock.sr1(keypkt, timeout=timeout, verbose=0)
        if resp is None:
            if verbose:
                print("Timeout.")
            continue
        if verbose:
            resp.show()
        if resp.sprintf("%GMLAN.service%") == "SecurityAccessPositiveResponse":   # noqa: E501
            if verbose:
                print("SecurityAccess granted.")
            return True
        # Invalid Key
        elif resp.sprintf("%GMLAN.service%") == "NegativeResponse" and \
                resp.sprintf("%GMLAN.returnCode%") == "InvalidKey":
            if verbose:
                print("Key invalid")
            continue

    return False
Exemple #20
0
def GMLAN_GetSecurityAccess(
        sock,  # type: SuperSocket
        key_function,  # type: Callable[[int], int]
        level=1,  # type: int
        timeout=None,  # type: Optional[int]
        verbose=None,  # type: Optional[bool]
        retry=0  # type: int
):
    # type: (...) -> bool
    """ Authenticate on ECU. Implements Seey-Key procedure.

    :param sock: socket to send the message on.
    :param key_function: function implementing the key algorithm.
    :param level: level of access
    :param timeout: timeout for sending, receiving or sniffing packages.
    :param verbose: set verbosity level
    :param retry: number of retries in case of failure.
    :return: True on success.
    """
    if verbose is None:
        verbose = conf.verb > 0
    retry = abs(retry)

    if key_function is None:
        return False

    if level % 2 == 0:
        warning("Parameter Error: Level must be an odd number.")
        return False

    while retry >= 0:
        retry -= 1

        request = GMLAN() / GMLAN_SA(subfunction=level)
        if verbose:
            print("Requesting seed..")
        resp = sock.sr1(request, timeout=timeout, verbose=0)
        if not _check_response(resp, verbose):
            if resp is not None and resp.returnCode == 0x37 and retry:
                if verbose:
                    print("RequiredTimeDelayNotExpired. Wait 10s.")
                time.sleep(10)
            if verbose:
                print("Negative Response.")
            continue

        seed = cast(Packet, resp).securitySeed
        if seed == 0:
            if verbose:
                print("ECU security already unlocked. (seed is 0x0000)")
            return True

        keypkt = GMLAN() / GMLAN_SA(subfunction=level + 1,
                                    securityKey=key_function(seed))
        if verbose:
            print("Responding with key..")
        resp = sock.sr1(keypkt, timeout=timeout, verbose=0)
        if resp is None:
            if verbose:
                print("Timeout.")
            continue
        if verbose:
            resp.show()
        if resp.service == 0x67:
            if verbose:
                print("SecurityAccess granted.")
            return True
        # Invalid Key
        elif resp.service == 0x7f and resp.returnCode == 0x35:
            if verbose:
                print("Key invalid")
            continue

    return False
Exemple #21
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     return (GMLAN() / GMLAN_SA(subfunction=x) for x in range(1, 10, 2))
Exemple #22
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     scan_range = kwargs.pop("scan_range", range(0x100))
     return (GMLAN() / GMLAN_DC(CPIDNumber=x) for x in scan_range)
Exemple #23
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     return [GMLAN() / GMLAN_IDO(subfunction=2)]
Exemple #24
0
    def post_execute(self, socket, state, global_configuration):
        # type: (_SocketUnion, EcuState, AutomotiveTestCaseExecutorConfiguration) -> None  # noqa: E501
        if not self._state_completed[state]:
            return

        if not self.random_probe_finished[state]:
            log_interactive.info("[i] Random memory probing finished")
            self.random_probe_finished[state] = True
            for tup in [
                    t for t in self.results_with_positive_response
                    if t.state == state
            ]:
                self.points_of_interest[state].append(
                    (tup.req.memoryAddress, True))
                self.points_of_interest[state].append(
                    (tup.req.memoryAddress, False))

        if not len(self.points_of_interest[state]):
            return

        log_interactive.info(
            "[i] Create %d memory points for sequential probing" %
            len(self.points_of_interest[state]))

        tested_addrs = [tup.req.memoryAddress for tup in self.results]
        pos_addrs = [
            tup.req.memoryAddress
            for tup in self.results_with_positive_response
            if tup.state == state
        ]

        new_requests = list()
        new_points_of_interest = list()

        for poi, upward in self.points_of_interest[state]:
            if poi not in pos_addrs:
                continue
            temp_new_requests = list()
            for i in range(self.probe_width,
                           self.sequential_probes_len + self.probe_width,
                           self.probe_width):
                if upward:
                    new_addr = min(poi + i, self.highest_possible_addr)
                else:
                    new_addr = max(poi - i, 0)

                if new_addr not in tested_addrs:
                    pkt = GMLAN() / GMLAN_RMBA(memoryAddress=new_addr,
                                               memorySize=self.probe_width)
                    temp_new_requests.append(pkt)

            if len(temp_new_requests):
                new_points_of_interest.append(
                    (temp_new_requests[-1].memoryAddress, upward))
                new_requests += temp_new_requests

        self.points_of_interest[state] = list()

        if len(new_requests):
            self._state_completed[state] = False
            self._request_iterators[state] = new_requests
            self.points_of_interest[state] = new_points_of_interest
            log_interactive.info("[i] Created %d pkts for sequential probing" %
                                 len(new_requests))
Exemple #25
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     return [GMLAN(service=0x3E)]
Exemple #26
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     scan_range = kwargs.pop("scan_range", range(0x10000))
     return (GMLAN() / GMLAN_RDBPI(identifiers=[x]) for x in scan_range)
Exemple #27
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     return [GMLAN() / GMLAN_RD(memorySize=0x10)]
Exemple #28
0
 def _get_initial_requests(self, **kwargs):
     # type: (Any) -> Iterable[Packet]
     scan_range = kwargs.pop("scan_range", range(1, 10, 2))
     return (GMLAN() / GMLAN_SA(subfunction=x) for x in scan_range)