Renesas RH850 Attacks (Part 2 of 7)
April 8th, 2025 by Brian
Work conducted by Ibrahima Keita.
Target Introduction: The Renesas RH850
Continuing our 7-part series on attacking the Renesas RH850.
Renesas RH850
The Renesas RH850 is a 32-bit RISC CPU by Renesas Electronics. It is a refresh of the NEC V850, and has been developed by Renesas as of 2018. It is commonly utilized in the automotive industry, and has a CAN interface, I2C, and UART support. It also has a main oscillator with variable clock speed (16/20/24 MHz), and is easily programmable and readable with the Renesas E1 Flash Programmer and E2 Studio.

The RH850 also contains an embedded flash region that stores both code and data. The exact size of this flash depends on the version of the RH850 you have, as they can come in 6MB, 8MB, and other variants.
Furthermore, it also has a series of protections that the developer can enable, preventing unauthorized access to the processor. As shown below, the protections are one-time password, ID authentication, and a disabled programming mode.

Communicating with an RH850
The Renesas E1 programmer is the intended tool for provisioning and programming an RH850. The pinout for its connector can be found below:
All communication to the RH850 from the E1 programmer uses the Universal Asynchronous Receiver-Transmitter (UART) protocol, which is a two-wire protocol allowing for information exchange between devices. This means that any device that can talk UART at the same baud rate that the RH850 expects should be able to act as a programmer.
This also means that using a logic analyzer (such as the Saleae Logic) allows us to easily sniff the traffic between the programmer and an RH850, allowing us to gain a deeper understanding of what exactly is being sent. As such, I was able to emulate an E1 programmer performing a memory read by performing logic captures and writing a Python library to send out the expected packets.
Documentation on how the connection is established, and how a flash read is performed, can be found below.
Notation & Structures
Before proceeding onwards, I will define data structures which will be heavily used in the workflows shown below.
Packets
Every packet has a basic structure, expanded upon by the specific process that utilizes it. The serialized structure is as follows:
struct RH_PACKET {
uint8_t Begin;
uint16_t Length;
uint8_t Index_Result;
uint8_t Parameters[Length - 1];
uint8_t Checksum;
uint8_t End;
}
Please note: the packet itself uses big endian, meaning the most significant byte will appear first in memory.
RH_PACKET.Begin
- Each (serialized)
RH_PACKET
starts with either01
or81
.- When the serialized packet starts with
01
, this is what is known as aRH_COMMAND
packet. - When the serialized packet starts with
81
, this is what is known as aRH_DATA
packet. This is the result of0x1 | RH_ISDATA
, whereRH_ISDATA
is0x80
.
- When the serialized packet starts with
RH_PACKET.Length
- The value of this field represents how many bytes are left to expect from the communication channel. This value should be, at minimum, 1.
RH_PACKET.Index_Result
- The value of this field depends on the purpose of the packet.
- In a
RH_COMMAND
packet (RH_PACKET.Begin == 0x1
), this specifies the command index. Here are some of the commands.
- In a
Command code | Command name | Description |
---|---|---|
0x00 | Inquiry command | Return ACK (to determine the current phase) |
0x12 | Erase command | Erase data on target area |
0x13 | Write command | Write data on target area |
0x15 | Read command | Read data on target area |
0x30 | ID authentication command | Authenticate ID for connection with the device |
0x34 | Baud rate setting command | Set baud rate for UART |
0x3A | Signature request command | Get signature information |
0x3B | Area information request command | Get area information |
- In a
RH_DATA
packet (Begin == 0x81
), this specifies the result number.RH_DATA
is utilized for acknowledgements, errors, and flash contents. Below is a list of the possible result codes.
Status code | Description |
---|---|
0x00 | Command code | OK (ongoing normally): used in Response code [RES] |
0x80 | Command code | ERR (occurrence of an error): used in Response code [RES] |
0x00 | OK (successful completion) |
0xC0 | Unsupported command error |
0xC1 | Packet error (Illegal length, Missing ETX, and so forth) |
0xC2 | Checksum error |
0xC3 | Flow error |
0xD0 | Address error |
0xD4 | Baud rate margin error |
0xDA | Protection error |
0xDB | ID mismatch error |
0xDC | Serial programming disable error |
0xE1 | Erase error |
0xE2 | Write error |
0xE7 | Sequencer error |
RH_PACKET.Parameters
- In a
RH_COMMAND
packet (Begin == 0x1
), this represents the parameters for each command. Each command has different parameter sizes (as some commands have no parameters, some have many parameters). - See the Renesas Documentation to identify most of the parameters.
RH_PACKET.Checksum
- The value of the checksum is a trivial calculation.
- Compute the 8-bit sum for for the
length
,result/index
, andparameters
bytes, allowing overflow. Call this value k. - Calculate the two’s complement of k, by inverting all of its bits and adding 1; call this k′.
- The checksum is now k′. Use this for a value.
- Compute the 8-bit sum for for the
RH_PACKET.End
- Always
0x3
, irrespective of the packet type.
Connecting to the RH850 & Performing a Flash Read
This will describe how to communicate with an RH850 via UART, and how to perform a flash read with it.
Handshake
The following sequence must happen before the flash programmer starts responding to commands. This forces the processor to change its mode to some command processing mode. This will be the expected flow, given the chip’s FLMD0
line is pulled high to VCC
.
sequenceDiagram Programmer->>+RH850: [00 00 00 00 00 00 00 00 00 00] RH850->>+Programmer: [00] Programmer->>+RH850: [55] RH850->>+Programmer: [C1]
Establishing a Connection & Getting Into Command Acceptance Mode
Before the RH850 can communicate properly with the E1 programmer, we need to set connection parameters. The following workflow is how it is done.
Register Request
First, request registers from the chip.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<REG_REQ>() RH850->>+Programmer: RH_DATA<REG_REQ>(SUCCESS) Programmer->>+RH850: RH_DATA<REG_REQ>(ACK) RH850->>+Programmer: RH_DATA<REG_REQ>(ACK)
Frequency Set
Next, set the frequencies of the chip.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<SET_FREQ>(OC = 0xF42400, CC = 0x07270E00) RH850->>+Programmer: RH_DATA<SET_FREQ>(SUCCESS) Programmer->>+RH850: RH_DATA<SET_FREQ>(ACK) RH850->>+Programmer: RH_DATA<SET_FREQ>(ACK)
Baud Rate Set
Then, set the baud rate. (0xF4240 = 1000000 bps
).
sequenceDiagram # Change Frequency Programmer->>+RH850: RH_COMMAND<SET_BAUD_RATE>(NewBaud = 0xF4240) RH850->>+Programmer: RH_DATA<SET_BAUD_RATE>(SUCCESS)
Inquire
Confirm we are in the new mode.
Note: The results of this operation depend on whether or not serial programming is enabled. If serial programming is enabled, then sending an inquiry packet will result in a success message, as shown below.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<INQUIRE>() RH850->>+Programmer: RH_DATA<INQUIRE>(SUCCESS)
However, if serial programming is disabled, then this message will appear, telling us that the RH850 will refuse to let us communicate with it, as shown below.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<INQUIRE>() RH850->>+Programmer: RH_DATA<INQUIRE>(SERIAL_PROGRAMMING_DISABLED)
Command Acceptance Mode
Tell the chip to accept commands.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<COMMAND_ACCEPTANCE>() RH850->>+Programmer: RH_DATA<COMMAND_ACCEPTANCE>(SUCCESS) Programmer->>+RH850: RH_DATA<COMMAND_ACCEPTANCE>(ACK) RH850->>+Programmer: RH_DATA<COMMAND_ACCEPTANCE>(ACK)
ID Authentication
This following command is optional, and is only needed if the RH850 has a stored ID. If it does not have an ID, the chip will be ready to accept commands. Otherwise, this command needs to be sent to allow for communication.
From here, we need to send the ID command, with our ID as a parameter.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<ID_AUTHENTICATION>(ID) RH850->>+Programmer: RH_DATA<ID_AUTHENTICATION>(SUCCESS) Programmer->>+RH850: RH_DATA<ID_AUTHENTICATION>(ACK) RH850->>+Programmer: RH_DATA<ID_AUTHENTICATION>(ACK) (if ID matches) RH850->>+Programmer: RH_DATA<ID_AUTHENTICATION>(NACK) (if ID does not match)
From here on out, the chip will maintain the state, and go into command acceptance mode.
Flash Read
Now that we have established a connection, let us attempt to perform a flash read. Request the signature from the processor.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<SIGREQ>() RH850->>+Programmer: RH_DATA<SIGREQ>(SUCCESS) Programmer->>+RH850: RH_DATA<SIGREQ>(ACK) RH850->>+Programmer: RH_DATA<SIGREQ>(ACK)
Don’t know what this command does either, but my educated guess is that it will allow for reading of the flash data.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<UNKNOWN_71>(Param = 0xFF) RH850->>+Programmer: RH_DATA<UNKNOWN_71>(SUCCESS)
After this, we can start requesting data from regions of memory. You can request blocks of memory between an address range. My understanding is that we can only get 0x400 bytes at a given time. So, you can just keep doing the process below until you get all the data you requested.
sequenceDiagram Programmer->>+RH850: RH_COMMAND<READ>(LowAddress = <LowerBound>, HighAddress = <HigherBound>) RH850->>+Programmer: RH_DATA<READ>(SUCCESS) Programmer->>+RH850: RH_DATA<SIGREQ>(ACK) RH850->>+Programmer: RH_DATA<RAW>() Programmer->+RH850: ... Programmer->>+RH850: RH_DATA<SIGREQ>(ACK) RH850->>+Programmer: RH_DATA<RAW>()
If all goes well, the packet you receive from here you should have the data sent to you, and you can parse it accordingly.
Revisiting the Security Features
As seen in the workflow for connecting and performing a flash read, there are two major immediate obstacles.
- The device will refuse to let us communicate if serial programming is disabled (see the Inquire command flow).
- If an ID was provisioned, it needs to be sent in order to unlock the device for reading and writing.
Even before we get to the ID, let us address the serial programming ability. Now, I find it very weird that the device will tell us over serial that we cannot communicate with it over serial, especially after we already sent data to it. Imagine asking someone if they can hear you, and they say no; that’s exactly what’s happening here. So, clearly it is contradictory.

But what if we could somehow get the device to believe that it can in fact communicate with us? For it to know that it cannot communicate with us, there has to be some value stored somewhere that lets it make that decision. Of course, it will not let us communicate with it, so we cannot just send a command to change that value. However, what if we could somehow mess with the logic it uses to determine that, which would allow us to further communicate with it?
Furthermore, if we could potentially mess with the logic for the serial programming check, could we extend that to bypass the ID authentication restriction (if it exists)?
These two questions were what we sought to answer during the course of this project. We want to bypass the serial programming protection and ID authentication features, but for that, we’re going to need a little bit of help.
We know the software might be secure, but what about the hardware itself? What if we attempt to utilize the laws of physics against the hardware, and force it to behave differently, perhaps in our favor? With these ideas in mind, we started looking at potential hardware attacks, which we start to detail in the next few blog posts.
On to Part 3, side-channel attacks and fault injection.