m22_ghidra_psoec gd_77_ramdumpI suspect a lot of you are thinking, what on earth is Ghidra
Well, that was my thought 2 days ago, when I was informed by Kai, DG4KLU that a open source reverse engineering tool, developed by the NSA had just been released to the public.
For more details visit https://ghidra-sre.org/
This is great news in relation with reverse engineering the GD-77 firmware, because Ghidra has a lot of the features, previously only available in very expensive programs like IDA Pro.
Armed with Ghidra, I have started to explore the internals of the firmware.
There are multiple ways to attempt to understand what each function does in the firmware, but one way is to work backwards from the hardware registers in the MK22 MCU, which do things like send data to the AT1846 RF transceiver chip, and to the external SPI Flash memory, the external EEPROM and also the keypad and the screen.
The memory addresses of these registers is documented in the reference document for the MK22, but since there are over 1300 registers, manually correlating each memory address in found in the firmware back to its name and function in the reference, would take forever.
Luckily I found out that its possible to create a Processor Specification (PSPEC) file for any microprocessor and use it when the firmware binary is imported into Ghidra
However, getting data on all 1300 registers, from the PDF reference document into the XML PSPEC file required a number of stages of manual and automatic processing, which I won’t bore you all with at the moment.
But eventually, I was able to use my newly minted PSPEC file to annotate all the disassembled and decompiled firmware code.
For example here, is some code which interacts with the SPI interface (though at the moment I don’t know which SPI device or what its sending or receiving)
Ghidra is also capable of decompiling to C code, and even though this could could not be recompiled back into a working version of the firmware, its a great way to get a better idea of what each function does
(this is not the same function as show in the disassembly view in the image above)
And there are also graphic features available to show the hierarchy of functions
And also Function Graphs
Not to get anyone’s hopes up, because there is still a big mountain to climb, in terms of understanding the internal workings of the firmware, so that it can be enhanced or bug fixed, but it does look like things will be a bit easier by using Ghidra
Update.
As requested by various people. Here is my PSPEC file for the MK22 processor.
Note I just added the hardware registers. I have not had time to add processor specific ISR vectors, but they would be easy to add
Also. I’ve taken some more memory snapshots, including these 2, one during transmission and one when receiving a signal from VK4NBL
So here are those files
Note.
My DMR ID is 5053238 (and my callsign is VK3KYY)
I’m pretty sure VK4NBL’s id is 5054068
Note. To import the memory snapshots, you have to press ALT+I which then appends / merges the file to the existing memory map
Don’t forget to use offset 0x1fff0000 when importing the RAM snapshot
In firmware 3.1.8
Using the memory dumps I have found a few interesting memory addresses
I’m now sure that the current channel data structure is located at 0x1fff3a04, or possibly a bit lower in the memory
0x1fff3a04 upper byte seems to be a flag, as its set to 0x05 when I’m on channel and 0x90 when I’m on a VFO
The next remaining 3 bytes are the Tx TG.
And the Rx Group list starts at 0x1fff3a08
If I change 0x1fff3a04 then press PTT it transmits on the TG I specified.
And…
It looks like the function at address 0x27b52 is called constantly, and if the memory location pointed to by register r1 is contains 0x0F, it seems to indicate that a signal has been received.
So if you put a break point on 0x27b5a the code only halts when there is a new signal received.
Looking at what references the function at 0x27b52, I found this
PTR_LAB_00027b8c+1_00027f50 XREF[1]: FUN_00027b90:00027cd0(R)
00027f50 8d 7b 02 00 addr LAB_00027b8c+1
00027f54 91 7b 02 00 addr FUN_00027b90+1
00027f58 53 7b 02 00 addr FUN_00027b52_event_loop+1
(I labelled the function at 0x27f58 with the extra text “_event_loop” , to make it easier to find, but I should have probably called it “_task”, as it looks like these 2 functions are possibly the top level task list which is bring run by the RTOS.)
Update..
Jason VK7ZJA has kindly sent me a list of what all the pins on the MK22 MCU seem to be connected to.
You can download the text file from here MK22 connections GD-77
Hopefully this will help getting to grips with the firmware
ken
wow that looks great
r00tstar
Please share the definition file and link to the register PDF if possible.
Roger Clark
I will add it to the Ghidra post
Roger Clark
I’ve also updated the post with 2 more memory dumps and also some interesting infromation, including where the current channel data is stored.
I have successfully been able to change the Tx TG, using the debugger to change the contents of a memory address, which should lead the way to allow direct entry of TG e.g by pressing something like * in front of the number, in the same way that private calls can be made by prepending with #.
However at the moment I don’t know which code handles the keypad data input.
I will try making some private calls and see if I can work out what data is different. In theory I think the only difference between a Private and Group call is some flags in the DMR
I have also been trying to find the display routines, but I can’t seem to cross reference the texts e.g. “Contact” with any code that uses those strings.
It looks like there is a strings table, but even if I look for references to the start of the strings table, I don’t get any luck.
Perhaps they use some sort of menu definition structure with indexes into the strings table and function pointers to the handlers ?
I was also looking for the code that handles the DMR ID lookup, but I’ve not found that yet either. I’m really keen to find the DMR ID function, as I want to increase the storage from 8 characters to 16, so that the DMR ID can store both callsign and name.
I think , the DMR ID system currently uses 12 byte records, with 4 bytes for DMR ID and 8 bytes for callsign (I need to double check this), so a total of 12 bytes per entry
So in theory it would be a simple change to change this to 16, but I can’t find any code that uses the number 12 in its calculations
I know the DMR ID list, is pre-sorted by DMR ID by the CPS (or ActiveClient), so the code must be finding the data by using the least squares algorithm, so is probably doing things by reading in 2 records, which are half the total number of records apart, and then based on that comparison, reading in another record , which is half of the half apart etc
I will try loading some test data into my DMR ID data, and take another memory snapshot and see if I can find any telltale signs in the memory which may lead back to the code.
Note. My previous memory snapshots are using the Digital Contacts to lookup the Callsign and name, as the DMR ID database is empty
Roger Clark
I’ve realised that I had not added the MK22 hardware specific ISR’s to the PSPEC file
I’ll need to upload that file again, but actually, it doesnt make any difference because all vectors point to the same handler function, which must be because the firmware uses an RTOS, and the RTOS handles what happen when each ISR is triggered
r00tstar
Looks like you posted the processor file twice instead of more dumps. The menu is at 0x0002D498 in the full rom dump. It loads the strings to ram and then puts a pointer to them. So “contact” is at 0x740E4 which points to 0x1FFF0894. I think there is more than one instance of this and its used as a lookup function so nothing is calling the strings directly. Heh, in ghidra it actually did a better job than in ida of illustrating this.
Roger Clark
Argghh
OK
I’ll check and repost
Roger Clark
I think I linked to the same file twice, try downloading the ram dump file again
Roger Clark
I’ve also updated the PSPEC ZIP to include the ISRs (but I’ve not tested it )
But all the ISR’s go to the same handler function, so its not worth re-importing if you’ve already used it.
r00tstar
We should make a wiki or github list with all of these addresses and explanations. When they add up release a symbols file like MD380.
r00tstar
The radio is running Freescale MQX RTOS: https://cache.freescale.com/files/32bit/doc/ref_manual/MQX_Reference_Manual.pdf
r00tstar
MQX source code, I don’t know if the versions match: https://github.com/wk2325272/MQX_3.8.1
Roger Clark
Thanks
I noticed the firmware uses the MQX RTOS, because of the file path strings I saw in the binary.
Because it’s a RTOS, it’s making it harder to reverse engineer, as there are at least 2 top level tasks running and they probably sporn other tasks as necessary.
I found a function pointer list, which may contain the top level list, but it was a bit confusing as there seemed to be 3 items in the list, 2 of which where tagged by Ghidra as functions and one was tagged as a label, to a point inside a function. However Ghidra may have made a mistake and the label may be a function in its own right, or perhaps the list I found was not what I thought it was.
I will look at the MD380Tools repo and see how they organised their wiki and create something similar for this.
I have found what a few more functions do in the code, including 2 of the functions which seem to be part of the display handling.
If you search for %s or %d there are multiple strings that look like they are formatting for printf or sprintf.
There are at least 2 of these, but I am not sure if they handle the formatting and displaying of the text, e.g. something like “%s\n%s” is used to display the current zone and channel.
What I am struggling to find is how the code interacts with the hardware. Both the AT1846S transceiver chip and the EEPROM are connected via I2C , the external Flash is connected via SPI, and I think the C6000 is also connected via SPI ( but possibly on a different channel)
However putting breakpoints in any function which references the I2C registers only causes the code to break during initialisation
I noticed that for the SPI, the base address of the SPI controller is passed to a function, which appears to setup a struct, and I suspect the struct is used by other functions.
Also, looking at the MK22 SDK , there is a hierarchy they use a hierarchy of base addresses and offsets, which is probably why Ghidra can’t many find hard coded addresses to the SPI or other hardware.
I am going to try setting some hardware watchpoints using the debugger, on the registers for the SPI0 controller and see whether GDB , the debugger and the MK22 it’s self is capable of causing the debugger to break on access to these internal hardware register addresses.
Since I don’t have elf files for the code, I am having to operate GDB from the command line, and manually referring back to Ghidra .
It’s a shame that Ghidra does not have an interface to GDB. But I posted an issue, and they confirmed it does not …
I have also been looking for where the code does the DMR ID lookup, but have not found it.
The base address of the DMR ID in the external flash is 0x30000, and I found multiple reference to this address, but some of them are unrelated, as they just seem to be the bit pattern needed for the clock control registers
I did find one place in the code which used 0x30000 which seemed to get called when there was an incoming signal, but it seemed to be called at least 15 times, which is far more times than would be needed to find a record in the DMR ID database, assuming it uses a least squares algorithm , and I only have 3000 entries in the DMR ID DB.
So I will need to look elsewhere for the DMR ID lookup
Roger Clark
I just added you as a collaborator on my Github Radioddity GD-77, which I was using to hold an archive of all the firmware’s that Radioddity has released
I’ll try to add some more pages to the wiki soon
r00tstar
The RTOS version is 4.0.2, the source code I posted matches up pretty close. I found stuff off the strings in the code including printf. The SPI stuff is in it, so are the other peripherals. You can probably find all the pointers in ram going through there.
ScreenMSGdisp_2EDB4 ROM 0002EDB4
USB_Control_Service ROM 0005BCF4
_bsp_dspi1_init ROM 00034B08
_bsp_enable_card ROM 00008E62
_int_unexpected_isr ROM 00065D8C
_io_adc_install ROM 0000BAF4
_io_flashx_install ROM 0000C10C
_ki2c_polled_install ROM 0000AB70
_kuart_polled_install ROM 0000A456
_mqx_STARTUP ROM 0000668C
_mqx_idle_task ROM 00066B2C
_mqx_init_task ROM 00066B8C
_task_destroy_internal ROM 000077B2
ki2c_int_install ROM 0000B434
menus_2D498 ROM 0002D498
mouse_test ROM 0003CA68
printf ROM 00050AE8
usb_device_get_status ROM 0005660C
usb_device_init ROM 000566DC
usb_device_recv_data ROM 0005695E
usb_device_register_application_notify ROM 00056B8A
usb_device_register_desc_request_notify ROM 00056BDA
usb_device_register_vendor_class_request_notify ROM 00056BB2
usb_device_reset ROM 00056C02
usb_device_send_data ROM 00056A1A
usb_device_set_address ROM 000565DE
usb_device_set_status ROM 00056686
usb_device_stall_endpoint ROM 00056B3C
usb_device_unstall_endpoint ROM 00056ADE
Roger Clark
Thanks
I created a wiki on one of my github repos, and invited @forkz and @talentraspel
I will add that info to the wiki
Roger Clark
See https://github.com/rogerclarkmelbourne/Radioddity_GD-77/wiki/Firmware-function-addresses-and-meanings