REM Some trivial disc protection REM -- an exercise in mangling a floppy disc : ON ERROR E$=REPORT$+" at line "+STR$(ERL):OFF:ERROR 0,E$ MODE13 SYS "OS_PrettyPrint","Warning! This program will probably corrupt a floppy disc that isn't entirely blank. Press Escape now to abort or any other key to carry on..."+CHR$0,0,CHR$0 IF GET : REM Pick a number, any number... serial_number%=TIME EOR RND(&7FFFFFFF) OSCLI"ADFS:Dismount 0" OSCLI"ADFS:NameDisc 0 Sh"+STR$~serial_number% : REM Add fudge value onto the end of the sound length to make it a valid REM immediate constant (i.e. ends in &00) SYS "OS_File",23,".Howl" TO ,,,,sound_len IF sound_len>&FFFF THEN ERROR 0,"Sound module is too long" IF (sound_len AND &FF)<>0 THEN sound_len=(sound_len+&100) AND &FF00 DIM sound_mod sound_len SYS "OS_File",16,".Howl",sound_mod,0 : screen_address=819200-81920 sound_address=screen_address-sound_len game_code_address=sound_address-1024 : DIM code 1024 FOR pass=0 TO 2 STEP 2 P%=code [OPT pass : .start_game_code : SWI &100 + 22 SWI &100 + 13 : ADR R0,vdu_in_block ADR R1,vdu_out_block SWI "OS_ReadVduVariables" ; Get address of screen memory : MOV R2,#screen_address LDR R3,[R1] ; R3 = address to read screen image into MOV R1,#1 MOV R4,#81920 SWI "ADFS_DiscOp" ; Read garbled title page straight into MOV R5,#81920 ; our screen memory SUB R3,R3,R5 BL seed_random_from_title .decode_screen_loop LDR R1,[R3] BL random EOR R1,R1,R0 STR R1,[R3],#4 SUBS R5,R5,#4 BNE decode_screen_loop : MOV R0,#6 MOV R3,#sound_len ; Claim some memory for sound module SWI "OS_Module" ; R2 = block of memory to load module into MOV R3,R2 MOV R2,#sound_address AND &FF00 ORR R2,R2,#sound_address AND &F0000 MOV R1,#1 MOV R4,#sound_len BL seed_random_from_title SWI "ADFS_DiscOp" ; Load scrambled module off disc MOV R5,#sound_len SUB R3,R3,R5 BL seed_random_from_title ; Decode module (as screen, above) .decode_sound_loop LDR R1,[R3] BL random EOR R1,R1,R0 STR R1,[R3],#4 SUBS R5,R5,#4 BNE decode_sound_loop : MOV R0,#11 SUBS R1,R3,#sound_len MOV R2,#sound_len SWI "OS_Module" ; Link decoded module to module chain MOV R0,#7 MOV R2,R1 SWI "OS_Module" ; Free temporary memory used ADR R0,splay_howl SWI "OS_CLI" ; Make noise : SWI "OS_Exit" ; Done! : .seed_random_from_title ; ; A subroutine to read the title of the disc and seed our random number ; generator with the appropriate value... if the title of the disc is wrong ; the data won't decode properly. ; STMFD R13!,{R0-R3,R14} ADR R0,colon_zero ADR R1,end_game_code SWI "ADFS_DescribeDisc" MOV R0,#0 ADD R1,R1,#24 MOV R0,#16 SWI "OS_ReadUnsigned" STR R2,rand_seed1 MOV R0,#0 STR R0,rand_seed2 LDMFD R13!,{R0-R3,PC} : .random STMFD R13!,{R1-R2,R14} ; This should be familiar! LDR R0,rand_seed1 LDR R1,rand_seed2 TST R1,R1,LSR#1 MOVS R2,R0,RRX ADC R1,R1,R1 EOR R2,R2,R0,LSL#12 EOR R0,R2,R2,LSR#20 STR R0,rand_seed1 STR R1,rand_seed2 LDMFD R13!,{R1-R2,PC} : .rand_seed1 EQUD 0 .rand_seed2 EQUD 0 .vdu_in_block EQUD 149:EQUD -1 .vdu_out_block EQUD 0 .colon_zero EQUS ":0":EQUB 0 .splay_howl EQUS "Splay_Howl":EQUB 0:ALIGN .end_game_code : .start_run_file .start_decoding_key SWI "OS_GetEnv" CMP R1,#&10000 ADRLT R0,not_enough_memory SWILT "OS_GenerateError" SUB R13,R1,#8192 ; Bit of stack space : MOV R0,#150 ; 1.5secs should be enough ADR R1,crash_machine STMFD R13!,{R1} MOV R2,#0 SWI "OS_CallAfter" ; Crash the machine after this time! ADR R0,start_decoding_key ADR R1,end_decoding_key ADR R2,start_decoding_code ADR R3,end_decoding_code .decode_loading_code_loop LDR R4,[R0],#4 LDR R5,[R2],#4 EOR R4,R4,R5 STR R4,[R2,#-4] CMP R0,R1 ADREQ R0,start_decoding_key CMP R2,R3 BNE decode_loading_code_loop MOV R0,#1 ADR R1,start_decoding_code ADR R2,end_decoding_code SWI &6E OR (1<<17) ; XOS_SynchroniseCodeAreas, but any machine ; not running 3.7+ won't know the SWI number ; ; (NB 1<<17 flag for setting X bit) ; ; Non-StrongARM machines will ignore this ; instruction since the X bit is set B start_decoding_code .not_enough_memory EQUD 0:EQUS "Not enough memory":EQUB 0:ALIGN .crash_machine B crash_machine ; Yes, I know there are nastier ways ; of doing this ;-) .end_decoding_key : .start_decoding_code MOV R1,#1 MOV R2,#game_code_address AND &FF00 ORR R2,R2,#game_code_address AND &F0000 ADR R3,end_decoding_code MOV R4,#1024 SWI "ADFS_DiscOp" ; Load game code off disc MOV R0,#1 ADR R1,end_decoding_code ADD R2,R1,#1024 SWI "XOS_SynchroniseCodeAreas" : LDMFD R13!,{R0} MOV R1,#0 SWI "OS_RemoveTickerEvent" ; Stop the impending crash... .end_decoding_code : ]:NEXT : OSCLI"ScreenLoad .Loading":OFF DIM in 8,out 4 in!0=149:in!4=-1 SYS "OS_ReadVduVariables",in,out REM Mangle the data appropriately with the encryption routines below PROCmangle(serial_number%,out!0,out!0+81920) PROCmangle(serial_number%,sound_mod,sound_mod+sound_len) PROCmanglewithkey(start_decoding_key,end_decoding_key,start_decoding_code,end_decoding_code) REM Write our screen, sound and loading code to the end of the disc SYS "ADFS_DiscOp",,2,screen_address,out!0,81920 SYS "ADFS_DiscOp",,2,sound_address,sound_mod,sound_len SYS "ADFS_DiscOp",,2,game_code_address,code,end_game_code-start_game_code : REM Set up the game directory structure on the disc OSCLI"Cdir ADFS::Sh"+STR$~serial_number%+".$.!Shoddy" OSCLI"Copy .!Sprites ADFS::Sh"+STR$~serial_number%+".$.!Shoddy.!Sprites ~CF~P~V" SYS "OS_File",10,"ADFS::Sh"+STR$~serial_number%+".$.!Shoddy.!Run",&FF8,,start_run_file,P% : END : REM These are encryption procedures to mimic the ARM functions above; they're REM slower but get the same results. : DEF PROCmangle(seed,start,end):LOCAL x% !rand_seed1=seed:!rand_seed2=0 FOR x%=start TO end STEP 4:!x%=!x% EOR USR(random):NEXT ENDPROC : DEF PROCmanglewithkey(k_start,k_end,d_start,d_end):LOCAL k%,x% k%=k_start FOR x%=d_start TO d_end STEP 4 !x%=!x% EOR !k%:k%+=4:IF k%=k_end THEN k%=k_start NEXT ENDPROC