Created
July 25, 2025 11:46
-
-
Save MurageKibicho/076d5096d20a1f9f9f743a8e554664e2 to your computer and use it in GitHub Desktop.
Hacking a dormant bitcoin wallet involves finding the wallet’s private key. Owning a bitcoin is equivalent to knowing a wallet’s private key. The process can be summarized as: A private key generates a public key. The public key is hashed by SHA256 + RIPEMD. The hash is encoded in Base58. The encoded Base58 string is the wallet address. We wrote…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Complete guide : https://leetarxiv.substack.com/p/hacking-dormant-bitcoin-wallets-c | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <assert.h> | |
#include <secp256k1.h> | |
#include <openssl/sha.h> | |
#include <openssl/ripemd.h> | |
//Run: clear && gcc PrivateKey.c -lsecp256k1 -lcrypto -o m.o && ./m.o | |
const char *BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | |
void EncodeInBase58(size_t inputLength, uint8_t *input, size_t outputLength, char *output) | |
{ | |
uint8_t temp[32] = {0};memcpy(temp, input, inputLength); | |
uint8_t result[64] = {0};int resultLength = 0; | |
for(size_t i = 0; i < inputLength; i++) | |
{ | |
int carry = temp[i]; | |
for(int j = 0; j < resultLength || carry; j++) | |
{ | |
if(j == resultLength) resultLength++; | |
carry += 256 * result[j]; | |
result[j] = carry % 58; | |
carry /= 58; | |
} | |
} | |
int leading_zeros = 0; | |
for(size_t i = 0; i < inputLength && input[i] == 0; i++) {output[leading_zeros++] = '1';} | |
for(int i = resultLength - 1; i >= 0; i--) {output[leading_zeros++] = BASE58_ALPHABET[result[i]];} | |
output[leading_zeros] = '\0'; | |
} | |
void PrintHexadecimalString(size_t stringLength, uint8_t *string) | |
{ | |
for(size_t i = 0; i < stringLength; i++) | |
{ | |
printf("%02X", string[i]); | |
} | |
printf("\n"); | |
} | |
//Assumes publicKeyString is 33 bytes | |
//Assumes generatedAddress is 64 bytes | |
void PublicKeyToBitcoinWalletAddress(uint8_t *publicKeyString, char *generatedAddress) | |
{ | |
uint8_t sha256Hash[32]; | |
SHA256(publicKeyString, 33, sha256Hash); | |
uint8_t ripemd160Hash[20]; | |
RIPEMD160(sha256Hash, 32, ripemd160Hash); | |
uint8_t versionedPayload[21]; | |
versionedPayload[0] = 0x00; // version byte for mainnet | |
memcpy(versionedPayload + 1, ripemd160Hash, 20); | |
uint8_t checksumInput[25]; | |
memcpy(checksumInput, versionedPayload, 21); | |
uint8_t hash1[32], hash2[32]; | |
SHA256(checksumInput, 21, hash1); | |
SHA256(hash1, 32, hash2); | |
memcpy(checksumInput + 21, hash2, 4); | |
EncodeInBase58(25, checksumInput, 64, generatedAddress); | |
} | |
int main() | |
{ | |
//Initialize secpContext | |
secp256k1_context *secpContext = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); | |
//Set upper bound and target wallet address | |
uint32_t upperBound = 7; | |
char *walletAddress = "19ZewH8Kk1PDbSNdJ97FP4EiCjTRaZMZQA"; | |
printf("%s\n", walletAddress); | |
//Test different private keys | |
for(uint8_t privateKey = 1; privateKey <= upperBound; privateKey++) | |
{ | |
uint8_t privateKeyString[32] = {0}; | |
privateKeyString[31] = privateKey; | |
assert(secp256k1_ec_seckey_verify(secpContext, privateKeyString) != 0); | |
printf("\nPrivate Key:\n");PrintHexadecimalString(32, privateKeyString); | |
//Generate public key | |
secp256k1_pubkey publicKey; | |
size_t publicKeyLength = 33; | |
uint8_t publicKeyString[33]; | |
assert(secp256k1_ec_pubkey_create(secpContext, &publicKey, privateKeyString) != 0); | |
secp256k1_ec_pubkey_serialize(secpContext, publicKeyString, &publicKeyLength, &publicKey, SECP256K1_EC_COMPRESSED); | |
printf("Public Key:\n");PrintHexadecimalString(33, publicKeyString); | |
//Generate wallet address | |
char generatedAddress[64]; | |
PublicKeyToBitcoinWalletAddress(publicKeyString, generatedAddress); | |
printf("Generated Address:%s\n",generatedAddress); | |
if(strcmp(generatedAddress, walletAddress) == 0) | |
{ | |
printf("**MATCH FOUND: Private Key = %u\n", privateKey); | |
break; | |
} | |
} | |
//Destroy secpContext | |
secp256k1_context_destroy(secpContext); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment