Ham radios are a fun way of learning how the radio spectrum works, and more importantly: they're embedded devices that may run weird chips/firmware! I got curious how easy it'd be to hack my Yaesu FT-70D, so I started doing some research. The only existing resource I could find for Yaesu radios was someone who posted about custom firmware for their Yaesu FT1DR.
The Reddit poster mentioned that if you go through the firmware update process via USB, the radio exposes its Renesas H8SX microcontroller and can have its flash modified using the Renesas SDK. This was a great start and looked promising, but the SDK wasn't trivial to configure and I wasn't sure if it could even dump the firmware... so I didn't use it for very long.
I'm going to assume that the file specific to the FT-70D, "FT-70D_ver111(USA).exe", will likely contain our firmware image. A PE file (.exe) can contain binary resources in the .rsrc section -- let's see what this file contains using XPEViewer:
Resources fit into one of many different resource types, but a firmware image would likely be put into a custom type. What's this last entry, "23"? Expanding that node we have a couple of interesting items:
RES_UPDATE_INFO looks like just binary data -- perhaps this is our firmware image? Unfortunately looking at the "Strings" tab in XPEViewer or running the strings utility over this data doesn't yield anything legible. The firmware image is likely encrypted.
Let's load the update utility into our disassembler of choice to figure out how the data is encrypted. I'll be using IDA Pro, but Ghidra (free!), radare2 (free!), or Binary Ninja are all great alternatives. Where possible in this article I'll try to show my rewritten code in C since it'll be a closer match to the decompiler and machine code output.
We know where the data is loaded by the application, so now we need to see how it's used. Doing static analysis from this point may be more work than it's worth if the data isn't operated on immediately. To speed things up I'm going to use a debugger's assistance. I used WinDbg's Time Travel Debugging to record an execution trace of the updater while it updates my radio. TTD is an invaluable tool and I'd highly recommend using it when possible. rr is an alternative for non-Windows platforms.
The decompiler output shows this function copies the RES_UPDATE_INFO resource to a dynamically allocated buffer. The qmemcpy() is inlined and represented by a rep movsd instruction in the disassembly, so we need to break at this instruction and examine the edi register's (destination address) value. I set a breakpoint by typing bp 0x406968 in the command window, allow the application to continue running, and when it breaks we can see the edi register value is 0x2be5020. We can now set a memory access breakpoint at this address using ba r4 0x2be5020 to break whenever this data is read.
We broke when dereferencing v2 and IDA has automatically named the variable it's being assigned to as Time. The Time variable is passed to another function which formats it as a string with %Y%m%d%H%M%S. Let's clean up the variables to reflect what we know:
The timestamp string is passed to sub_4082c0 on line 20 and the remainder of the update image is passed to sub_408350 on line 21. I'm going to focus on sub_408350 since I only care about the firmware data right now and based on how this function is called I'd wager its signature is something like:
I think we've found our function that starts decrypting the firmware! To confirm, we want to see what the output parameter's data looks like before and after this function is called. I set a breakpoint in the debugger at the address where it's called (bp 0x404842) and put the value of the edi register (0x2d7507c) in WinDbg's memory window.
Oof. This is substantially more complicated but looks like the meat of the decryption algorithm. We'll refer to this function, sub_407980, as decrypt_data from here on out. We can see what may be an immediate roadblock: this function takes in a C++ this pointer (line 5) and performs bitwise operations on one of its members (line 18, 23, etc.). For now let's call this class member key and come back to it later.
This function is the perfect example of decompilers emitting less than ideal code as a result of compiler optimizations/code reordering. For me, TTD was essential for following how data flows through this function. It took a few hours of banging my head against IDA and WinDbg to understand, but this function can be broken up into 3 high-level phases:
We now need to figure out how our key is set up for usage in the decrypt_data function above. My approach here is to set a breakpoint at the first instruction to use the key data in decrypt_data, which happens to be xor bl, [ecx + esi + 4] at 0x4079d3. I know this is where we should break because in the decompiler output the left-hand side of the XOR operation, the key material, will be the second operand in the xor instruction. As a reminder, the decompiler shows the XOR as:
The breakpoint is hit and the address we're loading from is 0x19f5c4. We can now lean on TTD to help us figure out where this data was last written. Set a 1-byte memory write breakpoint at this address using ba w1 0x19f5c4 and press the Go Back button. If you've never used TTD before, this operates exactly as Go would except backwards in the program's trace. In this case it will execute backward until either a breakpoint is hit, interrupt is generated, or we reach the start of the program.
Not a lot to see here except the same function called 4 times, initially with the timestamp string as an argument in position 0, a 64-byte buffer, and bunch of function calls using the return value of the last as its input. The function our debugger just broke into takes only 1 argument, which is the 64-byte buffer used across all of these function calls. So what's going on in sub_407e80?
The bitwise operations that look supsiciously similar to the byte to bit inflation we saw above with the firmware data. After renaming things and performing some loop unrolling, things look like this:
IDA thankfully supports disassembling the Hitachi/Rensas H8SX architecture. If we load our firmware into IDA and select the "Hitachi H8SX advanced" processsor type, use the default options for the "Disassembly memory organization" dialog, then finally choose "H8S/2215R" in the "Choose the device name" dialog...:
We don't have shit. I'm not an embedded systems expert, but my friend suggested that the first few DWORDs look like they may belong to a vector table. If we right-click address 0 and select "Double word 0x142A", we can click on the new variable unk_142A to go to its location. Press C at this location to define it as Code, then press P to create a function at this address:
Fusion is a new system and is still being developed. So far we have only seen the tip of what Fusion can do. Over the next few years, Yaesu will be releasing updates to the repeater and radios as well as producing new Fusion-capable equipment.
In the past when you bought an HT what you got was what you got - there was no way to update it. That has all changed. Because all of the firmware in your radio can be updated, the radio you bought today is capable of doing new things tomorrow.
The Fusion radios contain a custom integrated circuit that contains all of the C4FM signal processing. This chip takes the analog signal from the detector, converts it to digital, then through (mostly) hardware and firmware, decodes the signal into bits. These bits are either used by the Controller for display or other communications or
While most of the work is done in custom hardware, the chip also contains a general purpose Digital Signal Processor (DSP). The DSP allows the chip to be configured for different purposes (say DMR, MotoTrbo, Fusion, etc.). It also allows Yaesu to introduce new modes and make other improvements.
For the firmware and software, there will be a document generally describing the firmware version(s) and a compressed zip file. Note that the zip file may contain both the Controller Firmware and the DSP Firmware. In addition, it contains the specific instructions for installing the appropriate version. Print out these instructions and follow them step-by-step. Do not improvise!
This is the first in a series of three planned articles discussing the modification of Yaesu DR-1X repeaters for solid, link-ready analog FM or as a multi-mode digital voice repeater. The planned articles are:
This article will cover various considerations about the Yaesu DR-1X that would be common to any deployment scenario with an external controller, analog (such as Allstar) or digital (such as Pi-Star). All of the items below concern successful operations with either setup.
The DR-1XFR has firmware enhancements/changes that are incompatible with reasonable modifications to the repeaters. This author has never used a DR-2X but by all reports, the are completely locked down by Yaesu against modifications or outboard digital controllers.
Firmware string that lists other versions (e.g. 1.201) and, more importantly, lists a panel and DSP version in a line between the transmit and receive frequencies is a DR-1XFR and is not capable of modification for digital use.
All versions of V1.10 appear to have selectable wide/narrow deviation in the control panel despite the release notes stating that V1.10q is necessary. If for some reason your V1.10 unit does not have selectable wide/narrow, upgrade to V1.10q.
However some of the choices that went into the design and concept yielded mixed results. There were initial problems with the units blowing out the finals in the transmit when being run at full power which eventually caused Yaesu to stop marketing them as 50W at continuous duty. The other main issue is that the squelch is poor. This is important when dealing with weak or marginal signals. With a poor squelch, weak signals that would otherwise be readable are clipped out too quickly. The squelch is tunable like on most radios, but opening up the squelch more will result in long, loud squelch tails from strong signals. One of the original primary reasons to modify the DR-1X was to fix this problem.
c80f0f1006