—————————————- [0] Introduction .-=[ [0] Introduction ]=-. TVD is an acronym for “Trace-Vector Decoder”, which is a commonly-used This example was found in the game: ALTERED BEAST (C) ACTIVISION/SEGA. The TVD in this game (as in most/all of Rob’s protections) is used to |
|
0171E0 : LEA 17260,A0 | ; 17260 is written into the vector table @ 00000010, this is the ILLEGAL;INSTRUCTION vector, which is jumped to if the 68000 can’t make sense of the;current opcode, or if it’s deliberately called with the ‘ILLEGAL’ instruction;when we reach this code, we are inside an ILLEGAL EXCEPTION |
0171E4 : MOVE.L A0, 10 | |
0171EA : ILLEGAL | |
017260 : MOVEM.L D0/A0-A1,-(A7) | |
017264 : LEA 1729A,A0 | ;TRACE VECTOR = 1729A (this is the decoder) |
017268 : MOVE.L A0, 24 | |
01726E : LEA 176C4,A0 | ;PRIVV VECTOR = 176C4(called when a PRIVILEGE VIOLATIONoccurs;when the cpu tries to use an instruction in user mode which isn’t allowed.;In this game 176C4 contains an RTS instruction, and is used to exit the;protection check and return to the game code… |
017272 : MOVE.L A0, 20 | |
017278 : ADDI.L #2, E(A7) | ;Here is the “clever” bit… the ADDI instruction adds 2 to the return address;stored on the stack, the ORI instruction sets the interrupt mask in the saved;SR value on the stack (changes it from 2000 to 2700, turning off all irqs;except level 7), the BCHG instruction flips bit 7 in the saved SR high-byte;value. This will set the trace bit when this value is retrieved (when the next;RTE instruction is executed), thereby jumping to the TVD! |
017280 : ORI.B #7, C(A7) | |
017286 : BCHG #7, C(A7) | |
01728C : LEA 171A2,A1 | ;if the BCHG instruction @ 017286 set the zero flag, we jump into the TVD;halfway through (used to turn OFF the TVD later) |
017290 : BEQ.S 172AC | |
017292 : MOVEA.L (A1),A0 | |
017294 : MOVE.L 4(A1),(A0) | |
017298 : BRA.S 172C0 | ;jumps to the end of the TVD, which does an RTE, and starts the TVD 🙂 |
;*** trace vector decoder begins *** |
|
01729A : ANDI # F8FF,SR | ;turn on interrupts by setting irq mask to 000 |
01729E : MOVEM.L D0/A0-A1,-(A7) | ;save registers before use |
0172A2 : LEA 171A2,A1 | |
0172A6 : MOVEA.L (A1),A0 | ;A0 now = the address of the instruction decoded in the previous TVD loop;this writes the previously used encrypted value over the old instruction.;This means every time the TVD runs, it encrypts the last instruction executed,;which of course means you can’t let the TVD loop through a certain number of;times and dump the decrypted code from memory (Rob’s not that stupid!) |
0172A8 : MOVE.L 4(A1),(A0) | |
0172AC : MOVEA.L E(A7),A0 | ;A0 now = the next instruction to be decoded (the instruction we return to when;the next RTE instruction occurs. |
0172B0 : MOVE.L A0,(A1) | ;save the address in memory for next loop;moves the encrypted value into memory for next loop (used to overwrite the;decoded instruction once it’s been executed). |
0172B2 : MOVE.L (A0),4(A1) | |
0172B6 : MOVE.L -4(A0),D0 | ;get the encrypted dword from memory (4 bytes before the instruction we’re about;to decode) into D0 |
0172BA : NOT.L D0 | ;the extremely simple decryption routine. |
0172BC : SWAP D0 | ;the EOR writes the decoded instruction into (A0), which we are about to reach;when the RTE below is executed… |
0172BE : EOR.L D0,(A0) | |
0172C0 : MOVEM.L (A7)+,D0/A0-A1 | ;restore the registers |
0172C4 : RTE | ;return from exception.;remember that RTE has set the status register back to the saved value, which;means that the trace bit will still be set (unless cleared by another routine);therefore after executing the instruction that has just been decoded we’ll be;back into the TVD! |
Phew! A lot of commentary for such a little piece of |
|
0000C4 : 2028 FFFC MOVE.L -4(A0),D0 | ;these are the remaining instructions from the original TVD, that we need to;execute before doing anything else.;Now we can use registers D0, A0 and A1 for our purposes, since we restore them ;at the end… |
0000C8 : 4680 NOT.L D0 | |
0000CA : 4840 SWAP D0 | |
0000CC : B190 EOR.L D0,(A0) | |
0000CE : 2250 MOVEA.L (A0),A1 | ;get decrypted instruction into A1 |
0000D0 : 2008 MOVE.L A0,D0 | ;get address of instruction into D0 |
0000D2 : 0080 0060 0000 ORI.L # 600000,D0 ;***Please note, this value may differ on your Amiga, change this if you do not ;have memory @ 600000 (in my case I have 1mb Fastram located here) |
|
0000D8 : 2040 MOVEA.L D0,A0 | ;A0 = new address to write opcode to |
0000DA : 2089 MOVE.L A1,(A0) | ;write decrypted opcode into our new ‘high’ address |
0000DC : 06B9 0000 0001 0000 00C0 ADDI.L #1, C0 | ;keep count of how many traces we’ve run |
0000E6 : 4CDF 0301 MOVEM.L (A7)+,D0/A0-A1 | ;these are the final 2 instructions |
0000EA : 4E73 RTE | from the original TVD that we must execute. |
And that’s it! Now when this has all executed the game Now, I know there was no point in decoding the protection routines in -Wayne Kerr, May 2004 (Yes, I know, 15 years late!) |
Cracking
Shadow of the Beast 2 – Cracking Tutorial [French]
Download the ADF below Attachments ShadowOfTheBeast2_CRACK_TUTORIAL_FR_2020 File size: 3 MB Downloads: 625 Publication author offline 3 days mus@shi9 0 Comments: 1163Publics: 2786Registration: 06-03-2017
Great explanation. I remember the hard sweat to discover pretty much the same approach when I first cracked a RN protected game (I think it was Dragon Ninja) on my A500 with 1MB of RAM. Great times.
I’m pretty sure it depends on the game/what age the copylock code is! I’ve only cracked a handful of them, maybe one of our resident copylock specialists can tell you for sure. However I think 99% of them will use at least some part of the TVD code as a key, otherwise they would have to introduce a specific checksum routine to stop the TVD being tampered with – this way they kill 2 birds with 1 stone!
I was wondering whether the last 4 bytes of the TVD are always used as a decryption key?
Or is it dependent on the game/copylock generation?