diff --git a/README.md b/README.md index 782c4ef..09345fb 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,68 @@ -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 + +### _Linux - Install BerkeleyDB_ + +#### [Berkeley source installation](https://www.linuxfromscratch.org/blfs/view/svn/server/db.html) + +1. [Download Berkely to compile](https://anduin.linuxfromscratch.org/BLFS/bdb/db-5.3.28.tar.gz) + +2. First apply a fix so that this will compile with current versions of g++: + + `$ 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` + +4. Now, as the __root__ user: + + `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` + +## Wallet location + +### _Linux_ + +* `~/.bitcoin/wallets/[WALLET_NAME]/wallet.dat` -Extracting private keys from Bitcoin-QT/Litecoin-QT wallets ----------------------------------------------------------- -* 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` +### Types / CoinType + +* For Bitcoin, run `python3 main.py -d WALLET_NAME.dat -v 0` +* For Litecoin, run `python3 main.py -d WALLET_NAME.dat -v 48` + +----------------------------------------------------------- + +### _Output_ + +Print / Log - Wallet addresses and private keys -A list of addresses / private keys is printed. + \ No newline at end of file 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/main.py b/main.py new file mode 100644 index 0000000..a99f479 --- /dev/null +++ b/main.py @@ -0,0 +1,54 @@ +import argparse +from walletool.wallet_files import read_wallet_dat +from walletool.wallet_items import parse_wallet_dict, KeyWalletItem +from walletool.consts import addressTypes + + +def main(): + + # Parser Arguments + ap = argparse.ArgumentParser() + ap.add_argument('-d', '--dat', help='wallet.dat path', + 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 + 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 + wallet_data = read_wallet_dat(args.wallet) + 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_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__': + main() 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 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/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, 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) 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 deleted file mode 100644 index ec66d85..0000000 --- a/wt_extract_keys.py +++ /dev/null @@ -1,31 +0,0 @@ -import argparse -from walletool.wallet_files import read_wallet_dat -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) - 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] - 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) - addr_tuples.append((address, privkey)) - for address, privkey in addr_tuples: - print(address, privkey) - - -if __name__ == '__main__': - main()