mirror of
https://github.com/vxunderground/MalwareSourceCode.git
synced 2024-12-18 17:36:11 +00:00
271 lines
13 KiB
NASM
271 lines
13 KiB
NASM
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.
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|