In part 1 of this series of posts, Daniel suggested taking a look at the role the SCSI Manager plays in the Mac’s—and by extension, the Pippin’s—startup process. I took a break from examining the auth check code to dissect how the SCSI Manager behaves at startup on the Pippin, with the ultimate goal to discover if an exploit was even possible. After all, from my initial search of the ROM it’s clear that Apple had patched part of the boot process to only allow starting up from the internal CD-ROM drive—who’s to say there aren’t further patches deep in the SCSI code?
The tl;dr is that, after careful examination, I have determined that the SCSI code in the Pippin’s boot process is for the most part unchanged compared to a Mac of the same era. However I’m not yet sure if a “patch partition”-based exploit is possible.
Most of what follows I garnered from the “Monster Disk Driver Technote,” a mirror of which can be found here:
http://mirror.informatimago.com/next/developer.apple.com/technotes/tn/tn1189.html
Every SCSI-equipped Mac for the most part follows the same procedure for booting from a SCSI device:
- It looks for a valid Driver Descriptor Map in the first 512-byte block
- Loads the device’s driver(s) according to the information found in the DDM
- Mounts the disk’s HFS partition
- Loads the boot blocks from the startup volume and executes them
This has been the case since SCSI was introduced to the Macintosh line with the Mac Plus in 1986. Previously, Macs had primarily booted from floppy disk and occasionally from a non-SCSI hard drive such as the HD20 or HyperDrive (but usually with help from a boot floppy). In either event, the Mac had no concept of drive “partitions” or even “volumes” in the modern sense—the MFS file system consumed the entire disk, and that was it.
The Apple Partition Map, introduced at the same time SCSI arrived on the Mac, changes this behavior by placing the primary file system in its own partition. On a high level, the Mac sees the volume as its own big disk, but the APM also allows device drivers to live in their own partitions rather than in INIT files as was done with the HD20. This moves their load time to much earlier in the boot process independent of the System Software and—critically—eschews the need for a separate boot disk. The SCSI code in ROM recognizes the presence of an APM, loads the driver(s) directly from disk, then locates and boots a startup volume. In this way, Macs can boot directly from a hard drive, a CD-ROM drive, or any SCSI-capable storage medium so long as it has the proper drivers preconfigured.
What does all of this have to do with the Pippin? Well, the Pippin’s only internal storage is its 128KB of non-volatile Flash memory, and even if the Pippin ROM was written to look there for an OS, 128KB is barely enough to boot the original Macintosh—never mind the System 7.5-based OS that Pippin titles shipped with. Instead, the Pippin boots from its internal (SCSI) CD-ROM drive, presumably calling into the SCSI Manager to load any device drivers followed by mounting the HFS partition, verifying the contents of the “PippinAuthenticationFile,” then continuing to boot the OS if everything checks out.
Wait a minute…
Before searching for an operating system, the SCSI Manager is supposed to load device drivers directly from disk according to the Driver Descriptor Map. It does a basic checksum verification, then… executes them! They run before the auth check!
At least, in theory.
I took a look at the “Pippin Network CD” (product ID BDB-002) that originally shipped with the 1.0 Atmark units in Japan. I chose this particular disc because of two things: 1) It has an Apple Partition Map and 2) It contains a very small device driver partition with plenty of extra room in which I could hack a “proof-of-concept.” I rustled out the original driver from an ISO image of the disc with a hex editor, then added some code that does the equivalent of while (!Button());
. I then recalculated my hacked driver’s checksum using a quick program I wrote, poked the driver (and its proper checksum) back into the ISO, burned it to disc, booted my Pippin with it, and…
It booted directly to the login screen.
This tells me that one of two things might be happening:
- The Pippin’s version of the SCSI Manager in ROM does not in fact load device drivers from disc. The SCSI Manager does a number of checks before it determines that it needs to load drivers for a particular device, and it’s possible that the Pippin fails one of those checks, possibly intentionally. In this case, it may be that the driver lives in ROM and any drivers on Pippin discs exist for the benefit of mounting on actual Macs, where the hardware isn’t fixed and device drivers would be more necessary. Also, only a handful of Pippin discs have partition maps; the majority of them are formatted as a flat HFS volume. What does the SCSI Manager do in that case? Where do the requisite device drivers come from?
- I screwed up hacking my driver code into the disc image before burning it. 😛
Unfortunately, when I mount this disc on my Power Mac G3 in Mac OS 9.2.2, my driver code doesn’t run there either. There must be some condition(s) under which the SCSI Manager will skip loading drivers from a CD-ROM mastered with them.
Looks like I have some more digging to do…
Good investigation! Have you tried bin-patching code in another part of the disk image? For example, the “boot 3” resource in the System file (or more likely the System Enabler file) is sure to get run some time after the Happy Mac (or equivalent). I suppose you would have to find the resource in the raw image in order to keep the authenticated structures unchanged.
You might find this useful at some point. I have written some low-level Python bindings for Robert Leslie’s venerable “libhfs” code: https://github.com/elliotnunn/libhfs
Keep it up!!
I actually have hacked the ‘boot’ 2 resource in a past Pippin experiment– I tacked on some code that would print the value of (BoxFlag) to the upper-left corner of the screen in case a Pippin prototype reports a different machine type than a retail one. That code *did* run on the prototype I had at the time (the values are the same, BTW).
I imagine bin-patching a hacked System file or Enabler would execute my code, but I’m not sure to what extent that would be helpful. A patched System/Enabler would only run after a successful auth check– the boot blocks aren’t executed until after the auth check passes.
Once you have the ability to execute arbitrary code, you could switch-boot from a filesystem nested in some non-authenticated area! 😀
If you set up a second HFS partition on the cd, you could have the boot blocks or the ‘boot’ 2 in the authenticated partition run the boot blocks there. The partition that has the auth check would not be the one that boots.
For this to be useful, you would have to make the authenticated partition as small as possible so you have any disk space at all.
Knowing the authentication code would greatly help with this, especially if there are bugs in it. It would be amazing if you could control the hash output to be 0 or anything else where the signature is trivially calculable. If not, you could still only include the structures that are actually hashed.
Does the driver partition have a name of “Apple_Driver” or “Apple_Driver43”? The entry point for new drivers run by a new rom is 8 bytes into the driver code instead of 0 bytes in. This might be what is messing you up.
When a disk doesn’t have a driver, the Scsi Interface Module (SIM) is given an opportunity to install a driver (it is also given the chance to override the driver before).
I suppose the good news about the disk booting is that it tells you the checksum code doesn’t care about anything except what is on the main partition.
The original driver code looks like this:
I injected a
Jsr (myCode,PC)
at the location of label P1, so whether or not it’s a 4.3 driver shouldn’t matter– it should still call myCode.You are absolutely right re: what this tells me about the checksum code. It certainly tells me that it’s not hashing the raw disc contents, though I surmised that already based on how quickly the check happens during startup. This could be a good clue in the direction of where the auth routine looks for its source data. 🙂
I notice a slight error in your checksum code. Quoting from the technote:
“only the first bytesToSum modulo 64 K bytes of the driver are checksummed.”
So your code should have a “bytesToSum &= 0xFFFF” somewhere in it. Still, this shouldn’t affect your results unless the driver is really big. Does running your checksum on the original driver match the stored checksum?
Another interesting quote suggests that driver partitions are needed for the disk to be mounted at all, not just in the boot phrase: “You can overwrite the DDM to eliminate all foreign drivers from the disk and then restart the computer. Because there are no drivers in the DDM, the disk will not be mounted and you will be free to use it as you wish”
Maybe your code simply returns immediately instead of waiting for the button. I imagine a lot of the Toolbox Traps were not meant to be called at this phase in the startup process. Maybe removing the driver from the DDM and changing the partition type to “Apple_Void” would keep the cd from being mounted even on 9.2.2 systems.