引言
前段时间有位小姐姐下载了一个加密的压缩包资源,里面是最新在上映的电影,遂找到我想要我帮她破解一下。
博主想这还不简单,就到网上找了一个压缩包密码破解软件,但是使用的时候发现,他是用暴力破解字典来进行破解的,结果软件下载包里没自带。
这还不简单就生成一个破解字典,让程序去做咯~~~
心酸历程一——纯数字字典
据“数据分析”(即不可靠的数据推断),加密的密码长度一般不会超过6位,一般都是数字形式。那可以直接使用range从0生成到999999,然后做个format就可以了,如下面代码所示。
with open('violence_breaks_dictionary.txt','w') as f:
for i in range(0,1e6):
f.write('{}\n'.format(i))
轻松搞定纯数字字典,放到破解软件里破解了一番,等程序运行完,发现没有一个密码是正确的。随即实验了7位纯数字、8位纯数字。。。。。。甚至11位纯数字(一般手机号为11位),都不对。
如此可以看出,密码可能不为纯数字形式,可能是大写字母、小写字母与数字的组合。
心酸历程二——字母+数字字典
字母+数字的形式,着实有点费脑,因为要一次性生成1位到6位的所有组合情况,用for或者while循环,显然并不能直接做到。(ps:其实是可以的,但是那种方法有点不符合一个程序猿的基本素养)
number=[str(i) for i in range(10)] # 数字
ALPHABET=[chr(i) for i in range(65,26+65)] # 大写字母
alphabet=[chr(i) for i in range(97,97+26)] # 小写字母
char_set=('',)+tuple(number+ALPHABET+alphabet)
with open('violence_breaks_dictionary.txt','w') as f:
for i1 in char_set:
for i2 in char_set:
for i3 in char_set:
for i4 in char_set:
for i5 in char_set:
for i6 in char_set:
f.write(f'{i1}{i2}{i3}{i4}{i5}{i6}\n')
那么,问题来了,如何用有限的代码,来实现生成字母+数字形式的1到6位所有可能的组合的暴力破解的字典呢?
某头躺在床上,想到一个很棒的神奇,那就是递归。
所以有了一个版本的代码,如下所示。
number=[str(i) for i in range(10)] # 数字
ALPHABET=[chr(i) for i in range(65,26+65)] #大写字母
alphabet=[chr(i) for i in range(97,97+26)] #小写字母
char_set=tuple(number+ALPHABET+alphabet)
nl = []
def gan_number(n):
if n==1:
nl.extend(char_set)
yield char_set
else:
for i in char_set:
char_item=[i+item_ for item in gan_number(n - 1) for item_ in item]
nl.extend(char_item)
yield char_item
print(list(gan_number(6)))
print(nl)
跑了很久很久。。。千呼万唤始出来,看着最后的nl的输出,感觉貌似没有问题,但是数据太多,那就测试一下gan_number(2)的输出结果。
结果,很明显,并不好,因为n=1的数据重复了很多次,那么怎么办,很简单,gan_number(n - 1) 的调用不妨到循环里,只让他调用一次咯~~~r
number=[str(i) for i in range(10)] # 数字
ALPHABET=[chr(i) for i in range(65,26+65)] #大写字母
alphabet=[chr(i) for i in range(97,97+26)] #小写字母
char_set=tuple(number+ALPHABET+alphabet)
nl = []
def gan_number(n):
if n==1:
nl.extend(char_set)
yield char_set
else:
gan_=gan_number(n - 1)
for i in char_set:
char_item=[i+item_ for item in gan_ for item_ in item]
nl.extend(char_item)
yield char_item
print(list(gan_number(6)))
print(nl)
然后,事情哪有这么简单,too young,too simple.
咋回事,代码怎么不按照套路出牌~年轻人,不讲武德啊。(开个玩笑~)
这是怎么回事,那么不得不说到python迭代器(请参考这篇文章)了,详细的在这里面说了,这里就不重复了。
所以这里问题关键就是,迭代器是一个“阅完即焚”的东西,说白了,数据只能提取一次。
那么怎么办呢,那只能取消他迭代器的特性,简单的说,就是把数据全取出来,然后再让他去执行下面的for循环。
number=[str(i) for i in range(10)] # 数字
ALPHABET=[chr(i) for i in range(65,26+65)] #大写字母
alphabet=[chr(i) for i in range(97,97+26)] #小写字母
char_set=tuple(number+ALPHABET+alphabet)
nl = []
def gan_number(n):
if n==1:
nl.extend(char_set)
yield char_set
else:
gan_=tuple(gan_number(n - 1))
for i in char_set:
char_item=[i+item_ for item in gan_ for item_ in item]
nl.extend(char_item)
yield char_item
print(list(gan_number(6)))
print(nl)
如此,得到的就是我们所需要的结果,最后只需要把nl的数据保存成文件就行。
number=[str(i) for i in range(10)] # 数字
ALPHABET=[chr(i) for i in range(65,26+65)] #大写字母
alphabet=[chr(i) for i in range(97,97+26)] #小写字母
char_set=tuple(number+ALPHABET+alphabet)
nl = []
def gan_number(n):
if n==1:
nl.extend(char_set)
yield char_set
else:
gan_=tuple(gan_number(n - 1))
for i in char_set:
char_item=[i+item_ for item in gan_ for item_ in item]
nl.extend(char_item)
yield char_item
print(list(gan_number(6)))
with open('violence_breaks_dictionary.txt','w') as f:
for item in nl:
f.write(item+'\n')