einfaches Brut-Force Programm Memory Error

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

Hi

Ich bin ein ziemlicher Noob und habe erst gerade begonnen mit Python und programmieren, also bitte nicht lachen :D
Ich habe ein einfaches Programm geschrieben um die Sicherheit meiner Passwörter zu testen.

Code: Alles auswählen

import itertools
import time
zeichenAnzahl = 1
passwort = str("passwort")
geknackt = False
versuche = 0
while True:
    startZeit = time.time()
    passw = list(itertools.permutations("abcdefghijklmnopqrstuvwxyz", zeichenAnzahl))
    print("Versuche:", versuche)
    for kombination in passw:
        if geknackt == True:
            break
        komb = str()
        for i in kombination:
            komb += str(i)
            del i
        del kombination
        #print(komb)
        versuche+=1
        if komb == passwort:
            print("PASSWORT GEKNACKT", komb)
            geknackt = True
            endZeit = time.time()
            print("Passwort wurde in", endZeit-startZeit, "geknackt mit", versuche, "Versuchen.")
            False
        del komb
    zeichenAnzahl+=1
    del passw
Doch wenn ich das laufen lasse kriege ich nach kurzer Zeit einen Fehler.

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Users\Fam.Husistein\Desktop\test.py", line 9, in <module>
    passw = list(itertools.permutations("abcdefghijklmnopqrstuvwxyz", zeichenAnzahl))
MemoryError
Ich vermute, das dieser auf zu wenig Arbeitsspeicher hinweist, sicher bin ich mir aber nicht.
Wenn ich aber alle einzelne Passwort-Versuche ausgeben lasse, krieg ich keinen Fehler, aber dann ist es sehr langsam.

Hoffe ihr könnt mir helfen :?:
Zuletzt geändert von Anonymous am Montag 12. März 2012, 21:01, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Kein Wunder, wenn du irgendwann 26! ÷ (26-20)! (das ist ungefähr 5.601270293425078·10^(23)) Elemente in den RAM kopieren willst. Du brauchst das allerdings gar nicht. Entferne einfach das `list()` um den Aufruf von `itertools.permutations`.
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

:mrgreen:
Manchmal liegt die Lösung so nah :D

Danke habe jetzt keine Probleme mehr.
BlackJack

@nooby: Als nächstes solltest Du mal ``del`` vergessen. Das ist total sinnfrei was Du damit anstellst. ``del`` löscht den *Namen* aber nicht zwangsläufig das Objekt was an den Namen gebunden war. Ob und wann der Speicher davon freigegeben wird, entscheidet die Laufzeitumgebung. „Manuelle Speicherverwaltung” solltest Du in Python gar nicht erst versuchen.

Was Du da mit `komb` machst ist auch reichlich ineffizient. Ein einfacher `str()`-Aufruf ist das gleiche wie eine konstante, literale, leere Zeichenkette, nur halt mit einem extra Funktionsaufruf. Das wiederholte „aufaddieren” der Zeichen hat im schlechtesten Fall quadratische Laufzeit wenn jedes mal eine neue Zeichenkette mit dem alten Inhalt plus dem neuen Zeichen erstellt wird. Man benutzt dafür in Python die `join()`-Methode auf Zeichenketten statt so einer ``for``-Schleife.

``str("passwort")`` ist das selbe wie ``'passwort'``. Was denkst Du denn was der Funktionsaufruf bewirkt?

Einfach irgendwo einen Wert in den Quelltext zu schreiben, zum Beispiel ``False``, ist zwar nicht verboten, macht aber auch gar keinen Sinn.
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

Das mit den Del habe ich im Internet als Lösung gegen Memory Error gefunden.
War wohl doch nichts.
Das mit dem String habe ich gemacht, weil ich auch noch eine Version habe, bei der man die Passwörter eingeben kann und ich vorgesorgt habe, falls man ein Zahlenpasswort eingibt.
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

Habe es mal so gut wie möglich geändert.
Weitere Kritik erwünscht 8)

Code: Alles auswählen

import itertools
import time
zeichenAnzahl = 1
passwort = str("passwort")
geknackt = False
versuche = 0
while True:
    startZeit = time.time()
    passw = (itertools.permutations("abcdefghijklmnopqrstuvwxyz", zeichenAnzahl))
    print("Versuche:", versuche)
    print()
    print("AnzahlZeichen:", zeichenAnzahl)
    for kombination in passw:
        if geknackt == True:
            break
        komb = "".join(kombination)
        print(komb)
        versuche+=1
        if komb == passwort:
            print("PASSWORT GEKNACKT", komb)
            geknackt = True
            endZeit = time.time()
            print("Passwort wurde in", endZeit-startZeit, "geknackt mit", versuche, "Versuchen.")
            False

    zeichenAnzahl+=1
lunar

Das "False" am Schluss ist immer noch sowas von überflüssig… und den Körper der "for"-Schleife kannst Du auch wesentlich kürzer schreiben.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Statt `True` und manuellem Hochzaehlen von zeichenAnzahl bietet sich `for` und `itertools.count(1)` an.
Die zusaetzlichen Klammern bei der Zuweisung von `passw` sind auch ueberfluessig.
Statt `geknackt` mitzufuehren, kannst du auch einfach direkt abbrechen.
Das vereinzelte `False` ist auch immernoch ueberfluessig.

Daneben solltest du dir mal PEP8 anschauen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Und ``passwort = str("passwort")`` ist immer noch ein überflüssiger Aufruf von ``str``, das hat sich nicht geändert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

Ich habe noch Mal eine Frage.
Wenn ich beim obigen Beispiel als Passwort "Hallo" eingebe, wird das Passwort nicht geknackt.
Woran kann das liegen?

Ich habe die Anzahl Versuche mit den Versuchen die möglich wären durchgerechnet und es werden meiner Meinung nach nicht alle Kombinationen ausprobiert.

Habt ihr eine Idee woran das liegen könnte?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

nooby hat geschrieben:Wenn ich beim obigen Beispiel als Passwort "Hallo" eingebe, wird das Passwort nicht geknackt.
Woran kann das liegen?
1. Großbuchstabe
2. doppelte Zeichen
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

Das mit dem Grossbuchstaben kann einfach beheben.
Einfach alle Buchstaben noch in gross zur Liste hinzufügen, doch wie sieht es mit den doppelten Zeichen aus?
Wie kann ich dies beheben?
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Permutationen sind nun mal Permutationen. Es wird lediglich jede mögliche Anordnung einer bestimmten Länge mit dem vorgegebenem Zeichensatz durchprobiert.

Alternative dafür wäre itertools.product() wenn man das repeat-Schlüsselwort passend setzt.
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

Danke für die Hilfe!
Ich habe den Code jetzt entsprechend abgeändert.

Code: Alles auswählen

passw = itertools.product(zeichen, repeat=zeichenAnzahl)
Jetzt funktioniert es.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

cofi hatte Dir schon mal PEP8 genannt. Das solltest Du Dir mal angucken; ``repeat=zeichenAnzahl`` klingt arg nach Java :mrgreen: Und ob man ``passw`` nun nicht noch ``ord`` spendieren kann, ist auch fraglich ;-)

Als nächstes könntest Du das Knacken an sich in eine Funktion packen und es damit von der Nutzereingabe und der Zeitmessung entkoppeln. Beides kannst Du dann als separate Funktionen implementieren, die Du entsprechend aufrufst. Damit wird aus einem "Stück Code" imho erst ein wirkliches Programm :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

Ich habe noch Mals eine Frage:)
Wenn ich das Knacken in eine Funktion packe, werden dann die Import Anweisungen ebenfalls in die Funktion geschrieben, oder geschieht dies im Hauptprogramm?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

nooby hat geschrieben:Ich habe noch Mals eine Frage:)
Wenn ich das Knacken in eine Funktion packe, werden dann die Import Anweisungen ebenfalls in die Funktion geschrieben, oder geschieht dies im Hauptprogramm?
Nein, die import-Anweisungen sollten immer ganz oben im Modul stehen. Es gibt auch Situationen, in denen ein Import in einer Funktion sinnvoll ist, das kommt aber eher selten vor.
Das Leben ist wie ein Tennisball.
nooby
User
Beiträge: 91
Registriert: Montag 12. März 2012, 20:39
Wohnort: 127.0.0.1

Ich habe es jetzt ein Mal so gut wie möglich programmiert.

Code: Alles auswählen

import itertools
import time

def passwortKnacken(möglicheZeichen, passwort, zeichenAnzahl):
    while True:
        versuche = 0
        passw = itertools.product(möglicheZeichen, repeat=zeichenAnzahl)
        print(zeichenAnzahl)
        for kombination in passw:
            komb = "".join(kombination)
            versuche+=1   
            #print(komb)
            if komb == passwort:
                return komb, versuche
        zeichenAnzahl+=1


möglicheZeichen = input("Bitte gieb alle Zeichen ein, die im Passwort enthalten sind:")
passwort = input("Bitte gieb das Passwort zum testen ein:")
zeichenAnzahl = int(input("Bitte gieb die mindest Anzahl Zeichen ein:"))
startZeit = time.time()
geknackt = passwortKnacken(möglicheZeichen, passwort, zeichenAnzahl)
endZeit = time.time()
print("Das Passwort lautet", geknackt[0], "und wurde in", str(endZeit-startZeit), "Sekunden und", geknackt[1], "Versuchen geknackt.")
Aber das mit dem und dem zeichenAnzahl sieht aus wie Java bin ich nicht drausgekommen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

- Statt der ``while``-Schleife und dem manuellen Counter wurde Dir doch iirc schon ``itertools.count`` empfohlen. Das kannst Du darüber hinaus auch bei der Erhöhung der Zeichenanzahl nutzen.

- Ich würde den ``itertools.product``-Aufurf nicht an einen separaten Namen binden, der eigentlich nie gebraucht wird; stattdessen schreib den Ausdruck doch direkt in den Kopf der ``for``-Schleife.

- PEP8 bei den Namen sehe ich auch noch nicht.

- Ich finde deutsche Namen idR. etwas "sperrig". Englisch ist da oftmals viel kürzer :-)

- Benutzt Du Python3? Ich hoffe ja, wenn nicht, gäbs noch einiges zu meckern :mrgreen: (print, input)

- Du solltest den Rest-Code nicht auf Modulebene stehen lassen, sondern so verpacken:

Code: Alles auswählen

#!/usr/bin/env python

# imports
import ...
...

# Funktionen / Klassen
def foo():
    ...

# ganz unten dann
def main():
    # ab hier alle Aufrufe, die Du noch außerhalb der Funktion
    # stehen hast; also den Code auf Modul-Ebene!

if __name__ == "__main__":
    main()
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Einige Dinge, die aufgefallen sind:
- Umlaute in Namen sind sehr unüblich
- du setzt "versuche" bei jedem Durchlauf wieder auf 0
- Es heißt "gib" und nicht "gieb"
- "zum Testen"
- "Mindestanzahl"
- Zum Zusammensetzen von Strings solltest du die Suchmaschine deiner Wahl mal nach "String Formatting" befragen.
- "geknackt" ist ein unpassender Name. Schöner wäre zum Beispiel:

Code: Alles auswählen

passwort, versuche = passwortKnacken(möglicheZeichen, passwort, zeichenAnzahl)
Dann ist die Zeile mit der Ausgabe auch gleich übersichtlicher.

Zum "zeichenAnzahl" und Java: Schau dir mal PEP8 an, in Python ist der Style etwas anders.
Zum "ord": Schreibe "password" statt "passw". Die drei Zeichen sind an der falschen Stelle gespart.
Das Leben ist wie ein Tennisball.
Antworten