离线密码破解工具
一、程序功能概述
该程序是一款基于密码模式生成与哈希比对的离线密码破解工具,主要用于破解SHA-256算法加密的密码哈希值。其核心逻辑是通过生成符合常见密码设置习惯的候选密码,计算其SHA-256哈希值并与目标哈希集合比对,从而还原出原始密码。程序适用于在合法授权场景下(如密码审计、数据恢复)对已知哈希值的密码进行离线破解,无需与目标系统交互,仅依赖本地计算资源。
程序的核心功能可概括为四大模块:
-
哈希值处理模块:负责加载目标哈希集合、计算密码哈希值
-
密码生成模块:通过多种模式生成海量候选密码(包括常规模式与leet speak变体)
-
破解执行模块:分阶段比对候选密码哈希与目标哈希,记录破解结果
-
结果管理模块:保存破解结果并生成统计信息
二、核心函数解析
1. 哈希值处理函数
(1)sha256_hash(text)
-
功能:计算输入字符串的SHA-256哈希值
-
实现逻辑:
def sha256_hash(text): return hashlib.sha256(text.encode('utf-8')).hexdigest() -
细节说明:通过
hashlib库的sha256方法对UTF-8编码的字符串进行哈希计算,返回16进制字符串形式的哈希值,与目标哈希格式保持一致。
(2)load_hashes(filename)
-
功能:从文本文件加载目标哈希值集合
-
实现逻辑:
def load_hashes(filename): with open(filename, 'r') as f: hashes = [line.strip() for line in f if line.strip()] return hashes -
细节说明:读取文件时自动过滤空行和空白字符,确保加载的哈希值纯净。返回列表形式的哈希集合,为后续转换为集合做准备。
(3)save_results(cracked_hashes, output_file)
-
功能:将破解结果保存到指定文件
-
实现逻辑:
def save_results(cracked_hashes, output_file): with open(output_file, 'w', encoding='utf-8') as f: for hash_val, password in cracked_hashes.items(): f.write(f"{hash_val}:{password}\n") print(f"结果已保存到 {output_file}") -
细节说明:采用
哈希值:密码的格式写入文件,使用UTF-8编码确保特殊字符正常存储,便于后续查看和复用。
2. 密码生成函数
(1)generate_advanced_passwords()
-
功能:生成符合常见用户习惯的高级密码字典,覆盖多种组合模式
-
实现逻辑:通过6种模式生成候选密码,最终去重后返回
-
模式1:单词+年份+特殊字符基于积极词汇列表(如"Champion"、"Winner")、1950-2023年的年份字符串、特殊字符组合(如"!"、"@!")进行三重组合,例如"Hero2020!!"。
-
模式2:人名+数字+特殊字符基于人名列表(如"John"、"Maria")、0-999的数字字符串、特殊字符组合进行组合,例如"Michael123@"。
-
模式3:人名+年份+特殊字符结合人名、年份、特殊字符,例如"Anna1990#"。
-
模式4:单词+数字+特殊字符结合积极词汇、0-999数字、特殊字符,例如"King78$"。
-
模式5:短语组合基于常见前缀短语(如"I love "、"Best ")与积极词汇的组合,并扩展出"短语+单词+数字"、"短语+单词+数字+特殊字符"等变体,例如"My favorite Diamond56!"。
-
模式6:重复字符模式对基础单词(如"a"、"love"、"password")进行5-20次重复,模拟用户重复输入字符的习惯,例如"aaaaa"、"passwordpassword"。
-
-
数据规模:通过多重循环组合生成海量密码,最终通过
list(set(passwords))去重,避免重复计算。
(2)generate_leet_speak_passwords()
-
功能:生成leet speak(黑客语)风格的密码变体,模拟字符替换习惯
-
实现逻辑:
-
基础单词:选取常见密码相关词汇(如"password"、"admin"、"secret")
-
leet替换规则:定义字符映射表(如'a'→'4'或'@','e'→'3','o'→'0')
-
变体生成:
-
简单替换:对基础单词进行固定替换(如"password"→"p4ssw0rd")
-
复杂替换:对每个可替换字符尝试所有可能替换(如"love"→"l0ve"、"l@ve"等)
-
扩展变体:为替换后的单词添加数字(0-999)和特殊字符(!、@、#、$),例如"p4ssw0rd123!"
-
-
-
设计思路:利用用户常将字母替换为形似数字/符号的习惯(如用"3"代替"e"),针对性生成变体以提高破解概率。
3. 主函数main()
-
功能:统筹整个破解流程,串联各模块功能
-
执行流程:
-
配置参数:指定输入哈希文件(
1.txt)和输出结果文件(answer.txt) -
加载哈希:调用
load_hashes加载目标哈希,转换为集合(hash_set)以提高查找效率 -
分阶段破解:
-
阶段1:调用
generate_advanced_passwords生成高级密码,逐个计算哈希并与hash_set比对,记录破解结果(cracked1),完成后从hash_set移除已破解哈希 -
阶段2:调用
generate_leet_speak_passwords生成leet风格密码,重复比对逻辑,记录结果(cracked2),再次更新hash_set
-
-
结果合并:整合历史破解结果(
previous_cracked)与当前破解结果(cracked1、cracked2) -
结果输出:调用
save_results保存合并结果,打印破解统计信息(总哈希数、成功破解数、破解率)
-
三、数据结构分析
程序根据不同场景选择了合适的数据结构,以平衡性能与功能需求,核心数据结构如下:
1. 列表(List)
-
应用场景:
-
存储生成的候选密码(
passwords列表) -
加载目标哈希的初始容器(
hashes列表)
-
-
选择原因:
-
支持动态扩容,适合存储数量未知的候选密码
-
允许按索引遍历,便于批量处理密码(如每100000个打印一次进度)
-
列表推导式可高效过滤空行(
[line.strip() for line in f if line.strip()])
-
-
局限性与优化:列表的元素查找复杂度为O(n),因此仅用于存储,不用于哈希比对;通过
list(set(passwords))去重,利用集合的特性剔除重复密码,减少无效计算。
2. 集合(Set)
-
应用场景:
-
目标哈希集合(
hash_set) -
密码去重(
set(passwords))
-
-
选择原因:
-
集合的成员判断(
hash_value in hash_set)复杂度为O(1),远优于列表的O(n),大幅提升哈希比对效率(核心性能优化点) -
自动去重特性,可快速剔除重复密码或已破解哈希(
hash_set -= set(cracked1.keys()))
-
-
实现细节:程序在加载哈希后立即转换为集合(
hash_set = set(hashes)),确保后续所有比对操作高效执行;每次阶段破解完成后,通过集合差集操作移除已破解哈希,避免重复比对。
3. 字典(Dictionary)
-
应用场景:
-
存储破解结果(
cracked1、cracked2、previous_cracked、all_cracked)
-
-
选择原因:
-
键值对结构天然适合存储"哈希值-密码"映射,便于快速索引和合并
-
支持字典解包合并(
{**previous_cracked,** cracked1, **cracked2}),简化多阶段结果整合 -
遍历键值对可直接按格式写入文件(
for hash_val, password in cracked_hashes.items())
-
-
设计优势:通过字典存储破解结果,既保证了哈希值的唯一性(键不可重复),又能快速关联对应的原始密码,兼顾存储效率与查询便捷性。
四、算法设计思路
程序的核心算法是基于模式的定向暴力破解算法,区别于纯随机暴力破解,其通过模拟用户设置密码的习惯生成候选密码,在有限计算资源下提高破解成功率。
1. 密码生成策略
(1)基于用户行为的模式提取
程序通过分析常见密码结构,提炼出六大生成模式,覆盖以下用户习惯:
-
语义关联:使用积极词汇("Champion")、人名("John")等有意义的字符串
-
时间关联:加入年份(1950-2023),可能对应生日、注册年份等
-
数字补充:添加0-999的数字,满足密码长度要求或对应特殊数字(如生日、纪念日)
-
特殊字符修饰:使用!、@、#等特殊字符,符合多数系统对密码复杂度的要求(需包含特殊字符)
-
短语组合:通过常见前缀("I love ")与词汇组合,形成有意义的短语密码
-
字符重复:重复简单字符或单词(如"aaaaa"),模拟用户图方便的设置习惯
(2)Leet Speak变体生成算法
针对用户将字母替换为形似符号/数字的习惯,设计了分层替换策略:
-
基础替换:对每个基础单词执行固定替换(如所有'a'→'4')
-
多向替换:对每个可替换字符尝试所有可能替换(如'a'同时尝试'4'和'@')
-
扩展组合:在替换后的单词后添加数字和特殊字符,进一步扩展覆盖范围
该算法通过"字符替换+后缀扩展"的双层逻辑,显著提升对leet风格密码的破解能力。
2. 破解执行算法
(1)分阶段破解策略
程序将破解过程分为两个阶段,按优先级逐步尝试:
-
阶段1:优先尝试符合常规用户习惯的高级密码(覆盖更广泛的常见模式)
-
阶段2:再尝试leet speak变体(针对性破解字符替换类密码)
阶段划分的依据是密码出现的概率:常规模式密码比leet变体更常见,优先处理可提高早期破解效率,减少无效计算。
(2)动态剪枝机制
-
提前终止条件:当已破解的哈希数量等于目标哈希总数时(
len(cracked) == len(hash_set)),立即终止当前阶段的密码尝试,避免冗余计算 -
哈希集动态更新:每个阶段结束后,从目标哈希集中移除已破解的哈希(
hash_set -= set(cracked.keys())),确保后续阶段仅处理未破解的哈希,减少比对次数
(3)进度监控机制
通过计数器(i)和模运算(i % 100000 == 0),每处理100000个密码打印一次进度,便于用户掌握破解进度并评估耗时。
五、执行流程与性能分析
2. 性能优化点
-
哈希比对效率:使用集合(
hash_set)替代列表存储目标哈希,将单次比对时间从O(n)降至O(1),在百万级密码比对场景下可节省数小时计算时间 -
密码去重:通过
list(set(passwords))剔除重复密码,减少无效哈希计算(尤其在多模式组合生成时,重复概率较高) -
分阶段处理:优先尝试高概率密码,尽早破解部分哈希并减少后续计算量
-
内存控制:通过生成器思想(循环生成+即时比对)避免一次性加载所有密码到内存(虽然当前是一次性生成,但若密码量过大可优化为迭代生成)
3. 性能瓶颈
-
密码生成规模:高级密码生成模块通过多重循环(如单词×年份×特殊字符)生成的密码数量可能达到千万级甚至亿级,占用大量内存且生成耗时较长
-
单线程执行:程序采用单线程处理,未利用多核CPU资源,在大规模密码破解时效率受限
-
哈希计算开销:SHA-256计算虽高效,但在亿级密码场景下,累计计算时间仍会显著增加
六、局限性与改进方向
1. 现有局限性
-
模式覆盖不全:仅覆盖6种常规模式和leet变体,未包含如"日期格式(MMDDYYYY)"、"键盘连续字符(qwert)"等常见模式
-
无字典扩展能力:依赖硬编码的单词/人名列表,无法动态加载外部字典文件
-
单线程效率低:未利用多线程/多进程并行计算,不适合破解大规模哈希集合
-
内存占用高:一次性生成所有密码并存储在列表中,当密码量过大时可能导致内存溢出
2. 改进建议
-
扩展密码模式:添加日期组合、键盘序列、拼音+数字等模式,覆盖更多用户习惯
-
支持外部字典:增加
load_dictionary函数,允许加载自定义单词列表,提高灵活性 -
并行计算优化:使用
multiprocessing库实现多进程哈希计算,利用多核CPU加速比对 -
迭代生成密码:将密码生成改为迭代器模式(
yield),避免一次性加载所有密码到内存 -
进度保存与恢复:增加断点续传功能,保存已尝试的密码位置,避免程序中断后重新计算
-
破解优先级调整:根据密码长度、模式出现概率动态调整生成顺序,优先尝试高概率密码
七、总结
该程序是一款针对SHA-256哈希的离线密码破解工具,其核心优势在于基于用户行为模式的定向密码生成,通过模拟常见密码结构(如单词+年份+特殊字符、leet变体)提高破解效率,避免纯随机暴力破解的盲目性。程序通过集合优化哈希比对、分阶段破解、动态剪枝等策略,在有限资源下平衡了破解速度与成功率。
从技术实现来看,程序合理运用了列表、集合、字典等数据结构,结合哈希计算与模式生成算法,构建了完整的破解流程。但受限于单线程设计和固定模式,其在大规模哈希破解场景下的效率仍有提升空间。通过扩展密码模式、引入并行计算、支持外部字典等改进,可进一步增强工具的实用性与破解能力。
总体而言,该程序是"基于知识的暴力破解"思想的典型实现,适合用于小规模哈希集合的离线破解,或作为密码安全审计的辅助工具,帮助识别弱密码风险。
源代码:
import hashlib
import itertools
def sha256_hash(text):
"""计算字符串的SHA-256哈希值"""
return hashlib.sha256(text.encode('utf-8')).hexdigest()
def load_hashes(filename):
"""从文件加载哈希值"""
with open(filename, 'r') as f:
hashes = [line.strip() for line in f if line.strip()]
return hashes
def save_results(cracked_hashes, output_file):
"""保存破解结果到文件"""
with open(output_file, 'w', encoding='utf-8') as f:
for hash_val, password in cracked_hashes.items():
f.write(f"{hash_val}:{password}\n")
print(f"结果已保存到 {output_file}")
def generate_advanced_passwords():
passwords = []
cracked_patterns = [
"Champion2016!", # 单词 + 年份 + !
"Constantin12@", # 人名 + 数字 + @
]
passwords.extend(cracked_patterns)
# 扩展单词列表
positive_words = [
"Champion", "Winner", "Hero", "Master", "King", "Queen", "Star", "Fire",
"Warrior", "Leader", "Champ", "Victory", "Success", "Achiever", "Talent",
"Genius", "Brilliant", "Amazing", "Awesome", "Fantastic", "Excellent",
"Perfect", "Super", "Ultimate", "Supreme", "Elite", "Legend", "Legendary",
"Power", "Strong", "Mighty", "Great", "Best", "Top", "Prime", "Gold",
"Silver", "Bronze", "Diamond", "Platinum", "Crystal", "Ruby", "Emerald"
]
names = [
"Constantin", "Jesus", "John", "Michael", "David", "Robert", "Maria", "Anna",
"William", "James", "Joseph", "Thomas", "Charles", "Christopher", "Daniel",
"Matthew", "Anthony", "Donald", "Mark", "Paul", "Steven", "Andrew", "Kenneth",
"George", "Joshua", "Kevin", "Brian", "Edward", "Ronald", "Timothy", "Jason",
"Jeffrey", "Ryan", "Jacob", "Gary", "Nicholas", "Eric", "Jonathan", "Stephen",
"Larry", "Justin", "Scott", "Brandon", "Benjamin", "Samuel", "Gregory", "Alexander",
"Frank", "Patrick", "Raymond", "Jack", "Dennis", "Jerry", "Tyler", "Aaron", "Jose",
"Adam", "Nathan", "Henry", "Zachary", "Douglas", "Peter", "Kyle", "Noah", "Ethan",
"Jeremy", "Walter", "Christian", "Keith", "Roger", "Terry", "Austin", "Sean",
"Gerald", "Carl", "Harold", "Dylan", "Arthur", "Lawrence", "Jordan", "Jesse",
"Bryan", "Billy", "Bruce", "Gabriel", "Joe", "Logan", "Alan", "Juan", "Albert",
"Willie", "Elijah", "Wayne", "Randy", "Vincent", "Mason", "Liam", "Jayden", "Caleb"
]
# 更多特殊字符组合
special_combos = ["!", "@", "#", "$", "!!", "@@", "##", "$$", "!@", "@!", "#!", "$!"]
# 年份范围扩展
years = [str(i) for i in range(1950, 2024)]
# 常见数字后缀
numbers = [str(i) for i in range(0, 1000)]
# 模式1: 单词 + 年份 + 特殊字符
for word in positive_words:
for year in years:
for special in special_combos:
passwords.append(f"{word}{year}{special}")
# 模式2: 人名 + 数字 + 特殊字符
for name in names:
for num in numbers:
for special in special_combos:
passwords.append(f"{name}{num}{special}")
# 模式3: 人名 + 年份 + 特殊字符
for name in names:
for year in years:
for special in special_combos:
passwords.append(f"{name}{year}{special}")
# 模式4: 单词 + 数字 + 特殊字符
for word in positive_words:
for num in numbers:
for special in special_combos:
passwords.append(f"{word}{num}{special}")
# 模式5: 短语组合
phrases = [
"I love ", "I like ", "My favorite ", "Best ", "Top ", "Number one ",
"The best ", "The greatest ", "The ultimate ", "Super ", "Mega ",
"Ultra ", "Hyper ", "Pro ", "Professional ", "Master "
]
for phrase in phrases:
for word in positive_words:
passwords.append(f"{phrase}{word}")
for num in numbers[:100]:
passwords.append(f"{phrase}{word}{num}")
for special in special_combos:
passwords.append(f"{phrase}{word}{num}{special}")
# 模式6: 重复字符模式(基于bolsitaaaaaaaaa)
repeated_words = ["a", "love", "god", "jesus", "password", "test", "hello", "admin"]
for word in repeated_words:
for i in range(5, 20): # 重复5-20次
passwords.append(word * i)
return list(set(passwords))
def generate_leet_speak_passwords():
"""生成leet speak风格的密码"""
passwords = []
# 基础单词
base_words = [
"password", "admin", "secret", "champion", "winner", "hero", "master",
"king", "queen", "star", "fire", "love", "god", "jesus", "test",
"hello", "world", "computer", "system", "network", "server", "database"
]
# leet speak替换规则
leet_replacements = {
'a': ['4', '@'],
'e': ['3'],
'i': ['1', '!'],
'o': ['0'],
's': ['5', '$'],
't': ['7'],
'l': ['1'],
'b': ['8'],
'g': ['9']
}
# 生成leet speak变体
for word in base_words:
# 简单的leet替换
leet_word = word
leet_word = leet_word.replace('a', '4')
leet_word = leet_word.replace('e', '3')
leet_word = leet_word.replace('i', '1')
leet_word = leet_word.replace('o', '0')
leet_word = leet_word.replace('s', '5')
passwords.append(leet_word)
# 更复杂的leet替换
for char, replacements in leet_replacements.items():
for replacement in replacements:
if char in word:
leet_word = word.replace(char, replacement)
passwords.append(leet_word)
# 添加数字和特殊字符
for num in range(0, 1000):
passwords.append(f"{leet_word}{num}")
passwords.append(f"{leet_word}{num}!")
passwords.append(f"{leet_word}{num}@")
passwords.append(f"{leet_word}{num}#")
passwords.append(f"{leet_word}{num}$")
return list(set(passwords))
def main():
# 配置
input_file = "1.txt"
output_file = "answer.txt"
# 加载哈希值
print("正在加载哈希值...")
hashes = load_hashes(input_file)
print(f"已加载 {len(hashes)} 个哈希值")
# 将哈希列表转换为集合以便快速查找
hash_set = set(hashes)
print("开始增强破解...")
# 阶段1: 使用高级密码生成
print("阶段1: 高级密码生成")
advanced_passwords = generate_advanced_passwords()
print(f"生成高级密码: {len(advanced_passwords)} 个")
cracked1 = {}
for i, password in enumerate(advanced_passwords):
if i % 100000 == 0 and i > 0:
print(f"已尝试 {i} 个高级密码")
hash_value = sha256_hash(password)
if hash_value in hash_set:
cracked1[hash_value] = password
print(f"破解成功: {hash_value} -> {password}")
# 如果所有哈希都已破解,提前结束
if len(cracked1) == len(hash_set):
break
hash_set -= set(cracked1.keys())
# 阶段2: Leet speak密码
print("阶段2: Leet speak密码")
leet_passwords = generate_leet_speak_passwords()
print(f"生成Leet speak密码: {len(leet_passwords)} 个")
cracked2 = {}
for i, password in enumerate(leet_passwords):
if i % 100000 == 0 and i > 0:
print(f"已尝试 {i} 个Leet speak密码")
hash_value = sha256_hash(password)
if hash_value in hash_set:
cracked2[hash_value] = password
print(f"破解成功: {hash_value} -> {password}")
# 如果所有哈希都已破解,提前结束
if len(cracked2) == len(hash_set):
break
hash_set -= set(cracked2.keys())
all_cracked = {**previous_cracked, **cracked1, **cracked2}
# 保存结果
save_results(all_cracked, output_file)
# 统计结果
print(f"\n破解统计:")
print(f"总哈希数: {len(hashes)}")
print(f"成功破解: {len(all_cracked)}")
print(f"破解率: {len(all_cracked) / len(hashes) * 100:.2f}%")
# 显示破解的密码
if cracked1 or cracked2:
print("\n新破解的密码:")
for hash_val, password in {**cracked1, **cracked2}.items():
print(f"{hash_val}: {password}")
if __name__ == "__main__":
main()

65

被折叠的 条评论
为什么被折叠?



