In part 1 we looked at what CAN is and what the difference between CAN and OBDII traffic is on a vehicle network. In this part we’re going to look at simple reverse engineering techniques to determine which CAN IDs are of interest to us. For this exercise, we’d like to see if we can confuse the tachometer display.

First, we need to identify which ID Toyota is using for the Engine RPM on the CAN. Manufacturer specific IDs are not published so we’re going to have to figure it out ourselves. For this work, I hooked up my beaglebone canbus tool (you can build your own by following instructions here: Then I started my truck and let it run for about 15 seconds before powering it off. Dumping all CAN messages shows us a lot of traffic and it can be difficult to make sense of what’s going on. We’re going to use the unique_ids tool (part of the canbus-utils repo available at l to get a list of all of the IDs that were seen while the tool was running. My list was:


We need to do some filtering and looking at the data to identify which data bytes are of importance. We’re going to be using the watch_id tool that I wrote. Cheating, we’ll start by looking at ID 0x2C4. The bytes that change are color coded red for ease of display. Some fields may be a single byte, multiple bytes, or have multiple values in a bitmask.

$ node watch_id.js –id 0x2c4

The results from the tool were:


Looking at the results we can see that the first two bytes remained at zero until a point where they increase and remain steady at around 0x08CC (2252 decimal). The 5th byte goes from zero to 08 and then never changes. The last byte changes frequently. Later, the 4th byte changes from 0x10 to 0x0F.

We can figure that the first two bytes are a 16 bit integer, the 4th byte contains some kind of bitmask, the 5th likely contains a bitmask or flag, and the 4th is a single byte integer. Converting the first two bytes to a decimal integer we see that it appears to be a direct value of the current engine RPM which starts at 0, ramps up, and then settles lower as the engine comes to idle. We correlate this with the readout from the tachometer and can be pretty confident that we’ve found the RPM.

In this case, the RPM was a direct value. For other values (or even other manufacturers) there may be a static value or formula applied to get the proper result (e.g. RPM=bytes 1&2 + 1k). Now, we know the ID and packet formula for the RPM on the CAN. We can write a little tool that spams the bus with our “attack” messages in order to confuse the tachometer into displaying an incorrect value.