I wanted to patch the UART (again) but with better formatting, the original string was too small and couldn't be done by simply patching it.
So I've revisited something I had already done: Finding empty spaces in the binary, inserting a new string and replacing the pointer addresses.
I hadn't documented any details, so I had to start from zero,
last time I did this I was recovering from the surgery, had a lot of sleep deprivation and pain for months, so now I didn't remember anything!
Start with a working linux system with python3 and python3-pip installed, and your prefered HEX editor. I'm using HxD (Windows).
First stepsGet some basic file information:
file phoenix
phoenix: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.10.0, stripped
LSB means the file uses little-endian, that is, less significant bytes first, or reversed.
Ex. the number 0x11223344 would be encoded as 0x44332211.
Install cavefindersudo pip3 install cavefinder
Check you new string requirementsIn this example I'll be adding a larger string for the UART decoder, so it outputs HEX+char.
Remember you need a termination (null) char, also it's better to ensure the preceding byte is 0 in case there's a string there
For [%02X '%1$c'] , the decoder output for 0x41 would be: <41 'A'>, and requires at least 13 bytes.
Find empty spaceI recommend specifying slightly bigger size for future changes, ex. in this case 32 bytes should be more than enough.
cavefinder --size 32 phoenix
You'll get a lot of results, take any size matching your requirements.
There'll will be much bigger zones, but it's better to preserve them for other future purposes that really require larger sizes.
Section name: .rodata
Cave begin: 799690 - 0xc33ca
Cave end: 799722 - 0xc33ea
Cave size: 32 bytes
Virtaddr: 0xd33ca
info: Type: SHT_PROGBITS, Flags: SHF_ALLOC
So we have a good one at 0xC33CA. Note that the virtual address has an offset of 0x10000 (0xd33ca), remember this!
Better to align it to 32-bit, just in case, so our string will start at 0xC33CC.
Opening phoenix in the hex editor and jumping to the address:
/ Start
|
0C33C0 19 80 19 80 19 80 19 80 19 80 00 00 00 00 00 00 .€.€.€.€.€......
0C33D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0C33E0 00 00 00 00 00 00 00 00 00 00 03 30 03 30 03 30 ...........0.0.0
|
\ End
Insert the string:
0C33C0 19 80 19 80 19 80 19 80 19 80 00 00 25 30 32 58 .€.€.€.€.€..%02X
0C33D0 20 27 25 31 24 63 27 00 00 00 00 00 00 00 00 00 '%1$c'.........
0C33E0 00 00 00 00 00 00 00 00 00 00 03 30 03 30 03 30 ...........0.0.0
We're done with the first (easy) part.
Patching the pointersNow we have to find the original string, the pointers to it and redirect them to the new one.
Because I already spent a ton of time testing different locations, I know the original string is "%02x", placed very close to another string, "UART DATA".
Searching "UART DATA" quickly finds the location at 0BAAAC:
0BAAA0 00 00 00 00 55 61 72 74 00 00 00 00 25 30 32 78 ....Uart....%02x
0BAAB0 00 00 00 00 25 30 34 78 00 00 00 00 52 00 00 00 ....%04x....R...
0BAAC0 25 73 3A 25 30 32 78 5B 25 73 5D 00 7E 41 00 00 %s:%02x[%s].~A..
0BAAD0 57 00 00 00 55 41 52 54 20 44 41 54 41 00 00 00 W...UART DATA...
Address size is 32-bit, so: 000BAAAC
Add the previous 0x10000 offset, and reverse it (Remember, uses little endian), the result is ACAA0C00.
Our string starts at 0x000C33CC, requires the same conversion: 0xCC330D00
Search ACAA0C00 pattern (hex), you'll find plenty of values.
Now it's matter of replacing one at a time with CC330D00, and testing the binary in the scope.
I've found the pattern at: 0x53550, 0x53AA0, 0x54050, 0x54488, 0x553B4, 0x9196C,
so I've made different files called phoenix_53550, phoenix_53AA0...
After testing, the pointer for the UART decoder was the first one, at 0x53550:
053550 AC AA 0C 00 10 D0 4D E2 F0 4F 2D E9 41 DF 4D E2 ¬ª...ÐMâðO-éAßMâ
053550 CC 33 0D 00 10 D0 4D E2 F0 4F 2D E9 41 DF 4D E2 Ì3...ÐMâðO-éAßMâ
And enjoy a better UART decoder!