用Python生成暴力破解字典

1:33:00 PM 0 Comments

其实暴力破解字典就是将可输入的字符进行全排列,是非常简单的方法,只不过用C语言写起来很繁琐,因此我想到了Python。

先看看怎么生成所有可输入的字符吧(不考虑中文等字符),方法很多,这里列举2种:
chars = string.printable[:-5] # 后面5个是换行、tab等字符 chars = ''.join([chr(i) for i in xrange(32, 127)])
取下长度就发现有95个字符…

生成2位的全排列麻烦一些:
p = [] for i in chars:     for j in chars:         p.append(i + j)
当然也可以直接用列表来生成:
p = [i + j for i in chars for j in chars]
生成更多位当然也可以用更多的变量来实现,但如果位数是变量,那我就不知道得写几个了。
不过这也很简单,因为Python是动态语言,我只要动态构造一个列表解析即可:
n = 3 pattern = '["' + '%%s' * n + '" %% (' + 'i%d,' * n + ')' + ' for i%d in chars' * n + ']' pattern %= tuple(range(n) * 2) p = eval(pattern)
你会发现当n大于3时,生成已经慢得要死了,而且很可能出现内存错误。因为954= 81450625,已经接近1亿了,要在内存里放那么多字符串可不容易。

最容易想到的方法就是改成生成器表达式,也就是把中括号改成小括号,这样瞬间就生成了,而遍历的方法仍然是用for。
不过用eval总觉得有些不好,生成的式子也很难看懂。于是切换到Python 2.6,用itertools.product()函数就行了:
import itertools import string n = 3 itertools.product(string.printable[:-5], repeat=n)
没有2.6咋办呢,看看文档里给出的源码吧,写得比我的易懂些,但是性能会差一些(速度约为我的1/4):
def product(*args, **kwds):     # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy     # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111     pools = map(tuple, args) * kwds.get('repeat', 1)     result = [[]]     for pool in pools:         result = [x+[y] for x in result for y in pool]     for prod in result:         yield tuple(prod)
注意result用的是列表解析,事实上用生成器表达式更节省内存。
当然,标准模块是C实现,所以速度仍然是比我快很多的。

此外,因为是生成1~n位的全排列,所以还得合并生成器。如果是自己写yield的,那只要再套个for循环即可;而如果是用生成器表达式,写起来就麻烦多了。
好在itertools里还有chain()和chain.from_iterable()这2个函数(后者为2.6新增)。

于是最终的函数如下:
import itertools import string  def crackdict(max, min=1, chars=None):     assert max >= min >= 1      if chars is None:         import string         chars = string.printable[:-5]      p = []     for i in xrange(min, max + 1):         p.append(itertools.product(string.printable[:-5], repeat=i))      return itertools.chain(*p)  #测试一下: max, min = 4, 1 d = crackdict(max, min)  print sum((1 for i in d)) print sum([95 ** i for i in xrange(min, max + 1)])
4位一共用生成了82317120个(95 + 952 + 953 + 954)字符串,时间为14.4秒左右。

Some say he’s half man half fish, others say he’s more of a seventy/thirty split. Either way he’s a fishy bastard.