Skip to content

Commit 0e1a9e8

Browse files
committed
Upgrade CLI interface
1 parent 5b964fc commit 0e1a9e8

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ A tool to recover lost bitcoin private keys from dead hard drives.
66
## Usage
77

88
```bash
9-
python3 keyhunter.py /dev/sdX
9+
python3 keyhunter.py -i /dev/sdX --log ./sdX_log.log -o ./sdX_found_keys_list.txt
1010
# --or--
11-
./keyhunter.py /dev/sdX
11+
./keyhunter.py -i /dev/sdX --log ./sdX_log.log -o ./sdX_found_keys_list.txt
1212
```
1313

1414
The output should list found private keys, in base58 key import format.

keyhunter.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def find_keys(filename: str | Path) -> set[str]:
9090
f"Found {('new key' if is_new_key else 'key again')} "
9191
f"at offset {global_offset:,} = 0x{global_offset:_x} "
9292
f"(using magic bytes {magic_bytes.hex()}): {priv_key_wif} "
93-
f"({key_count:,} keys total, {len(keys):,} unique keys"
93+
f"({key_count:,} keys total, {len(keys):,} unique keys)"
9494
)
9595
pos += 1
9696

@@ -126,7 +126,11 @@ def setup_logging(log_filename: Optional[str | Path] = None) -> logging.Logger:
126126
return logger
127127

128128

129-
def main_keyhunter(haystack_filename: str | Path, log_path: Optional[str | Path] = None):
129+
def main_keyhunter(
130+
haystack_file_path: str | Path,
131+
log_path: Optional[str | Path] = None,
132+
output_keys_file_path: Optional[str | Path] = None,
133+
):
130134
setup_logging(log_path)
131135
logger.info("Starting keyhunter")
132136

@@ -135,10 +139,10 @@ def main_keyhunter(haystack_filename: str | Path, log_path: Optional[str | Path]
135139
else:
136140
logger.info("Logging to console only.")
137141

138-
if not Path(haystack_filename).is_file():
139-
raise FileNotFoundError(f"File not found: {haystack_filename}")
142+
if not Path(haystack_file_path).is_file():
143+
raise FileNotFoundError(f"File not found: {haystack_file_path}")
140144

141-
keys = find_keys(haystack_filename)
145+
keys = find_keys(haystack_file_path)
142146

143147
keys = sorted(list(keys))
144148
logger.info(f"Found {len(keys)} keys: {keys}")
@@ -148,19 +152,40 @@ def main_keyhunter(haystack_filename: str | Path, log_path: Optional[str | Path]
148152
for key in keys:
149153
print(key)
150154

155+
if output_keys_file_path:
156+
with open(output_keys_file_path, "w") as f:
157+
for key in keys:
158+
f.write(key + "\n")
159+
151160
logger.info(f"Finished keyhunter. Found {len(keys):,} keys.")
152161

153162

154163
def get_args():
155164
parser = argparse.ArgumentParser(description="Find Bitcoin private keys in a file.")
156-
parser.add_argument("filename", help="The file to search for keys.")
165+
parser.add_argument(
166+
"-i",
167+
"--input",
168+
required=True,
169+
dest="input_file_path",
170+
help="The input file (disk image, corrupt wallet.dat, etc.) to search for keys.",
171+
)
157172
parser.add_argument("-l", "--log", dest="log_path", help="Log file to write logs to.")
173+
parser.add_argument(
174+
"-o",
175+
"--output",
176+
dest="output_file_path",
177+
help="Output file to write the WIF write keys to.",
178+
)
158179
return parser.parse_args()
159180

160181

161182
def main_cli():
162183
args = get_args()
163-
main_keyhunter(args.filename, log_path=args.log_path)
184+
main_keyhunter(
185+
args.input_file_path,
186+
log_path=args.log_path,
187+
output_keys_file_path=args.output_file_path,
188+
)
164189

165190

166191
if __name__ == "__main__":

0 commit comments

Comments
 (0)