So, once I finally sat down to debug with the ST-LINK, I found myself doing some new things. First off, I was debugging a program I had no source for, secondly, I was debugging without PlatformIO taking care of the details of setting up the debugger and launching.
GDB requires a debug server, st-util.
Once ST-util was running, I could then launch gdb and attache to the remote target on port 4242.
Which left me looking at nothing, because, again, memory was protected. Switching GDB to register layout showed me nothing, which broke one of my primary plans:
SWD isn't supposed to prevent reading registers, and my plan had been to hack the firmware to set the stack pointer to a known value, then reset and wait for a watchpoint to hit. The resulting registers would have MY values.
And this did not work.
So I had to come up with a plan B.
Plan B started with me dumping the RAM using:
dump memory binary ~/Documents/lerdge/ram2.bin 0x20000000 0x20020000
In the hex editor, this RAM file wound up giving me some fantastic results...like, for instance:
0123456789abcdefABCDEF
0123456789abcdefABCDEF
Very nice.
#%')+-/1357:<>@BDFHKMOQSUWY[]_acegikmoqsuwz|~’±²³´µ¶·¸¹º»¼½¾¿ÀÁÃÄÅÆÇÈÉÊ0123456789:;<=>?@ABCDEFGHIJKLMNOQRSTUVWXYZ[\^_p!q!r!s!t!u!v!w!x!y!z!{!|!}!~!!AÿBÿCÿDÿEÿFÿGÿHÿIÿJÿKÿLÿMÿNÿOÿPÿQÿRÿSÿTÿUÿVÿWÿXÿYÿZÿABCDEFGHIJKLMNOPQRSTUVWXYZ!
And this...this led me to some ideas.
See, I'd made some custom startup code for the Malyan M200, and it got me to thinking.
If we look at ST's startup code for the STM32F407x, we see:
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
What this means in english is that to initialize globals/statics, there's a single loop that copies data from ROM into RAM, and one of these is an ASCII table lookup.
So this table and those bytes inside could form a clue. And most interesting is that the bytes between the characters also form a clue. Some of them have zeros...and zeros we know the byte for. So I wrote a python script that searched the encrypted ROM for byte sequences exactly the length of each character set that alternated with a fixed value.
With a few false starts, I identified some theoretical tables, and proceeded to write a relatively simple lookup that mapped the ASCII bytes, ran it through. MOST of what I saw was garbage. But, buried in the muck was this:
@ûç&RAMNANDW5QXXSSDUUSBUSB3
What followed was a series of trial and error. on a hunch, I simply mapped all bytes in a given range to "s." Remember, we know the value for " " = it's 0x65, and we are 100% certain we know that value, thanks to our friend the stack pointer.
The result of this run gave me gems like "SD ssss IO Essss." You know what that looks like to me? "SD card IO Error."
Which, with a bit more futzing, is exactly what it turned out to be.
Now I was confident about how the encryption worked. I even had ~60 values I'd worked out with confidence, but overall, there wasn't a clear pattern. I was certain that for some ranges, the encryption worked by starting from a seed value and incrementing up by four bits, nibble swapped.
But that didn't work across the board and conflicted with well known, 100% confidence bytes like 0x65.
So I came up with a new plan.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.