Desktop database viruses

I was reminded of something today. Let me take you back to Macintosh System Software 6.0. (We’d retroactively call it Classic Mac OS 6 now.) Actually, this probably dates back before 6.0. And if you were around then, you probably know all of this. We’re going to talk about desktop database viruses.

Before I go any further, let me specify with 100% clarity: This problem was fixed 30 years ago, and has absolutely no bearing on Mac OS X/modern macOS. There is probably almost zero overlap between the Apple of 1990 and the Apple of 2021. Modern Apple may make the occasional mistake, but nothing like what I’m about to describe.

Note also that I’m going to simplify this significantly by talking about only the 680×0, not the PowerPC. Mac OS on PowerPC changed a lot, but the PowerPC came years after these problems were fixed, so it’s irrelevant to this discussion.

Background: Resources and applications

Let’s start with the Resource Manager. Mac files could contain a data and a resource fork. A resource fork contained one or more (and often many) resources, stored by type and ID. There were a lot of resource types defined for both the system software and applications. Just for example:

  • Icon “lists” were type ICN# resources.
  • General code segments were stored CODE resources.
  • Windowing code (frames, hit detection, etc) were stored in WDEF resources.
  • Code for custom controls (like buttons) were stored in CDEF resources.
  • Code for custom menus were stored in MDEF resources.
  • Simple black and white icons were ICON resources.
  • Color icons were stored in cicn resources.
  • Applications defined their metadata (“This is MacWrite!”) with a BNDL resources.
  • Applications defined their document types (“This is a MacWrite document; use this icon to display it!”) with one FREF resource per document type.

The resource fork could be viewed as sort of a limited database, each resource having a type and an ID. It wasn’t intended to scale, and there were no queries except by sequence or by ID. (Just so nobody jumps on me: IDs were unique within a type only. Much of Apple’s System Software relied on this: resources would be extended later with a different type of the same ID so the original resource record wouldn’t need to be updated. For example, ICN# defined a black and white icon and its mask. The Macintosh System Software would automatically draw the color icl8 of the same ID on color Macs when possible. This will not be on the exam.)

Applications were built as resource files. Most applications were only resource files. (Some rare applications stored license info or something else in their data forks.)

This information is hard to look up these days, and it doesn’t matter materially to the rest of this. The point is that you’d build your application, and it would contain code and resources.

  • If you wanted a custom window appearance or behaviour you’d put that code in a separate build process and output a WDEF resource. This was all reasonable and by design.
  • By convention, you’d use IDs in a given range (128 to 32,767 for most resource types) and the system would use other IDs (-32,768 to 127 for most resource types).
  • Apple eventually reserved all resource types not containing at least one uppercase letter for future use.
  • Nothing actually enforced any of these rules; they were for developer safety, as conflicting with an Apple resource could cause glitches, a failure to launch, or a crash or other bad behaviour somewhere in your application.

One of the features of the Resource Manager was that resource files opened later would override files opened earlier. The first resource file opened by the system software was System. (Logically, anyway.) Other resource files were opened, including ultimately your application.

This behaviour was actually critically important to Classic Mac OS! Your custom WDEF, let’s say ID 128, was part of the resource chain. If your window specified it should be drawn by WDEF 128, it wasn’t referred to as “WDEF 128 in your application’s resource fork.” It was WDEF 128 in your application’s resource chain, which happened to be satisfied by your application’s WDEF 128.

Likewise, a call to WDEF 0 wasn’t really to System WDEF 0, it was to WDEF 0 in the application’s resource chain… it just happened to be satisfied by WDEF 0 in System. This Wild West approach was even abused “well” in some cases, like overriding the System WDEF to change the behaviour to add features. These could patch the behaviour and then call back to the System WDEF. Window shading was done by third parties before Apple got to it. We’re still good!

(As an aside, there were other ways to customize window behaviour: a-trap patches were probably much more commonly used by legitimate code. Classic Mac OS was a wild beast.)

The Desktop database

One of the things the Macintosh System Software did was track application/file associations. Remember BNDL and FREF? These were part of applications, but they were cached centrally per disk in the desktop database. I don’t actually recall how this was done; I’m not sure if they were still BNDL and FREF resources. I think probably not. Various actions would copy BNDL and FREF resources from the application to the desktop database (whatever form that took). There was a Desktop Manager, but it relied on files that applications could (but shouldn’t) write to directly.

The desktop database would be automatically opened when a disk was inserted by opening the desktop database file — which meant adding it to the resource chain. And if you’ve understood all of the above, you might already see the problem — but don’t worry if you don’t. I’ll explain it!

Pandora’s box was open

Now we’ve set the stage. The way the Resource Manager works is perfectly sensible, but the desktop database which was built on top of it doesn’t take into account all the quirks of it. Remember I said later opened resource files took priority over earlier resources? Everything overrides System! Ouch! And let’s now make it worse: In those days, the System Software didn’t protect itself and it was possible to write to various resource forks.

Let’s review:

  1. Resources in the desktop database are automatically added to the resource chain.
  2. Code resources in the later resource files are prioritized over earlier resource files.
  3. Code is unsigned, and code can write to the system and things considered “the system” can write to other applications (including modifying their code).
  4. Code can also write to the desktop database.

We have everything in place for a viral horror story. Let’s go through this with an infected app:

  1. You run an infected or delivery application.
  2. The virus spreads itself to the system file.
  3. The virus spreads itself to applications.
  4. The virus spreads itself to the desktop database of all mounted disks, present and future.

An infection being caused by running an application is pretty typical stuff. But it’s the choice of the desktop database that’s the real killer. We don’t just have an infected app now, we have an infected disk:

  1. Another user inserts the infected disk — the system software immediately adds the desktop database to the resource chain and starts calling code from it, and just like that, the computer is infected!
  2. The virus spreads itself to the system file.
  3. The virus spreads itself to applications.
  4. The virus spreads itself to the desktop database of all mounted disks, present and future.

In fact, the desktop database is such a great vector for propagation that I lied above. The first successful desktop database virus (WDEF) doesn’t actually do steps 2 and 3 ever. We don’t have infected applications! We just have the delivery application, which you may never see, and infected desktop databases potentially on any disk we touch. As a result, the intention of WDEF was that it be basically harmless. Unfortunately, it had bugs that made it not harmless. Later desktop database viruses, like MDEF/Garfield and CDEF, did infect applications however and were intentionally destructive.

It was hard to get rid of permanently. The next user of the infected disk could be you just a few days after you’ve painstakingly removed all traces of the virus. Wham, you’re infected. Again.

To say this virus spread rapidly was an understatement. It’s hard to imagine a more perfect attack vector for viruses! I was in high school at the time, and some of our network shares were infected by admin. That led to every student’s disks being infected.

The situation was truly awful. Locking down those network shares so admin didn’t casually write to them helped. John Norstad’s freeware Disinfectant (1988) helped, Commercial active virus protection like Symantec Antivirus for Mac (1989) helped even more if you weren’t perfectly careful. It was hard to be perfectly careful. Symantec Antivirus would scan disks as you inserted them and alert you to processes trying to modify code, for instance.

System Software 7.0 saves the day

Apple solved this in 1991. System Software 7.0 changed the way the desktop database worked, at least on larger volumes. I don’t think exactly what they did was publicly documented, but the desktop database was renamed, split and no longer stored in a resource fork. There were likely other fixes to how older style desktop databases were loaded, too, as it solved the problem of viruses being spread as soon as floppies were inserted.

Unfortunately, that didn’t stop infections that spread via applications or system files. Some later viruses included MBDF, co-created by Mark Pilgrim (of Dive Into fame).

But the desktop viruses were the worst.

Epilogue: Mac OS X

Over time, System 7 became Mac OS. Mac OS 8/9 became the Classic environment in Mac OS X, whereas a different version of those Mac OS APIs became Carbon. Carbon was a way to build a proper Mac OS X application.

The desktop database viruses were never a problem in the Classic environment, since it didn’t auto-load resources from disks. There was still a System, and later opened files still took priority over it, but this wasn’t a major problem. Classic was ultimately removed in Mac OS X 10.5.

Meanwhile, resource forks were still supported in Carbon for years. I think the dropping of support for 32-bit applications in Mac OS X 10.15 (2019) finished them off since Carbon was never released in 64-bit form, but they might have survived in more esoteric ways. Custom icons on a file used to be stored in the resource fork, for instance, but this was changed years ago. The resource chain was never a danger in Caron, though, as everything under the APIs was implemented differently.

I’m sure there are people with better info than the above, but I think it’s basically correct.