I'm trying to send commands to to the input of a cmd.exe
application using the low level read/write console functions. I have no trouble reading the text (scraping) using the ReadConsole...()
and WriteConsole()
functions after having attached to the process console, but I've not figured out how to write for example "dir"
and have the console interpret it as a sent command.
Here's a bit of my code:
CreateProcess(NULL, "cmd.exe", NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
AttachConsole(pi.dwProcessId);
strcpy(buffer, "dir");
WriteConsole(GetStdHandle(STD_INPUT_HANDLE), buffer, strlen(buffer), &charRead, NULL);
STARTUPINFO
attributes of the process are all set to zero, except, of course, the .cb
attribute.
Nothing changes on the screen, however I'm getting an Error 6: Invalid Handle
returned from WriteConsole
to STD_INPUT_HANDLE
. If I write to (STD_OUTPUT_HANDLE)
I do get my dir
written on the screen, but nothing of course happens. I'm guessing SetConsoleMode()
might be of help, but I've tried many mode combinations, nothing helped. I've also created a quick console application that waits for input (scanf()
) and echoes back whatever goes in, didn't work.
I've also tried typing into the scanf()
promp and then peek into the input buffer using PeekConsoleInput()
, returns 0, but the INPUT_RECORD
array is empty.
I'm aware that there is another way around this using WriteConsoleInput()
to directly inject INPUT_RECORD structured events into the console, but this would be way too long, I'll have to send each keypress into it.
I hope the question is clear. Please let me know if you need any further information. Thanks for your help.
Update 1:
I am able to send keypresses to a cmd
process using WriteConsoleInput()
with INPUT_RECORD
structs, however, the AttachConsole
sometimes throws ERROR_GEN_FAILURE #31: A device attached to the system is not functioning.
, and thus the INPUT_RECORD
are not sent (Error 6: Invalid Handle
). Sleep(1000)
after CreateProcess()
before AttachConsole()
solves this. The characters dir
are typed in automatically, but I can't figure out how to send the RETURN
key:
ir[0].EventType = KEY_EVENT;
ir[0].Event.KeyEvent.bKeyDown = TRUE;
ir[0].Event.KeyEvent.dwControlKeyState = 0;
ir[0].Event.KeyEvent.uChar.UnicodeChar = '\n';
ir[0].Event.KeyEvent.wRepeatCount = 1;
ir[0].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
ir[1].EventType = KEY_EVENT;
ir[1].Event.KeyEvent.bKeyDown = FALSE;
ir[1].Event.KeyEvent.dwControlKeyState = 0;
ir[1].Event.KeyEvent.uChar.UnicodeChar = '\n';
ir[1].Event.KeyEvent.wRepeatCount = 1;
ir[1].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
ir[1].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(VK_RETURN, MAPVK_VK_TO_VSC);
WriteConsoleInput(GetStdHandle(STD_INPUT_HANDLE), ir, 2, &charRead);
WriteConsoleInput
returns 0
, but nothing happens in the console, I've tried setting SetConsoleMode()
to ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
and a combination thereof, with no results, though. If I press enter from the keyboard, however, the automatically-typed dir
command executes (unlike the times when I just WriteConsole()
), so I guess I'm on the right track.
Doesn't SSH send over the actual keypresses and gets the actual screen buffer (like TAB, and CTRL+C CTRL+D work)? I'm after something of the like.
Update 2:
I found the problem with injecting the return command. Should have been ir[1].Event.KeyEvent.uChar.AsciiChar = '\r';
i.e. an \r
instead of a \n
, super simple.
It seems that there is no way of using WriteConsole()
to input commands, one should get by by sending WriteConsoleInput()
INPUT_RECORDs or by creating pipes (which are not always perfect, but great for most straight forward applications). One great advantage of using WriteConsoleInput()
is that you one can send VK_UP
and VK_DOWN
, to access console history, (if we're in CMD) and VK_TAB
for auto-completion, all CTRL+_ sequences, ESC and FUNCTION keys and even MOUSE CLICKS.
More information here: http://msdn.microsoft.com/en-us/library/ms687403%28v=vs.85%29.aspx plus tonnes of examples here: http://controllingtheinter.net/forums/viewtopic.php?f=116&t=366
If anyone has other great ideas feel free to chip in. Thank you to all those who took interest in this. Hope this helps someone in the future.