From 7d4a16138635ecefdad861647066fab40555f353 Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 00:41:06 -0700 Subject: [PATCH 01/12] Linted codebase --- check_bchain.py | 4 +++- check_dogechain.py | 5 ++++- walletool/bc_data_stream.py | 3 +-- walletool/wallet_items.py | 3 ++- wt_extract_keys.py | 7 +++++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/check_bchain.py b/check_bchain.py index a0b2d16..a3879a5 100644 --- a/check_bchain.py +++ b/check_bchain.py @@ -5,6 +5,7 @@ var_re = re.compile('var (.+?) = (.+?);') + def main(): ap = argparse.ArgumentParser() ap.add_argument('file', help='address file; one address per line') @@ -30,5 +31,6 @@ def main(): continue print(vs) + if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/check_dogechain.py b/check_dogechain.py index 94687bf..d74b3d9 100644 --- a/check_dogechain.py +++ b/check_dogechain.py @@ -4,6 +4,7 @@ import sys import time + def main(): ap = argparse.ArgumentParser() ap.add_argument('file', help='address file; one address per line') @@ -12,7 +13,8 @@ def main(): for line in open(args.file): line = line.strip() while True: - r = requests.get('https://dogechain.info/api/v1/address/balance/%s' % line) + r = requests.get( + 'https://dogechain.info/api/v1/address/balance/%s' % line) if r.status_code == 429: # Too Many Requests print('Throttled, hold on...', file=sys.stderr) time.sleep(60) @@ -26,5 +28,6 @@ def main(): print(r) time.sleep(0.5) + if __name__ == '__main__': main() diff --git a/walletool/bc_data_stream.py b/walletool/bc_data_stream.py index 3345dcd..68bef2d 100644 --- a/walletool/bc_data_stream.py +++ b/walletool/bc_data_stream.py @@ -1,12 +1,11 @@ # -- encoding: UTF-8 -- +import struct import sys assert sys.version_info[0] == 3 # TODO: Use six for 2/3 compat # From Joric's pywallet. -import struct - class SerializationError(Exception): pass diff --git a/walletool/wallet_items.py b/walletool/wallet_items.py index 0094dc1..4f29f72 100644 --- a/walletool/wallet_items.py +++ b/walletool/wallet_items.py @@ -147,7 +147,8 @@ def parse(cls, key, value): data.update(parse_BlockLocator(vds)) elif type == 'ckey': data['public_key'] = kds.read_bytes(kds.read_compact_size()) - data['encrypted_private_key'] = vds.read_bytes(vds.read_compact_size()) + data['encrypted_private_key'] = vds.read_bytes( + vds.read_compact_size()) elif type == 'mkey': data['nID'] = kds.read_uint32() data['encrypted_key'] = vds.read_string() diff --git a/wt_extract_keys.py b/wt_extract_keys.py index ec66d85..45fbf23 100644 --- a/wt_extract_keys.py +++ b/wt_extract_keys.py @@ -3,10 +3,13 @@ from walletool.wallet_items import parse_wallet_dict, KeyWalletItem from walletool.consts import addrtypes + def main(): ap = argparse.ArgumentParser() - ap.add_argument('-d', '--dat', help='wallet.dat path', required=True, dest='filename') - ap.add_argument('-v', '--version', help='address version, as integer, 0xHEX, or any of the following known coins:\n[%s]' % ', '.join(sorted(addrtypes)), required=True) + ap.add_argument('-d', '--dat', help='wallet.dat path', + required=True, dest='filename') + ap.add_argument('-v', '--version', + help='address version, as integer, 0xHEX, or any of the following known coins:\n[%s]' % ', '.join(sorted(addrtypes)), required=True) args = ap.parse_args() if args.version.startswith('0x'): version = int(args.version[2:], 16) From 860a3a07698fa11313f702e9c39c3e688fefe7ea Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 01:04:03 -0700 Subject: [PATCH 02/12] Renamed to Main.py and renamed consts.py export --- wt_extract_keys.py => main.py | 12 ++++++------ walletool/consts.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) rename wt_extract_keys.py => main.py (80%) diff --git a/wt_extract_keys.py b/main.py similarity index 80% rename from wt_extract_keys.py rename to main.py index 45fbf23..64337b6 100644 --- a/wt_extract_keys.py +++ b/main.py @@ -1,24 +1,24 @@ import argparse from walletool.wallet_files import read_wallet_dat from walletool.wallet_items import parse_wallet_dict, KeyWalletItem -from walletool.consts import addrtypes +from walletool.consts import addressTypes def main(): ap = argparse.ArgumentParser() ap.add_argument('-d', '--dat', help='wallet.dat path', required=True, dest='filename') - ap.add_argument('-v', '--version', - help='address version, as integer, 0xHEX, or any of the following known coins:\n[%s]' % ', '.join(sorted(addrtypes)), required=True) + ap.add_argument('-t', '--type', + help='address version, as integer, 0xHEX, or any of the following known coins:\n[%s]' % ', '.join(sorted(addressTypes)), required=True) args = ap.parse_args() if args.version.startswith('0x'): version = int(args.version[2:], 16) elif args.version.isdigit(): version = int(args.version) else: - if args.version not in addrtypes: - raise ValueError('invalid version (see --help)') - version = addrtypes[args.version] + if args.version not in addressTypes: + raise ValueError('invalid type (see --help)') + version = addressTypes[args.version] w_data = read_wallet_dat(args.filename) addr_tuples = [] for item in parse_wallet_dict(w_data): diff --git a/walletool/consts.py b/walletool/consts.py index 53617c0..76b91b9 100644 --- a/walletool/consts.py +++ b/walletool/consts.py @@ -1,4 +1,4 @@ -addrtypes = { +addressTypes = { 'bitcoin': 0, 'litecoin': 48, 'namecoin': 52, From b8dcd2af50345a3ff9833a40c03823b85b34ef45 Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 01:04:40 -0700 Subject: [PATCH 03/12] Renamed version to type --- main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index 64337b6..5b40304 100644 --- a/main.py +++ b/main.py @@ -11,14 +11,14 @@ def main(): ap.add_argument('-t', '--type', help='address version, as integer, 0xHEX, or any of the following known coins:\n[%s]' % ', '.join(sorted(addressTypes)), required=True) args = ap.parse_args() - if args.version.startswith('0x'): - version = int(args.version[2:], 16) - elif args.version.isdigit(): - version = int(args.version) + if args.type.startswith('0x'): + version = int(args.type[2:], 16) + elif args.type.isdigit(): + version = int(args.type) else: - if args.version not in addressTypes: + if args.type not in addressTypes: raise ValueError('invalid type (see --help)') - version = addressTypes[args.version] + version = addressTypes[args.type] w_data = read_wallet_dat(args.filename) addr_tuples = [] for item in parse_wallet_dict(w_data): From ed3b982747454742f36c197bcaf438d4018a5930 Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 01:18:47 -0700 Subject: [PATCH 04/12] Rename internal version to coinType and comment --- main.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/main.py b/main.py index 5b40304..1da6fd6 100644 --- a/main.py +++ b/main.py @@ -5,29 +5,43 @@ def main(): + + # Parser Arguments ap = argparse.ArgumentParser() ap.add_argument('-d', '--dat', help='wallet.dat path', required=True, dest='filename') ap.add_argument('-t', '--type', help='address version, as integer, 0xHEX, or any of the following known coins:\n[%s]' % ', '.join(sorted(addressTypes)), required=True) args = ap.parse_args() + + # Parser Logic - Checking for hex if args.type.startswith('0x'): - version = int(args.type[2:], 16) - elif args.type.isdigit(): - version = int(args.type) + coinType = int(args.type[2:], 16) + elif args.type.isdigit(): ## Else: Use set addressTypes + coinType = int(args.type) else: if args.type not in addressTypes: raise ValueError('invalid type (see --help)') version = addressTypes[args.type] + + # Start reading wallet information w_data = read_wallet_dat(args.filename) addr_tuples = [] for item in parse_wallet_dict(w_data): if isinstance(item, KeyWalletItem): - address = item.get_address(version=version) - privkey = item.get_private_key(version=version) + address = item.get_address(version=coinType) + privkey = item.get_private_key(version=coinType) addr_tuples.append((address, privkey)) for address, privkey in addr_tuples: print(address, privkey) + # log = input("Save log of Output? (Y/n): ") + # if (log.lower() == "n"): + # print(f'Address: \n{address} \n*2 Private-key: \n{privkey}') + # else: + # file_output = open('wallet-output.txt', "w") + # file_output.write() + # print(f'Address: \n{address} \n*2 Private-key: \n{privkey}') + # print() if __name__ == '__main__': From bd1109cd4326416680c9de15e85c07713d789cb9 Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 01:24:52 -0700 Subject: [PATCH 05/12] Renamed filename to wallet --- main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index 1da6fd6..fa9dcf7 100644 --- a/main.py +++ b/main.py @@ -5,27 +5,27 @@ def main(): - + # Parser Arguments ap = argparse.ArgumentParser() ap.add_argument('-d', '--dat', help='wallet.dat path', - required=True, dest='filename') + required=True, dest='wallet') ap.add_argument('-t', '--type', help='address version, as integer, 0xHEX, or any of the following known coins:\n[%s]' % ', '.join(sorted(addressTypes)), required=True) args = ap.parse_args() - + # Parser Logic - Checking for hex if args.type.startswith('0x'): coinType = int(args.type[2:], 16) - elif args.type.isdigit(): ## Else: Use set addressTypes + elif args.type.isdigit(): # Else: Use set addressTypes coinType = int(args.type) else: if args.type not in addressTypes: raise ValueError('invalid type (see --help)') version = addressTypes[args.type] - + # Start reading wallet information - w_data = read_wallet_dat(args.filename) + w_data = read_wallet_dat(args.wallet) addr_tuples = [] for item in parse_wallet_dict(w_data): if isinstance(item, KeyWalletItem): From 34597871225868cca8d1265ef1c18f2a07603e70 Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 01:27:01 -0700 Subject: [PATCH 06/12] renamed w_data to wallet_data --- main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index fa9dcf7..2b1a32f 100644 --- a/main.py +++ b/main.py @@ -25,9 +25,9 @@ def main(): version = addressTypes[args.type] # Start reading wallet information - w_data = read_wallet_dat(args.wallet) + wallet_data = read_wallet_dat(args.wallet) addr_tuples = [] - for item in parse_wallet_dict(w_data): + for item in parse_wallet_dict(wallet_data): if isinstance(item, KeyWalletItem): address = item.get_address(version=coinType) privkey = item.get_private_key(version=coinType) From 31a47a7482cb84d65bfd4b70a11d6c6485cc0b60 Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 01:51:44 -0700 Subject: [PATCH 07/12] Update: Parsed wallet is now list and added log --- main.py | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/main.py b/main.py index 2b1a32f..a99f479 100644 --- a/main.py +++ b/main.py @@ -26,22 +26,28 @@ def main(): # Start reading wallet information wallet_data = read_wallet_dat(args.wallet) - addr_tuples = [] + addr_list = ['', ''] for item in parse_wallet_dict(wallet_data): if isinstance(item, KeyWalletItem): address = item.get_address(version=coinType) privkey = item.get_private_key(version=coinType) - addr_tuples.append((address, privkey)) - for address, privkey in addr_tuples: - print(address, privkey) - # log = input("Save log of Output? (Y/n): ") - # if (log.lower() == "n"): - # print(f'Address: \n{address} \n*2 Private-key: \n{privkey}') - # else: - # file_output = open('wallet-output.txt', "w") - # file_output.write() - # print(f'Address: \n{address} \n*2 Private-key: \n{privkey}') - # print() + addr_list[0] += address + addr_list[1] += privkey + + # Log address and private key + log = input("Save log of Output? (Y/n): ") + if (log.lower() == "n"): + print(f'\nAddress:\n{addr_list[0]} \n\nPrivate-Key: \n{addr_list[1]}') + elif (log.lower() == "y"): + file_output = open('wallet-output.txt', "w") + file_output.write(f'Address:\n{addr_list[0]} \n\nPrivate-Key: \n{addr_list[1]}') + print(f'\nAddress:\n{addr_list[0]} \n\nPrivate-Key: \n{addr_list[1]}') + print('\n>> Output saved as {wallet-output.txt}. <<') + else: + file_output = open('wallet-output.txt', "w") + file_output.write(f'Address:\n{addr_list[0]} \n\nPrivate-Key: \n{addr_list[1]}') + print('\n>> Output saved as {wallet-output.txt}. <<') + if __name__ == '__main__': From 6703ad2f2b6656dee76a311196f26c13ee7e8b38 Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 01:54:58 -0700 Subject: [PATCH 08/12] Changed from depreciated bsddb3 to berkeleydb --- walletool/wallet_files.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/walletool/wallet_files.py b/walletool/wallet_files.py index 8220782..0ce5e0f 100644 --- a/walletool/wallet_files.py +++ b/walletool/wallet_files.py @@ -4,7 +4,7 @@ def read_wallet_dat(filename): - from bsddb3 import db + from berkeleydb import db filename = os.path.realpath(filename) env = db.DBEnv() env.set_lk_detect(db.DB_LOCK_DEFAULT) From c631616b68868b2d34f53772faf13341494f2e6f Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 01:56:34 -0700 Subject: [PATCH 09/12] Added project requirements --- requirements.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6f49d23 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +berkeleydb==18.1.5 +requests==2.27.1 From 9bf2980bfc162ac91f576d86d5424c70b1b7aa9a Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 02:00:04 -0700 Subject: [PATCH 10/12] Updated readme --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 782c4ef..63299e6 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,49 @@ -walletool ~ a tool for reading wallet.dat files -=============================================== +# Walletool - Read wallet.dat files -Installation ------------- +## Access [Bitcoin-Core](https://bitcoin.org/en/bitcoin-core/) and [Litecoin-Core](https://litecoin.org/) wallets __addresses__ and __private keys__ -* Install Python 3.x. -* Install the `bsddb3` module (if you're on Windows, use Gohlke's site). +----------------------------------------------------------- + +## Requirements + +* Install python 3.6+ +* Install `requirements.py` by running: + * `$pip install -r requirements.txt` +* Your wallet must be **UNENCRYPTED**! + +## Installation + + + + +----------------------------------------------------------- + +## Wallet location on different OS's + +### _Linux_ + +* `~/.bitcoin/wallets/[WALLET_NAME]/wallet.dat` + +### _Windows_ + +default location: + +* TODO: Add default location -Extracting private keys from Bitcoin-QT/Litecoin-QT wallets ----------------------------------------------------------- +### Types / CoinType + +* For Bitcoin, run `python3 main.py -d wallet.dat -v 0` +* For Litecoin, run `python3 main.py -d wallet.dat -v 48` + +----------------------------------------------------------- + +### _Output_ -* Have your `wallet.dat` handy. -* For Bitcoin, run `python wt_extract_keys.py -d wallet.dat -v 0` -* For Litecoin, run `python wt_extract_keys.py -d wallet.dat -v 48` +Print / Log - Wallet addresses and private keys -A list of addresses / private keys is printed. + \ No newline at end of file From 8c9eee5754f05824f7aec182bea85130e862e52c Mon Sep 17 00:00:00 2001 From: David Mudriy Date: Tue, 26 Jul 2022 02:00:50 -0700 Subject: [PATCH 11/12] Linted readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 63299e6..7139e79 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,12 @@ * Install python 3.6+ * Install `requirements.py` by running: * `$pip install -r requirements.txt` -* Your wallet must be **UNENCRYPTED**! +* Your wallet must be __UNENCRYPTED__! ## Installation - ----------------------------------------------------------- ## Wallet location on different OS's @@ -31,6 +30,7 @@ default location: * TODO: Add default location ----------------------------------------------------------- + ### Types / CoinType * For Bitcoin, run `python3 main.py -d wallet.dat -v 0` From cf49980742f32a92a79da56ef9993e385d95318a Mon Sep 17 00:00:00 2001 From: thundeR2GE <32917060+thundeR2GE@users.noreply.github.com> Date: Tue, 26 Jul 2022 02:27:42 -0700 Subject: [PATCH 12/12] Updated readme --- README.md | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7139e79..09345fb 100644 --- a/README.md +++ b/README.md @@ -13,28 +13,47 @@ ## Installation - +### _Linux - Install BerkeleyDB_ ------------------------------------------------------------ +#### [Berkeley source installation](https://www.linuxfromscratch.org/blfs/view/svn/server/db.html) -## Wallet location on different OS's +1. [Download Berkely to compile](https://anduin.linuxfromscratch.org/BLFS/bdb/db-5.3.28.tar.gz) -### _Linux_ +2. First apply a fix so that this will compile with current versions of g++: -* `~/.bitcoin/wallets/[WALLET_NAME]/wallet.dat` + `$ sed -i 's/\(__atomic_compare_exchange\)/\1_db/' src/dbinc/atomic.h` + +3. Install Berkeley DB by running the following commands: + + `cd build_unix && + ../dist/configure --prefix=/usr \ + --enable-compat185 \ + --enable-dbm \ + --disable-static \ + --enable-cxx && + make` -### _Windows_ +4. Now, as the __root__ user: -default location: + `make docdir=/usr/share/doc/db-5.3.28 install && + chown -v -R root:root \ + /usr/bin/db_* \ + /usr/include/db{,_185,_cxx}.h \ + /usr/lib/libdb*.{so,la} \ + /usr/share/doc/db-5.3.28` -* TODO: Add default location +## Wallet location + +### _Linux_ + +* `~/.bitcoin/wallets/[WALLET_NAME]/wallet.dat` ----------------------------------------------------------- ### Types / CoinType -* For Bitcoin, run `python3 main.py -d wallet.dat -v 0` -* For Litecoin, run `python3 main.py -d wallet.dat -v 48` +* For Bitcoin, run `python3 main.py -d WALLET_NAME.dat -v 0` +* For Litecoin, run `python3 main.py -d WALLET_NAME.dat -v 48` -----------------------------------------------------------