⬆️ ⬇️

Source Code Analysis and Prince of Persia Copy Protection

image


Part 1: introduction



On April 17, 2012, Jordan Mekner published the source code of Prince of Persia.



Even despite the fact that this is the version for Apple II, written in assembler processor 6502, it was very nice to dive into the code of this legendary game. As usual, I was waiting for a lot of program interesting.



The obviously weak Apple II programming environment was in fact the foundation of incomparable innovation and creativity: self-modifying code, internal loader, smart floppy disk format, and shifting lookup tables. In each of its module Prince Of Persia stores the treasures of engineering.

')

Reading the source allowed me not only to learn more about the game development process in the 80s, but also again caused a sense of appreciation for those things that are considered natural today.



As usual, I kept detailed notes and created this article based on them. I hope it inspires others to read the source code and improve their development skills.



Acknowledgments: I want to thank Miles.J for 6502.org and Roland Gustafsson (author RWTS18) for sharing their knowledge with me.



Where to begin?



The source code is available in the repository on GitHub and can be downloaded with one command:



git clone git://github.com/jmechner/Prince-of-Persia-Apple-II.git 


The interesting part is in the /Prince-of-Persia-Apple-II/01 POP Source/Source/ folder, which contains a game engine made up of many .S files.



This is the first thing that programmers did not have at the time: high-level languages ​​with high-quality compilers. In order to achieve good speed, developers had to work directly with hardware in 6502 assembly language. It is from this that these .S files consist.







According to Jordan Mekner’s book Making of Prince of Persia , Merlin assembler was used in PoP.



One of the good features of Merlin is the ORG directive, which lets you tell the assembler where the instructions will be loaded into RAM: the PoP ORG is located at the beginning of each file.



Interesting fact: ORG directives were really just directions. In Apple II, there was no operating system, no linker or bootloader: the developer himself had to somehow manage to transfer instructions from the floppy disk to the right place.



The second important point that needs to be understood for the perception of PoP as a whole is the way information is exchanged between modules. Since at that time there was no cross-file linker (and the final executable file, only fragments), the modules must exchange data, making the transition to the void ... in which other modules should have been.







An example of this we can see in the bootloader BOOT.S in line 138 :



 jmp $ee00 


And it is quite mysterious.



To follow the flow of instructions, we need to find out what is in $ee00 . With the help of a small grep command, you can see org = $ee00 in HIRES.S and transfer.



Since there were no linkers, the developers of the 80s needed to know the engine's memory scheme and understand the limitations of RAM. This is now quite rare, because most professionals rely on garbage collectors or the use of vectors with automatic resizing.



6502 assembler



I will talk about it in order to present a general picture and explain how to perform the transition between subsystems. To understand the contents of each module, you need to know a little about the central processor. Fortunately, the 6502 is a simple 16-bit processor with only three registers capable of addressing 64 KB of RAM (bank switching has expanded this volume to 128 KB), with no floating point functions and no segmentation, having only 56 instructions.







The figure shows how simple it all was:





Most of the operations are designed to load and store the register, the X and Y registers have simple instructions, and the drive (A) is a bit more complicated, but generally quite straightforward and well documented.



Two excellent books that, unfortunately, have been removed from print today: Apple II Reference Manual and Inside the Apple IIe .







starting point



In the 80s there was no IDE and C source files with the main method, so it’s impossible to tell where the program started. To understand where to start reading, we need to know how the Apple II was loaded:



  1. Reading the first byte of X sector 0 on track 0 from a floppy disk.
  2. Load X sectors from track 0 into RAM at $800 .
  3. Begin code execution at $800 .


To find the starting point, we need to determine which module is specified to run at $800 by searching for the ORG directive:



  fabiensanglard$ find . -name "*.S" -exec grep -H "org = \$800" {} \; ./01 POP Source/Source/BOOT.S:org = $800 ./02 POP Disk Routines/CP.525/POPBOOT0.S:org = $800 ./03 Disk Protection/POPBOOT0.S:org = $800 ./04 Support/MakeDisk/DRAZ/DRAZ.S:org = $800 ./04 Support/MakeDisk/S/BOOT.S:org = $800 


So, the starting point is in BOOT.S : this file, as we will see later, contains the PoP bootloader.



Recommended reading



Jordan Mekner published his magazines (they can be purchased as a book or pdf). This is a very accurate description of what game developers must go through when creating a game: doubts, pressure, despair, hope and delight.







To understand more about the technical part, study the developer’s notes intended for Atari / Amiga / PC developers (the work on these ports wasn’t very good, but I’ll not detract from the significance of the magazine “Making Of”).



















Several videos of the legendary rotoscoping process and the introduction to Tina LaDeau (Princess) mentioned in Jordan's diary.









Note: Jordan Mekner participated in AMA on Reddit in January 2013, you can read it here .



Part 2: bootloader



To save RAM and computing resources, Apple II game developers did not use the operating system that came with the computer. Therefore, they had to write their own loader: a small program that loaded the game engine from a floppy disk into RAM.



The procedures contained in the Apple II ROM: RWTS16 was a set of instructions that managed the floppy disk and allowed it to read / write 16 sectors of 256 bytes per a track of 35 tracks. In total, it was 140 KB to disk.



But in the games Brøderbund not used RWTS16. They found a better format: RWTS18, which provided more data and proved to be a reliable copy protection mechanism.



Traditional loader







Before focusing on the differences, I will list what is usually done in the video game industry:



When the computer starts, three components interact:









When you start Apple II:



  1. The computer has installed its instruction pointer on the Apple download instructions.
  2. Apple's boot procedures used RWTS16 to boot sectors from a floppy disk into RAM at $800 .
  3. These sectors contained a game loader.
  4. Apple II download procedures then went over to $800 .






From this point on, the game loader was responsible for loading the game engine from a floppy disk into RAM:



  1. Using the RWTS16 Apple II procedures ...
  2. He transferred the game engine from the floppy disk to the RAM ...
  3. And then went to the engine.


RWTS16







The RWTS16 was a floppy disk format shipped with the Apple II. It is described in detail in the brilliant book " Beneath Apple DOS ". In short, it consisted of a set of procedures in the ROM that controlled the disk drive for writing and reading 16 sectors per track.



Sectors of 256 bytes were recorded on the track as follows:







Because the drives lacked precision, huge gaps needed to be left between sectors in order to ensure wipe / restart without overlaps:



As you can see in the figure below, the drive head could write a little before or after the “perfect” position. Clearances compensated for these inaccuracies:







RWTS18







RWTS18 was a floppy disk format created by Roland Gustafsson for Brøderbund. It was completely different from RWTS16 in that it not only provided more storage, but also made life much harder for hackers.



The increased capacity of the RWTS18 was provided by an important observation: during the development of the games, the data read was used rather than the write. RWTS18 almost completely abandoned the concept of sectors: it recorded the tracks entirely and read the much larger sectors.



This scheme eliminated most of the gaps that RWTS16 had to have between sectors: between sectors there were only XXX bytes of self-synchronization.







As a result, the RWTS18 provided storage of 768 bytes in each of the 6 sectors and 157 KB per disk instead of 140 KB available on the RWTS16.



But the increased capacity was not the only advantage of the RWTS18. He also created copy protection mechanisms:





Note: RWTS18 has not completely abandoned the sectors for two reasons:





Note: Roland Gustafsson added his comment:



According to the specification, when reading a disk, 18 sectors could be transferred to 18 different pages of RAM, and not just be consecutive readings of 18 sectors ($ 1200 bytes) in any resulting order. This method is now used for hard drives, it seems to be called “scatter-read” (and then it just seemed like a great idea to me!).



The self-modifying code I used made it possible to perform 4 cyclic reads instead of 6, saving 2 cycles on read / write. In addition, he allowed to “discard” read operations, when each sector / page was not necessarily needed. There was an API that controlled all the necessary variations. The cycles of reading and writing internal tracks were extremely dense. In fact, the recording procedures had to pre-process the data a bit in advance in order to perform the recording in one turn. If I'm not mistaken, the stock was only 20%.


Interesting fact: Roland Gustafsson was so in love with Apple II that he made the license plate number " D5 AA 96 " for his car (this corresponds to the three byte mark of the prologue RWTS16.



.



An interesting fact: the RWTS18 source code was written using the LISA assembler, which had a marked-up file format, and not just text files. Roland plans to publish the source code as soon as he can extract it. If you know how to do this, help him.



An interesting fact: RWTS18 was so difficult to decipher that strange legends arose: they used to think that slow disk drives were needed to create RWTS18 disks.



An interesting fact: the hackers still managed to crack Prince Of Persia ... but for further distribution they had to reverse engineer the game and burn it to three disks formatted with RWTS16. The original version of PoP was sold on two disks with RWTS18. Even Apple II emulators can run only the hacked version of Prince Of Persia!



Prince Of Persia Loader







Now we have all the information to start with the PoP downloader:



PoP started loading in the usual way: the first track was formatted with RWTS16, so the Apple II boot procedures loaded the PoP bootloader into RAM.







Then the PoP loader using RWTS16 loaded the RWTS18 procedures from the rest of track 0.







Then the loader used RWTS18 to download the game engine from other tracks formatted with RWTS18.



The loader switched to the game engine, which also used the RWTS18 procedures for loading game resources.



Interview with Roland Gustafsson



Roland agreed to answer a few questions, here is our interview:



Fabien Sanglar: Hello, Roland, can you tell us a little about yourself: when you were born, where you grew up, did you like school and how did you become a programmer?



Roland Gustafsson: I was born in Sweden, but I lived all my life in California. I didn’t really like it at school, but I graduated from high school and at that time I was already programming and lived well in my 17 years. (That's why I didn't go to college: at the university, computer science teaching was in no way connected with new interesting machines, which were called “personal computers.” It was in the late 70s.)



FS: How did it happen that in the 80s you started working for Brøderbund? How long have you worked there? How did the idea of ​​RWTS18 come to you, why did you write it? What else have you worked for in Brøderbund besides RWTS18?



RG: I was never an employee of Brøderbund, I didn’t have a real job, I was always a freelancer.



The idea of ​​RW18 was born out of necessity. We had Bank Street products (after Bank Street Writer) that could not fit on a standard 16-sector disc. I used to do tricks, so I was asked if I could think of something to store more data. I have been working on copy protection for years, thinking outside the box and fully understanding the capabilities of Disk II. A little thought, I came to the most effective way that came to mind. It happened on the plane on the way to Japan, so I had a lot of time on paper and a pencil. My friend Corey Kosak was confident that he had found a way to store 19 sectors (the theoretical limit), but it used such expensive mathematical calculations that a weak 6502 wouldn't cope with them. I use base 64 to manage nibbles by using mathematics; moreover, it was possible to store more data if I could not work with base 78 or something like that, I don’t remember. Math introduced a little into a stupor. And working with base 64 was, of course, very easy for binary systems.



FS: How did you work with Brøderbund (I'm interested in the schedule, salary, passionate people like you)? Can you compare that experience with modern working conditions?



RG: I didn’t have a real job, I didn’t want it, I don’t like offices.



FS: Have you ever worked on Prince of Persia? Did you help the developers of the game or did you finish the work by transferring the source code in assembler and manual?



RG: I worked directly with Jordan Mekner on the implementation of RW18 and copy protection. We often had interesting moments when we came up with devious ways to make copying more complex. In some cases, the game seemed to work, but as a result it became impossible to play it. In the case of most other games, I started working after their completion and added copy protection. An exception was the program RW18, which had to be implemented during the development phase! I wrote a simple manual so that it can be easily used.



FS: In the book Hackers: Heroes of the Computer Revolution (Hackers: Heroes of the Computer Revolution) there is a chapter dedicated to the fight against Spiradisc and Sierra On-Line against piracy. Looking back, can you call RWTS18 an effective way to protect the Brøderbund from piracy of games? Have you studied the copy protection mechanisms of other publishers (Spiradisc)? If so, what do you think of them?



RG: The only copy protection that I have carefully studied is the cassette version of Microsoft Flight Simulator. Then I realized that there is copy protection. From that moment on, I developed my security system and rarely studied what others were doing. I myself came to the concept of protection with a spiral disk and used it in many Brøderbund and Gebelli games. I did not know if anyone else had thought of the technology with 18 sectors, but I heard many years later that someone had copied it or had come to this method. But I'm still not sure. I know for sure that RW18 was invented by me.



FS: Let's continue the topic of fighting software piracy: have you followed the techniques of your opponents to improve RWTS18? Opponents sometimes pay tribute to the skill of those who are struggling: have you ever been impressed by what the pirates were able to do (for example, a pirated copy of PoP on three RWTS16 disks)?



RG: Yes, I at least studied Locksmith, Nibbles Away and other copying software, and also read topics about hardware. I added a hardware copy protection code that was so well done that Apple couldn’t figure out how to protect against it even in the then not yet announced and secret Apple // e. Therefore, they brought this computer to my home and I made the protection work. I hid Apple // e for a long time, until it was announced and released.



Honestly, I think that the idea of ​​creating a three-disk version for a two-disk game with RW18 was stupid and not very impressive. It was better for them to create a copy system that completely recreated this RW18 format and just make exact copies! The game would be much better, faster, etc ...



FS: What kind of hack do you consider the greatest in the entire history of software development?



RG: Nothing comes to mind. I can say that when someone finds a surprisingly clever solution to a complex problem that requires inventive thinking, it is always worth recognizing.



FS: What game do you like the most?

RG: Even though I have not played for a long time, I can name the original version of Tetris for the GameBoy "network" game, when players fight against each other. I played it very hard at Brøderbund.



FS: Do you have a role model, a personal hero in the computer industry?



RG: The fact that Steve Wozniak insisted on publishing the source code for the original Apple II's ROM has become extremely important to my learning. I once met him at an Apple user meeting in San Francisco, I managed to talk to him and get detailed information about the Disk II system, which allowed me to do copy protection.



FS: What moment are you most proud of as a software engineer?



RG: Always, when I manage to exceed expectations, “get a rabbit out of a hat,” these are amazing moments. I still think RW18 is one of my best tricks.



FS: What are you working on now?



RG: I am the Technical Director of Oceanhouse Media, we are developing mobile applications. Apple has made a real breakthrough with iOS and app development! We are developing for other mobile markets, and we still have a lot to do. Yes, I'm still a big Apple fan.



Recommended reading







" Beneath Apple DOS " is a great book that describes the internal design of Apple II computers. It is very useful for understanding RWTS16 and broadcasting 6 + 2.







Hackers: Heroes of the Computer Revolution has a chapter on Sierra On-Line and on the complex relationship with their anti-hacker prodigy who developed Spiradisc - Mark Duchaineau.



Now that we have all the knowledge we need, we can actually dive into the code and figure out where each of the files is in incredible chaos, which is the structure of the Apple II RAM.



Part 3: more about the loader



A detailed commented version of the source code can be found on GitHub .



Here is a diagram of this infamous RAM, which will be updated below:







BOOT.S



BOOT.S begins with the output of $01 to the instruction stream ( line: 21 ).This forces Apple's firmware to automatically load one sector from track 0 into RAM at $800and go there:







After installing several software switches, it BOOT.Suses RWTS16 to load a series of sectors into RAM using the offset table ( line: 79 ). It BOOT.Sturned out that in these sectors contains the rest of the procedures and RWTS18:







After moving the RWTS18 procedures to another bank at the address $D000(for ease of use), it uses RWTS18 to load the whole track 1 at the address $E000( line: 136 ) and goes to the mysterious one $ee00.







HIRES.S



We have no idea what was on track 1 and whether this data should be located at $ee00.



But you can use grep to find out:



  fabiensanglard$ find . -name "*.S" -exec grep -H "org = \$ee00" {} \; ./01 POP Source/Source/HIRES.S:org = $ee00 ./01 POP Source/Source/MOVER.S:org = $ee00 


A little studying the code, we found that we are interested HIRES.S.







HIRES.Sat the beginning contains the transition table, which takes us to another mysterious address: $f880( line: 13 ).



MASTER.S



And again we do not know what should be the address $f880.



But you can use grep again to find out:



  fabiensanglard$ find . -name "*.S" -exec grep -H "org = \$f880" {} \; ./01 POP Source/Source/MASTER.S:org = $f880 ./04 Support/MakeDisk/S/MASTER.S:org = $f880 ./04 Support/MakeDisk/S/MASTER525.S:org = $f880 


So, the address $f880is the content MASTER.S. We can edit the memory allocation table: it







MASTER.Shas the following contents:



  jmp FIRSTBOOT jmp LOADLEVEL jmp RELOAD jmp LoadStage2 jmp RELOAD jmp ATTRACTMODE jmp CUTPRINCESS jmp SAVEGAME jmp LOADGAME jmp DOSTARTGAME jmp EPILOG jmp LOADALTSET 


At this stage, the game engine is loaded into RAM and is ready to load the legendary DOUBLE-HIGH screen:







[Approx. .: . , , , - .]

Source: https://habr.com/ru/post/326714/



All Articles