Skip to content

Instantly share code, notes, and snippets.

@azazar
Last active May 19, 2025 07:11
Show Gist options
  • Save azazar/8a40efa63df1bd01f9c560d902aaa0b3 to your computer and use it in GitHub Desktop.
Save azazar/8a40efa63df1bd01f9c560d902aaa0b3 to your computer and use it in GitHub Desktop.
Scans directories for Bitcoin wallet.dat files with private keys and dumps all identified keys
import re
import hashlib
import base58 # pip install base58
import os
import sys
def hash256(data):
"""Perform SHA-256 hash twice."""
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
def to_wif(private_key_hex):
"""Convert the hex private key to WIF format."""
# Add the version byte (0x80 for Bitcoin mainnet, 0xEF for testnet)
version_byte = b'\x80'
priv_key_bytes = bytes.fromhex(private_key_hex)
# Add version byte in front of the private key
versioned_private_key = version_byte + priv_key_bytes
# Add compression flag (optional, here it's considered)
versioned_private_key += b'\x01'
# Perform double SHA-256 hash on the versioned private key
checksum = hash256(versioned_private_key)[:4]
# Add the checksum at the end of the versioned private key
payload = versioned_private_key + checksum
# Convert to Base58
wif = base58.b58encode(payload).decode('utf-8')
return wif
def salvage(priv_hex, filename):
wif_key = to_wif(priv_hex)
print(f"{wif_key} # {filename}")
# Save the WIF key to a file
filename_sanitized = re.sub(r'[^a-zA-Z0-9]', '_', filename) # Sanitize filename
filename_sanitized = filename_sanitized.strip('_')[:255] # Limit filename length to 255 characters
try:
os.makedirs("salvaged_keys", exist_ok=True) # Create directory if it doesn't exist
with open(f"salvaged_keys/{filename_sanitized}.txt", "a") as f:
f.write(f"# {filename}\n{wif_key}\n")
except OSError as e:
print(f"Error saving {filename}: {e}", file=sys.stderr)
# New helper to handle any single file
def process_file(path, salvaged_keys):
try:
with open(path, "rb") as f:
matches = re.findall(b'\x01\x01\x04\x20(.{32})', f.read())
except OSError as e:
print(f"Error reading {path}: {e}", file=sys.stderr)
return
for priv in matches:
priv_hex = priv.hex()
if priv_hex not in salvaged_keys:
salvage(priv_hex, path)
salvaged_keys.add(priv_hex)
def scan_path(arg, salvaged_keys):
if os.path.isfile(arg):
process_file(arg, salvaged_keys)
elif os.path.isdir(arg):
for root, dirs, files in os.walk(arg):
for file in files:
if file.endswith(".dat"):
process_file(os.path.join(root, file), salvaged_keys)
if len(sys.argv) > 1:
salvaged_keys = set() # Set to store salvaged keys
for arg in sys.argv[1:]:
scan_path(arg, salvaged_keys)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment