Wings of Fury (c) 1990 by Broderbund

1. AMiGA or WINUAE (Configuration: 2MB CHIP!!!)
2. ACTION REPLAY freezer (or ROM Image)
3. Original Game or CAPS-Image
4. Assembler (ASM-One / Trash-M One / Seka or similar)
5. Little knowledge about tracevector-decoding

Copylock-Crack, Novella still active!

Hiho and welcome to my first Copylock tutorial… This one is for *Wings Of Fury* which consists
of an copylock protected exe-file…. If the word tracevectordecoder is something you?ve never
heard before than plz start with reading the tvd tutorial by wayne k. ! You know what it?s
all about, okay… So, if you run your copy of the original disk the game will load in the file
wings_of_fury/wings … after loading you?ll notice a funny trackgrind followed by a little
delay and the game will crash! So as you probably will know the copylock routine just calculated
a checksum-key over the not dos-readable track 1 and tried to decrypt the main exe file in memory using
that key! Due to the fact that the gamecopy doesn?t own the correct track 1 the key is calculated wrong and so
the game is not decrypted correct and causes the game to say goodbye! 😉 So let?s see what?s going on
with loading in the exe file …. Enter AR and type:
lm wings_of_fury/wings, $40000 … and disassemble the stuff with:
d $40028 (we don?t use $40000 coz we jump over the dos-executable header)
Scrolling down some lines you?ll see this:

First of all the gamecode switches into supervisor mode (not shown here)… Some instructions later you see lotsa stuff moved onto the stack! Now what are
all these bytes good for ?
Well, the “crap” that is moved onto the stack with MOVE.L #$XXXXXXXX,-(A7) is in fact pure codedata!!! After
the last instruction is pushed onto the stack at $40092 the start-adress of that code which A7 now
points to is stored at $24 which is our tracevector !!! After doing that, the ORI.W #$A71F, SR at $4009E sets the
trace bit in the status register which will cause the amiga to jump to the adress stored at $24 after every processor
instruction! This means that after executing adress $400A2 (ADDQ.L #$6, $24) the trace routine is called. Perhaps you have recognized
that all instructions that follow from adress $400A8 are pure senseless garbage! 😉 Now what the tracevector-routine does is to
decrypt every next instruction that the processor executes and to crypt the one that was executed before!! This means that you can?t let
the code decrypt the whole copylock code and finally disassemble the decrypted stuff!
So in fact, the amiga does NOT execute the MOVEQ #$FFFFFF85, D1 at $400A8 because the traceroutine will decrypt
this instruction to be another one!
So how can we find out what the decrypted copylock code looks like ???
First of all we have to view onto the code that is *moved* to the stack with all those “-(A7)” moves because this is the part that
crypts/decrypts the upcoming instructions.
To reach our aim, we will replace the MOVE.L A7, $24 that moves the adress in A7 to the tracevector at $24
with a branchloop…. this means the exe file will stop at this part and we can enter our AR to disassemble the code from this adress.
Type in:
a $40098 … to start assemble-mode and insert the following instruction:
BRA $40098 … and overwrite the exe-file with:
sm wings_of_fury/wings, 40000 579CC !!!
Now reset your machine and boot the gamedisk until nothing happens anymore which means that our loop is running!
Enter AR, view the registers using r and disassemble from the adress that is stored in A7 like shown below.

(Also if you used same memoryconfig than me the adresses may differ, so plz work with the ones showed on your computer!

Now without getting deeper into tvd stuff the first 2 eor.l?s crypt the last instruction that was executed before, the
other 2 at the end are decrypting the next one. Now to see the decrypted code we will patch the last *RTE* which exits the
traceroutine with a jump to a little piece of code which will rescue every single instruction. When this *RTE* is executed, A6 points
to the next decrypted instruction, ready for being saved. 😉 So, behave like shown in the pic below:

As you can see I just replace the *RTE* with a jump to adress $7FF00 which will hold our little patchcode (assembled right after).
Now before we continue the gamecode with jumping right behind our branchloop we will have to store the adress in A7 to the tracevector
adress at $24 coz we have overwritten this instruction in the exefile. Now jump back into gamecode (program counter+2) and wait until copylock
routine has finished and the game begins to continue loading (this stage is not reached with a copy of the original) !!
We stored the A6 pointer at $7FFF0 every time so we can see which adress held the last decrypted instruction. Now to finally disassemble this
code we have to add $80000 to this adress coz we saved the decrypted instructions to A6+$80000 in our patchcode. Due to the fact that this
is the pointer to the LAST decrypted instruction we have to sub a little offset to see the beginning…. (the offset value 384 is not calculated I just searched for the beginning manually hehe) … So enter AR again and do this:

After scrolling down some lines I came to the point that this is NOT the real copylock routine that has been decrypted… It?s way too
short and it ends up with this:

UUhm…. seems as if another routine is been moved onto the stack and then used as a new tracevector-decoder! ;-(
Now before you start screaming, this is finally the routine that decrypts the real copylock code! So somehow we will
have to make the Action Replay pop up when the last instruction of the first copylock-code (MOVE.L A7,$24) has been decrypted to
see what routine A7 is pointing to! But how can we manage that ?
Easy!! Instead of patching the traceroutine to rescue the decrypted instructions we will insert a simple counter that
only adds 1 after every crypt/decrypt loop. Using this method I found out that the first decoder loops $108 times!!
So to find out what the second decoderoutine looks like reboot the game and patch the first decoder like this:

(also remember to put the adress stored in A7 to $24 again before executing the code!). Now the tricky thing is that we
set a breakpoint to adress $7FF0C which means that the AR will pop up if the decodeloop just decrypted the $108?s instruction! So if this happens, A7 points to the new decoderoutine!
Okay, after executing the code again with g the AR will pop up immediately….
Disassemble the code beginning from the adress A7 is pointing to, it will look like this:

Wow, this is the final decryption routine for the real copylock-code.
If we wanted this tutorial to get even bigger we could now behave like done with the first decoder… inserting a patch
that saves all decrypted instructions into highmem. But we don?t need to do it because I guess that meanwhile most of you know the inner work of a copylock. So instead we are inserting a patch like this:

So what is this patch about?
Due to the fact that the decoderoutine does decryption like
EOR.L D0, (A0)+
EOR.L D0, (A0)
we start with subtracting 4 from A0 to have a pointer onto the next instruction to be executed. Then the
CMP.W #$2006, (A0)
compares if the decrypted instruction is MOVE.L D6, D0, which is $2006 as hex value!
So why MOVE.L D6, D0 ??? Well, in most copylocks the key is calculated and then moved from D6 to D0 this way! 😉 The “MOVE.L D6, D0” Instruction appears only one time in the copylock so we can easily set a breakpoint to the NOP in our patch… so if AR pops us, D6 will hold the correct copylockkey because the next instruction would move it from D6 to D0!!
Type x now to continue gamecode, AR will pop up immediately!

Voila, D6 holds the correct key which is: $6E7CB168 !
In our crackpatch we will use this situation to put the correct key into D6 !!


Now all we have to do is to code a little patch which will do all those steps we did before automatically… To make sure our patch is executed we will replace the branchloop in the exe file with a jump subroutine to $7C000. Then we will code a little
program that copies our patch to $7C000 and put this small program in the startup-sequence right before the wings exe-file!
So first of all, enter AR, load in the mainfile and insert the jump like shown below:

Next task is to boot up your Assembler, reserve some chipram or whatever and type in the following sourcecode:

LEA PATCH(PC),A0 ; Simply copy the patch to $7C000
LEA $7C000,A1 ; No comments here!
MOVE.B (A0)+,(A1)+

MOVE.L A0,$7D000 ; Save A0
MOVE.L A7,A0 ; Pointer to decoder to A0
ADD.L #$28,A0 ; Now A0 points to the last RTE of decoder 1
MOVE.W #$4EF9,(A0)+ ; Replace with JMP $7C032 …
MOVE.L #$7C032,(A0) ; … which is JMP DECODERPATCH1
MOVE.L $7D000,A0 ; Restore A0
MOVE.L A7,$24 ; We have overwritten the MOVE.L A7, $24 in the exe, so we do it now!
ADDQ.L #$4,$24 ; … +4 because we performed a jsr to here, stack decreased by 4 though!
MOVE.L #$0,$7D000 ; Clear Counter which is used by DECODERPATCH1
RTS ; Back to the EXE!
CMP.W #$107,$7D000 ; Decrypted the $108?s instruction ?
BNE.B NOTYET ; Nah, not yet!
MOVE.W #$4EF9,$50(A7) ; Yeah, replace last two instructions of decoder 2
MOVE.L #$7C052,$52(A7) ; with JMP $7C052 (which is JMP DECODERPATCH2)
ADDQ.W #1,$7D000 ; Increase Counter
RTE ; Back to game
CMP.W #$2006,-4(A0) ; Next instruction to execute “MOVE.L D6, D0” ?
BNE.B NOTYET2 ; Nah, not yet!
MOVE.L #$6E7CB168,D6 ; Otherwise move correct key to D6
MOVEM.L (A7)+,D0/A0 ; Back to game

Now finally assemble the sourcecode and save the EXE to your crackdisk using WO, naming it for example delocker or something. At last change the
“startup-sequence” in the S Directory to load the delocker first, so that it looks like this:

cd wings_of_fury

Now boot up your crack and have a play… Somebody told me that this game also has
an novella protection but I didn?t came to the point where it appears! So if you find
it … feel free to crack it, write an tutorial and append it to this one! 😉
Alpha One ?2005


Publication author

offline 5 days


Comments: 1160Publics: 2780Registration: 06-03-2017

Notify of

Inline Feedbacks
View all comments
18 years ago

yup..and very cool game 🙂

18 years ago

Very Good Tutorial!


This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.


This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Password generation

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Would love your thoughts, please comment.x