UDS in Scapy#
Overview#
Preparations#
from scapy.all import * # If you launch `scapy` directly, this import isn't necessary
conf.contribs['CANSocket'] = {'use-python-can': False}
conf.contribs['ISOTP'] = {'use-can-isotp-kernel-module': True}
load_contrib("isotp")
load_contrib("automotive.uds")
Examples#
Create a socket.
basecls
has to be set asUDS
.
sock = ISOTPNativeSocket("vcan0", tx_id=0x6f1, rx_id=0x610, ext_address=0x10, rx_ext_address=0xf1, basecls=UDS)
---------------------------------------------------------------------------
Scapy_Exception Traceback (most recent call last)
Cell In[2], line 1
----> 1 sock = ISOTPNativeSocket("vcan0", tx_id=0x6f1, rx_id=0x610, ext_address=0x10, rx_ext_address=0xf1, basecls=UDS)
File /usr/local/lib/python3.13/site-packages/scapy/contrib/isotp/isotp_native_socket.py:336, in ISOTPNativeSocket.__init__(self, iface, tx_id, rx_id, ext_address, rx_ext_address, bs, stmin, padding, listen_only, frame_txtime, fd, basecls)
334 log_isotp.warning('Provide a basecls ')
335 self.basecls = basecls
--> 336 self._init_socket()
File /usr/local/lib/python3.13/site-packages/scapy/contrib/isotp/isotp_native_socket.py:365, in ISOTPNativeSocket._init_socket(self)
352 can_socket.setsockopt(SOL_CAN_ISOTP,
353 CAN_ISOTP_LL_OPTS,
354 self.__build_can_isotp_ll_options(
(...)
357 tx_dl=CAN_FD_ISOTP_DEFAULT_LL_TX_DL if self.fd
358 else CAN_ISOTP_DEFAULT_LL_TX_DL))
359 can_socket.setsockopt(
360 socket.SOL_SOCKET,
361 SO_TIMESTAMPNS,
362 1
363 )
--> 365 self.__bind_socket(can_socket, self.iface, self.tx_id, self.rx_id)
366 # make sure existing sockets are closed,
367 # required in case of a reconnect.
368 if getattr(self, "outs", None):
File /usr/local/lib/python3.13/site-packages/scapy/contrib/isotp/isotp_native_socket.py:238, in ISOTPNativeSocket.__bind_socket(self, sock, iface, tx_id, rx_id)
235 def __bind_socket(self, sock, iface, tx_id, rx_id):
236 # type: (socket.socket, str, int, int) -> None
237 socket_id = ctypes.c_int(sock.fileno())
--> 238 ifr = self.__get_sock_ifreq(sock, iface)
240 if tx_id > 0x7ff:
241 tx_id = tx_id | socket.CAN_EFF_FLAG
File /usr/local/lib/python3.13/site-packages/scapy/contrib/isotp/isotp_native_socket.py:232, in ISOTPNativeSocket.__get_sock_ifreq(self, sock, iface)
229 if ret < 0:
230 m = u'Failure while getting "{}" interface index.'.format(
231 iface)
--> 232 raise Scapy_Exception(m)
233 return ifr
Scapy_Exception: Failure while getting "vcan0" interface index.
Create a packet and send it
rdbi_pkt = UDS()/UDS_RDBI(identifiers=[0x172a])
rx = sock.sr1(rdbi_pkt, timeout=1)
rx.show()
Begin emission:
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
###[ UDS ]###
service = ReadDataByIdentifierPositiveResponse
###[ ReadDataByIdentifierPositiveResponse ]###
dataIdentifier= GatewayIP
###[ Raw ]###
load = '\x00\\xc0\\xa8\x11\\x97\\xff\\xff\\xff\x00\\xc0\\xa8\x11\x01'
Alternative way to send and receive a packet
rdbi_pkt = UDS()/UDS_RDBI(identifiers=[0x172a])
rx = sock.sniff(timeout=1, count=1, started_callback=lambda: sock.send(rdbi_pkt))
rx[0].show()
Begin emission:
Finished sending 1 packets.
*
Received 1 packets, got 1 answers, remaining 0 packets
###[ UDS ]###
service = ReadDataByIdentifierPositiveResponse
###[ ReadDataByIdentifierPositiveResponse ]###
dataIdentifier= GatewayIP
###[ Raw ]###
load = '\x00\\xc0\\xa8\x11\\x97\\xff\\xff\\xff\x00\\xc0\\xa8\x11\x01'
Basecls is
UDS(Packet)
UDS
implements fake layers to auto-fill fieldsIdentifiers can be customized
OEM specific packets can be added to the parser, easily
Customization of Packets#
Define identifier
0x172a
asGatewayIP
rdbi_pkt = UDS()/UDS_RDBI(identifiers=[0x172a])
print(repr(rdbi_pkt))
UDS_RDBI.dataIdentifiers[0x172a] = 'GatewayIP'
print(repr(rdbi_pkt))
<UDS service=ReadDataByIdentifier |<UDS_RDBI identifiers=[GatewayIP] |>>
<UDS service=ReadDataByIdentifier |<UDS_RDBI identifiers=[GatewayIP] |>>
Also the received packet is affected
print(repr(rx))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [1], in <module>
----> 1 print(repr(rx))
NameError: name 'rx' is not defined
Define a payload class
class DBI_IP(Packet):
name = 'DataByIdentifier_IP_Packet'
fields_desc = [
ByteField('ADDRESS_FORMAT_ID', 0),
IPField('IP', 0),
IPField('SUBNETMASK', 0),
IPField('DEFAULT_GATEWAY', 0)]
Connect
RDBIPR
with new payload class
bind_layers(UDS_RDBIPR, DBI_IP, dataIdentifier=0x172a)
Enjoy your new packet parser (
show2()
is called to rebuild the packet)
rx[0].show2()
###[ UDS ]###
service = ReadDataByIdentifierPositiveResponse
###[ ReadDataByIdentifierPositiveResponse ]###
dataIdentifier= GatewayIP
###[ DataByIdentifier_IP_Packet ]###
ADDRESS_FORMAT_ID= 0
IP = 192.168.17.151
SUBNETMASK= 255.255.255.0
DEFAULT_GATEWAY= 192.168.17.1
Get all possible packets of a layer in Scapy
explore("scapy.contrib.automotive.uds")
Packets contained in scapy.contrib.automotive.uds:
Class |Name
-----------|-----------------------------------------------
UDS |UDS
UDS_ATP |AccessTimingParameter
UDS_ATPPR |AccessTimingParameterPositiveResponse
UDS_AUTH |Authentication
UDS_AUTHPR |AuthenticationPositiveResponse
UDS_CC |CommunicationControl
UDS_CCPR |CommunicationControlPositiveResponse
UDS_CDTCI |ClearDiagnosticInformation
UDS_CDTCIPR|ClearDiagnosticInformationPositiveResponse
UDS_CDTCS |ControlDTCSetting
UDS_CDTCSPR|ControlDTCSettingPositiveResponse
UDS_DDDI |DynamicallyDefineDataIdentifier
UDS_DDDIPR |DynamicallyDefineDataIdentifierPositiveResponse
UDS_DSC |DiagnosticSessionControl
UDS_DSCPR |DiagnosticSessionControlPositiveResponse
UDS_ER |ECUReset
UDS_ERPR |ECUResetPositiveResponse
UDS_IOCBI |InputOutputControlByIdentifier
UDS_IOCBIPR|InputOutputControlByIdentifierPositiveResponse
UDS_LC |LinkControl
UDS_LCPR |LinkControlPositiveResponse
UDS_NR |NegativeResponse
UDS_RC |RoutineControl
UDS_RCPR |RoutineControlPositiveResponse
UDS_RD |RequestDownload
UDS_RDBI |ReadDataByIdentifier
UDS_RDBIPR |ReadDataByIdentifierPositiveResponse
UDS_RDBPI |ReadDataByPeriodicIdentifier
UDS_RDBPIPR|ReadDataByPeriodicIdentifierPositiveResponse
UDS_RDPR |RequestDownloadPositiveResponse
UDS_RDTCI |ReadDTCInformation
UDS_RDTCIPR|ReadDTCInformationPositiveResponse
UDS_RFT |RequestFileTransfer
UDS_RFTPR |RequestFileTransferPositiveResponse
UDS_RMBA |ReadMemoryByAddress
UDS_RMBAPR |ReadMemoryByAddressPositiveResponse
UDS_ROE |ResponseOnEvent
UDS_ROEPR |ResponseOnEventPositiveResponse
UDS_RSDBI |ReadScalingDataByIdentifier
UDS_RSDBIPR|ReadScalingDataByIdentifierPositiveResponse
UDS_RTE |RequestTransferExit
UDS_RTEPR |RequestTransferExitPositiveResponse
UDS_RU |RequestUpload
UDS_RUPR |RequestUploadPositiveResponse
UDS_SA |SecurityAccess
UDS_SAPR |SecurityAccessPositiveResponse
UDS_SDT |SecuredDataTransmission
UDS_SDTPR |SecuredDataTransmissionPositiveResponse
UDS_TD |TransferData
UDS_TDPR |TransferDataPositiveResponse
UDS_TP |TesterPresent
UDS_TPPR |TesterPresentPositiveResponse
UDS_WDBI |WriteDataByIdentifier
UDS_WDBIPR |WriteDataByIdentifierPositiveResponse
UDS_WMBA |WriteMemoryByAddress
UDS_WMBAPR |WriteMemoryByAddressPositiveResponse
Get all fields of a packet
ls(UDS_RC)
Tester present sender
tps = UDS_TesterPresentSender(sock)
tps.start()
print("Do whatever you need to do")
tps.stop()
Security Access Seed
Security Access Key