web-dev-qa-db-fra.com

Comment puis-je corriger l'erreur «TypeError: impossible de sérialiser l'objet« _io.BufferedReader »» lors d'une tentative de multiprocessus

J'essaie de basculer le filetage de mon code vers le multitraitement pour mesurer ses performances et, espérons-le, atteindre un meilleur potentiel de forçage brutal car mon programme est destiné à forcer les fichiers .Zip protégés par mot de passe. Mais chaque fois que j'essaie d'exécuter le programme, j'obtiens ceci:

BruteZIP2.py -z "Generic Zip.zip" -f  Worm.txt
Traceback (most recent call last):
  File "C:\Users\User\Documents\Jetbrains\PyCharm\BruteZIP\BruteZIP2.py", line 40, in <module>
    main(args.Zip, args.file)
  File "C:\Users\User\Documents\Jetbrains\PyCharm\BruteZIP\BruteZIP2.py", line 34, in main
    p.start()
  File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\multiprocessing\process.py", line 112, in start
self._popen = self._Popen(self)
  File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\multiprocessing\context.py", line 223, in _Popen
return _default_context.get_context().Process._Popen(process_obj)
  File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\multiprocessing\context.py", line 322, in _Popen
return Popen(process_obj)
  File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\multiprocessing\popen_spawn_win32.py", line 65, in __init__
reduction.dump(process_obj, to_child)
  File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\multiprocessing\reduction.py", line 60, in dump
ForkingPickler(file, protocol).dump(obj)
TypeError: cannot serialize '_io.BufferedReader' object

J'ai trouvé des fils qui avaient le même problème que moi, mais ils étaient tous deux sans réponse/non résolus. J'ai également essayé d'insérer Pool au-dessus de p.start() car je pense que cela est dû au fait que je suis sur une machine Windows, mais cela ne m'a pas aidé. Mon code est le suivant:

  import argparse
  from multiprocessing import Process
  import zipfile

  parser = argparse.ArgumentParser(description="Unzips a password protected .Zip by performing a brute-force attack using either a Word list, password list or a dictionary.", usage="BruteZIP.py -z Zip.zip -f file.txt")
  # Creates -z arg
  parser.add_argument("-z", "--Zip", metavar="", required=True, help="Location and the name of the .Zip file.")
  # Creates -f arg
  parser.add_argument("-f", "--file", metavar="", required=True, help="Location and the name of the Word list/password list/dictionary.")
  args = parser.parse_args()


  def extract_Zip(zip_file, password):
      try:
          Zip_file.extractall(pwd=password)
          print(f"[+] Password for the .Zip: {password.decode('utf-8')} \n")
      except:
          # If a password fails, it moves to the next password without notifying the user. If all passwords fail, it will print nothing in the command Prompt.
          print(f"Incorrect password: {password.decode('utf-8')}")
          # pass


  def main(Zip, file):
      if (Zip == None) | (file == None):
          # If the args are not used, it displays how to use them to the user.
          print(parser.usage)
          exit(0)
      Zip_file = zipfile.ZipFile(Zip)
      # Opens the Word list/password list/dictionary in "read binary" mode.
      txt_file = open(file, "rb")
      for line in txt_file:
          password = line.strip()
          p = Process(target=extract_Zip, args=(Zip_file, password))
          p.start()
          p.join()


  if __name__ == '__main__':
      # BruteZIP.py -z Zip.zip -f file.txt.
      main(args.Zip, args.file)

Comme je l'ai déjà dit, je crois que cela se produit principalement parce que je suis actuellement sur une machine Windows. J'ai partagé mon code avec quelques autres qui étaient sur des machines Linux et ils n'ont eu aucun problème à exécuter le code ci-dessus.

Mon objectif principal ici est de démarrer 8 processus/pools pour maximiser le nombre de tentatives effectuées par rapport au threading, mais en raison du fait que je ne peux pas obtenir de correctif pour le message TypeError: cannot serialize '_io.BufferedReader' object, Je ne sais pas quoi faire ici et comment puis-je le réparer. Toute aide serait appréciée.

3
Arszilla

Les descripteurs de fichiers ne sérialisent pas très bien ... Mais vous pouvez envoyer le nom du fichier Zip au lieu du Zip filehandle (une chaîne sérialise bien entre les processus). Et évitez Zip pour votre nom de fichier car il est intégré. J'ai choisi Zip_filename

p = Process(target=extract_Zip, args=(Zip_filename, password))

puis:

def extract_Zip(zip_filename, password):
      try:
          Zip_file = zipfile.ZipFile(Zip_filename)
          Zip_file.extractall(pwd=password)

L'autre problème est que votre code ne s'exécutera pas en parallèle à cause de cela:

      p.start()
      p.join()

p.join attend la fin du processus ... peu utile. Vous devez stocker les identifiants de processus dans join à la fin.

Cela peut entraîner d'autres problèmes: créer trop de processus en parallèle peut être un problème pour votre machine et n'aidera pas beaucoup après un certain point. Considérons un multiprocessing.Pool à la place, pour limiter le nombre de travailleurs.

Un exemple trivial est:

with multiprocessing.Pool(5) as p:
    print(p.map(f, [1, 2, 3, 4, 5, 6, 7]))

Adapté à votre exemple:

with multiprocessing.Pool(5) as p:
    p.starmap(extract_Zip, [(Zip_filename,line.strip()) for line in txt_file])

( starmap développe les tuples en 2 arguments distincts pour s'adapter à votre extract_Zip méthode, comme expliqué dans Python multiprocessing pool.map pour plusieurs arguments )

4