SRC:sending keyboard input to external application


Some years ago, when I first thought over the idea of creating a telnet server I faced several problems. One of them was the problem of sending the user input to the spawned shell. The simple solution was to use some kind of input redirection, but that would result in most of the keys unusable. Therefore, I started thinking of another mechanism. Actually, the secret of sending keyboard input is hidden in the windows messages. Every time you press a key ( or do what ever in your Windows )a bunch of messages are generated and send to the windows. You can use tools such as Spy++ or Winspector to monitor and examine these messages. There are quite many of them but we are currently interested in only three of them WM_KEYDOWN, WM_KEYUP and WM_CHAR.
o WM_KEYDOWN is sent when a nonsystem( ALT key not pressed ) key is pressed.
o WM_KEYUP is sent when the key is released.
o WM_CHAR is sent when the WM_KEYDOWN message is translated to a character code.

So all you have to do to send keyboard input to external application is to find its window handle ( usually one will use FindWindow or similar function ) and send the appropriate message via the SendMessage or PostMessage function.

Following is a listing of a program that I once wrote so that I could use the rexec command from a batch file. ( generally the program "should" work with any program that asks for user password for ex. runas.exe )
The rexec program does not accept password from the command line ( and it is OK due to security reasons ), but sometimes when run in trusted environment or something it is useful to be able to give it the password from the command line. The solution I figured out was to create a program that would read the password from its command line then run the rexec command and send the password as keyboard input to it.

Here is sample usage starting automatically notepad.exe through the runas command for a user 'foo' with password 'MySecret_Password'
send.exe MySecret_Password runas.exe /user:foo notepad.exe


You can get the compiled binary here.
Or compile it yourself from the following listing:


/**********************************************************
* I take no responsibility for what you or others might do
* with this knowledge.
***********************************************************/

#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <time.h>


void SendKey( HWND window, char ch )
{
char shift[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_+{}:\"<>?";

if( strchr( shift, ch ) )
{
SendMessage( window, 0x00000100, 0x00000010, 0x002A0001 ); //WM_KEYDOWN SHIFT
SendMessage( window, 0x00000102, ch, 0x001E0001 ); //WM_CHAR ch
SendMessage( window, 0x00000101, 0x00000010, 0x002A0001 ); //WM_KEYUP SHIFT
}
else SendMessage( window, 0x00000102, ch, 0x001E0001 ); //WM_CHAR ch
}

HWND GetConsoleWindow( )
{

char title[ 1024 ];
char buff[ 1024 ];

GetConsoleTitle( title, 1000 );

// let's give it an unique name hoping no one will change it till we are done
srand( ( unsigned )time( NULL ) );
sprintf( buff, "my_53cr37_7i713[ %d ]", rand( ) );

SetConsoleTitle( buff );

HWND window = FindWindow( NULL, buff );

// restore the real title
SetConsoleTitle( title );
return( window );
}

int main( int argc, char ** argv )
{

if( argc < 3 )
{
printf( "This program will TRY to sends text to command line program\n" );
printf( "The only use I have found so far is to automatically send passwords\n" );
printf( "to applications like runas.exe or rexec.exe in batch files\n" );
printf( "Check http://www.kpym.com/ for more info\n" );
printf( "\n" );
printf( "I take no responsibility for what you or others might do\n" );
printf( "with this knowledge.\n" );
printf( "\n" );
printf( "usage:\n" );
printf( "send.exe text command arg1 arg2 ... argN\n" );
return( 1 );
}

// note this buffer can crash
char command[ 1024 ];
char * pass = argv[ 1 ];

strcpy( command, argv[ 2 ] );
for( int i = 3; i < argc; i++ )
{
strcat( command , " \"" );
strcat( command , argv[ i ] );
strcat( command , "\"" );
}

HWND window = GetConsoleWindow( );

// start the real rexec command
PROCESS_INFORMATION pi;
STARTUPINFO si = { 0 };
si.cb = sizeof( si );

if( !CreateProcess( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) )
{
printf( "can't spawn '%s'\n", command );
return( 2 );
}

Sleep( 200 ); // give it some time so rexec can load

// send the password
for( int i = 0; i < strlen( pass ); i++ ) SendKey( window, pass[ i ] );
SendKey( window, 0x0D ); // send return key

// wait for rexec to finish
WaitForSingleObject( pi.hProcess, INFINITE );
return( 0 );
}

Wednesday, December 28, 2005


© 2002 - 2008 Kroum Grigorov
This page is powered by Blogger. Isn't yours?