Part 2 — CAN Bus Reverse Engineering With SocketCAN
Introduction
The objective of this article is to introduce some practical examples and approaches for reverse engineering a vehicle CAN bus network, using low cost tools and open source software.
In Part 1 we created a Virtual CAN interface (vcan0) in our Linux enviornment and used that interface to send and receive a CAN frame, using candump and cansend. In this part (Part 2) we are going to develop a very small C application which provides minimum code for using SocketCAN to send a CAN frame.
Getting started
We should have can-utils setup already, and depending on your previous activities you may already have build-essential setup. This package provides some essential development tools such as a C (software) Compiler, C (software) Libraries and make. Easy thing to do, is just get it
$ sudo apt-get install build-essential
super_easy_can_tx
I’ve created a github project called super_easy_can_tx which uses the (hardcoded) interface vcan0 to send a CAN frame. This application is not great and I would never use an application like this normally, however, the intention is to introduce several lines of code that will show how to make an application using SocketCAN.
Choose a favourite location for your development and download the zip, or alternatively clone the repository
$ cd ~/MyDevlopmentFolder
$ git clone https://github.com/davidevansg/super_easy_can_tx.git
Let’s look at the contents of super_easy_can_tx using the tree command
$ cd super_easy_can_tx
$ tree
The only files we’re really interested is main.c, with defs.h and Makefile supporting. There’s also some supporting scripts enable_vcan.sh and disable_vcan.sh which helps to automate the setup of a (virtual) CAN interface, which was discussed in Part 1.
main.c
It’s worth looking at main.c during this bit.
Important to note that we have to include the Linux CAN headers, note the Linux CAN related headers below.
The starting point of this application is the main function, which calls a function (CANIfcInit).
The function ‘CANIfcInit’ is tasked with creating a (SocketCAN) socket (line 7 below), checking if the nominated CAN interface IF_VCAN0 (vcan0 : see defs.h) exists (line 16 below), and binds the socket to the interface (line 25 below). Assuming there is no issue creating this socket, this function will return ‘SUCCESS’ (line 31 below), and is checked in the if statement (line 4 above). As this condition has been met, we can make and send a CAN frame using the function ‘MakeAndSendCANFrame’
As the socket has been created (accessible via the variable can_fd), we can use this along with the (socket) ‘send’ function to send a CAN frame.
A can_frame structure is declared as the variable ‘fra’ (line 3 below) which will be used to populate the elements of the CAN Frame structure. This structure definition can found here, but is essentially:
- can_id — The ID of the CAN Frame
- can_dlc — The length of the data array (0 .. 8 (CAN_MAX_DLEN))
- data — The data array
In this example the can_id element of the ‘fra’ structure is set to to 0x100 (line 5 below), and the can_dlc element of the ‘fra’ structure is set to 8 (CAN_MAX_DLEN) (line 6 below). The data array (fra.data[x]) has been commented out (not used in the application), and is just included for reference (more on this later).
The image below is a representation of what we have just created, note the values for can_id, can_dlc and how there is no values set in the data element.
Our element ‘fra’ now has enough information to send to the socket (and onto the Virtual CAN interface). Now we must use the send function, referring to the man(ual) for send it requires:
- Parameter 1: socket (can_fd we set up earlier in CANIfcInit)
- Parameter 2: payload buffer (bytes taken up by our fra structure)
- Parameter 3: length of the payload buffer (the sizeof the structure can_frame)
- Parameter 4: (optional) flags
Once this function is called it will return the amount of bytes written to this socket, arguably I should have used an signed integer for the variable ‘size’ (see line 4) but I’m really only interested in if the ‘fra’ structure has been sent. If the return value is not equal to the (expected) size of the can_frame structure (see line 19 below) I can assume the message has not been sent, otherwise, it will continue into the ‘else’ condition (see line 24) and Print the contents of the message to the user.
Building super_easy_can_tx
To build this application, navigate to the directory and run the make command
$ cd super_easy_can_tx
$ make
Running the tree command again we should now see an additional file named ‘super_easy_can_tx’ (see red in image below).
This is our executable created from main.c, defs.h and using the Makefile.
Running the application (ideally with another terminal running candump) will provide the following.
$ (Terminal 1) candump vcan0
// $ (Terminal 2) cd super_easy_can_tx
$ (Terminal 2) ./super_easy_can_tx
All this application will do is setup the socket to the interface vcan0 send 1 CAN frame with a can_id of 0x100 and a can_dlc of 8 to this interface, print the contents of the CAN frame to the user and quit the application. We are verifying this has been sent by also running candump in the image above.
It’s worth mentioning that we have some random data values (see B0|0x7D, B1|0x8B, B2|0xCB, B3|0xFA … in the image above, and data in candump above). As we are setting the can_dlc to 8, but not setting the data element of the can frame to anything, this array contains uninitialised (undefined) values. It’s unlikely this will cause a problem, as you should always know what you want to put in this array (and consequently determine the can_dlc), but a mismatch between the can_dlc and what you intend to populate the data array could produce unexpected behaviour, especially on a real vehicle.
If we were to change the can_dlc to a different value (e.g. 6), we would see 6 bytes in the CAN frame (as seen in the candump output below)
As can be seen below in the picture, data[6] and data[7] are not used at all, this is because can_dlc has been changed to 6, and only the first 6 data bytes (grouped in the blue line) are sent, leaving data[6] and data[7] unused.
In the next part, I will introduce periodic messaging, and send a CAN frame at a specific time interval, along with some data in the CAN frame.