MalwareSourceCode/MSDOS/Virus.MSDOS.Unknown.npad.asm

271 lines
13 KiB
NASM
Raw Normal View History

2021-01-12 23:52:14 +00:00
INTERRUPTS SEGMENT AT 0H ;This is where the keyboard interrupt
ORG 9H*4 ;holds the address of its service routine
KEYBOARD_INT LABEL DWORD
INTERRUPTS ENDS
SCREEN SEGMENT AT 0B000H ;A dummy segment to use as the
SCREEN ENDS ;Extra Segment
ROM_BIOS_DATA SEGMENT AT 40H ;BIOS statuses held here, also keyboard buffer
ORG 1AH
HEAD DW ? ;Unread chars go from Head to Tail
TAIL DW ?
BUFFER DW 16 DUP (?) ;The buffer itself
BUFFER_END LABEL WORD
ROM_BIOS_DATA ENDS
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG
ORG 100H ;ORG = 100H to make this into a .COM file
FIRST: JMP LOAD_PAD ;First time through jump to initialize routine
CNTRL_N_FLAG DW 0 ;Cntrl-N on or off
PAD DB '_',499 DUP(' ') ;Memory storage for pad
PAD_CURSOR DW 0 ;Current position in pad
PAD_OFFSET DW 0 ;Chooses 1st 250 bytes or 2nd
FIRST_POSITION DW ? ;Position of 1st char on screen
ATTRIBUTE DB 112 ;Pad Attribute -- reverse video
SCREEN_SEG_OFFSET DW 0 ;0 for mono, 8000H for graphics
IO_CHAR DW ? ;Holds addr of Put or Get_Char
STATUS_PORT DW ? ;Video controller status port
OLD_KEYBOARD_INT DD ? ;Location of old kbd interrupt
N_PAD PROC NEAR ;The keyboard interrupt will now come here.
ASSUME CS:CODE_SEG
PUSH AX ;Save the used registers for good form
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH DS
PUSH ES
PUSHF ;First, call old keyboard interrupt
CALL OLD_KEYBOARD_INT
ASSUME DS:ROM_BIOS_DATA ;Examine the char just put in
MOV BX,ROM_BIOS_DATA
MOV DS,BX
MOV BX,TAIL ;Point to current tail
CMP BX,HEAD ;If at head, kbd int has deleted char
JE IN ;So leave
SUB BX,2 ;Point to just read in character
CMP BX,OFFSET BUFFER ;Did we undershoot buffer?
JAE NO_WRAP ;Nope
MOV BX,OFFSET BUFFER_END ;Yes -- move to buffer top
SUB BX,2
NO_WRAP:MOV DX,[BX] ;Char in DX now
CMP DX,310EH ;Is the char a Cntrl-N?
JNE NOT_CNTRL_N ;No
MOV TAIL,BX ;Yes -- delete it from buffer
NOT CNTRL_N_FLAG ;Switch Modes
CMP CNTRL_N_FLAG,0 ;Cntrl-N off?
JNE CNTRL_N_ON ;No, only other choice is on
CNTRL_N_OFF:
MOV ATTRIBUTE,7 ;Set up for normal video
MOV PAD_OFFSET,250 ;Point to 2nd half of pad
LEA AX,PUT_CHAR ;Make IO call Put_Char as it scans
MOV IO_CHAR,AX ;over all locations in pad on screen
CALL IO ;Restore screen
IN: JMP OUT ;Done
CNTRL_N_ON:
MOV PAD_OFFSET,250 ;Point to screen stroage part of pad
LEA AX,GET_CHAR ;Make IO use Get_char so current screen
MOV IO_CHAR,AX ;is stored
CALL IO ;Store Screen
CALL DISPLAY ;And put up the pad
JMP OUT ;Done here.
NOT_CNTRL_N:
TEST CNTRL_N_FLAG,1 ;Is Cntrl-N on?
JZ IN ;No -- leave
MOV TAIL,BX ;Yes, delete this char from buffer
CMP DX,5300H ;Decide what to do -- is it a Delete?
JNE RUBOUT_TEST ;No -- try Rubout
MOV BX,249 ;Yes -- fill pad with spaces
DEL_LOOP:
MOV PAD[BX],' ' ;Move space to current pad position
DEC BX ;and go back one
JNZ DEL_LOOP ;until done.
MOV PAD,'_' ;Put the cursor at the beginning
MOV PAD_CURSOR,0 ;And start cursor over
CALL DISPLAY ;Put up the new pad on screen
JMP OUT ;And take our leave
RUBOUT_TEST:
CMP DX,0E08H ;Is it a Rubout?
JNE CRLF_TEST ;No -- try carriage return-line feed
MOV BX,PAD_CURSOR ;Yes -- get current pad location
CMP BX,0 ;Are we at beginning?
JLE NEVER_MIND ;Yes -- can't rubout past beginning
MOV PAD[BX],' ' ;No -- move space to current position
MOV PAD[BX-1],'_' ;And move cursor back one
DEC PAD_CURSOR ;Set the pad location straight
NEVER_MIND:
CALL DISPLAY ;And put the result on the screen
JMP OUT ;Done here.
CRLF_TEST:
CMP DX,1C0DH ;Is it a carriage return-line feed?
JNE CHAR_TEST ;No -- put it in the pad
CALL CRLF ;Yes -- move to next line
CALL DISPLAY ;And display result on screen
JMP OUT ;Done.
CHAR_TEST:
MOV BX,PAD_CURSOR ;Get current pad location
CMP BX,249 ;Are we past the end of the pad?
JGE PAST_END ;Yes -- throw away char
MOV PAD[BX],DL ;No -- move ASCII code into pad
MOV PAD[BX+1],'_' ;Advance cursor
INC PAD_CURSOR ;Increment pad location
PAST_END:
CALL DISPLAY ;Put result on screen
OUT: POP ES ;Having done Pushes, here are the Pops
POP DS
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
IRET ;An interrupt needs an IRET
N_PAD ENDP
DISPLAY PROC NEAR ;Puts the whole pad on the screen
PUSH AX
MOV ATTRIBUTE,112 ;Use reverse video
MOV PAD_OFFSET,0 ;Use 1st 250 bytes of pad memory
LEA AX,PUT_CHAR ;Make IO use Put-Char so it does
MOV IO_CHAR,AX
CALL IO ;Put result on screen
POP AX
RET ;Leave
DISPLAY ENDP
CRLF PROC NEAR ;This handles carriage returns
CMP PAD_CURSOR,225 ;Are we on last line?
JGE DONE ;Yes, can't do a carriage return, exit
NEXT_CHAR:
MOV BX,PAD_CURSOR ;Get pad location
MOV AX,BX ;Get another copy for destructive tests
EDGE_TEST:
CMP AX,24 ;Are we at the edge of the pad display?
JE AT_EDGE ;Yes -- fill pad with new cursor
JL ADD_SPACE ;No -- Advance another space
SUB AX,25 ;Subtract another line-width
JMP EDGE_TEST ;Check if at edge now
ADD_SPACE:
MOV PAD[BX],' ' ;Add a space
INC PAD_CURSOR ;Update pad location
JMP NEXT_CHAR ;Check if at edge now
AT_EDGE:
MOV PAD[BX+1],'_' ;Put cursor in next location
INC PAD_CURSOR ;Update pad location to new cursor
DONE: RET ;And out.
CRLF ENDP
GET_CHAR PROC NEAR ;Gets a char from screen and advances position
PUSH DX
MOV SI,2 ;Loop twice, once for char, once for attribute
MOV DX,STATUS_PORT ;Get ready to read video controller status
G_WAIT_LOW: ;Start waiting for a new horizontal scan -
IN AL,DX ;Make sure the video controller scan status
TEST AL,1 ;is low
JNZ G_WAIT_LOW
G_WAIT_HIGH: ;After port has gone low, it must go high
IN AL,DX ;before it is safe to read directly from
TEST AL,1 ;the screen buffer in memory
JZ G_WAIT_HIGH
MOV AH,ES:[DI] ;Do the move from the screen, one byte at a time
INC DI ;Move to next screen location
DEC SI ;Decrement loop counter
CMP SI,0 ;Are we done?
JE LEAVE ;Yes
MOV PAD[BX],AH ;No -- put char we got into the pad
JMP G_WAIT_LOW ;Do it again
LEAVE: INC BX ;Update pad location
POP DX
RET
GET_CHAR ENDP
PUT_CHAR PROC NEAR ;Puts one char on screen and advances position
PUSH DX
MOV AH,PAD[BX] ;Get the char to be put onto the screen
MOV SI,2 ;Loop twice, once for char, once for attribute
MOV DX,STATUS_PORT ;Get ready to read video controller status
P_WAIT_LOW: ;Start waiting for a new horizontal scan -
IN AL,DX ;Make sure the video controller scan status
TEST AL,1 ;is low
JNZ P_WAIT_LOW
P_WAIT_HIGH: ;After port has gone low, it must go high
IN AL,DX ;before it is safe to write directly to
TEST AL,1 ;the screen buffer in memory
JZ P_WAIT_HIGH
MOV ES:[DI],AH ;Move to screen, one byte at a time
MOV AH,ATTRIBUTE ;Load attribute byte for second pass
INC DI ;Point to next screen postion
DEC SI ;Decrement loop counter
JNZ P_WAIT_LOW ;If not zero, do it one more time
INC BX ;Point to next char in pad
POP DX
RET ;Exeunt
PUT_CHAR ENDP
IO PROC NEAR ;This scans over all screen positions of the pad
ASSUME ES:SCREEN ;Use screen as extra segment
MOV BX,SCREEN
MOV ES,BX
MOV DI,SCREEN_SEG_OFFSET ;DI will be pointer to screen postion
ADD DI,FIRST_POSITION ;Add width of screen minus pad width
MOV BX,PAD_OFFSET ;BX will be pad location pointer
MOV CX,10 ;There will be 10 lines
LINE_LOOP:
MOV DX,25 ;And 25 spaces across
CHAR_LOOP:
CALL IO_CHAR ;Call Put-Char or Get-Char
DEC DX ;Decrement character loop counter
JNZ CHAR_LOOP ;If not zero, scan over next character
ADD DI,FIRST_POSITION ;Add width of screen minus pad width
LOOP LINE_LOOP ;And now go back to do next line
RET ;Finished
IO ENDP
LOAD_PAD PROC NEAR ;This procedure intializes everything
ASSUME DS:INTERRUPTS ;The data segment will be the Interrupt area
MOV AX,INTERRUPTS
MOV DS,AX
MOV AX,KEYBOARD_INT ;Get the old interrupt service routine
MOV OLD_KEYBOARD_INT,AX ;address and put it into our location
MOV AX,KEYBOARD_INT[2] ;OLD_KEYBOARD_INT so we can call it.
MOV OLD_KEYBOARD_INT[2],AX
MOV KEYBOARD_INT,OFFSET N_PAD ;Now load the address of our notepad
MOV KEYBOARD_INT[2],CS ;routine into the keyboard interrupt
MOV AH,15 ;Ask for service 15 of INT 10H
INT 10H ;This tells us how display is set up
SUB AH,25 ;Move to twenty places before edge
SHL AH,1 ;Mult by two (char & attribute bytes)
MOV BYTE PTR FIRST_POSITION,AH ;Set screen cursor
MOV STATUS_PORT,03BAH ;Assume this is a monochrome display
TEST AL,4 ;Is it?
JNZ EXIT ;Yes - jump out
MOV SCREEN_SEG_OFFSET,8000H ;No - set up for graphics display
MOV STATUS_PORT,03DAH
EXIT: MOV DX,OFFSET LOAD_PAD ;Set up everything but LOAD_PAD to
INT 27H ;stay and attach itself to DOS
LOAD_PAD ENDP
CODE_SEG ENDS
END FIRST ;END "FIRST" so 8088 will go to FIRST first.