2009-12-07 2 views
2

Мне нужно автоматизировать приложение командной строки. Он просит пользователя ввести пароль. Все мои попытки отправить пароль через STDIN не удались. Теперь я пытаюсь сделать это с помощью программы-обертки с использованием .NET..NET: ввод данных во входной буфер процесса

Я начинаю приложение, создающее новый процесс, устанавливая StartInfo -свойств, а затем начать процесс:

Dim app_path As String 
Dim app_args As String 
Dim myProcess As Process = New Process() 
myProcess.StartInfo.FileName = app_path 
myProcess.StartInfo.Arguments = app_args 
myProcess.StartInfo.UseShellExecute = False 
myProcess.Start() 

Я пытаюсь использовать StartInfo.RedirectStandardInput собственности, но без успеха.

Теперь я наткнулся на функцию WriteConsoleInput из kernel32.dll, что я включил, как это:

Declare Function WriteConsoleInput Lib "kernel32.dll" Alias "WriteConsoleInputA" (ByVal hConsoleInput As Integer, ByVal lpBuffer As String, ByVal nNumberOfCharsToWrite As Integer, ByRef lpNumberOfCharsWritten As Integer) As Boolean 

я могу получить дескриптор процесса через myProcess.Handle собственности. Но отправка ввода в буфер ввода с использованием этого способа также невозможна.

Я нашел эти вопросы, но они не помогли:

  • Как я пишу «PAGE DOWN» в поле ввода консоли буфера? (+1475353)

  • Java - прохождение вход во внешний C/C++ приложения (1421273)

  • Управление с консоли Windows приложение ж/STDIN трубы (723424)

Использование StraceNtX.exe I получил этот выход на данный момент приложение ждет ввода:

[T4024] GetConsoleMode(f, 12d35c, 12d3af, 77bff894, ...) = 1 
[T4024] SetConsoleMode(f, 0, 12d3af, 77bff894, ...) = 1 
[T4024] ReadConsoleInputA(f, 12d348, 1, 12d360, ...) = 1 

Может кто-нибудь сказать мне, что еще попробовать или как сделать выше правильно? Спасибо!


на основе Tim Робинсонам answere Я получил этот код сейчас, но он не работает:

myProcess = New Process() 
myProcess.StartInfo.FileName = app_path 
myProcess.StartInfo.Arguments = app_args 
myProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal 
myProcess.StartInfo.UseShellExecute = False 
myProcess.Start() 
' Wait for process requesting passwort input 
System.Threading.Thread.Sleep(3000) 
Dim len As Integer 
len = 0 
Dim handle As Integer 
handle = GetStdHandle(STD_INPUT_HANDLE) 
WriteConsoleInput(handle, "Test", 4, len) 

Моя программа является командной строки приложение, которое должно выступать в качестве обертки.

Вход отправляется, но не указан в поле пароля, но под полем пароля отображается новый промах (даже не отображая ввод).

Тим, не могли бы вы привести мне пример?

+1

Что приложение, которое нуждается пароль? Там может быть проще, чем это. –

+1

Это консольное приложение для диспетчера сертификатов Cisco cisco_cert_mgr.exe Но я действительно искал для любого другого решения, но, похоже, его нет. – sc911

ответ

2

Извините за мой поздний ответ, был очень занят.

Вот пример полного кода, удаленный от моего кода. Надеюсь, я не исключил что-то важное.

Private Sub runWaitInput(ByVal exe As String, ByVal parameter As String, ByVal trigger As String, ByVal input As String) 
    ' runs an process, waits for a certain string in stdout and then enters text ' 
    Dim proc As Process 
    Dim stdOut As StreamReader 
    Dim ch As Int32 
    Dim buffer As String = "" 
    Dim InputRecords(0) As KeyEventStruct 

    ' create process ' 
    proc = New Process() 
    proc.StartInfo.FileName = exe 
    proc.StartInfo.Arguments = parameter 
    proc.StartInfo.UseShellExecute = False 
    proc.StartInfo.RedirectStandardOutput = True 
    proc.Start() 

    ' redirect stdOut ' 
    stdOut = proc.StandardOutput 
    While Not proc.HasExited 
     ' read character ' 
     ch = stdOut.Read() 
     Console.Write(Convert.ToChar(ch)) 
     buffer = buffer & Convert.ToChar(ch) 
     ' read output and check for trigger-text ' 
     If buffer.LastIndexOf(trigger) <> -1 Then 
      buffer = "" 
      InputRecords(0) = New KeyEventStruct 
      InputRecords = generateInputRecord(input & Convert.ToChar(13)) 
      WriteConsoleInput(STD_INPUT_HANDLE, InputRecords, InputRecords.Count(), New Integer) 
     End If 
    End While 
    Console.Write(stdOut.ReadToEnd()) 
End Sub 

Function generateInputRecord(ByVal str As String) As KeyEventStruct() 
    Dim ret(str.Count() - 1) As KeyEventStruct 
    For i = 0 To str.Count - 1 Step 1 
     With ret(i) 
      .EventType = 1 
      .bKeyDown = True 
      .uChar.AsciiChar = Convert.ToInt32(str(i)) 
      .dwControlKeyState = 0 
      .wRepeatCount = 1 
      .wVirtualKeyCode = 0 
      .wVirtualScanCode = 0 
     End With 
    Next 
    Return ret 
End Function 

Он использует следующий модуль:

Imports System.Runtime.InteropServices 

Module ConsoleUtils 

    <Flags()> Public Enum ControlKeyState As Integer 
     RightAltPressed = &H1 
     LeftAltPressed = &H2 
     RightCtrlPressed = &H4 
     LeftCtrlPressed = &H8 
     ShiftPressed = &H10 
     NumLockOn = &H20 
     ScrollLockOn = &H40 
     CapsLockOn = &H80 
     EnhancedKey = &H100 
    End Enum 

    <StructLayout(LayoutKind.Explicit)> Public Structure CHAR_UNION 
     <FieldOffset(0)> Public UnicodeChar As Short 
     <FieldOffset(0)> Public AsciiChar As Byte 
    End Structure 

    <DllImport("kernel32", EntryPoint:="WriteConsoleInputA", CharSet:=CharSet.Auto, SetLastError:=True, ThrowOnUnmappablechar:=True)> _ 
     Public Function WriteConsoleInput(_ 
      ByVal hConsoleInput As IntPtr, _ 
      ByVal lpBuffer() As KeyEventStruct, _ 
      ByVal nLength As Integer, _ 
      ByRef lpNumberOfEventsWritten As Integer _ 
     ) As Boolean 
    End Function 

    <DllImport("KERNEL32.DLL", EntryPoint:="GetStdHandle", SetLastError:=False, ExactSpelling:=True, CallingConvention:=CallingConvention.StdCall)> _ 
     Public Function GetStdHandle(_ 
      ByVal nStdHandle As Integer _ 
     ) As Integer 
    End Function 

    <StructLayout(LayoutKind.Sequential)> Public Structure KeyEventStruct 
     Public EventType As Short 
     <MarshalAs(UnmanagedType.Bool)> Public bKeyDown As Boolean 
     Public wRepeatCount As Short 
     Public wVirtualKeyCode As Short 
     Public wVirtualScanCode As Short 
     Public uChar As CHAR_UNION 
     Public dwControlKeyState As ControlKeyState 
    End Structure 

    Public ReadOnly STD_OUTPUT_HANDLE As IntPtr = New IntPtr(GetStdHandle(-11)) 
    Public ReadOnly STD_INPUT_HANDLE As IntPtr = New IntPtr(GetStdHandle(-10)) 
    Public ReadOnly STD_ERROR_HANDLE As IntPtr = New IntPtr(GetStdHandle(-12)) 

End Module 

С помощью этой функции вы можете запустить процесс и ждать линии вывода (то есть «пароль:»). Затем функция войдет в предоставленный текст с последующим возвратом.

Надеюсь, это поможет!

С уважением sc911

0

WriteConsoleInput ожидает ручку консоли, а не ручку процесса. Ваша проблема заключается в том, как схватить этот консольный дескриптор.

Если ваш процесс является консольным приложением и вы не перенаправляете что-либо при запуске дочернего процесса, тогда дочерний процесс будет прикреплен к консоли вашего собственного процесса.В этом случае, вы можете быть в состоянии:

  1. Запуск дочернего процесса с перенаправлением выключен
  2. вызов GetStdHandle(STD_INPUT_HANDLE) разжиться вашей собственной консоли ручки
  3. Pass, что консоль Дескриптор WriteConsoleInput

Если у вас есть приложение с графическим интерфейсом, вы можете назначить себе консоль, используя AllocConsole.

Редактировать: Сначала я не заметил, но это неправильное определение для WriteConsoleInput. Он принимает массив INPUT_RECORD, а не строку. Мой собственный эксперимент с runas.exe работает нормально, как только я скопировал the function prototype from pinvoke.net.

+0

Я сделал тест на это (см. Изменение выше), но он не работает. Можете ли вы привести мне пример? – sc911

+0

Похоже, что он ведет себя аналогично runas.exe; Я взломаю тест, используя это. –

+0

@ sc911, см. Мое редактирование ответа - ваша декларация для WriteConsoleInput неверна –

Смежные вопросы