Cracking LucasArts copy protection

This week I’ve decided to crack the copy protection on Monkey Island 1:

My crack bypasses the copy protection prompt entirely, and will work with DosBox, ScummVM, DREAMM and original hardware both EGA and VGA versions. My intention now with it is to make a universal patching app since indiscriminately distributing DISK01.LEC could be viewed as piracy. I’d also like to do this with other games.

Doing this in 2026 may seem redundant, after all the VGA version the patch merely does in DISK01.LEC what the “PC Gamer” version of the MONKEY.EXE interpreter does anyway, however that would miss the point. It’s important for the long-term preservation of these games, even if it “isn’t needed” or can be achieved in a different way. Patching the game in this exact way should have already been done by “someone”, however so far as I can tell it never has been - the legacy patches from the 90’s worked in different ways to this, and until now no “someone” bothered to do it.

3 Likes

Actually, I am that “someone” long time ago, when the tools to decompile and recompile arrived, but I did it for personal use only, and never released it.

Also, I did the opposite in the Ultimate Talkie Edition, as the protection script still is in the CD version, but never called. An “uncrack” so to speak. I added the bootparm 1 for the curious folks, making it possible to actually run it.

This is the relevant part of the boot script:

[0730] (48) if (Local[0] == 1) {
[0737] (1A)   Local[0] = 0;
[0742] (0A)   startScript(155,[]);
[0745] (80)   breakHere();
[0746] (68)   VAR_RESULT = isScriptRunning(155);
[074A] (28)   unless (!VAR_RESULT) goto 0745;
            }
            VAR_MAINMENU_KEY = 319;
[074F] (48) if (Local[0] == 0) {
[076E] (0A)   startScript(152,[]);
[0771] (80)   breakHere();
[0772] (68)   VAR_RESULT = isScriptRunning(152);
[0776] (28)   unless (!VAR_RESULT) goto 0771;
            } else {
[077E] (1A)   Bit[395] = 1;
            }

This runs before the check whether debug mode is active or not, so it can be started by just adding a 1 as a command line parameter in DOS. (EDIT: My mistake. Command line bootparm are not possible in the Ultimate Talkies. See my next post!)

In the original EGA version, this part looks like this:

[074A] (48) if (Local[0] == 0) {
[0751] (33)   SetScreen(0,200)
[0757] (0A)   startScript(152,[])
[075A] (80)   breakHere()
[075B] (68)   VAR_RESULT = isScriptRunning(152)
[075F] (28)   unless (!VAR_RESULT) goto 075A;
[0764] (0A)   startScript(149,[])
[0767] (80)   breakHere()
[0768] (68)   VAR_RESULT = isScriptRunning(149)
[076C] (28)   unless (!VAR_RESULT) goto 0767;
[0771] (18) } else {
[0774] (1A)   Bit[395] = 1;
[0779] (**) }

Thus, any bootparm other than 0 will skip this. Of course, this also requires debug mode enabled in the original game.

In Monkey 2, things are a bit more complicated, as the protection script is part of the difficulty screen. I based my version on the Amiga Kixx release, which is the only official version with the difficulty screen intact, but without the protection, and it is not one of those interpreter cracks.

3 Likes

I like the way you think. It also explains where I got the original MI2 patch idea (for some reason I thought the PC version always had the two byte patch in the data file, but actually it comes with a hacked interpreter file!) MI2 is going to be complicated to skip directly to the level select, the Mac version actually duplicates the level select screen instead of loading the copy protection script and doing that is off the table because it would not work with translations/would not be universal as a patch. If you have any ideas on MI2 do let me know!

So far I do have a working batch file now to patch disk01.lec (I’m using swiss file knife for the patching) and I’ll probably put it onto GitHub once I’ve worked a few other things out (I want the file to be able to reverse patch as well and support more games than just MI1). In terms of the script itself, I’m patching script 152:

[0000] (48) if (VAR_VIDEOMODE == 4) {
[0007] (1A)   Local[8] = 5;
[000C] (1A)   Local[9] = 5;
[0011] (1A)   Local[10] = 3;
[0016] (18) } else {
[0019] (1A)   Local[8] = 3;
[001E] (1A)   Local[9] = 11;
[0023] (1A)   Local[10] = 1;
[0028] (**) }
[0028] (2C) InitCharset(4);
[002B] (18) goto 0030;
[002E] (98) systemOps(3);
[0030] (72) loadRoom(90);
[0032] (33) RoomColor(0,1);

This is where room 90 is loaded, you can simply change the goto as follows:

[0000] (48) if (VAR_VIDEOMODE == 4) {
[0007] (1A)   Local[8] = 5;
[000C] (1A)   Local[9] = 5;
[0011] (1A)   Local[10] = 3;
[0016] (18) } else {
[0019] (1A)   Local[8] = 3;
[001E] (1A)   Local[9] = 11;
[0023] (1A)   Local[10] = 1;
[0028] (**) }
[0028] (2C) InitCharset(4);
[002B] (18) goto 01EE;
[002E] (98) systemOps(3);
[0030] (72) loadRoom(90);
[0032] (33) RoomColor(0,1);

I considered going the boot param rout however I feel this is cleaner because any skip from the boot param happens before this script is loaded, thus this patch can’t possibly interfere with such a skip.

The target binary pattern (in hex) from the goto location is 6b69f16a1b335a6b69696869e9e9e963 and just the first two bytes need to be changed (the destination of the goto) to a968. There’s no point hardcoding offsets because firstly the location will be different across different builds and there are many official release builds, but also it’s the script you’re looking for anyway so even if the offset were hypothetically the same it doesn’t matter because you’d still need to check the value of the bytes at the offset to ensure you’re not patching the wrong game!

As I think of it, command line bootparms don’t work with every interpreter version. Some official versions have a hardcodec bootparm. Especially the v5 talkie uses -7873 to skip the protection of Fate of Atlantis. Thus, command line bootparms can not be used in the Ultimate Talkie Editions. It is still possible to enable debug mode and enter them in-game, though.

I didn’t check, but I suspect that the officially hacked MI2 also uses a hardcoded bootparm, thus skipping the difficulty screen.

Those are my changes in MI2 copycrap, which I made by comparing the regular pc version with the Amiga Kixx release:

--- 001_SCRP_128_orig.dmp.txt	2026-10-17 09:02:30.024511300 +0200
+++ 001_SCRP_128.dmp.txt	2020-10-18 11:43:50.000000000 +0200
@@ -1,3 +1,6 @@
+            if (Local[0]==0){
+              goto 1000;
+            }
 [0000] (1A) Local[0] = 3;
 [0005] (1A) Local[1] = 11;
 [000A] (2C) CursorHide();
@@ -50,4 +53,13 @@
 [019F] (27) PutCodeInString(48, "MONKEY ISLAND 2\xFE\x01 `I want it all\\  All the\xFE\x01  puzzles\\  All the work\\`");
 [01E9] (27) PutCodeInString(49, "MONKEY 2 LITE\xFE\x01 `I've never played an\xFE\x01  adventure game before.\xFE\x01   I'm scared.`");
 [023D] (A0) stopObjectCode();
+[1000]      Local[0] = 1;
+            Local[1] = 1;
+            CursorHide();
+            UserputOff();
+            VAR_VERB_SCRIPT = 132;
+            beginOverride();
+            goto 1018;
+[1018] (62) stopScript(142);
+            goto 00EC;
 END



--- 003_SCRP_130_orig.dmp.txt	2026-10-17 09:04:55.469778100 +0200
+++ 003_SCRP_130.dmp.txt	2020-10-18 11:43:50.000000000 +0200
@@ -1,5 +1,10 @@
-[0000] (1A) Local[8] = 3;
-[0005] (1A) Local[9] = 11;
+[0005] (1A) if(Local[0]==0){
+              Local[8] = 1;
+              Local[9] = 1;
+            } else {
+              Local[8] = 3;
+              Local[9] = 11;
+            }
 [000A] (1A) Local[10] = 1;
 [000F] (2C) InitCharset(7);
 [0012] (2C) CursorCommand([0,0,0,0]);
@@ -14,10 +19,13 @@
 [0038] (80) breakHere();
 [0039] (80) breakHere();
 [003A] (80) breakHere();
-[003B] (0A) startScript(128,[]);
+[003B] (0A) startScript(128,[Local[0]]);
 [003E] (80) breakHere();
 [003F] (68) VAR_RESULT = isScriptRunning(128);
 [0043] (28) unless (!VAR_RESULT) goto 003E;
+            if(Local[0]==0){
+              goto 0282;
+            }
 [0048] (14) print(255,[Text(" ")]);
 [004D] (14) print(255,[Text(" ")]);
 [0052] (9A) Local[6] = VAR_TMR_1;
@@ -77,7 +85,7 @@
 [01A6] (48) if (Var[106] == 11) {
 [01AD] (18)   goto 0139;
 [01B0] (**) }
-[01B0] (44) if (VAR_DEBUGMODE > 1) {
+[01B0] (44) if (VAR_DEBUGMODE >= 1) {
 [01B7] (48)   if (Var[106] == -100) {
 [01BE] (18)     goto 027E;
 [01C1] (**)   }
@@ -114,13 +122,18 @@
 [027B] (**)   }
 [027B] (18)   goto 003B;
 [027E] (**) }
-[027E] (2E) delay(30);
+[027E] (2E) Local[0]=1;
+            delay(30);
 [0282] (3F) drawBox(0,0;,319,60,160);
 [028D] (07) setState(1154,0);
 [0291] (07) setState(1155,0);
 [0295] (14) print(255,[Text(" ")]);
 [029A] (14) print(255,[Text(" ")]);
 [029F] (80) breakHere();
+            if(Local[0]==0){
+              CursorCommand([0,10,3]);
+              RoomIntensity(0,3,3);
+            }
 [02A0] (14) print(254,[Color(81),Center(),Pos(157,27),Text("\xFF\x07/\x00")]);
 [02B0] (14) print(254,[Color(81),Left(),Pos(51,57),Text("\xFF\x070\x00")]);
 [02C0] (14) print(254,[Color(81),Left(),Pos(51,122),Text("\xFF\x071\x00")]);
@@ -130,10 +143,14 @@
 [02E3] (5D) setClass(1157,[32]);
 [02EA] (5D) setClass(1158,[32]);
 [02F1] (5D) setClass(1159,[32]);
+            if(Local[0]==0){
+              VAR_VERB_SCRIPT = 131;
+            }
 [02F8] (2C) CursorShow();
 [02FA] (1A) Var[106] = 0;
 [02FF] (80) breakHere();
 [0300] (48) unless (Var[106] == -2) goto 02FF;
+            VAR_MAINMENU_KEY = 319;
 [0307] (2C) CursorHide();
 [0309] (2C) UserputOff();
 [030B] (14) print(255,[Text(" ")]);
1 Like

Interesting! That’s modified scripts 128 and 130, which is what I thought we’d have to do to skip the copy protection without skipping difficulty select. Your code adds lines to the code, which I presume is what the Amiga KIXX version does, I don’t want to be adding any lines to the code and script 128 is proving to be a PITA with modifying.

Scummbler sucks with rebuilding v5 scripts, is there another way to build v5 without Summbler?

No it doesn’t use a hardcoded bootparam. What it does is allow any 4 digits to be entered and difficulty select is not skipped. The Mac version uses the hardcoded -7873 bootparam, however it has a block of code in script 130 that doesn’t exist in other versions to achieve that. To put that another way, there’s no -7873 bootparam in other versions.

The Monkey Island Madness interpreter skips the copy protection and difficulty selection. I assume it works by skipping the copy protection script from loading from script 1 thus allowing it to continue and ultimately load script 92 without loading the copy protection scripts. Script 1 actually sets the difficulty to normal before it loads the copy protection scripts as it is.

What’s interesting is that’s 4 entirely different methods used by official releases that we know about to disable copy protection with MI2. It clearly shows that they didn’t think ahead with it when implementing it in the first place. Copy protection for games is only intended to provide relief from piracy for the release window of the game, which is why it’s often disabled on re-releases.

It’s dead-easy to allow the user to type in any 4 digits, but skipping the copy protection prompt without changing the size of script and without knowing in advance the offsets (allowing for any translation and system variant) to be patched is not so simple. Even changing the size of the script isn’t possible if it can’t be recompiled after editing.

Most of the added lines are there for bootparam 1 in the Ultimate Talkie to keep the possibility to run the protection if the curios user wishes to. Those IF blocks are not in the KIXX release. Interesting enough, the KIXX release has all the unused parts NOP’d out, thus it was pretty straight forward for me were I needed the goto instructions. Seems like a talented hex edit rather than a re-compile.

The Special Edition uses the regular protected scripts and skips right into hard mode by the interpreter, just like the Madness version, thus I had to crack the script anyway in order to make it usable with the DOS talkie version of the SCUMM V5 interpreter.

I may have missed the point, but why would you want to skip the “copy protection”?

To answer why some people call their crack a “trainer:” back when games released on C64 were subsequently cracked so they could be copied, the crackers would add things like their own loading screens/music (which evolved into demo scene) as well as “trainer” screens to set infinite lives or unlimited ammo, while you are changing some variables and flags anyway.

It’s interesting to note here that the copy protection on C64 games was done with various techniques, some easier some harder to near-impossible to crack, while for PC games like MI1, it is even advised in its manual to create a copy and play that one (keeping the original disks pristine and safe).
Some proof that actually none of the Lucasfilm games had any (disk) copy protection at all and advised to copy/backup your disks:

So the codewheel (or other things like “nth word on page X”, exit visa codes,…) is more of a check for owning an actual complete copy than preventing the program to be copied. After all, the cost of photocopying the manual was prohibitive at first (or comparable to buying the game - which in hindsight is always the best investment, but hey we were broke as kids) then preventing the copying by using dark red paper. Later on the first CD-ROM releases ditched the check as a blank CD-ROM and a CD-burner was too expensive. Years later relying on dll’s that have been revoked pose a bigger issue with game preservation than a creative ownership check like MI’s codewheel. (Yes, I’m looking at you SafeDisc)

As for the reasons they disabled copy protection on re-releases like Monkey Madness it’s a combination of (at the time) more expensive-to-copy physical media and maybe even more so that they did not want to produce extra codewheels to save on costs.

To my knowledge the codewheel is the same for all versions and platforms it was released on, so a small program and/or the PDF of the codewheel in all its positions should do the trick too. After all, game preservation should be about preserving the entire game including manuals and so on.
Taking one of my favourites, Zak, the bundled newspaper is an integral part of the game (and probably the reason it isn’t loved as much as it should be by the everyone who has plays it today in scummVM without ever bothering to read the manual/newspaper). (Even the very first puzzle to get your cashcard, is spelled out for you in the manual. I can imagine it kept a lot of people from progressing any further on their cracker copy at a time there were no online walkthroughs).

Anyway sorry for the rant, and I do find the technical side really interesting, but I’m with team CodeWheel.

4 Likes

Something like this?

(An implementation for Monkey Island 2 is available in the Mixnmojo Funzone.)

It was more the non-working crack. :wink: One of the most common English C64 cracks had a disk error (on side 3 AFAIR). It was a little bit frustrating because you stumbled over it after several hours of play …

I’m happy to report that I read the PDF from GOG. :smiley:

2 Likes

Would you be able to send me the file please (just a raw dump of scripts 128 and 130 would do)?

Um, why wouldn’t you?

The point of my project isn’t to stop you from having the games in the unmodified state at all, it’s simply to allow the best possible crack for the copy protection and in the process document it. In fact what I can also do is reverse the cracks applied by the legacy cracking apps restoring copy protection and ultimately I’d like to also do that. My intention is just to offer the user choices.

It’s best not to make assumptions. Both MI1 and MI2 came on CD-ROM in Germany with copy protection in multiple releases:

That version is dated 1997 and has a CMI demo on it, it does not contain the Enhanced version of MI1 it’s the VGA floppy and it uses a 3rd-party app to save the games to the hard disk when playing from CD-ROM (even though the Enhanced CD-ROM saves directly to the hard disk as does the Madness version of MI2). Note also that the German version of the MI2 code wheel was higher security with the answers printed on a red background to prevent photocopying. Even though that was the case for MI2, the MI1 code wheel was not printed that way in the same box/release.

If we want to know why these choices were made we can’t be making assumptions, we have to ask questions and find the people who made the decisions to answer those questions.

Oops, forgot to say that with LogicDeLuxe’s project he is using an EXE interpreter/launcher that support voice for Monkey Island 2 and building it from the Special Edition which itself does not contain copy protection. So with his project hacking it required because otherwise it copy protection would be added.

Most of them, but not all. C64 Maniac Mansion did come with a disk based protection and is in turn missing Nuke’m Alarms, which was added when the game was ported to other platforms.

Sorry, I did not keep them. You have to dissect that version for yourself. Basically, all parts I’m skipping with any bootparam other than 1 is NOP’d out.

I’m not sure that the German publisher exactly knew what they were doing. There was absolutely no reason not to update that release to the enhanced CD version. The multi-lingual CD released in other countries even has German included. In Day of the Tentacle and in Zehn Adventures, they also added the infamous mailbox bug in Maniac Mansion. ScummVM is not effected, since it is a bug of the hacked interpreter, but I did make a patch for the DOS version here: http://www.gratissaugen.de/files/MMFIX.ZIP

It restores the original EXE and adds a proper bypass in the script. Unlike the code wheel, the door is not skipped, as that would disable Bernard from trying. It just accepts any code. There are some bad cracks around, which let any keypad in the game accept any code. I found out since my initial version of the patch was based on one of those.

I’ve also seen a version of Indy 3 with the code table is in the box, even though, the included version of the game wasn’t protected.

It is basically the EXE from the Fate of Atlantis talkie CD patched to load the General MIDI driver, which in turn is extracted from the Sam & Max demo. The downsides of that interpreter version is, that it does not support CD audio nor EGA.

1 Like

Later they were published on the CDs of several gaming magazines. At least one of them printed the code wheel on paper in the magazine so the readers could cut out the the wheel. (PC Player did this AFAIR.)

Really? :thinking: I have the original German MI2 disk version and the code wheel looks exactly like the one in your picture. I haven’t the box handy at the moment, so I can’t check. But I’m confident that it hasn’t a red background … :thinking:

Simple: It was a licensing issue.

The German company Softgold had the distribution rights only for the disk versions, but not for the CD-ROM editions of all Lucasfilm/Arts games. That’s the reason why the CD-ROM versions of Monkey Island and Loom are extremely rare in Germany. (And I’ve never seen the Indy 4 Talkie in retail stores in Germany.)

That’s wild! The PC Gamer version (English) came on the CD with the July 2000 Magazine and it had an interpreter that skips the copy protection.

The red background is only where the digits are printed, like in that photo.

I agree with you.

The reason why the 5 language “Enhanced” CD-ROM version was so common here was because it was distributed with new PCs, and it’s also why it came without a box. I did import a copy of the big-box release from the US, but I’m pretty sure it was never sold that way in Australia.

1 Like

FYI: It was the PC Player issue 1/98. The code wheel for Monkey Island 2 was on page 133. I can’t remember (and can’t check at the moment) how GameStar did it with Monkey Island 1. But it seems that they also provided a printed code wheel.

In Germany “Karstadt” sold these OEM versions of Monkey Island and Loom without a computer - but only for a very short time.

I could also have sworn my German Amiga version of MI2 didn’t have a red background for the digits, though I am too lazy to make the trek to the basement to verify that.

And that’s probably the only reason why I’d be in team cracker for these old games, as it’s really tedious to keep the manuals or gadgets required to actually play the game nearby. (As a teenager, I stored all the manuals in the largest drawer of my desk, so they were always within reach. But I don’t have that luxury right now.)

Edit:
Forgot to share this anecdote: I did not own a legit copy of Indy4 back then, and the disks I had came with the copy protection, which would ask for the correct configuration of the stone disks for a certain combination of sun, moon and volcano, which was displayed after pressing Enter. Presumably, you had to look up the answer in the manual. However, I soon discovered that if I hit Enter before the copy protection screen was displayed, it would always settle on the exact same combination, which was easy enough to brute-force and memorize. Not sure if that was a bug, or already some kind of crack, though.

3 Likes

MI2 works the same way, you can hold down Enter literally from the command line and you’ll always have the same recipe.

With MI2 it’s not a bug, they decided to take the “randomness” from when you press Enter (or another key) rather than relying on “rand()”.

Indy4 has the copy protection printed in the manual.

When I was a kid I would crack everything I possibly could. That doesn’t extend to MI1 disk, but only because of my age at the time. I remember cracking “Trolls” - with a hex editor - just because I was sick of the copy protection prompt. The answers in the data file were in plain text and I thought “you beaut I can enter in the same digits now” but somehow the game just skipped the copy protection prompt entirely after I corrupted it.