.NET - Tastendrücke senden ohne Fokus auf ein Objekt

  • VB

  • Jannik
  • 4623 Aufrufe 14 Antworten

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • .NET - Tastendrücke senden ohne Fokus auf ein Objekt

    Hallo,

    ich habe erneut ein kleines Problem:

    Ich möchte eine Art Anti-Keylogger Feature in ein Programm einbauen, welches zufällige Buchstaben und Zeichen einfach ins Nichts schicken soll (bzw. an ein nicht sichtbares Objekt), währrend der Benutzer ein Passwort eingibt. Dazu müsste ich nun zufällige Tastendrücke simulieren, ohne das der Benutzer etwas davon mitkriegt und die Passwort-Textbox aufeinmal die Handle/den Fokus verliert.

    Leider finde ich keine Alternative neben:
    SendKeys.SendWait() und My.Computer.Keyboard.SendKeys()

    Für die beiden Lösungen muss man leider den Fokus verändern und das ganze ist sehr sehr langsam.

    Wie würdet ihr das machen? Gibt es da eine Möglichkeit? Ein zweites Programm, was nebenbei läuft, wäre nicht so gut, da einige Keylogger auch die Prozesse anzeigen, in denen die Keys gedrückt wurden.

    Wäre über eure Hilfe sehr dankbar,
    Jannik
  • Ich glaube nicht, dass es möglich ist Tastendrücke ins Nirvana zu senden, davon abgesehen hast du aber doch ein grundsätzlicheres Problem deiner Idee schon erkannt?!

    Ein zweites Programm, was nebenbei läuft, wäre nicht so gut, da einige Keylogger auch die Prozesse anzeigen, in denen die Keys gedrückt wurden.


    Ein solcher Keylogger würde doch ohnehin nur die Characters anzeigen, die dein Programm auch empfangen hat.

    Wie würdet ihr das machen? Gibt es da eine Möglichkeit?


    Spontan würde ich einfach eine zufällige Characterfolge in das Textfeld schreiben, mir diese aber merken und nach dem Druck auf Enter wieder ausfiltern. Um den Nutzer nicht zu verwirren müsstest du den Inhalt des Feldes natürlich ausblenden, das Passwort müsste also blind eingegeben werden, ich halte das aber bei üblichen Passwortlängen für zumutbar.
  • Spontan würde ich einfach eine zufällige Characterfolge in das Textfeld schreiben, mir diese aber merken und nach dem Druck auf Enter wieder ausfiltern. Um den Nutzer nicht zu verwirren müsstest du den Inhalt des Feldes natürlich ausblenden, das Passwort müsste also blind eingegeben werden, ich halte das aber bei üblichen Passwortlängen für zumutbar.


    Danke, das hilft mir schonmal, ich weiß allerdings, wie du das genau meinst mit den "zufällige Characterfolge in das Textfeld schreiben. Könntest du mir das mal genauer erklären? :)

    Ich denke, ich lasse dann eine Variable nebenbei mit laufen und so weiter, aber wie genau, musst du mir noch ein bisschen weiter erklären :)
  • Danke, das hilft mir schonmal, ich weiß allerdings, wie du das genau meinst mit den "zufällige Characterfolge in das Textfeld schreiben. Könntest du mir das mal genauer erklären?


    Sobald dein Passwortfeld den Fokus bekommt rufst du im entsprechenden Event Handler eine Methode auf und generierst einen zufälligen String. Diesen schreibst du dann buchstabenweise in zufälligen Zeitabständen (zB. zwischen 100-500ms) mittels SendKeys() in dein Textfeld, solange bis du entweder an das Stringende gekommen bist, das Textfeld den Fokus verliert oder der Nutzer auf Enter drückt/die Eingabe absendet. Anschließend vergleichst du die fertige Eingabe mit den gesendeten Characters und konstruierst daraus das Passwort.

    Damit dein Programm dazwischen nicht einfriert wirst du die Methode, die die Zufallseingaben übernimmt wohl in einem eigenen Thread laufen lassen müssen. Einfach ist anders, aber so sollte es zumindest gehen.
  • Ich habe einen anderen Ansatz.

    Der User gibt das Passwort ein: geheim

    In das Textfeld wird aber geschrieben: gtehkjeimrm

    Du legst die erst mal paar Zufallszahlen bereit, also 1 2 2 1. Die Summe darf höchstens so groß sein, wie die Mindestlänge des Passworts, hier 6.

    Gibt der User das 1. Zeichen ein, streust du nun eine zufällige Zeichenkette ein, hier das t.
    Dann gibt der User 2 weitere Zeichen ein und du streust zufällig kj ein.
    User gibt wieder 2 Zeichen ein, du streust zufällig mr ein.
    User gibt 1 Zeichen ein, du streust zufällig nichts ein.

    Da du hier nichts von der Zeit abhängig machst, kannst du auch viel einfacher das echte Passwort geheim speichern. Deine zufällig eingestreuten Zeichen kannst du sofort wieder vergessen.

    Ich habe mir das gerade so erdacht, also wenn hier ein grober Denkfehler ist, dann bitte unbedingt bescheid sagen.

    Ich glaube jetzt, das ist das gleiche was niles geschrieben hat, aber nicht mit "in zufälligen Zeitabständen" sondern mit zufälligen Zeichenabständen.

    Gruß

    FeliX_22

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von FeliX_22 ()

  • Jaa, nochmal danke, der Ansatz ist Nils sehr ähnllich.
    Naja, ich weiß nicht so recht, ob SendKeys schnell genug arbeitet, sodass der User nicht mitbekommt..
    Aber nun gut, ich probier es später aus.

    Würdet ihr KeyUp / KeyPress / KeyDown oder gar TextChanged benutzen?

    Jannik
  • FeliX_22 schrieb:

    Ich habe mir das gerade so erdacht, also wenn hier ein grober Denkfehler ist, dann bitte unbedingt bescheid sagen.


    Das geht sicher auch, der Grund warum ich eher auf zufällige Zeiteinheiten setzen würde ist der, dass ein Keylogger, der die Zeitabstände zwischen den Tastenanschlägen mitloggen würde die generierten Tastenanschläge erkennen könnte. Denn SendKeys() wird erkennbar schneller arbeiten als ein Durchschnittsnutzer, der sein Passwort blind eingeben muss.
    Allerdings ist das wohl ein pathologisches Szenario, zumindest ich habe noch nie davon gehört, dass Keylogger in der Praxis sowas protokollieren. Unter diesem Gesichtspunkt ist dann deine Variante, da einfacher zu implementieren, die bessere.

    Jannik schrieb:

    Würdet ihr KeyUp / KeyPress / KeyDown oder gar TextChanged benutzen?


    Um was genau zu tun? Die erste Zufallseingabe sollte bereits erfolgen, sobald das Textfeld den Fokus bekommt, danach kannst du dann im Prinzip jedes dieser Events benutzen, TextChanged bietet sich insofern an, als du nicht überprüfen musst ob der Nutzer ein PW-Zeichen oder eine Taste wie Enter gedrückt hat.

    Edit: Wobei das ganze natürlich etwas trickreich zu implementieren ist, denn diese Events werden ja alle durch SendKeys.Send() wieder getriggert.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von nile ()

  • Okay, hab ein bisschen gepfeilt, aber bin noch zu keiner Lösung gekommen leider:

    PHP-Quellcode

    1. Private Sub passwordtxt_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles passwordtxt.GotFocus
    2. thread = New Threading.Thread(AddressOf threadsendkey)
    3. thread.Start()
    4. End Sub
    5. Private Sub threadsendkey()
    6. Dim abc As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    7. Dim random As New Random()
    8. While True
    9. While virtualkeys = False
    10. virtualkeys = True
    11. My.Computer.Keyboard.SendKeys(abc.Substring(random.Next(0, 61), 1), True)
    12. Threading.Thread.Sleep(random.Next(100, 500))
    13. End While
    14. End While
    15. End Sub
    16. Private Sub passwordtxt_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles passwordtxt.KeyPress
    17. If virtualkeys Then
    18. e.Handled = True
    19. virtualkeys = False
    20. End If
    21. End Sub
    Alles anzeigen


    Für den Anfang ganz okay, allerdings sind kommen immer noch ein paar SendKeys() zeichen durch, was kann ich noch verbessern?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Jannik ()

  • Der kritische Bereich ist dieser:

    Quellcode

    1. e.Handled = True
    2. virtualkeys = False


    Wenn der Thread hier abgewürgt wird, dann werden einige "virtualkeys", wie du sie nennst, nicht abgefangen. Um das zu verhindern musst du diesen Bereich als atomar (= nicht unterbrechbar) deklarieren mittels einer Lock-Variablen (zumindest heißen die Dinger in C# so). In vb.net nutzt man dazu laut google das SyncLock Statement.
  • Ich versteh den Sinn von SyncLock nicht ganz, heißt das, der Teil wir in einem Rutz ausgeführt, ohne das ein anderer Thread nebenbei etwas ausführen kann?


    Richtig, man braucht solche Mechanismen um den sogenannten wechselseitigen Ausschluss zu garantieren.

    Was bei deinem Code passieren kann:

    1. Die innere while-Schleife wird betreten, virtualkeys wird auf true gesetzt.
    2. Der Nutzer drückt eine Taste, das KeyPressed Event wird ausgelöst
    -> dein KeyPresshandler fängt die gedrückte Taste ab, setzt virtualkeys auf false
    3. threadsendkey() läuft weiter und sendet eine Taste, die nicht abgefangen wird

    Das Phänomen solltest du leicht beobachten können, wenn du dein Programm ausführst und dann eine Taste konstant hinunterdrückst.

    Was ich hier schrieb:
    Der kritische Bereich ist dieser:


    ist allerdings Blödsinn. Der kritische Bereich ist natürlich, wie aus obigem hervorgeht, die innere while Schleife in threadsendkey().

    Wie setze ich das korrekt ein...?


    Kann ich dir leider nicht sagen, dafür bin ich in VB nicht sattelfest genug. Aber dürfte nicht allzu kompliziert sein, wenn ich mir das msdn Beispiel anschaue ;)
  • Ich versteh das einfach nicht, bzw bekomme ich das einfach nicht hin.....

    PHP-Quellcode

    1. Private Sub threadsendkey()
    2. Dim abc As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    3. Dim random As New Random()
    4. While True
    5. While virtualkeys = False
    6. SyncLock objLock
    7. virtualkeys = True
    8. My.Computer.Keyboard.SendKeys(abc.Substring(random.Next(0, 61), 1), True)
    9. End SyncLock
    10. Threading.Thread.Sleep(random.Next(100, 500))
    11. End While
    12. End While
    13. End Sub
    Alles anzeigen


    Wie du bereits gesagt hast, habe ich nun die While Schleife erweitert, es klappt aber noch immer nicht, wenn ich das a gedrückt halte, erscheinen trotzdem noch ab und an andere Buchstaben, und auch öfters mal das große A...

    Ich brauche Hilfe, kenn sich da jemand aus, bzw Nile, hast du ne Ahnung?? ;)
  • Hmm, da sich nichts ändert kann ich mir das prinzipiell nur so erklären, dass SyncLock nur taugt, um eigene Threads voneinander abzusichern, die Systemprozesse (die die Tastatureingaben behandeln) sind offensichtlich immer noch in der Lage deinen Thread abzuwürgen und den entsprechenden Handler aufzurufen.

    Dann eben anders: Wenn wir schon nicht garantieren können, dass threadsendkey() nicht unterbrochen wird, dann muss eben ein zusätzlicher Kontrollmechanismus her, damit dein Handler erkennt, woher der Tastendruck kommt. Dazu bietet es sich an, neben virtualkeys eine zusätzliche char-Variable virtualkey anzulegen, mittels der überprüft wird, ob der empfangene Character dem entspricht, der mittels SendKey() gesendet wurde. Das sollte dann ungefähr so aussehen:

    Quellcode

    1. Private Sub threadsendkey()
    2. Dim abc As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    3. Dim random As New Random()
    4. [B]Dim virutalkey as String[/B]
    5. While True
    6. While virtualkeys = False
    7. virtualkeys = True
    8. [B]virtualkey = abc.Substring(random.Next(0, 61), 1)[/B]
    9. My.Computer.Keyboard.SendKeys([B]virtualkey[/B], True)
    10. Threading.Thread.Sleep(random.Next(100, 500))
    11. End While
    12. End While
    13. End Sub
    14. Private Sub passwordtxt_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles passwordtxt.KeyPress
    15. If (virtualkeys && [B]virtualkey == e.KeyChar[/B]) Then
    16. e.Handled = True
    17. virtualkeys = False
    18. End If
    19. End Sub
    Alles anzeigen


    Jetzt können zwei Sachen passieren:

    1. Der Nutzer drückt eine von der virtuellen verschiedene Taste
    -> wird erkannt
    2. Der Nutzer drückt die gleiche Taste
    -> dann wird theoretisch der echte Tastendruck ausgefiltert, aber logischerweise der virtuelle durchgelassen (virtualkeys = false), was aber dann offensichtlich keine Rolle spielt.

    Hoffe mal das ich nichts übersehen habe, aber eigentlich sollte das so klappen.
  • Das ist brilliant, sehr gut, das klappt schonmal viel viel Besser, danke :)
    Ich teste mal ein bisschen und poste dann den finalen Code später, ich melde mich ;)

    Edit:\\

    Quellcode

    1. Private Sub Open_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Activated
    2. passtype = True
    3. End Sub
    4. Private Sub Open_Deactivate(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Deactivate
    5. passtype = False
    6. End Sub
    7. Private Sub passwordtxt_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles passwordtxt.GotFocus
    8. If sendkeyprot And Not thread.IsAlive Then
    9. passtype = True
    10. thread = New Threading.Thread(AddressOf threadsendkey)
    11. thread.Start()
    12. End If
    13. End Sub
    14. Private Sub threadsendkey()
    15. virtualkeys = False
    16. Dim abc As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    17. Dim random As New Random()
    18. While passtype
    19. While virtualkeys = False And passtype
    20. virtualkeys = True
    21. virtualkey = abc.Substring(random.Next(0, 61), 1)
    22. My.Computer.Keyboard.SendKeys(virtualkey, True)
    23. Threading.Thread.Sleep(random.Next(50, 250))
    24. End While
    25. End While
    26. End Sub
    27. Private Sub passwordtxt_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles passwordtxt.KeyPress
    28. If virtualkeys And virtualkey = e.KeyChar Then
    29. e.Handled = True
    30. virtualkeys = False
    31. End If
    32. End Sub
    Alles anzeigen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Jannik ()