所以我试图制作一个暴力破解密码的程序。
首先,我为长度为1的密码制作了一个程序:
password = input('What is your password?\n')
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
def brute_force():
for char in chars:
if char == password:
return char
print(brute_force())
然后我编辑了一个长度为2的密码:
def brute_force():
guess = [None, None]
for char in chars:
guess[0] = char
for char2 in chars:
guess[1] = char2
if ''.join(guess) == password:
return ''.join(guess)
最后我为长度为3的密码做了同样的事情:
def brute_force():
guess = [None, None, None]
for char in chars:
guess[0] = char
for char2 in chars:
guess[1] = char2
for char3 in chars:
guess[2] = char3
if ''.join(guess) == password:
return ''.join(guess)
我怎么能概括为一个名为length的变量,它包含密码长度的整数值?
您可以使用以下递归函数:
def brute_force(string, length, goal):
if not length:
if string == goal:
return string
return False
for c in chars:
s = brute_force(string + c, length - 1, goal)
if s:
return s
return False
您可以使用以下语法调用:
>>> brute_force('', 3, 'bob')
'bob'
>>> brute_force('', 2, 'yo')
'yo'
为什么这样做?
我们总是用三个变量调用每个函数:string
,length
和goal
。变量string
保持当前的猜测到这一点,所以在第一个例子中,string
将是bob
所有的一切,如ab
,bo
等。
下一个变量length
包含了多少个字符,直到string
是正确的长度。
下一个变量goal
是我们刚刚通过的正确密码,并与之进行比较。
在函数的主体中,我们需要首先检查length
是0
的情况(通过检查not length
完成0
评估为False
)。当我们已经有一个字符串是目标的长度并且我们只想检查它是否正确时就是这种情况。
如果匹配,则返回字符串,否则返回False
。我们返回解决方案或False
来指示调用我们的函数(堆栈中的上述调用)我们找到了正确的密码(或不是)。
我们现在已经完成了length = 0
的情况,现在需要处理其他情况。
在这些情况下,目标是获取我们被调用的字符串并循环遍历chars
中的所有字符,每次调用brute_force
函数(递归)时,我们调用的字符串的串联结果和那个角色(c
)。
这将创建一个类似于树的树,其中检查到原始length
的每个字符串。
我们还需要知道在调用下一个函数时如何处理length
和goal
变量。
那么,要处理这些问题,我们只需要考虑下一个功能需要知道的内容。它已经有string
(因为这是连接chars
字符串中的下一个字符的结果)和length
只会少一个,因为我们刚刚通过连接添加一个到string
并且goal
显然将是同样 - 我们仍在搜索相同的密码。
现在我们已经调用了这个函数,它会在每个后续调用中从长度中减去一个函数,直到最终到达length == 0
的情况。我们再次处于简单的情况,并且已经知道该怎么做了!
所以,在调用它之后,函数将返回两个东西中的一个,False
指示最后一个节点没有找到密码(所以这会发生在像ab
这样的东西在我们搜索bob
到达结尾的情况下所以返回False
在没有找到解决方案之后),或者,呼叫可以返回实际的解决方案。
处理这些情况很简单,如果我们得到实际解决方案,我们只想将其返回到链中,如果我们失败了(False
),我们只想返回False
而这将向我们上方的节点表明我们做了没有成功,并告诉它继续搜索。
所以现在,我们只需要知道如何调用该函数。我们只需要发送一个空的string
和一个目标length
和goal
值并让递归发生。
请注意,最后一件事是,如果您希望它更整洁,您可以将函数定义修改为:
def brute_force(length, goal, string=''):
...
并在其中更改递归调用。这样,您可以使用以下内容调用函数:brute_force(3, 'bob')
,并且不需要指定string
应该从哪个开始。如果您愿意,这只是您可以添加的内容,但功能无需工作。
除了向你展示这是如何工作的答案之外,我想提请注意这样一个事实:标准库有这样的功能,形状为itertools.product
-not itertools.permutations
,因为这不允许重复,因此会仅生成具有所有唯一字符的猜测:
from itertools import product
def brute_force():
for length in range(min_length, max_length + 1):
for p in product(chars, repeat=length):
guess = ''.join(p)
if guess == password:
return guess
这是一个解决方案:
password = input('What is your password? ')
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
def brute_force(length, check_callback, guess = ""):
if check_callback(guess):
return guess
elif len(guess) == length: #Reached maximum length and didn't find the password
return None
for char in chars:
retval = brute_force(length, check_callback, guess = guess + char)
if retval is not None:
return retval
return None #Couldn't find anything
print(brute_force(len(password), lambda guess: (guess == password))) #len(password) => cheating just for this example
length
是函数最大的猜测长度。 check_callback
应该猜测并返回一个真正的值,如果它工作。该函数返回第一个成功的猜测,如果找不到任何东西,则返回None
。
我承认我忘记了猜测长度,并被@Joe Iddon's answer提醒。
现在,即使猜测的长度不合适,该函数也会检查正确的答案,这在某些情况下是浪费的。这是一个不这样做的函数:
def brute_force(length, check_callback, guess = ""):
if len(guess) == length: #Reached maximum length
return (guess if check_callback(guess) else None)
for char in chars:
retval = brute_force(length, check_callback, guess = guess + char)
if retval is not None:
return retval
return None #Couldn't find anything
print(brute_force(len(password), lambda guess: guess == password)) #len(password) => cheating just for this example
试试这个:
password = input('What is your password?\n')
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
answer = ''
for i in range(len(password)):
for char in chars:
if char==password[i]:
answer += char
print(answer)
它不是使用嵌套循环,而是依次猜测每个字符。