2009-12-07 5 views
2

Je dois automatiser une application de ligne de commande. Il demande à l'utilisateur d'entrer un mot de passe. Toutes mes approches pour envoyer le mot de passe via STDIN ont échoué. Maintenant, j'essaye de le faire avec un wrapper-programm en utilisant .NET..NET: Injecter des données dans l'entrée-tampon du processus

Je commence l'application la création d'un nouveau processus, le réglage des StartInfo -properties puis démarrer le processus:

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() 

J'ai essayé d'utiliser la propriété StartInfo.RedirectStandardInput mais sans succès.

Maintenant, je suis tombé sur la fonction WriteConsoleInput du kernel32.dll que j'inclus comme ceci:

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 

je peux obtenir la poignée du processus via la propriété myProcess.Handle. Mais l'envoi d'une entrée dans le tampon d'entrée de cette manière n'était pas possible non plus.

Je trouve ces questions, mais ils n'ont pas aidé:

  • Comment puis-je écrire « Vers le bas » dans le tampon d'entrée de la console? (1475353)

  • Java - passage d'entrée dans une application externe C/C++ (1421273)

  • Commande d'un tuyau App console Windows w/stdin (723424)

Utilisation StraceNtX.exe I a obtenu cette sortie pour l'instant l'application est en attente d'entrée:

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

quelqu'un peut-il me dire, quoi d'autre pour essayer ou comment faire ce qui précède la bonne façon? Merci!


Basé sur answere Tim Robinsons J'ai ce code maintenant, mais il ne fonctionne pas:

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) 

Mon programm est une application qui devrait agir commandline comme une enveloppe.

L'entrée est envoyée, mais d'une manière qu'il ne soit pas tapé dans le champ de mot de passe mais en dessous du champ de mot de passe une nouvelle PROMT est affiché (sans même montrer l'entrée).

Tim, pouvez-vous me donner un exemple?

+1

Quelle est l'application qui a besoin du mot de passe? Il peut y avoir un moyen plus facile que cela. –

+1

Il s'agit de l'application Cisco Certificate Manager Console cisco_cert_mgr.exe Mais j'ai déjà cherché une solution différente, mais il semble n'y en avoir aucune. – sc911

Répondre

2

Désolé pour ma réponse en retard, été très occupé.

Voici un exemple de code complet, extrait de mon code. J'espère que je n'ai pas supprimé quelque chose de crucial.

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 

Il utilise le module suivant:

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 

Avec cette fonction, vous pouvez démarrer le processus et attendre une ligne de sortie (à savoir « mot de passe: »). Ensuite, la fonction entrera le texte fourni suivi d'un retour.

J'espère que cela aide!

Cordialement sc911

0

WriteConsoleInput attend un handle de console, pas un handle de processus. Votre problème est comment obtenir cette poignée de console. Si votre processus est une application console et que vous ne redirigez rien lors du démarrage du processus enfant, le processus enfant sera attaché à la console de votre propre processus.Dans ce cas, vous pourrez peut-être:

  1. Démarrer le processus d'enfant avec redirection désactivée
  2. Appel GetStdHandle(STD_INPUT_HANDLE) pour mettre la main sur votre propre poignée de console
  3. Pass cette poignée de console pour WriteConsoleInput

Si vous avez une application graphique, vous pouvez vous attribuer une console en utilisant AllocConsole.

Modifier: Je n'ai pas remarqué au début, mais ce n'est pas la bonne définition pour WriteConsoleInput. Il faut un tableau de INPUT_RECORD, pas une chaîne. Ma propre expérience avec runas.exe fonctionne OK une fois que j'ai copié the function prototype from pinvoke.net.

+0

J'ai fait un test sur cela (voir changement ci-dessus), mais cela ne fonctionne pas. Peux-tu me donner un exemple? – sc911

+0

Il semble qu'il se comporte de la même manière que runas.exe; Je vais bidouiller un test en utilisant ça. –

+0

@ sc911, voir mon edit à la réponse - votre déclaration pour WriteConsoleInput est fausse –

Questions connexes