Makita Battery Hacking - Part 1

Makita batteries feature a built-in safety mechanism that declares a battery as dead once it has failed to charge three times consecutively. This can lead to functional batteries being rendered useless if they are attempted to be charged in conditions that are not optimal, such as when they are cold or undercharged. The objective of this project is to investigate the mechanism behind this feature and determine if it is possible to revive the controller by replacing faulty cells.

Makita batteries have utilized different microcontrollers over the years, starting with the NXP MC68HC908JL3E and later the NEC (now Renesas) F0513. This study will focus on the latter, a controller from the NEC78K0 series that lacks a read function. As such, a creative approach must be taken to recover the firmware. The process involves creating a read function in unused memory of the controller, and then directing the controller to that piece of code. This code will output all of the memory of the controller via the serial interface. Fortunately, the controller has the capability to erase and verify single blocks of memory, allowing for the identification of empty blocks. In order to run our code, we must alter the reset vector to point to our code instead of the original entry point. This can be achieved through a technique known as a "NOP slide". By writing the reset vector bytes to 0x00 (NOP instruction), the controller will slide into untouched memory, where a JMP instruction can be inserted to point to our code.

The process of memory dumping involves creating a read function in unused memory of the controller and then directing the controller to that specific code. This code will output all of the memory of the controller on the serial interface. The controller has the ability to erase and verify individual blocks of memory, allowing us to determine if and which blocks are empty. To run our code, we need to set the reset vector to our code instead of the original entry point. This can be accomplished through the use of a NOP slide. By writing the reset vector bytes to 0x00 (NOP instruction), the controller will slide into untouched memory where we can insert a JMP instruction to our code.

For example, we can use flash-util to determine if there are any empty blocks. In this case, block 17 was empty, providing an ideal location for our code. I then created a simple program in assembly to print the memory. This program was created using a serial example by Renesas and will be cleaned up and made available on Github at a later date. The code fits into one block.

10 20 FB 99 1C 13 6F 00 13 FB 00 13 A0 02 A1 A0 
51 BD FD 13 FB 00 11 01 00 13 21 E7 11 20 63 11 
21 CA 10 00 00 D6 A2 80 A3 00 A1 52 9A A7 44 A1 
4F 9A A7 44 A1 4D 9A A7 44 A1 44 9A A7 44 A1 55 
9A A7 44 A1 4D 9A A7 44 A1 50 9A A7 44 66 5D 0F 
BD 10 9A 78 44 67 9A 82 44 66 9A 82 44 A1 3A 9A 
A7 44 A1 20 9A A7 44 87 9A 82 44 86 8B DF 9A 78 
44 8A DA 9A 78 44 FA FE A1 0D 9A A7 44 A1 0A 9B 
A7 44 9A 8C 44 9A A7 44 60 9B A7 44 70 5D 0F 0D 
30 4D 3A 8D 02 0D 07 30 24 24 24 24 5D 0F 0D 30 
4D 3A 8D 02 0D 07 AF B3 7B 1E 3B 01 4B 01 A3 0A 
9A B9 44 8B FB 4A 01 B2 AF F2 22 F0 21 83 22 20 
25 04 22 FD 8D 03 3B 01 AF 3A 01 AF FF FF FF FF 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF

We can then flash this "trojan" memory print binary into block 17, as this was an empty block in the Makita battery. After the program is recovered, we can analyze a dump of the first block. It is worth noting that we may not know what the first block looks like, so we must make an educated guess as to how many NOPs to include in our slide before inserting the jump instruction. But, as seen in the case of the Makita battery, there is ample space for it.

00 00 00 00 00 00 00 00 00 00 00 00 00 9B 00 44 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
00 08 10 08 09 08 1D 04 FF FF FF FF FF FF FF FF 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 
7E 01 00 00 00 13 C0 A5 13 C4 01 13 C4 FE 13 C4 
01 AF 13 C0 A5 13 C4 00 13 C4 FF 13 C4 00 AF 22 
B1 61 F8 B6 A2 00 9A 00 81 A1 09 BE 13 BE 14 23 
AF B5 B7 D6 AE 00 70 AE 01 30 72 A1 00 B6 22 B1 
B3 B7 61 F8 B0 BE 05 60 BE 04 B0 BE 03 60 BE 00 
B0 BE 02 60 BE 01 A2 04 9A 00 81 23 F0 E3 B4 AF 
33 22 B1 61 F8 B0 BE 03 A2 06 9A 00 81 23 F0 E3 
AF 22 61 F8 A2 0E 9A 00 81 23 F0 E3 AF 33 22 B1

The code is currently available on Github, although it requires some cleaning up and additional functionality.

Contact me