Skip to navigation

Cracker protection: CheckSecretStash

Name: CheckSecretStash [Show more] Type: Subroutine Category: Cracker protection Summary: Check whether the secret code stash is correctly set up, as part of the anti-cracker code
Context: See this subroutine in context in the source code References: No direct references to this subroutine in this source file
.CheckSecretStash LDA doNotCheckSecret \ If bit 7 of doNotCheckSecret is set then jump down to BMI stas2 \ part 2 of GetRowVisibility to skip checking the secret \ code stash \ The following code does a check on the secret entry \ code for the current landscape to ensure that it \ matches the entered code in the keyboard input buffer \ \ If the check fails, then the game restarts by jumping \ to MainTitleLoop to display the title screen \ \ Specifically, the following code checks for four bytes \ in the secretCodeStash that correspond to the results \ of the comparisons made in the CheckSecretCode routine \ \ This ensures that crackers who manage to bypass the \ CheckSecretCode routine will find that the game \ restarts, unless they also disable this rather \ well-hidden check LDA stashOffset-255,X \ We know that X is 255 from the loop above, so this \ sets A = stashOffset \ \ The value of stashOffset is set in the SetSecretStash \ routine during the landscape drawing process, where it \ is set to a value that is unique and consistent for \ each individual landscape \ We now set stashAddr(1 0) to point to the four bytes \ in the secretCodeStash that correspond to the four \ comparisons we made for the secret entry code in the \ CheckSecretCode routine CLC \ Set stashAddr = A + 41 ADC #41 \ STA stashAddr \ So that's the low byte LDX #3 \ Set X = 3 so we can use it to count four bytes in the \ loop below (as well as in the following calculation) TXA \ Set stashAddr+1 = HI(secretCodeStash) - 3 + 3 CLC \ = HI(secretCodeStash) ADC #HI(secretCodeStash) - 3 STA stashAddr+1 \ So we now have the following: \ \ stashAddr(1 0) = secretCodeStash + stashOffset + 41 \ \ When the secretCodeStash gets populated in the \ CheckSecretCode routine, we add one byte for each \ iteration and comparison in the secret code generation \ process \ \ That process starts by performing 38 iterations and \ storing the results in the secretCodeStash from offset \ stashOffset to stashOffset + 37 \ \ It then generates the four BCD numbers that make up \ the secret code, storing the results in the stash from \ offset stashOffset + 38 to stashOffset + 41 \ \ (And it then generates one more result, but we ignore \ that) \ \ So stashAddr(1 0) points to the last of those bytes in \ the secretCodeStash, i.e. the byte at stashOffset + 41 \ \ The value that is stashed in the secretCodeStash is \ the result of subtracting the entered code from the \ generated code, which will be zero if they match, and \ then %01111111 is added to the result (%01111111 being \ the object flags for the Sentinel, which is all part \ of the obfuscation of this process) \ \ So if the secretCodeStash contains %01111111, this \ means that particular byte matched, so if all four \ bytes at offset stashOffset + 38 to stashOffset + 41 \ equal %01111111, this means the secret code was deemed \ correct by CheckSecretCode LDY #0 \ Set Y = 0 so we can fetch a value from the address in \ stashAddr(1 0) in the following (we don't change its \ value) \ We use X as the loop counter to work through all four \ bytes, as we set it to 3 above .stas1 LDA (stashAddr),Y \ Fetch the contents of address stashAddr(1 0) CMP #%01111111 \ If it does not match %01111111 then this byte from the BNE talt2 \ secret code was not matched by the CheckSecretCode \ routine (so it must have been bypassed by crackers), \ so jump to MainTitleLoop via talt2 to restart the game DEC stashAddr \ Decrement stashAddr(1 0) to point to the previous byte \ in memory (we decrement as we initialised stashAddr \ above to point to the last result byte in memory, so \ this moves on to the next of the four bytes) DEX \ Decrement the loop counter BPL stas1 \ Loop back until we have checked all four secret code \ bytes \ The four code bytes have now been checked, but we have \ one more check to do, that of the comparison just \ before the four bytes \ \ This comparison would have been between inputBuffer+4 \ and a BCD number from the landscape's sequence of seed \ numbers \ \ When the landscape code is entered, it is converted \ into four BCD numbers in inputBuffer, and the rest of \ the buffer is padded out with &FF, so inputBuffer+4 \ contains &FF at the point of comparison \ \ &FF is not a valid BCD number, so it can never match a \ BCD number from the landscape's sequence of seed \ numbers, so we know that this comparison can never \ have matched \ \ So if stashAddr(1 0) contains %01111111 to indicate a \ match, then we know that the stash has been modified \ by a cracker, so we restart the game LDA (stashAddr),Y \ Fetch the contents of address stashAddr(1 0) CMP #%01111111 \ If it matches %01111111 then we know the stash has BEQ talt2 \ been compromised, so jump to MainTitleLoop via talt2 \ to restart the game SEC \ Set bit 7 of doNotCheckSecret so we do not repeat the ROR doNotCheckSecret \ secret code check again (at least, until we reach the \ next landscape) .stas2 \ Fall through into part 2 of GetRowVisibility to \ continue with the visibility calculations