org &4000 ; entry point in the loader .firstoffset equ 12 ; loader address ld l,(ix+0) ld h,(ix+1) ; disable interrupt and save registers di push hl push de push bc exx push hl push de push bc exx ; search for first loader sub_decrypt routine .searchstart ld a,(hl) inc hl cp &ed jr nz,searchstart ld a,(hl) inc hl cp &4f jr nz,searchstart ; calculate sub_decrypt address ld bc,firstoffset+2 sbc hl,bc ; point to table that store subroutine info ld de,tbl_sub_protect_a ld bc,0 ; let's decrypt first sub call prepare_code ; counter protections ld a,0 ld (prot_counter),a ; main loop ; search for subgroup routine type .loop push hl pop iy ld a,(prot_counter) inc a ld (prot_counter),a ld a,(iy+0) ; loader cracked! cp &c3 jr z,end_decrypt ; subroutines start for ld bc,... cp &01 jr z,firstgroup ; sub start for ld,iy.. cp &fd jp z,thirdgroup ; sub start for ld sp,... cp &31 jp z,secondgroup ; sub start for ld hl,... cp &21 jp z,fourthgroup ; exx cp &d9 jr z,spendcycle ; unknown subroutine (we need to add new sub to the tables ) ld hl,unknown_str jp printa .end_decrypt ; store final loader address in &bec0 ld (&bec0),hl ld hl,completed jp printa .spendcycle ; we found an exx single instruction... we update refresh register without run the exx ld a,(prot_counter) dec a ld (prot_counter),a inc hl ld a,(refresh) inc a ld (refresh),a cp &7f jr c,loop jr z,loop ld a,0 ld (refresh),a jr loop ; first routine to search the known sub-routines for decrypt ; 9 different sub-routines starting ld bc,... .firstgroup ld de,tbl_sub_protect_a ld c,1 ld a,(iy+7) cp &c6 jr z,decry inc c ld a,(iy+9) cp &aa jr z,decry ld a,(iy+3) inc c cp &fd jr z,decry ld a,(iy+6) inc c cp &37 jr z,decry inc c cp &cb jr z,decry ld a,(iy+7) inc c cp &ac jr z,decry ld a,(iy+9) inc c cp &d9 jr z,decry ld a,(iy+7) inc c cp &d6 jr z,decry ld a,0 jp unknown ; call the prepare_code sub .decry call prepare_code jp loop ; search for ld sp,... (2 types) .secondgroup ld de,tbl_sub_protect_b ld a,(iy+15) ld c,0 cp &3b jr z,decry inc c cp &c1 jr z,decry ld a,1 jp unknown ; search for ld iy,... (2 types) .thirdgroup ld de,tbl_sub_protect_c ld c,0 ld a,(iy+12) cp &ed jr z,decry inc c ld a,(iy+10) cp &ed jr z,decry ld a,2 jp unknown ; search for ld hl,... (7 types) .fourthgroup ld de,tbl_sub_protect_d ld c,0 ld a,(iy+14) cp &c2 jr z,decry inc c ld a,(iy+6) cp &ed jr z,decry ld a,(iy+7) inc c cp &35 jr z,decry inc c cp &ed jr z,decry inc c cp &2f jr z,decry inc c cp &78 jr z,decry ld a,(iy+9) inc c cp &d9 jr z,decry ld a,3 jp unknown .unknown add a,"A" ld (prot),a ld hl,unknown_prot ; restore registers printa exx pop bc pop de pop hl exx ; print message .loopprint ld a,(hl) cp &ff jr z,return call &bb5a inc hl jr loopprint .return pop bc pop de pop hl ret ; de=table loader subroutines info ; hl=loader subroutine to decrypt ; here we calculate the subroutine length and the infos about routine relocation .prepare_code ex hl,de ld b,0 ld a,c add a,c add a,c ld c,a add hl,bc ld c,(hl) inc hl ex de,hl push de ld de,execute ; then copy the subroutine from the loader to a buffer ldir pop bc push hl ; fetch the code exceptions (routines that need some different relocating work) ld a,(bc) cp &d9 jr z,exception_1 cp &b2 jr z,exception_1 cp &fd jr z,exception_2 or a jr nz,default ex de,hl ld bc,execute+6 ld (hl),c inc hl ld (hl),b ex de,hl jr cont exception_2 push bc ld hl,execute+2 ld bc,execute+10 ld (hl),c inc hl ld (hl),b pop bc jr default exception_1 push bc ld hl,execute+11 ld bc,execute+13 ld (hl),c inc hl ld (hl),b pop bc ; default relocation code default ld (de),a inc de inc bc ld a,(bc) ld (de),a cont inc de ld hl,callback ld bc,endcall-callback ; append to the buffer the callback routine that will restore stack and r register ldir ; execute the subroutine call buffer call refresh_adjust ld (refresh),a pop hl inc hl inc hl ret ; ajust the loader subroutine r register .refresh_adjust ld a,(refresh) cp &2 jr c,adjust sub &2 ret .adjust add a,&7e ret .callback ld a,r ld(refresh),a ld sp,(stack) ret .endcall ; tables about loader subroutine ; lenght,code reloc 1, code reloc 2 tbl_sub_protect_a defb &16,&20,&f6 defb &0e,&20,&f6 defb &10,&20,&f6 defb &1a,&20,&ee defb &0f,&20,&f6 defb &0c,&20,&f8 defb &0e,&20,&f6 defb &1d,&d9,&e9 defb &0e,&20,&f6 tbl_sub_protect_b defb &15,&0,&0 defb &14,&0,&0 tbl_sub_protect_c defb &1d,&20,&eb defb &19,&fd,&e9 tbl_sub_protect_d defb &0f,&00,&00 defb &0e,&20,&f6 defb &0b,&20,&f9 defb &0e,&20,&f6 defb &0d,&20,&f7 defb &0b,&20,&f9 defb &22,&b2,&c0 stack defs 2 unknown_prot defm "Unknown protection group " prot defb 0 defb &ff unknown_str defm "Unknown protection" defb &ff completed defm "Loader cracked!" defb &ff prot_counter defb 0 ; internal buffer used to execute every subroutine buffer ld (stack),sp defb &3e refresh defb 0 ld r,a execute defs 60