DBC#
DBC is a file format to describe datafields in CAN frames
OEM specified to encode information into can frames
Information is compressed very space efficient (example 13 Bit Speed, 4 bits gear etc.) since original CAN has only 8 byte payload
DBC files are used to automatically generate c files that send the messages
Example:
B0_
defines a CAN-frame of length 8 with the identifier 341 as data objectBMS_1
.This data object contains three different signals,
SG_climit
,SG_current
, andSG_soc
.The signal
SG_climit
contains the following definitions:7|8
: This signal starts at bit position 7 and has a length of 8 bits.@0+
: The endianess of the signal is big-endian and the transferred value is unsigned.(5,0)
: The transferred value has a scaling factor of 5 and the offset value 0.[0|35]
: The transferred value has a value range from 0 to 35.“A”
: The unit of the transferred value is labeled with “A”.
Signal fields can be located at any position in a CAN frame
BO_341 BMS_1: 8 XXX
SG_climit : 7|8@0+ (5,0) [0|35] "A" XXX
SG_current: 11|12@0+ (-0.25,500) [-500|1000] "A" XXX
SG_soc : 39|16@0+ (0.0025,0) [0|100] "%" XXX
Future versions are part of ARXML (AUTOSAR XML) (*. arxml)
DBC tools#
SavvyCAN has a graphical editor for DBC files and can analyze CAN frames in real time https://www.savvycan.com/
The cantools project has a commandline representation of CAN frames and allows the creation of graphs eerimoq/cantools
canmatrix is a useful tool to convert DBC files in various other formats, e.g. Wireshark dissectors ebroecker/canmatrix
dbcc is a project that allows the creation of C code for build and dissect howerj/dbcc
DBC support in Scapy#
SignalPacket objects can be used to define DBC data objects
SignalField and derivatives allow the definition of DBC signals
BO_ 4 muxTestFrame: 7 TEST_ECU
SG_ myMuxer M : 53|3@1+ (1,0) [0|0] "" CCL_TEST
SG_ muxSig4 m0 : 25|7@1- (1,0) [0|0] "" CCL_TEST
SG_ muxSig3 m0 : 16|9@1+ (1,0) [0|0] "" CCL_TEST
SG_ muxSig2 m0 : 15|8@0- (1,0) [0|0] "" CCL_TEST
SG_ muxSig1 m0 : 0|8@1- (1,0) [0|0] "" CCL_TEST
SG_ muxSig5 m1 : 22|7@1- (0.01,0) [0|0] "" CCL_TEST
SG_ muxSig6 m1 : 32|9@1+ (2,10) [0|0] "mV" CCL_TEST
SG_ muxSig7 m1 : 2|8@0- (0.5,0) [0|0] "" CCL_TEST
SG_ muxSig8 m1 : 0|6@1- (10,0) [0|0] "" CCL_TEST
SG_ muxSig9 : 40|8@1- (100,-5) [0|0] "V" CCL_TEST
BO_ 3 testFrameFloat: 8 TEST_ECU
SG_ floatSignal2 : 32|32@1- (1,0) [0|0] "" CCL_TEST
SG_ floatSignal1 : 7|32@0- (1,0) [0|0] "" CCL_TEST
from scapy.all import *
from scapy.layers.can import *
from scapy.contrib.cansocket import *
class muxTestFrame(SignalPacket):
fields_desc = [
LEUnsignedSignalField("myMuxer", default=0, start=53, size=3),
ConditionalField(LESignedSignalField("muxSig4", default=0, start=25, size=7), lambda p: p.myMuxer == 0),
ConditionalField(LEUnsignedSignalField("muxSig3", default=0, start=16, size=9), lambda p: p.myMuxer == 0),
ConditionalField(BESignedSignalField("muxSig2", default=0, start=15, size=8), lambda p: p.myMuxer == 0),
ConditionalField(LESignedSignalField("muxSig1", default=0, start=0, size=8), lambda p: p.myMuxer == 0),
ConditionalField(LESignedSignalField("muxSig5", default=0, start=22, size=7, scaling=0.01),
lambda p: p.myMuxer == 1),
ConditionalField(LEUnsignedSignalField("muxSig6", default=0, start=32, size=9, scaling=2, offset=10, unit="mV"),
lambda p: p.myMuxer == 1),
ConditionalField(BESignedSignalField("muxSig7", default=0, start=2, size=8, scaling=0.5),
lambda p: p.myMuxer == 1),
ConditionalField(LESignedSignalField("muxSig8", default=0, start=3, size=3, scaling=10),
lambda p: p.myMuxer == 1),
LESignedSignalField("muxSig9", default=0, start=41, size=7, scaling=100, offset=-5, unit="V"),
]
class testFrameFloat(SignalPacket):
fields_desc = [
LEFloatSignalField("floatSignal2", default=0, start=32),
BEFloatSignalField("floatSignal1", default=0, start=7)
]
bind_layers(SignalHeader, muxTestFrame, identifier=0x123)
bind_layers(SignalHeader, testFrameFloat, identifier=0x321)
dbc_sock = CANSocket("vcan0", basecls=SignalHeader)
pkt = SignalHeader()/testFrameFloat(floatSignal2=3.4)
pkt.show2()
hexdump(pkt)
dbc_sock.send(pkt)
###[ SignalHeader ]###
flags =
identifier= 0x321
length = 8
fd_flags =
reserved = 0
###[ testFrameFloat ]###
floatSignal2= 3.4000000953674316
floatSignal1= 0.0
0000 00 00 03 21 08 00 00 00 00 00 00 00 9A 99 59 40 ...!..........Y@
16
DBC reverse engineering#
The knowledge about DBC definitions is necessary for any attacks on vehicle functions
Reverse-Engineering methods:
Live-Monitoring:
Sniff traffic on the bus
Perform a defined action on the vehicle (e.g. Press a button)
Check for changes in the monitored traffic
New IDs? New CAN-Data?
Statistical Reverse Engineering [Sto18]
TAV (Transistion Aggregation Vector)#
Let the vector \(\mathbf{x}:=(b_{63}, b_{62}, \dots, b_0) \in \mathbb{F}_2^{64}\) define the data bits of a CAN-frame.
The matrix \(\mathbf{X}\) represents all CAN-data frames of an entire log file. The TAV of all data bits is computed by the following equation: