Author

Topic: Bitcoin private key/wallet.dat data recovery patch (Read 123 times)

legendary
Activity: 2870
Merit: 7490
Crypto Swap Exchange
Since the tool can read from /dev directory directly, the tool should be able to read single file (image file of HDD).

I would recommend you to make image file/raw copy of your HDD with tools which can attempt to read from bad sector without crash or at least skip bad sector.
Since you're linux user and can use terminal, i would recommend you to use gddrescue.
HCP
legendary
Activity: 2086
Merit: 4361
That is likely to have unintended consequences for the while loop code:
Code:
    while(flg || bufpos < buffill) {

Returning a negative value from refill_buf() (which it will be if (ret < 0))... then that evaluation could end up false depending on the value of bufpos and buffill... which might end the scan prematurely.

Additionally, I think that various values won't be updated properly (ie. buffill, fpos etc) and the program will just attempt to scan the same data over and over in what will effectively be an infinite loop.


Have you considered making a 1:1 image of the drive using a utility that can "ignore" read errors, and then working with the image file? Huh Alternatively, have you tried using an old version of PyWallet to scan that drive?

In any case, making an image and working with the image would be the sensible thing to do, to prevent any unintended overwriting of data on that disk.
newbie
Activity: 20
Merit: 2
Quote
static int refill_buf(void) {
   int ret;
   //printf("refill_buf: fill = %i pos = %i\n", buffill, bufpos);
   if(bufpos > BUF_WATERMARK) {
      memcpy(buf, buf + BUF_SEGMENT, BUF_LEN-BUF_SEGMENT);
      buffill -= BUF_SEGMENT;
      bufpos -= BUF_SEGMENT;
   }
   if(buffill < BUF_LEN) {
      ret = read(f, buf+buffill, BUF_LEN-buffill);
      if(ret < 0) {
         printf("Device read jumping");
         return ret;
      }
      //printf("Read %i bytes\n", ret);
      buffill += ret;
      fpos += ret;
      if(fpos > fnextcp) {
         show_progress();
         fnextcp = fpos + (ftotallen/1024);
      }
      return ret;
   } else {
      return -1;
   }
}

Maybe this will do it.
newbie
Activity: 20
Merit: 2
Full source

Quote
/*
Copyright (c) 2011 Aidan Thornton.  All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal with the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
  1. Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimers.
  2. Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimers in the
     documentation and/or other materials provided with the distribution.
  3. Neither the names of ,      INSTITUTION>, nor the names of its contributors may be used to endorse
     or promote products derived from this Software without specific prior
     written permission.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
WITH THE SOFTWARE.
*/

#define _GNU_SOURCE
#define _FILE_OFFSET_BITS 64
#include
#include
#include
#include
#include
#include
#include

#include

#include
#include
#include

#include "eccrypto.h"
#include "oids.h"
#include "integer.h"

struct key_info {
   std::vector privkey;
   std::vector pubkey;
   std::vector pubkey_comp;
   int found_priv:1;
   int found_pub:1;
   int found_pub_comp:1;
   int recovered:1;
   int recovered_comp:1;

   key_info() : found_priv(0), found_pub(0), found_pub_comp(0),
           recovered(0), recovered_comp(0) {}
};


//"\x01\x03\x6B\x65\x79\x41\x04"

#define STATE_FOUND_PUBKEY 6
#define STATE_FOUND_PUBKEY_COMP 7
#define STATE_FOUND_PUBKEY_2 13
#define STATE_FOUND_PRIVKEY 10
#define STATE_FOUND_PUBKEY_J 19

static const short statemap[][12] = {
   { 0x00, 15, 0x01, 1, 0x03, 11, -1, 0 }, // 0
   { 0x00, 15, 0x03, 2, 0x01, 8, -1, 0 }, // 1: 01
   { 0x00, 15, 0x6b, 3, 0x42, 12, 0x01, 1, 0x03, 11, -1, 0 }, // 2: 01 03
   { 0x00, 15, 0x65, 4, 0x01, 1, 0x03, 11, -1, 0 }, // 3: 01 03 6b
   { 0x00, 15, 0x79, 5, 0x01, 1, 0x03, 11, -1, 0 }, // 4: 01 03 6b 65
   { 0x00, 15, 0x41, 6, 0x21, 7, 0x01, 1, 0x03, 11, -1, 0 }, // 5: 01 03 6b 65 79
   { 0x00, 15, 0x01, 1, 0x03, 11, -1, 0 }, // 6: 01 03 6b 65 79 41
   { 0x00, 15, 0x01, 1, 0x03, 11, -1, 0 }, // 7: 01 03 6b 65 79 21
   { 0x00, 15, 0x01, 8, 0x03, 2, 0x04, 9, -1, 0}, // 8: 01 01
   { 0x00, 15, 0x20, 10, 0x01, 1, 0x03, 11, -1, 0}, // 9: 01 01 04
   { 0x00, 15, 0x01, 1, 0x03, 11, -1, 0 }, // 10: 01 01 04 20
   { 0x00, 15, 0x42, 12, 0x01, 1, 0x03, 11, -1, 0}, // 11: 03
   { 0x00, 13, 0x01, 1, 0x03, 11, -1, 0}, // 12: 03 42
   { 0x00, 16, 0x01, 1, 0x03, 11, -1, 0}, // 13: 03 42 00 
   { }, // unused
   { 0x00, 16, 0x01, 1, 0x03, 11, -1, 0 }, // 15: 00
   { 0x00, 17, 0x01, 1, 0x03, 11, -1, 0 }, // 16: 00 00   
   { 0x00, 17, 0x01, 1, 0x03, 11, 0x41, 18, -1, 0 }, // 17: 00 00 00
   { 0x00, 15, 0x01, 1, 0x03, 11, 0x04, 19, -1, 0 }, // 18: 00 00 00 41
   { 0x00, 15, 0x01, 1, 0x03, 11, -1, 0 }, // 19: 00 00 00 41 04
};


std::map, key_info* > pubkey_map;
std::map, key_info* > privkey_map;

typedef std::map, key_info* >::iterator keymap_iter;

#define BUF_SEGMENT 65536
#define BUF_LEN (65536*4)
#define BUF_WATERMARK (65536*3)
unsigned char buf[BUF_LEN]; int f; int bufpos, buffill;
unsigned long long fpos, ftotallen, fnextcp;
int num_recovered, num_pend_pub, num_pend_pub_comp, num_pend_priv, num_dups;

DB *dbp;

static void show_progress(void) {
   fprintf(stderr, "%4.1f%% done, %i keys recovered, %i %i %i pend\r", 100.0*(fpos-buffill+bufpos)/ftotallen, num_recovered, num_pend_pub, num_pend_pub_comp, num_pend_priv);
   fflush(stderr);
}

static int refill_buf(void) {
   int ret;
   //printf("refill_buf: fill = %i pos = %i\n", buffill, bufpos);
   if(bufpos > BUF_WATERMARK) {
      memcpy(buf, buf + BUF_SEGMENT, BUF_LEN-BUF_SEGMENT);
      buffill -= BUF_SEGMENT;
      bufpos -= BUF_SEGMENT;
   }
   if(buffill < BUF_LEN) {
      ret = read(f, buf+buffill, BUF_LEN-buffill);
      if(ret < 0) {
         perror("Device read");
         exit(1);
      }
      //printf("Read %i bytes\n", ret);
      buffill += ret;
      fpos += ret;
      if(fpos > fnextcp) {
         show_progress();
         fnextcp = fpos + (ftotallen/1024);
      }
      return ret;
   } else {
      return -1;
   }
}

static void dump_hex(unsigned char* data, int len) {
   int i;
   for(i = 0; i < len; i++) {
      printf("%02x", data);
   }
   printf("\n");
}

// structure of a private key:
// "308201130201010420" + private key (32 bytes) + "a081a53081a2020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffff ffffffffffffffffffffffefffffc2f300604010004010704410479be667ef9dcbbac55a06295ce 870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a 68554199c47d08ffb10d4b8022100fffffffffffffffffffffffffffffffebaaedce6af48a03bbf d25e8cd0364141020101a14403420004" + public key (64 bytes)

// structure of compressed private key
// "3081D30201010420" + private key (32 bytes) + "a08185308182020101302c06072a8648ce3d0101022100fffffffffffffffffffffffffffffffff ffffffffffffffffffffffefffffc2f300604010004010704210279be667ef9dcbbac55a06295ce 870b07029bfcdb2dce28d959f2815b16f81798022100fffffffffffffffffffffffffffffffebaa edce6af48a03bbfd25e8cd0364141020101a124032200" + compressed public key (33 bytes)

static void save_recovered_key(unsigned char* pubkey, unsigned char* privkey, bool compressed)
{
   DBT key, data; int ret;
   unsigned char keybuf[70],  valbuf[300];
   if(dbp == NULL) return;
   memset(&key, 0, sizeof(DBT));
   memset(&data, 0, sizeof(DBT));

   if(compressed) {
      memcpy(keybuf, "\x03key\x21", 5);
      memcpy(keybuf+5, pubkey, 33);
      key.data = keybuf;
      key.size = 33+5;

      memcpy(valbuf,"\xd6",1); // length
      memcpy(valbuf+1, "\x30\x81\xD3\x02\x01\x01\x04\x20", Cool;
      memcpy(valbuf+9, privkey, 32);
      memcpy(valbuf+41, "\xa0\x81\x85\x30\x81\x82\x02\x01\x01\x30\x2c\x06\x07\x2a\x86\x48\xce\x3d\x01\x01\x02\x21\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xfc\x2f\x30\x06\x04\x01\x00\x04\x01\x07\x04\x21\x02\x79\xbe\x66\x7e\xf9\xdc\xbb\xac\x55\xa0\x62\x95\xce\x87\x0b\x07\x02\x9b\xfc\xdb\x2d\xce\x28\xd9\x59\xf2\x81\x5b\x16\xf8\x17\x98\x02\x21\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xba\xae\xdc\xe6\xaf\x48\xa0\x3b\xbf\xd2\x5e\x8c\xd0\x36\x41\x41\x02\x01\x01\xa1\x24\x03\x22\x00", 141);
      memcpy(valbuf+182, pubkey, 33);
      data.data = valbuf;
      data.size = 215;
   } else {
      memcpy(keybuf, "\x03key\x41\x04", 6);
      memcpy(keybuf+6, pubkey, 64);
      key.data = keybuf;
      key.size = 64+6;

      memcpy(valbuf,"\xfd\x17\x01",3); // length
      memcpy(valbuf+3, "\x30\x82\x01\x13\x02\x01\x01\x04\x20", 9);
      memcpy(valbuf+12, privkey, 32);
      memcpy(valbuf+44, "\xa0\x81\xa5\x30\x81\xa2\x02\x01\x01\x30\x2c\x06\x07\x2a\x86\x48\xce\x3d\x01\x01\x02\x21\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xfc\x2f\x30\x06\x04\x01\x00\x04\x01\x07\x04\x41\x04\x79\xbe\x66\x7e\xf9\xdc\xbb\xac\x55\xa0\x62\x95\xce\x87\x0b\x07\x02\x9b\xfc\xdb\x2d\xce\x28\xd9\x59\xf2\x81\x5b\x16\xf8\x17\x98\x48\x3a\xda\x77\x26\xa3\xc4\x65\x5d\xa4\xfb\xfc\x0e\x11\x08\xa8\xfd\x17\xb4\x48\xa6\x85\x54\x19\x9c\x47\xd0\x8f\xfb\x10\xd4\xb8\x02\x21\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xba\xae\xdc\xe6\xaf\x48\xa0\x3b\xbf\xd2\x5e\x8c\xd0\x36\x41\x41\x02\x01\x01\xa1\x44\x03\x42\x00\x04",174);
      memcpy(valbuf+218, pubkey, 64);
      data.data = valbuf;
      data.size = 279+3;
   }

   ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE);
   if(ret == DB_KEYEXIST) {
      printf("Skipping DB write, key already exists\n");
   } else if(ret != 0) {
      fprintf(stderr, "Error: DB write failed!\n");
      dbp->close(dbp, 0);
      exit(1);
   }
}

// really dirty hack to force a rescan at next startup
static void invalidate_best_block() {
   DBT key, data; int ret;
   unsigned char keybuf[10],  valbuf[0];
   if(dbp == NULL) return;
   memset(&key, 0, sizeof(DBT));
   memset(&data, 0, sizeof(DBT));
   
   key.data = (void*)("\x09" "bestblock");
   key.size = 10;
   data.data = (void*)"\x00\x00\x00\x00\x00";
   data.size = 5;
   ret = dbp->put(dbp, NULL, &key, &data, 0);
   if(ret != 0) {
      fprintf(stderr, "Error: DB write failed!\n");
      dbp->close(dbp, 0);
      exit(1);
   }
}

static void try_recover_key(key_info *kinfo) {
   if(kinfo->found_pub && kinfo->found_priv && !kinfo->recovered) {
      printf("pubkey = "); dump_hex(&kinfo->pubkey[0], 64);
      printf("privkey = "); dump_hex(&kinfo->privkey[0], 32);
      save_recovered_key(&kinfo->pubkey[0], &kinfo->privkey[0], false);
      kinfo->recovered = 1;
      num_recovered++; num_pend_pub--;
      if(!kinfo->recovered_comp) num_pend_priv--;
   } else if(kinfo->found_pub_comp && kinfo->found_priv && !kinfo->recovered_comp) {
      printf("pubkey_comp = "); dump_hex(&kinfo->pubkey_comp[0], 33);
      printf("privkey = "); dump_hex(&kinfo->privkey[0], 32);
      save_recovered_key(&kinfo->pubkey_comp[0], &kinfo->privkey[0], true);
      kinfo->recovered_comp = 1;
      num_recovered++; num_pend_pub_comp--;
      if(!kinfo->recovered) num_pend_priv--;
   }
   show_progress();
}

static void do_recover_privkey(int keypos) {
   std::vector privkey(32);
   std::vector gen_pubkey(64);
   if(buffill - keypos < 32) {
      fprintf(stderr, "Not enough data in buffer to recover key!\n");
      return;
   }
   memcpy(&privkey[0], buf+keypos, 32);

   keymap_iter iter = privkey_map.find(privkey);
   if(iter != privkey_map.end()) {
      //printf("Duplicate potential private key, skipping\n");
      num_dups++;
      show_progress();
      return;
   } else {
      CryptoPP::ECDSA::PrivateKey privateKey;      
      CryptoPP::ECDSA::PublicKey publicKey;
      CryptoPP::Integer pkey_i(&privkey[0], 32);
      privateKey.Initialize( CryptoPP::ASN1::secp256k1(), pkey_i );
      privateKey.MakePublicKey(publicKey);

      const CryptoPP::ECP::Point& q = publicKey.GetPublicElement();
      q.x.Encode(&gen_pubkey[0], 32); q.y.Encode(&gen_pubkey[32], 32);

      key_info* kinfo;
      iter = pubkey_map.find(gen_pubkey);
      if(iter != pubkey_map.end()) {
         kinfo = iter->second;
      } else {
         kinfo = new key_info();
         kinfo->pubkey = gen_pubkey;
         kinfo->found_pub = 0;
         pubkey_map[gen_pubkey] = kinfo;
      }

      kinfo->found_priv = 1;
      kinfo->privkey = privkey;
      privkey_map[privkey] = kinfo;
      num_pend_priv++;
      //printf("Found potential privkey: ");
      //dump_hex(&privkey[0], 32);
      try_recover_key(kinfo);
   }
}

static void do_recover_pubkey_uncomp(int keypos) {
   std::vector pubkey(64);
   if(buffill - keypos < 64) {
      fprintf(stderr, "Not enough data in buffer to recover key!\n");
      return;
   }
   memcpy(&pubkey[0], buf+keypos, 64);

   key_info* kinfo;
   keymap_iter iter = pubkey_map.find(pubkey);
   if(iter != pubkey_map.end()) {
      kinfo = iter->second;
      if(kinfo->found_pub) {
         //printf("Duplicate potential public key, skipping\n");
         num_dups++;
         show_progress();
         return;
      }
   } else {
      kinfo = new key_info();
      kinfo->pubkey = pubkey;
      pubkey_map[pubkey] = kinfo;
   }

   kinfo->found_pub = 1;
   kinfo->pubkey = pubkey;
   num_pend_pub++;

   //printf("Found potential pubkey: ");
   //dump_hex(&pubkey[0], 64);
   try_recover_key(kinfo);
}

static void do_recover_pubkey_comp(int keypos) {
   std::vector pubkey_comp(33);
   std::vector gen_pubkey(64);
   if(buffill - keypos < 33) {
      fprintf(stderr, "Not enough data in buffer to recover key!\n");
      return;
   }
   memcpy(&pubkey_comp[0], buf+keypos, 33);

   CryptoPP::ECDSA::PublicKey publicKey;
    publicKey.AccessGroupParameters().Initialize( CryptoPP::ASN1::secp256k1() );
   CryptoPP::ECP::Point q;
   try {
      publicKey.GetGroupParameters().GetCurve().DecodePoint(q,&pubkey_comp[0],33);
   } catch(CryptoPP::Exception& e) {
      printf("CryptoPP exception decompressing pubkey: %s\n", e.what());
      return;
   }
   publicKey.SetPublicElement(q);
   q.x.Encode(&gen_pubkey[0], 32); q.y.Encode(&gen_pubkey[32], 32);
   
   key_info* kinfo;
   keymap_iter iter = pubkey_map.find(gen_pubkey);
   if(iter != pubkey_map.end()) {
      kinfo = iter->second;
      if(kinfo->found_pub_comp) {
         //printf("Duplicate potential compressed public key, skipping\n");
         num_dups++;
         show_progress();
         return;
      }
   } else {
      kinfo = new key_info();
      kinfo->pubkey = gen_pubkey;
      pubkey_map[gen_pubkey] = kinfo;
   }

   kinfo->found_pub_comp = 1;
   kinfo->pubkey = gen_pubkey;
   kinfo->pubkey_comp = pubkey_comp;
   num_pend_pub_comp++;

   //printf("Found potential compressed pubkey: ");
   //dump_hex(&pubkey_comp[0], 33);
   try_recover_key(kinfo);
}


static void do_recover_pubkey() {
   if(buffill - bufpos < 1)
      return;

   if(buf[bufpos] == 0x04) {
      do_recover_pubkey_uncomp(bufpos+1);
   } else if(buf[bufpos] == 0x02 || buf[bufpos] == 0x03) {
      do_recover_pubkey_comp(bufpos);
   }
}

// nasty hack to try and recover BitcoinJ public+private keys
// probably quite unreliable
static void do_recover_pubkey_j() {
   std::vector pubkey(64);
   if(buffill - bufpos < 64 || bufpos < 64) {
      fprintf(stderr, "Not enough data in buffer to recover potential BitcoinJ key!\n");
      return;
   }

   int bufpos_priv = -1;
   for(int i = bufpos-64; i < bufpos-37; i++) {
      if(memcmp(buf+i, "\x00\x00\x00\x20", 4) == 0) {
         bufpos_priv = i+4; break;
      }
   }
   if(bufpos_priv < 0)
      return;

   do_recover_pubkey_uncomp(bufpos);
   do_recover_privkey(bufpos_priv);
}

static void do_scan(void) {
   int flg = 1, len; unsigned char *p;
   int stateid = 0;
   while(flg || bufpos < buffill) {
      const short *next_tbl = statemap[stateid];
      flg = refill_buf();
      for(;Wink {
         if(next_tbl[0] < 0 || next_tbl[0] == buf[bufpos]) {
            stateid = next_tbl[1]; break;
         }
         next_tbl += 2;
      }
      bufpos++;
      if(stateid == STATE_FOUND_PUBKEY || stateid == STATE_FOUND_PUBKEY_2 || stateid == STATE_FOUND_PUBKEY_COMP ) {
         //printf("Found potential key!\n");
         refill_buf();
         do_recover_pubkey();
      } else if(stateid == STATE_FOUND_PUBKEY_J ) {
         refill_buf();
         do_recover_pubkey_j();         
      } else if(stateid == STATE_FOUND_PRIVKEY) {
         refill_buf();
         do_recover_privkey(bufpos);
      }
   }
}

int main(int argc, char** argv) {
   u_int32_t flags; int ret;
   num_recovered = num_pend_pub = num_pend_pub_comp = num_pend_priv = num_dups = 0;
   if(argc < 2 || argc > 3) {
      fprintf(stderr, "bitcoin-wallet-recover v0.3\n");
      fprintf(stderr, "(C) 2011-2012 Aidan Thornton. All rights reserved.\n");
      fprintf(stderr, "See LICENSE.txt for full copyright and licensing information\n");
      fprintf(stderr, "\n");
      fprintf(stderr, "Usage: %s []\n", argv[0]);
      exit(1);
   }

   bufpos = 0; buffill = 0;
   f = open(argv[1], O_RDONLY);
   if(f < 0) {
      perror("Opening input");
      exit(1);
   }
   ftotallen = lseek(f, 0, SEEK_END);
   fpos = fnextcp = 0;
   lseek(f, 0, SEEK_SET);
   //printf("DEBUG: f = %i\n", f);

   if(argc >= 3) {
      ret = db_create(&dbp, NULL, 0);
      if (ret != 0) {
         fprintf(stderr, "Error: couldn't create DB to open output wallet\n");
         exit(1);
      }
      flags = DB_CREATE;
      ret = dbp->open(dbp,
            NULL, // transaction pointer
            argv[2],
            "main", // logical database name
            DB_BTREE,
            flags,
            0);
      if (ret != 0) {
         fprintf(stderr, "Error: couldn't open output wallet\n");
         exit(1);
      }
   } else {
      dbp = NULL;
   }
   
   do_scan();
   if(dbp && num_recovered > 0)
      invalidate_best_block();
   if(dbp)
      dbp->close(dbp, 0);
   fprintf(stderr, "Done - %i keys recovered, %i %i %i fail %i dups!     \n", num_recovered, num_pend_pub, num_pend_pub_comp, num_pend_priv, num_dups);
   if(num_recovered <= 0) {
      fprintf(stderr, "Sorry, nothing found :-(\n");
   } else {
      if(dbp) {
         fprintf(stderr, "Note: recovered addresses won't be listed under 'Receive coins' in the client\n\n");
      }
      fprintf(stderr, "If this helped, feel free to make a donation to the author at:\n");
      fprintf(stderr, "    *** 1CxDtwy7SAYHu7RJr5MFFUwtn8VEotTj8P ***\n");
      fprintf(stderr, "Please backup your wallet regularly and securely!\n\n");
      if(dbp) {
         fprintf(stderr, "After running the client and confirming your coins are all there, please either:\n");
         fprintf(stderr, " * Send all your coins to a new wallet that's securely backed up in one big transaction, or\n");
         fprintf(stderr, " * Stop the client and take a backup of your wallet before making any transactions\n");
         fprintf(stderr, "I'd also recommend using the -upgradewallet option, though it's not required\n\n");
      }
   }
   return 0;
}

newbie
Activity: 20
Merit: 2
Hey, everyone I'm trying to use the following tool:

https://bitcointalksearch.org/topic/bitcoin-private-keywalletdat-data-recovery-tool-25091

To recover keys off an old 2011 era hard drive.  The problem is the drive has some bad sectors and I get a drive I/O error crashing the program.

Quote
static int refill_buf(void) {
   int ret;
   //printf("refill_buf: fill = %i pos = %i\n", buffill, bufpos);
   if(bufpos > BUF_WATERMARK) {
      memcpy(buf, buf + BUF_SEGMENT, BUF_LEN-BUF_SEGMENT);
      buffill -= BUF_SEGMENT;
      bufpos -= BUF_SEGMENT;
   }
   if(buffill < BUF_LEN) {
      ret = read(f, buf+buffill, BUF_LEN-buffill);
      if(ret < 0) {
         perror("Device read");
         exit(1);
      }
      //printf("Read %i bytes\n", ret);
      buffill += ret;
      fpos += ret;
      if(fpos > fnextcp) {
         show_progress();
         fnextcp = fpos + (ftotallen/1024);
      }
      return ret;
   } else {
      return -1;
   }
}

Is there a simple way to modify the code to skip ahead instead of jumping to the Device read exit block? 
Jump to: