Classmate uses this technique. It is also possible to embed backspace characters into the filename. Filenames with backspace characters in them cannot be loaded from the prompt. Instead, a Basic program must be written with printable characters as placeholders, and then the memory image must be altered to replace them with backspace characters.
Now you see it
Since the VTOC also carries the sector of the catalog, it can be altered to point to another location within the track that holds the VTOC. That causes the disk to display a fake catalog, while allowing a program to access the real catalog sectors directly.
The Toy Shop uses this technique to show the program title, copyright, and author credits.
Now you don’t
Since DOS carries a hard-coded track number for the VTOC, it is easy to patch DOS to look at a different track entirely. The original default track can then be used for data. Any attempt to show the catalog from a regular DOS disk will display garbage.
Ali Baba uses this technique, by moving the entire catalog track to track five.
10:7.12 BASIC tricks
Circular Line linking
In BASIC on the Apple ][, each line contains a reference to the next line to list. As such, several interesting effects are possible. For example, the listing can be made circular, by pointing to a previous line, causing an infinite loop of listing. The simplest example of that looks like this:
801:01 08 00 00 3A 00 00 00
This program contains one line whose line number is zero, and whose content is a single colon. An attempt to list this program will show an infinite number of “0 :” lines. However it can be executed without issue.
Missing
The listing can be forced to skip lines, by pointing to a line that appears after the next line, like this:
801:10 08 00 00 3A 00 10 08 01 00 BA 22
80D:31 22 00 16 08 02 00 3A 00 00 00
Listing the program will show just two lines:
However, there is a second line (numbered “one”) which contains a PRINT statement. Running the program will display the text in line one.
Out-of-order
The listing can list lines in an order that does not match the execution, for example, backwards:
801:13 08 03 00 BA 22 30 22 00 1C 08 01 00 BA 22
810:31 22 00 0A 08 03 00 BA 22 32 22 00 00 00
This program contains three lines, numbered from zero to two. The list will show the second and third lines in reverse order. The illusion is completed by altering the line number of the first line to a value larger than the other lines. However, the execution of the first line first cannot be altered in this way.
Out-of-bounds
The listing can even be forced to fetch from arbitrary memory, such as the graphics screen or the memory-mapped I/O space:
801:55 CO 00 00 3A 00 00 00
This program contains a single line whose line number is zero, and whose content is a single colon. An attempt to list this program will cause the second text screen to be displayed instead, and the machine will appear to crash. Further misdirection is possible by placing an entirely different program at an alternative location, which will be listed instead.
Imagine the feeling when the drive light turns itself on while the program is being listed!
It might even be possible to create a program with lines that touch the memory-mapped I/O space, and activate or deactivate a stepper-motor phase. If those lines were listed in a specific order, then the drive could be enticed to move to a different track. That track could lie about its position on the disk, but carry alternative content to the proper track, resulting in perhaps subtly different behavior. Are we having fun yet?
Start address
The first line of code to execute can be altered dynamically at runtime, by a “POKE 103,
Line address
Normally, the execution will generally proceed linearly through the program (excluding instructions that legally transfer control, such as subroutine calls and loops), regardless of the references to individual lines. However, the next line (technically, the next token) to execute can be altered dynamically at runtime, by a “POKE 184,
0 POKE 184,14 : END : PRINT "!"
It is also possible to alter the high address by a “POKE 185,
“REM crash”
801:0E 08 00 00 B2 0D 04 50 52 23 36 0D 00 00 00
This program contains one line, which looks like the following, where the “^” character stands for the Control key.
When listed with DOS active, it will trigger a reboot. It works because the same I/O routine is used for displaying the text as for typing commands from the keyboard. Zardax uses this technique.
Self-modification
A program can even modify itself dynamically at runtime. For example, this program will display “2” instead of “1.” The address of the POKE corresponds to the location of the text in memory.
A program can also extend its code dynamically at runtime:
A FOR loop must be terminated by a NEXT token, in order to be legal code. Notice that the program does not contain a NEXT token, as expected. Instead, the values in the DATA line supply the NEXT token and a subsequent :. The inclusion of a : allows extending the line further, simply by adding more values to the DATA line and altering the corresponding address of the POKE.
By using this technique, even entirely new lines can be created.
10:7.13 Rastan
Rastan is mentioned here only because it is a title for an Apple ][ system (okay, the IIGS) that carried the means to bypass its own copy-protection! The program contained two copy-protection techniques. One was a disk verification check, which executed shortly after inserting the second disk. The other was a checksum routine which performed part of the calculation between each graphics frame, until it formed the complete value. If the match failed, only then would it display a message. It means that the game would run for a little while before failing, making it extremely difficult to determine where the check was performed.
The Rastan backdoor
In order to avoid waiting for the protection check every time a new version of the code was built, John Brooks inserted a backdoor routine which executed before the first protection check could run. The backdoor routine had the ability to disable both protection checks in memory, as well as to add new functionality, such as invincibility and level warping. And where was this backdoor routine located? Inside the highscore file!
Yes. The highscore file had a special format, whereby code could be placed beginning at the third byte of the file. As long as the checksum of the file was valid (an exclusive-OR of every byte of the file yielded a zero), the code would be executed.
Here is the dispatcher code in Rastan:
.A16
;checksum data
2000D JSR $21216
;note this address
20010 JSR $2D1C2
Here is the checksum routine:
.A16
;source address
21216 TXA
;taken if no highscore file
21217 BEQ $21240
;length of data
21219 LDA $0,X
2121D TAY
2121E SEP #$20
.A8
21220 PHX
;checksum seed
21221 LDA #0
;checksum data
21223 EOR $0,X
21227 INX
21228 DEY
21229 BNE $21223
2122
B PLX
2122C REP #$30
.A16
2122E AND #$FF
;taken if bad checksum,
;no copy
21231 BNE $21240
;length of data
21233LDA $0,X
21237 DEC
21238 LDY #$D1C0
;copy to $2D1C0
2123B MVN #2, #0
2123E PHK
2123F PLB
21240 RTS
We can see that the data are copied to $2D1C0, the first word is the length of the data, and the first byte after the length (so $2D1C2) is executed directly in 16-bit mode. By default, the file carried an immediate return instruction, but it could have been anything, including this:
;always pass protection
;(BRA $+$0F)
2D1C2 LDA #$0D80
2D1C5 STA $22004
;always pass checksum
;(BRA $+$19)
2D1C8 LDA $1780
2D1CB STA $3CAD0
2D1CE RTS
Conclusion
There were many tricks used to protect programs on the Apple ][, and what is listed here is not even all of them. Copy-protection and cracking were part of a never-ending cycle of invention and advances on both sides. As the protectors came to understand the hardware more and more, they were able to develop techniques like delayed fetch, or consecutive quarter-tracks. The crackers came up with NMI cards, and the mighty E.D.D. In response, the protectors hooked the NMI vector and exploited a vulnerability in E.D.D.’s read routine. (This is my absolute favorite technique.) The crackers just boot-traced the whole thing.
We can only stand and admire the ingenuity and inventiveness of the protectors like Roland Gustafsson or John Brooks. They were helped by the openness of the Apple ][ platform and especially its disk system. Even today, we see some of the same styles of protections: anti-disassembly, self-modifying code, compression, and, of course, anti-debugging.
The cycle really is never-ending.
Acknowledgements
Thanks to William F. Luebbert for What’s Where In The Apple, and Don Worth and Pieter Lechner for Beneath Apple DOS. Both books have been on my bookshelf since 1983, and were consulted very often while writing this paper.
Thanks to reviewers 4am, Olivier Guinart, and John Brooks, for their invaluable input.
10:8 Reverse Engineering the Tytera MD380
by Travis Goodspeed KK4VCZ, with kind thanks to DD4CR and W7PCH.
The following is an adventure of reverse engineering the Tytera MD380, a digital hand-held radio that can be had for barely more than a hundred bucks. In this article, I explain how to read and write the radio’s configuration over USB, and how to break the readout protection on its firmware, so that you fine readers can write your own strange and clever software for this nifty gizmo. I also present patches to promiscuously receive audio from unknown talkgroups, creating the first hardware scanner for DMR. Far more importantly, these notes will be handy when you attempt to reverse engineer something similar on your own.
This article does not go into the security problems of the DMR protocol, but those are sufficiently similar to P25 that I’ll just refer you to Why (Special Agent) Johnny (Still) Can’t Encrypt by Sandy Clark and Friends.60
I hope that you’ll have the chance to conveniently patch a pilfered bootloader, to sniff undocumented USB commands, or to patch brand new features into the firmware of your own radio.
Hardware Overview
The MD380 is a hand-held digital voice radio that uses either analog FM or Digital Mobile Radio (DMR). It is very similar to other DMR radios, such as the CS700 and CS750 from Connect Systems.61
DMR is a trunked radio protocol using two-slot TDMA, so a single repeater tower can be used by one user in Slot 1 while another user is having a completely different conversation on Slot 2. Just like GSM, the tower coordinates which radio should transmit when.
The CPU of this radio is an STM32F405 from STMicroelectronics. This contains a Cortex M4, so all instructions are Thumb and all function pointers are odd. The LQFP100 package of this chip is used. It has a megabyte of Flash and 192 kilobytes of RAM. The STM32 has both JTAG and a ROM bootloader, but both of these are protected by a Readout Device Protection (RDP) feature. On page 327, I’ll show you how to bypass these protections and jailbreak your radio.
There is also a radio baseband chip, the HR C5000. At first I was reconstructing the pinout of this chip from the CS700 Service Manual, but the full documentation can be had from Docln, a Chinese PDF sharing website.
Aside from a bunch of support components that we can take for granted, there is an SPI Flash chip for storing the codeplug. “Codeplug” is a Motorola term for the radio settings, such as frequencies, contacts, and talk groups; I use the term here to distinguish the radio configuration in SPI Flash from the code and data in CPU Flash.
A Partial Dump
From lsusb -v on Linux, we can see that the device implements USB DFU, most likely as a fork of some STMicro example code. The MD380 appears as an STMicro DFU device with storage for Internal Flash and SPI Flash with a VID:PID of 0483:df11.
Further, the .rdt codeplug files are SPI Flash images in the DMU format, which is pretty much just wrapper with a bare minimum of metadata around a flat, uncompressed memory image. These codeplug files contain the radio’s contact list, repeater frequencies, and other configuration info. We’ll get back to this later, as what we really want to do is dump and patch the firmware.
Unfortunately, dumping memory from the device by the standard DFU protocol doesn’t seem to yield useful results, just the same repeating binary string, regardless of the alternate we choose or the starting position.
In this brave new world, where folks break their bytes on the little side by order of Golbasto Momarem Evlame Gurdilo Shefin Mully Ully Gue, Tyrant of Lilliput and Eternal Enemy of Big Endians and Blefuscu, it’s handy to spot four byte sequences that could be interrupt handlers. In this case, what we’re looking at is the first few pointers of an interrupt vector table. This means that we are grabbing memory from the beginning of internal flash at 0x08000000!
Note that the data repeats every kilobyte, and also that dfu-util is reporting a transfer size of 1,024 bytes. The -t switch will order dfu-util to dump more than a kilobyte per transfer, but everything after the first transfer remains corrupted.
This is because dfu-util isn’t sending the proper commands to the radio firmware, and it’s getting the page as a bug rather than through proper use of the protocol. (There are lots of weird variants of DFU, created by folks only using DFU with their own tools and never testing for compatibility with each other. This variant is particularly weird, but manageable.)
Tapping USB with VMWare
Before going further, it was necessary to learn the radio’s custom dialect of DFU. Since my Total Phase USB sniffers weren’t nearby, I used VMWare to sniff the transactions of both the MD380’s firmware updater and codeplug configuration tools.
I did this by changing a few lines of my VMWare .vmx configuration to dump USB transactions out to vmware.log, which I parsed with ugly regexes in Python. These are the additions to the .vmx file.
The logs showed that the MD380’s variant of DFU included non-standard commands. In particular, the LCD screen would say “PC Program USB Mode” for the official client applications, but not for any third party application. Before I could do a proper read, I had to find the commands that would enter this programming mode.
DFU normally hides extra commands in the UPLOAD and DNLOAD commands when the block address is less than two. (Hiding them in blocks OxFFFF and OxFFFE would make more sense, but if wishes were horses, then beggars would ride.)
To erase a block, a DFU host sends 0x41 followed by a little endian address. To set the address pointer (block 2’s address), the host sends 0x21 followed by a little endian address.
In addition to those standard commands, the MD380 also uses a number of two-byte (rather than five-byte) DNLOAD transactions, none of
which exist in the standard DFU protocol. I observed a number of commands, many of which I still only partially understand.
Non-Standard DNLOAD Extensions
91 01
Enables programming mode on LCD.
a2 01
Seems to return model number.
a2 02
Sent only by config read.
a2 31
Sent only by firmware update.
a2 03
Sent by both.
a2 04
Sent only by config read.
a2 07
Sent by both.
91 31
Sent only by firmware update.
91 05
Reboots, exiting programming mode.
Custom Codeplug Client
Once I knew the extra commands, I built a custom DFU client that would send them to read and write codeplug memory. With a little luck, this might have given me control of firmware, but as you’ll see, it only got me half way.
Because I’m familiar with the code from a prior target, I forked the DFU client from an old version of Michael Ossmann’s Ubertooth project.62
Sure enough, changing the VID and PID of the ubertooth-dfu script was enough to start dumping memory, but just like dfu-util, the result was a repeating sequence of the first block’s contents. Because the block size was 256 bytes, I received only the first 0x100 bytes repeated.
PoC or GTFO, Volume 2 Page 18