简体   繁体   English

具有子流程的Python多处理停止工作

[英]Python multiprocessing with subprocess stops working

Can you help me? 你能帮助我吗?
- Avoid the program to hang after ~16.000 permutations, - 避免程序在〜16.000排列后挂起
- All processes should stop if one finds the solution (see output), -如果找到解决方案,则所有进程都应停止 (请参见输出),
- Give me general advice to make my code better, faster and learn more about python? -给我一些一般性建议,以使我的代码更好,更快,并更多地了解python?

I try to brute force my True Crypt container because I forgot my password. 我尝试强行使用我的True Crypt容器,因为我忘记了密码。 I can still remember the words, but I miss the combination. 我仍然记得这些单词,但我错过了组合。 Therefore I thought about this script. 因此,我想到了这个脚本。

What should it do? 应该怎么办? I hand it a word list and it should a) build all permutations and b) try if it finds the right one. 我给它一个单词列表,它应该a)建立所有排列,b)尝试找到正确的排列。 Because I work on Windows 7 I use True Crypt command-line interface for trying, which I access via a python subprocess. 因为我在Windows 7上工作,所以我使用True Crypt命令行界面进行尝试,我可以通过python子进程进行访问。

After writing a single threaded version I thought about making it faster. 编写单线程版本后,我考虑过使其速度更快。 I first tried multiple threads then found the GIL and used multiprocessing. 我首先尝试了多个线程,然后找到了GIL并使用了多处理。 For me this is a learning experience, I never used Python before and know only Java and PHP. 对我来说,这是一次学习经历,我以前从未使用过Python,并且只知道Java和PHP。 And I never did parallel programming before. 我以前从未做过并行编程。

The code: 编码:

import subprocess, os, sys, time, multiprocessing, Queue, itertools

wordlist = [
"foo",
"bar",
"zoo",
"hello",
"World",
]
tcFile = r"C:\dev\tc-brute-force\test.pa"
tcProg = r"C:\Program Files\TrueCrypt\TrueCrypt.exe"
tcMountLetter = "z"
verbose = 5 # as higher as more output is shown fatal=0-5=trace
counter = 0
numberofworkers = multiprocessing.cpu_count()*2
curenttime = time.time()

def getDuration(starttime):
        return time.time() - starttime

def callTC(password, event):
    commandArgs = [
        tcProg,
        '/a',
        '/s',
        '/q',
        '/v', tcFile,
        '/l', tcMountLetter,
        '/p',  password,
    ]

    child = subprocess.Popen(commandArgs, \
        stderr=open(os.devnull, 'w'), \
        stdout=open(os.devnull, 'w'))
    result = child.communicate() # Really important to get error code!

    if verbose > 4:
        print subprocess.list2cmdline(commandArgs).rstrip() + \
            " Status out=" + str(result[0]) + \
            " err=" + str(result[1]) + \
            ", code=" + str(child.returncode)

    if child.returncode == 0:
        event.set()
        print "Successfully opened TrueCrypt file with '%s' at iteration %d, duration %.3fs" % (password, counter, getDuration(curenttime))

def callTCDaemon(queue, event):
    while True:
        if queue.empty():
            break
        else:
            password = queue.get()
            callTC(password, event)

if __name__ == '__main__':

    manager = multiprocessing.Manager()
    event = manager.Event()
    worker = manager.Queue(numberofworkers)

    # start processes
    pool = []
    for i in xrange(numberofworkers):
        process = multiprocessing.Process(target=callTCDaemon, args=(worker, event))
        process.start()
        pool.append(process)

    # generate permutations
    for x in xrange(1, (len(wordlist)+1) ):
        for permutation in itertools.permutations(wordlist, x):

            # shutdown if result is found
            if event.is_set():
                # wait till finished
                for p in pool:
                    p.join(2)

                print "Finished TrueCrypt brute-force, after %d attempts, duration %.3fs" % (counter, getDuration(curenttime))
                sys.exit(1)

            counter += 1    
            combination = ""

            # build string from permutation
            for i in range(0, len(permutation)):
                combination += permutation[i]

            # output progress
            if verbose == 4 and counter%100 == 0:
                print "%15d|%15.3fs: %s" % (counter, getDuration(curenttime), combination)

            # avoid queue overload
            while worker.qsize() > 100:
                if verbose > 3: print "Wait because queue is full, size=%d" % (worker.qsize)
                time.sleep(4)           

            worker.put(combination)

Example output (altered a bit): 示例输出(略有变化):

C:\dev\tc-brute-force>python TrueCryptBruteForceProcesses.py
            100|         23.013s: fooWorld
            200|         48.208s: barHelloWorld
Successfully opened TrueCrypt file with 'Worldfoo' at iteration 0, duration 50.218s
Successfully opened TrueCrypt file with 'Worldbar' at iteration 0, duration 50.249s
Successfully opened TrueCrypt file with 'Worldzoo' at iteration 0, duration 50.260s
Successfully opened TrueCrypt file with 'Worldhello' at iteration 0, duration 50.304s
Successfully opened TrueCrypt file with 'foobarzoo' at iteration 0, duration 50.354s
Successfully opened TrueCrypt file with 'helloWorld' at iteration 0, duration 50.433s
Successfully opened TrueCrypt file with 'foobarhello' at iteration 0, duration 50.438s
Successfully opened TrueCrypt file with 'foobarWorld' at iteration 0, duration 50.440s
Successfully opened TrueCrypt file with 'foozoobar' at iteration 0, duration 50.473s
Finished TrueCrypt brute-force, after 209 attempts, duration 50.733s

There are three main parts in the brute-force code: 蛮力代码包含三个主要部分:

  • generate passwords 产生密码
  • check a single password 检查一个密码
  • check many passwords concurrently 同时检查许多密码

Generate passwords 产生密码

Yield all possible permutations: 产生所有可能的排列:

import itertools

def generate_passwords(wordlist):
    for password_length in range(1, len(wordlist) + 1): # no repeats
        for password in itertools.permutations(wordlist, password_length):
            yield " ".join(password)

Check password 确认密码

Look at TRUECRYPT EXPLAINED . 看看TRUECRYPT的解释 Maybe you don't need to spawn a subprocess for each password. 也许您不需要为每个密码生成一个子进程。

from subprocess import call

def valid_password(password):
    rc = call(true_crypt_command(password), close_fds=True)
    return rc == 0, password

Check many password concurrently 同时检查多个密码

import sys
from multiprocessing.dummy import Pool # use threads

wordlist = "foo bar zoo hello World".split()
pool = Pool(20) # check 20 passwords in parallel
for i, (found, password) in enumerate(
    pool.imap_unordered(valid_password, generate_passwords(wordlist))):
    if i % 1000 == 0: # report progress
       sys.stderr.write("\rchecked %d" % i)
    if found:
       print("Found: '%s'" % password)
       break
else:
    sys.exit("failed to find")

pool.close() 
####pool.join() # uncomment if it is not the end

Except for true_crypt_command() function that generates TrueCrypt command line, it is the full source. 除了生成TrueCrypt命令行的true_crypt_command()函数外,它是完整源代码。

Another code example: Brute force http basic auth . 另一个代码示例: 蛮力http basic auth

Will imap_unordered stop all the other threads/processes if one reaches rc==0? 如果一个达到rc == 0,imap_unordered是否会停止所有其他线程/进程?

If you exit the program immediately after the break then OS kills all remaining threads automatically (they are daemon thread so they won't survive). 如果您在break后立即退出程序,则OS会自动杀死所有剩余线程(它们是守护程序线程,因此它们将无法生存)。

If your program continues to run after the loop then upto 20 threads (size of the pool) might continue to run. 如果您的程序在循环后继续运行,则可能最多继续运行20个线程(池的大小)。 You can wait for them to end if you uncomment pool.join() . 如果取消注释pool.join()则可以等待它们结束。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM