├── README.md ├── PkMaker.py └── v2Lookup.py /README.md: -------------------------------------------------------------------------------- 1 | # PKGenerator_Checker 2 | Generate Bitcoin Private Keys and check them against blockexplorer.com 3 | 4 | Stupid Python Script that Generates random private keys and checks them in realtime...call this poor mans Mining for BTC - same chances as solo but you could find an address w/ money in it 🤑 This is for entertainment only and is designed to demonstrate how IMPOSSIBLE it is to realistically get a collision and take control of someone else's coin...Credits to @Shlomi for the inspiration... 5 | 6 | # Instructions 7 | 8 | BIG OL DISCLAIMER: I cannot emphasize this enough - this is for **DEMONSTRATION** and **ENTERTAINMENT** purposes ... you will have much better success finding employment, buying bitcoin and holding it than to have this little goofy script find a populated private key with a balance....though if you happen to find a populated address you may as well call the pressess and let em know you beat the odds with that extreme luck. 9 | 10 | 1. Clone this script - download it or in the terminal use `git clone https://github.com/Frankenmint/PKGenerator_Checker/` 11 | 2. Let's install some dependencies! `pip install ecdsa hashlib base58 requests cfscrape` 12 | 3. Navigate to the directory: `cd PKGenerator_Checker` 13 | 5. Run it! `python PkMaker.py` 14 | 15 | # Notes 16 | 17 | 18 | * What's Going on?: A random 32 byte Number is generated and encoded into Hex - Basially a number between 1 and 2^256 OR if counting in decimal form: [115792089237316195423570985008687907853269984665640564039457584007913129639936](http://www.calculatorsoup.com/calculators/algebra/exponent.php). Then, that key is hashed a few times into a public address [according to these standard rules](https://en.bitcoin.it/w/images/en/9/9b/PubKeyToAddr.png) and is fired off to blockexplorer.com using their API. The script then prints the balance to the console window. 19 | * I threw this together while following along [this video series](https://www.youtube.com/playlist?list=PLH4m2oS2ratfeNpZAoVwPlQqEr3HgNu7S) and reccomend YOU instead watch through the tutorials for your own benefit and to better grasp what happens at the protocol level for [Bitcoin](https://bitcoin.org) 20 | * I had to use cfscraper to get around the issue of cloudflare on the v2 version of the script which uses bitcoinlist.io this version will scan an entire page at a time of keys..though idk if the underlying site is to be trusted (ie they just tell you the funds are zero and sweep the funds into their own wallet first) 21 | 22 | Here's a demonstration of it in action 23 | 24 | ![demo working](http://g.recordit.co/z6QqeZyEM1.gif "We're Generating Private Keys and Checking Them on the Fly!") 25 | 26 | -------------------------------------------------------------------------------- /PkMaker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import ecdsa 5 | import hashlib 6 | import base58 7 | import requests 8 | import time 9 | from smtplib import SMTP_SSL as SMTP 10 | import logging 11 | import blockcypher 12 | 13 | 14 | wif = "" 15 | 16 | 17 | 18 | logging.basicConfig(filename='BTC_PrivateKeys_'+time.strftime("%Y-%m-%d-%H-%M")+'.csv', \ 19 | level=logging.INFO, format='%(message)s', datefmt='%Y-%m-%d,%H:%M:%S') 20 | logging.getLogger("requests").setLevel(logging.WARNING) 21 | logging.info ('"Timestamp", "WifKey", "PublicAddress"') 22 | 23 | 24 | 25 | def ping_address(publicAddress): 26 | global pk 27 | global wif 28 | global publicKey 29 | 30 | """ 31 | sends Request to a Block Explorer 32 | Use blockcypher Python package to fetch unlimited balances... 33 | """ 34 | 35 | balance = blockcypher.get_total_balance(publicAddress) 36 | print balance 37 | 38 | # "WifKey", "HexKey", "PublicAddress", "PublicKey", "Balance" 39 | #Comment out this line if you wish to NOT record blank keys 40 | logging.info (''+ time.strftime("%m-%d-%y %H:%M:%S") +','+ wif +','+publicAddress) 41 | 42 | if float(balance) > 0.00000000: 43 | logging.info (''+ time.strftime("%m-%d-%y %H:%M:%S") +','+ wif +','+publicAddress+' ,balance '+balance) 44 | 45 | print "Congratulations...alert the world cause you just made some sort of history friend!" 46 | 47 | 48 | def wif_conversion(pk): 49 | global wif 50 | padding = '80' + pk 51 | # print padding 52 | 53 | hashedVal = hashlib.sha256(padding.decode('hex')).hexdigest() 54 | checksum = hashlib.sha256(hashedVal.decode('hex')).hexdigest()[:8] 55 | # print hashedVal 56 | # print padding+checksum 57 | 58 | payload = padding + checksum 59 | wif = base58.b58encode(payload.decode('hex')) 60 | print wif 61 | 62 | 63 | while True: 64 | 65 | pk = os.urandom(32).encode("hex") 66 | wif_conversion(pk) 67 | 68 | sk = ecdsa.SigningKey.from_string(pk.decode("hex"), curve = ecdsa.SECP256k1) 69 | vk = sk.verifying_key 70 | publicKey = ("\04" + vk.to_string()) 71 | ripemd160 = hashlib.new('ripemd160') 72 | ripemd160.update(hashlib.sha256(publicKey).digest()) 73 | networkAppend = '\00' + ripemd160.digest() 74 | checksum = hashlib.sha256(hashlib.sha256(networkAppend).digest()).digest()[:4] 75 | binary_address = networkAppend + checksum 76 | publicAddress = base58.b58encode(binary_address) 77 | print publicAddress 78 | while True: 79 | try: 80 | ping_address(publicAddress) 81 | except ValueError: 82 | print "Aaaannnnd we got Timed Out" 83 | print pk 84 | print publicAddress 85 | time.sleep(3) 86 | continue 87 | except KeyError: 88 | print "we may be denied or something, keep the script moving" 89 | time.sleep(10) 90 | break 91 | 92 | # msg = "I own your Private Key for %s" %(publicAddress) 93 | # signed_msg = sk.sign(msg) 94 | # encoded_msg = signed_msg.encode("hex") 95 | -------------------------------------------------------------------------------- /v2Lookup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import time 4 | import logging 5 | from lxml import html 6 | from random import randint 7 | import cfscrape 8 | 9 | 10 | print("\n\nLookup keys @RANDOM via bitcoinlist.io!") 11 | print("---------------------------------------") 12 | print("---------------------------------------") 13 | 14 | scraper = cfscrape.create_scraper() 15 | iterating = 0 16 | napLength = 15 # time in seconds to sleep for 17 | iterLimits = 7 # how many API lookups till we take a Nap 18 | 19 | from smtplib import SMTP_SSL as SMTP 20 | from time import sleep 21 | 22 | host = "smtp.ymail.com" 23 | usrnme = "myemail@yahoomail.com" 24 | pswd = "myFancyPantsPasswording" 25 | subject = "check this private key pls" 26 | 27 | def send_email(from_addr, to_addr, body_text): 28 | """ 29 | Send an Email 30 | """ 31 | 32 | msg_body = "" 33 | parts = ["From: %s" % from_addr, 34 | "To: %s" % to_addr, 35 | "MIME-Version: 1.0", 36 | "Content-type: text/html", 37 | "Subject: %s" % subject, 38 | "", 39 | body_text 40 | , "\r\n"] 41 | msg_body = "\r\n".join(parts) 42 | server = SMTP(host, 465) 43 | # server.set_debuglevel(1) 44 | server.ehlo() 45 | server.login(usrnme,pswd) 46 | server.sendmail(from_addr, to_addr, msg_body) 47 | server.quit() 48 | 49 | 50 | 51 | def generatePage(): 52 | return randint(0,904625697166532776746648320380374280100293470930272690489102837043110636675) 53 | 54 | 55 | 56 | def grabPks(pageNum): 57 | # cloudflare blocks bots...use scraper library to get around this or build your own logic to store and use a manually generated cloudflare session cookie... I don't care 😎 58 | # req = requests.get("https://www.bitcoinlist.io/"+str(pageNum)) 59 | req = scraper.get("https://www.bitcoinlist.io/"+str(pageNum)).content 60 | if(req == b'Rate Limit Exceeded'): 61 | print("adjust the rate limiting because they're blocking us :(") 62 | manPenalty = napLength * 3 63 | print("manually sleeping for {} seconds".format(manPenalty)) 64 | time.sleep(manPenalty) 65 | print("okay let's try again... NOW SERVING {}".format(pageNum)) 66 | return grabPks(pageNum) 67 | else: 68 | tree = html.fromstring(req) 69 | pk = tree.xpath("/html/body/div[1]/div[3]/div[4]/div/div/div[2]/table/tbody/tr/td[1]/small/text()") 70 | resCmpress = tree.xpath("/html/body/div[1]/div[3]/div[4]/div/div/div[2]/table/tbody/tr/td[3]/small/a//text()") 71 | resXtend = tree.xpath("/html/body/div[1]/div[3]/div[4]/div/div/div[2]/table/tbody/tr/td[2]/small/a//text()") 72 | balance = tree.xpath("/html/body/div[1]/div[3]/div[4]/div/div/div[2]/table/tbody/tr/td[4]/font//text()") 73 | return pk, resCmpress, resXtend, balance 74 | 75 | 76 | 77 | while True: 78 | muhPage = generatePage() 79 | if (iterating >= iterLimits): 80 | print("\ntaking a {0} second Nap..ZZZzzzzz".format(napLength)) 81 | time.sleep(napLength) 82 | iterating = -1 83 | iterating +=1 84 | print ("\nNOW SERVING {}\n".format(muhPage)) 85 | pkArray = grabPks(muhPage) 86 | for i in range(len(pkArray[0])): 87 | thisBalance = pkArray[3][i] 88 | print( "PK: {0} Addr: {1} Balance: {2}".format(pkArray[0][i][-10:], pkArray[1][i][:7], thisBalance)) 89 | if(thisBalance == ' 0'): 90 | continue 91 | else: 92 | print ("balance = " + thisBalance) 93 | print("We may have found something! check out Private Key {0}, for compressed Address {1}".format(pkArray[0][i], pkArray[1][i])) 94 | send_email("myemail@gmail.com", "myemail@gmail.com", "check out Private Key {0}, for Adress {1}, and {2}. Found a balance of {3}".format(pkArray[0][i], pkArray[1][i], pkArray[2][i], thisBalance )) 95 | raise SystemExit 96 | # print ("Ext: {0}, Stndrd {1}".format(endExt, endCmp)) 97 | 98 | 99 | ''' HEY THERE PIRATE! 100 | 101 | THIS IS A 2017... no... 2018 FACELIFT TO THE TOY APP POOR MANS MINING. 102 | HUNT THEM 2010 ERA COINS!!!! Currently the Script uses Directory.IO 103 | and blockchain.info to parse (at random) the entire sha256 keylist page by page 104 | 256 different lookups per page (1 for compressesed public address one for standard. 105 | Feel Free to checkout Line 63 IF YOU REALLY WANT TO KNOW HOW BIG THIS IS... 106 | and impractical mind you! This script may be your friend if you - can setup 107 | and distribute this, like a botnet so that its scanning all the time from different 108 | machines and ultimately pinging you on anything found. You are literally stealing 109 | someone else's private key - if the BTC utxo's are OLD like 2010 old you may be 110 | able to comformably claim those - if the funds are a couple months old however, 111 | you may need to consider returning a large portion if not all of them back to the 112 | rightful owner. Just like with my PK generator/checker tool this is literally for 113 | enteratinment purposes and not designed for extended real world use. Your IP 114 | Address may become blocked from using this toy extensively, proceed with caution. 115 | If you DO actually happen to find a collision (ie someone else's private key), 116 | pat yourself on the back because that's supposed to not be possible...and maybe 117 | send a few duckets my way: 18ZVx4i7FKYj6GYa1XgBM2ZfQdjE6nUMgt 118 | 119 | ''' 120 | --------------------------------------------------------------------------------