파이썬에서는 multiprocessing 모듈을 이용해서 여러 코어에서 동시에 조합을 시도할 수 있습니다. 다만, 비밀번호 크래킹을 단순 brute-force(완전 탐색)로만 하면 경우의 수가 기하급수적으로 커져서 사실상 현실적으로 풀기 힘들어집니다. 그래서 실제 보안 연구나 해킹 실무에서는 여러 현대식 접근 방식이 사용되는데, 아래 코드 하단에 정리합니다.
import itertools
import zipfile
import msoffcrypto
import io
import os
import multiprocessing as mp
class PasswordCracker:
"""
다양한 조합으로 비밀번호를 추측하여 ZIP, DOCX, XLSX, PPTX 파일의
암호를 해독하는 클래스입니다.
멀티프로세싱을 사용하여 속도를 높입니다.
"""
def __init__(self, passwd_string, min_len, max_len, processes=None):
"""
클래스를 초기화합니다.
Args:
passwd_string (str): 비밀번호에 사용될 문자열(예: '0123456789abc').
min_len (int): 추측할 비밀번호의 최소 길이.
max_len (int): 추측할 비밀번호의 최대 길이.
processes (int, optional): 사용할 프로세스(코어)의 수. 지정하지 않으면 CPU 코어 수만큼 사용.
"""
self.passwd_string = passwd_string
self.min_len = min_len
self.max_len = max_len
self.processes = processes or mp.cpu_count()
def crack(self, file_path):
"""
주어진 파일의 암호를 해독하는 메인 함수입니다.
파일 확장자에 따라 적절한 해독 메서드를 호출합니다.
Args:
file_path (str): 암호를 해독할 파일의 경로.
Returns:
str or None: 비밀번호를 찾으면 비밀번호를, 찾지 못하면 None을 반환.
"""
file_ext = os.path.splitext(file_path)[1].lower()
if file_ext == ".zip":
return self._crack_zip(file_path)
elif file_ext in [".pptx", ".docx", ".xlsx"]:
return self._crack_office(file_path)
else:
print(f"[!] {file_ext} 형식은 지원하지 않습니다. (zip, office만 지원)")
return None
# --- ZIP 파일 해독 관련 메서드 ---
def _try_zip_password(self, args):
"""
하나의 비밀번호로 ZIP 파일의 압축을 해제해 보는 함수입니다.
성공하면 비밀번호를 반환하고, 실패하면 None을 반환합니다.
Args:
args (tuple): (파일 경로, 비밀번호) 튜플.
Returns:
str or None: 성공 시 비밀번호, 실패 시 None.
"""
file_path, password = args
try:
zFile = zipfile.ZipFile(file_path)
zFile.extractall(pwd=password.encode('utf-8'))
return password
except:
return None
def _crack_zip(self, file_path):
"""
멀티프로세싱을 사용하여 ZIP 파일의 암호를 해독하는 함수입니다.
각 비밀번호 추측 시도마다 터미널에 진행 상황을 표시합니다.
Args:
file_path (str): ZIP 파일의 경로.
Returns:
str or None: 비밀번호를 찾으면 비밀번호를, 찾지 못하면 None을 반환.
"""
print(f"[*] ZIP 파일 '{file_path}' 암호 해독 시작...")
with mp.Pool(self.processes) as pool:
for length in range(self.min_len, self.max_len + 1):
attempts = ("".join(p) for p in itertools.product(self.passwd_string, repeat=length))
args_gen = ((file_path, pwd) for pwd in attempts)
# imap_unordered를 사용하여 결과를 비동기적으로 처리
for result in pool.imap_unordered(self._try_zip_password, args_gen, chunksize=1000):
# 현재 시도하고 있는 비밀번호를 터미널에 표시
print(f"[*] 시도 중: '{result if result else result, ' 실패한 추측'}'", end='\r')
if result:
print(f"\n[+] 비밀번호는 '{result}' 입니다.(zip)")
pool.terminate() # 비밀번호를 찾으면 모든 프로세스 종료
return result
print("\n[-] 비밀번호를 찾지 못했습니다.(zip)")
return None
# --- MS Office 파일 해독 관련 메서드 ---
def _try_office_password(self, args):
"""
하나의 비밀번호로 MS Office 파일의 암호를 해제해 보는 함수입니다.
성공하면 비밀번호를 반환하고, 실패하면 None을 반환합니다.
Args:
args (tuple): (파일 경로, 비밀번호) 튜플.
Returns:
str or None: 성공 시 비밀번호, 실패 시 None.
"""
file_path, password = args
try:
with open(file_path, "rb") as f:
office_file = msoffcrypto.OfficeFile(f)
office_file.load_key(password=password)
decrypted = io.BytesIO()
office_file.decrypt(decrypted)
return password
except:
return None
def _crack_office(self, file_path):
"""
멀티프로세싱을 사용하여 MS Office 파일의 암호를 해독하는 함수입니다.
각 비밀번호 추측 시도마다 터미널에 진행 상황을 표시합니다.
Args:
file_path (str): MS Office 파일의 경로.
Returns:
str or None: 비밀번호를 찾으면 비밀번호를, 찾지 못하면 None을 반환.
"""
print(f"[*] MS Office 파일 '{file_path}' 암호 해독 시작...")
with mp.Pool(self.processes) as pool:
for length in range(self.min_len, self.max_len + 1):
attempts = ("".join(p) for p in itertools.product(self.passwd_string, repeat=length))
args_gen = ((file_path, pwd) for pwd in attempts)
# imap_unordered를 사용하여 결과를 비동기적으로 처리
for result in pool.imap_unordered(self._try_office_password, args_gen, chunksize=500):
# 현재 시도하고 있는 비밀번호를 터미널에 표시
print(f"[*] 시도 중: '{result if result else result, ' 실패한 추측'}'", end='\r')
if result:
print(f"\n[+] 비밀번호는 '{result}' 입니다.(office)")
pool.terminate() # 비밀번호를 찾으면 모든 프로세스 종료
return result
print("\n[-] 비밀번호를 찾지 못했습니다.(office)")
return None
if __name__ == "__main__":
# 비밀번호에 사용될 문자와 최소/최대 길이 설정
passwd_string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
cracker = PasswordCracker(passwd_string, min_len=3, max_len=4)
# 파일 경로 지정
file_path = "워드암호파일_123.docx"
cracker.crack(file_path)