Bitcoin Forum
July 26, 2017, 07:00:14 PM *
News: BIP91 seems stable: there's probably only slightly increased risk of confirmations disappearing. You should still prepare for Aug 1.
 
   Home   Help Search Donate Login Register  
Pages: « 1 2 3 [4] 5 »  All
  Print  
Author Topic: Bitcoin private key/wallet.dat data recovery tool!  (Read 57187 times)
tspacepilot
Legendary
*
Offline Offline

Activity: 1400


I may write code in exchange for bitcoins.


View Profile
September 17, 2015, 04:19:34 PM
 #61


Code:
#include <stdio.h>

main() {
  int c, i;

  // privkeys are preceeded by: 3081 d302 0101 0420 and are 32 bytes long:
  while ((c = getchar()) != EOF)
    if (c == 0x81 &&
        getchar() == 0xd3 && getchar() == 0x02 && getchar() == 0x01 &&
        getchar() == 0x01 && getchar() == 0x04 && getchar() == 0x20) {
      for (i = 0; i < 32; i++)
        printf("%02x", getchar());
      printf("\n");
    }
}

Simple and useful program, dooglus, thanks for sharing it.  One follow up question, I can see how you're just checing for each byte and then printing if you find them.  But the code you pasted just checks for 7 bytes.  There should be a check for 0x30 before the 0x81, right?  Or what am I missing?

Suppose the disk image contains: "2930 3081 d302 0101 0420 privkey". Checking for 0x30 would cause my simple program to miss that privkey completely, since it never backtracks. I figured it was better to maybe get some false positives than to miss some private keys.

In tests, my code encountered bytes like these, and so missed the privkey:

    0081 d302 0101 0420 3081 d302 0101 0420 privkey

It output:

    3081 d302 0101 0420 privke

since the 7 bytes before the real 8 byte prefix triggered the matching code.

I'm guessing that's quite an uncommon situation.

Oh I see what you mean.  I guess you could make it more robust if you, say, recurse when you find 0x30 so that you check all potential 8 byte windows.  Anyway, thanks again.

1501095614
Hero Member
*
Offline Offline

Posts: 1501095614

View Profile Personal Message (Offline)

Ignore
1501095614
Reply with quote  #2

1501095614
Report to moderator
1501095614
Hero Member
*
Offline Offline

Posts: 1501095614

View Profile Personal Message (Offline)

Ignore
1501095614
Reply with quote  #2

1501095614
Report to moderator
1501095614
Hero Member
*
Offline Offline

Posts: 1501095614

View Profile Personal Message (Offline)

Ignore
1501095614
Reply with quote  #2

1501095614
Report to moderator
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction. Advertise here.
1501095614
Hero Member
*
Offline Offline

Posts: 1501095614

View Profile Personal Message (Offline)

Ignore
1501095614
Reply with quote  #2

1501095614
Report to moderator
dooglus
Legendary
*
Offline Offline

Activity: 2226



View Profile
September 18, 2015, 02:56:08 AM
 #62

IMHO your code should use nested If's instead of ANDs, that way not finding expected byte should reset search to the beginning, without ever encountering false positives or missing something:

You might be surprised to learn this, but your code is equivalent to mine.

Both

Code:
if (a() && b()) ...

and

Code:
if (a()) if (b()) ...

don't call b() if a() returns a falsy value.

For example:

Code:
#include <stdio.h>

main() {
  if (printf("hello\n") == 1234 &&
      printf("world\n"))
    printf("omfg\n");
}

Then...

Code:
$ gcc if-shortcut.c
$ ./a.out
hello
$

Just-Dice                 ██             
          ██████████         
      ██████████████████     
  ██████████████████████████ 
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
    ██████████████████████   
        ██████████████       
            ██████           
   Play or Invest                 ██             
          ██████████         
      ██████████████████     
  ██████████████████████████ 
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
    ██████████████████████   
        ██████████████       
            ██████           
   1% House Edge
dooglus
Legendary
*
Offline Offline

Activity: 2226



View Profile
September 18, 2015, 02:54:35 AM
 #63

IMHO your code should use nested If's instead of ANDs, that way not finding expected byte should reset search to the beginning, without ever encountering false positives or missing something:

You might be surprised to learn this, but your code is equivalent to mine.

Both

Code:
if (a() && b()) ...

and

Code:
if (a()) if (b()) ...

don't call b() if a() returns a falsy value.

For example:

Code:
#include <stdio.h>

main() {
  if (printf("hello\n") == 1234 &&
      printf("world\n"))
    printf("omfg\n");
}

Then...

Code:
$ gcc if-shortcut.c
$ ./a.out
hello
$

Edit: see http://stackoverflow.com/a/628538/1253362 for confirmation of this.

Just-Dice                 ██             
          ██████████         
      ██████████████████     
  ██████████████████████████ 
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
    ██████████████████████   
        ██████████████       
            ██████           
   Play or Invest                 ██             
          ██████████         
      ██████████████████     
  ██████████████████████████ 
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
    ██████████████████████   
        ██████████████       
            ██████           
   1% House Edge
itod
Legendary
*
Offline Offline

Activity: 1008


^ will code for bitcoins


View Profile
September 18, 2015, 12:52:53 PM
 #64

You might be surprised to learn this, but your code is equivalent to mine.

Interesting, you are right, I thought left-to-right evaluation for && operator is not guaranteed.

Solution may be to introduce another variable to buffer first next getchar() value, and then in case of missed match take the value of c from that buffer instead of getchar() in the while loop condition statement.
JeWay
Hero Member
*****
Offline Offline

Activity: 560


View Profile
September 18, 2015, 03:27:51 PM
 #65

This is actually a good tool to use, but kinda hard to use for a newbie

                      ▄████▄
                    ▄███▀▀███▄
                  ▄███▀    ▀███▄█████████
                ▄███▀        ▀████     ██
              ▄███▀            ▀██     ██
            ▄███▀               ██     ██
          ▄███▀                 ██     ██
         ███▀                   ██     ██▄
         ██                     ██      ▀██▄
         ██                   ▄██▀        ███
         ██                 ▄██▀        ▄██▀
         ██            ▄▄▄███▀         ██▀
         ██     █████████▀▀            ██
         ██     ██                     ██
         ██     ██                     ██
         ██     ██                     ██
         ██     ██                     ██
         ████████████████████████████████
.
.
.
....
PROPY
▐ 
  ▌
  ▌
Slack      Telegram      Facebook      Twitter
Bitcointalk      Medium      Reddit
dooglus
Legendary
*
Offline Offline

Activity: 2226



View Profile
September 18, 2015, 03:53:02 PM
 #66

You might be surprised to learn this, but your code is equivalent to mine.

Interesting, you are right, I thought left-to-right evaluation for && operator is not guaranteed.

Solution may be to introduce another variable to buffer first next getchar() value, and then in case of missed match take the value of c from that buffer instead of getchar() in the while loop condition statement.

I expect reading characters one by one is introducing lots of overhead, and it would be better to do some kind of buffering. Or maybe stdio.h handles that for me. There's also ungetc():

     ungetc() pushes  c back  to stream,  cast to  unsigned char,
     where  it  is  available  for  subsequent  read  operations.
     Pushed-back characters  will be  returned in  reverse order;
     only one pushback is guaranteed.

which could be all I need to avoid missing keys.

My main aim in sharing this was to show a very simple way of scanning a device for private keys that recently worked for me. It took maybe 5 hours to scan my whole (full-disk encrypted) 1 TB root partition.

Just-Dice                 ██             
          ██████████         
      ██████████████████     
  ██████████████████████████ 
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
    ██████████████████████   
        ██████████████       
            ██████           
   Play or Invest                 ██             
          ██████████         
      ██████████████████     
  ██████████████████████████ 
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
    ██████████████████████   
        ██████████████       
            ██████           
   1% House Edge
marcusiscoo1
Newbie
*
Offline Offline

Activity: 1


View Profile
November 10, 2015, 06:29:05 AM
 #67

So after doing a scan with System Rescue CD, it find 226 keys. How do I transfer them to a usb? After Googling the issue, I cant seem to find a way to mount a usb in System Rescue so I can move files to it. Can anyone help me? Also plan on donating if I am able to get my wallet back. Thank you.
tspacepilot
Legendary
*
Offline Offline

Activity: 1400


I may write code in exchange for bitcoins.


View Profile
November 10, 2015, 04:49:51 PM
 #68

So after doing a scan with System Rescue CD, it find 226 keys. How do I transfer them to a usb? After Googling the issue, I cant seem to find a way to mount a usb in System Rescue so I can move files to it. Can anyone help me? Also plan on donating if I am able to get my wallet back. Thank you.

What is a System Rescue CD?  It sounds like you've got some proprietary software there and maybe you have to read the manual.  If you just need help mounting a USB drive on a linux system, I can help you with that.

LuckyYOU
Sr. Member
****
Offline Offline

Activity: 294



View Profile
November 17, 2015, 08:28:44 PM
 #69

This is actually a good tool to use, but kinda hard to use for a newbie

Yeah a detailed video would handy to be honest. I got stuck in the beginning already..

wget http://www.makomk.com/~aidan/wallet-recover-0.3-linux.tar.gz
Do i need a linux server for this or can i do this with windows also?

siameze
Legendary
*
Offline Offline

Activity: 1064



View Profile
November 17, 2015, 09:23:19 PM
 #70

This is actually a good tool to use, but kinda hard to use for a newbie

Yeah a detailed video would handy to be honest. I got stuck in the beginning already..

wget http://www.makomk.com/~aidan/wallet-recover-0.3-linux.tar.gz
Do i need a linux server for this or can i do this with windows also?

Isn't the answer to your question rather obvious from the name of the file ?




                     ▀▀█████████▀████████████████▄
                        ████▄      ▄████████████████
                     ▄██████▀  ▄  ███████████████████
                  ▄█████████▄████▄███████████████████
                ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀████████
                                               ▀▀███▀
    ▄█▀█       ▄▀  ▄▀▀█  ▄▀   █████████████████▄ ██▀         ▄▀█
   ▄█ ▄▀      ▀█▀ █▀ █▀ ▀█▀  ███████████████████ █▀ ▀▀      ▄▀▄▀
  ▄█    ▄███  █     █   █   ████████████████████  ▄█     ▄▀▀██▀ ▄███
███▄▄▄  █▄▄▄ █▄▄ ▄▄▀   █▄▄ ██████████████████▀▀   █▄▄ ▄▄ █▄▄█▄▄▄█▄▄▄
                           ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
                            ▀▀█████████████▄
                                █████████████▄
                                  █████████████▄
                                    ▀███████▀▀▀▀▀
                                      ▀████▀
                                        ▀█▀
LetItRideINNOVATIVE ▬▬▬
DICE GAME
                        ▄███████████▄
                       ██  ██████████▄
                     ▄█████████████  ██▄
            ▄▄▀█▄▄▄▄▄████████████████████▄
        ▄▄█▀   ███████████  █████  ████  █
    ▄██████ ▄▄███████████████████████████▀
 ▄▀▀ ██████████████████████████  ████  █
█  ▄███████████▀▀▀█████████████████████
██████████████    ████████▀▀██████  █▀
██████████████▄▄▄██████████   ▀▀▀▀▀▀▀
███▀ ▀██████████████████████
██    ███████████████████████
██▄▄██████████████████████████
██████████████▀   ██████████
  █████████████   ▄██████▀▀
     ▀▀██████████████▀▀
         ▀▀██████▀▀
PROVABLY
F A I R
▄█████████████▀ ▄█
██            ▄█▀
██          ▄██ ▄█
██ ▄█▄    ▄███  ██
██ ▀███▄ ▄███   ██
██  ▀███████    ██
██    █████     ██
██     ███      ██
██      ▀       ██
██              ██
▀████████████████▀
BUY  BACK
PLANS
[BTC]
tspacepilot
Legendary
*
Offline Offline

Activity: 1400


I may write code in exchange for bitcoins.


View Profile
November 18, 2015, 01:19:25 AM
 #71

I think the code that dooglus posted just a few posts back should run on windows, assuming you know how to run a compiler on that system (I don't).

facembanijung
Newbie
*
Offline Offline

Activity: 1


View Profile
April 23, 2016, 10:24:28 PM
 #72

The ideal solution would be USB -> USB using a Linux live CD, with either no hard drive plugged in, or by running "swapoff" to make sure no virtual memory is in use at the time of the copy.

free mp3 download[/u] (https://mp3jung.com)
rfisher1968
Sr. Member
****
Offline Offline

Activity: 314


View Profile
April 26, 2016, 12:40:00 AM
 #73

I compiled it on windows using Cygwin and ran it just on a wallet.dat file. Worked great.

I'm going to modify the code and inject 32 different bytes into each, is there any problem with this?

I think the code that dooglus posted just a few posts back should run on windows, assuming you know how to run a compiler on that system (I don't).
tspacepilot
Legendary
*
Offline Offline

Activity: 1400


I may write code in exchange for bitcoins.


View Profile
April 27, 2016, 04:29:38 PM
 #74

I compiled it on windows using Cygwin and ran it just on a wallet.dat file. Worked great.

I'm going to modify the code and inject 32 different bytes into each, is there any problem with this?

I think the code that dooglus posted just a few posts back should run on windows, assuming you know how to run a compiler on that system (I don't).

What do you mean, "inject 32 different bytes into each"?  Good to know that the script runs on any system.

rfisher1968
Sr. Member
****
Offline Offline

Activity: 314


View Profile
April 27, 2016, 06:33:35 PM
 #75

I guess I should have said a new/different private key. I didn't know if it would work.

I compiled it on windows using Cygwin and ran it just on a wallet.dat file. Worked great.

I'm going to modify the code and inject 32 different bytes into each, is there any problem with this?

I think the code that dooglus posted just a few posts back should run on windows, assuming you know how to run a compiler on that system (I don't).

What do you mean, "inject 32 different bytes into each"?  Good to know that the script runs on any system.
rfisher1968
Sr. Member
****
Offline Offline

Activity: 314


View Profile
May 01, 2016, 12:47:09 PM
 #76

I just created the code to insert random private key into wallet.dat and bitcoin core says wallet.dat is corrupt. I just got my answer.

Code:
#include <stdio.h>
#include <string.h>
#include <time.h>

void rnd_init( void )
{
    srand((unsigned)time(NULL));
}

int rnd( void )
{
    int tmp;

tmp = rand();
return (tmp&0xff);
}

main()
{
    int c, i=0;

    FILE* file = fopen("wallet.dat","r");
FILE* file2 = fopen("new.dat","w");

rnd_init();

    if ( file != NULL )
    {
    printf("wallet.dat opened\n");
    while ( (c = fgetc(file)) != EOF )
{
    fputc(c,file2);
    if ( c == 0x020 && i == 6 )
{
    printf("found: ");
    for (i = 0; i < 32; i++)
{
    printf("%02x", fgetc(file));
fputc(rnd(),file2);
}
printf("\n");
    i = 7;
}
else if ( c == 0x04 && i == 5 )
{
    i = 6;
}
else if ( c == 0x01 && i == 4 )
{
    i = 5;
}
else if ( c == 0x01 && i == 3 )
{
    i = 4;
}
else if ( c == 0x02 && i == 2 )
{
    i = 3;
}
else if ( c == 0xd3 && i == 1 )
{
    i = 2;
}
else if ( c == 0x81 && i == 0 )
{
    i = 1;
}
else
{
    i = 0;
}
}
    fclose(file);
fclose(file2);
}
 
    // privkeys are preceeded by: 3081 d302 0101 0420 and are 32 bytes long:
    //while ((c = getchar()) != EOF)
    //if (c == 0x81 &&
    //    getchar() == 0xd3 && getchar() == 0x02 && getchar() == 0x01 &&
    //    getchar() == 0x01 && getchar() == 0x04 && getchar() == 0x20) {
    //  for (i = 0; i < 32; i++)
    //    printf("%02x", getchar());
    //  printf("\n");
    //}
}
tspacepilot
Legendary
*
Offline Offline

Activity: 1400


I may write code in exchange for bitcoins.


View Profile
May 07, 2016, 12:09:45 AM
 #77

I just created the code to insert random private key into wallet.dat and bitcoin core says wallet.dat is corrupt. I just got my answer.

Code:
#include <stdio.h>
#include <string.h>
#include <time.h>

void rnd_init( void )
{
    srand((unsigned)time(NULL));
}

int rnd( void )
{
    int tmp;

tmp = rand();
return (tmp&0xff);
}

main()
{
    int c, i=0;

    FILE* file = fopen("wallet.dat","r");
FILE* file2 = fopen("new.dat","w");

rnd_init();

    if ( file != NULL )
    {
    printf("wallet.dat opened\n");
    while ( (c = fgetc(file)) != EOF )
{
    fputc(c,file2);
    if ( c == 0x020 && i == 6 )
{
    printf("found: ");
    for (i = 0; i < 32; i++)
{
    printf("%02x", fgetc(file));
fputc(rnd(),file2);
}
printf("\n");
    i = 7;
}
else if ( c == 0x04 && i == 5 )
{
    i = 6;
}
else if ( c == 0x01 && i == 4 )
{
    i = 5;
}
else if ( c == 0x01 && i == 3 )
{
    i = 4;
}
else if ( c == 0x02 && i == 2 )
{
    i = 3;
}
else if ( c == 0xd3 && i == 1 )
{
    i = 2;
}
else if ( c == 0x81 && i == 0 )
{
    i = 1;
}
else
{
    i = 0;
}
}
    fclose(file);
fclose(file2);
}
 
    // privkeys are preceeded by: 3081 d302 0101 0420 and are 32 bytes long:
    //while ((c = getchar()) != EOF)
    //if (c == 0x81 &&
    //    getchar() == 0xd3 && getchar() == 0x02 && getchar() == 0x01 &&
    //    getchar() == 0x01 && getchar() == 0x04 && getchar() == 0x20) {
    //  for (i = 0; i < 32; i++)
    //    printf("%02x", getchar());
    //  printf("\n");
    //}
}

Are you sure you didn't just get the format wrong?  I'm pretty sure the wallet format has more than just the list of private keys.  Actually, it's documented somewhere on the wiki, I've looked at it before.

dooglus
Legendary
*
Offline Offline

Activity: 2226



View Profile
May 07, 2016, 04:24:13 PM
 #78

I just created the code to insert random private key into wallet.dat and bitcoin core says wallet.dat is corrupt. I just got my answer.

Code:
   printf("found: ");
   for (i = 0; i < 32; i++)
{
   printf("%02x", fgetc(file));
fputc(rnd(),file2);
}

I think you would have better luck if you did a fgetc() with each of those fputc() calls. That way you are effectively overwriting the old privkey with a new random one rather than inserting new bytes into the file which will corrupt it.

Edit: oh, you are already doing that. Smiley So I'm not sure what went wrong. I'll take another look.

Edit2: wallet.dat stores the public keys as well as the private keys and complains if they don't match. That's why you're getting the error you're getting.

From walletdb.cpp:

Code:
            // Old wallets store keys as "key" [pubkey] => [privkey]
            // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
            // using EC operations as a checksum.
            // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
            // remaining backwards-compatible.

Just-Dice                 ██             
          ██████████         
      ██████████████████     
  ██████████████████████████ 
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
    ██████████████████████   
        ██████████████       
            ██████           
   Play or Invest                 ██             
          ██████████         
      ██████████████████     
  ██████████████████████████ 
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
██████████████████████████████
    ██████████████████████   
        ██████████████       
            ██████           
   1% House Edge
almightyruler
Legendary
*
Offline Offline

Activity: 1316


View Profile
May 06, 2017, 09:01:54 AM
 #79

So I wrote my own simple "privkey finder":

Code:
#include <stdio.h>

main() {
  int c, i;

  // privkeys are preceeded by: 3081 d302 0101 0420 and are 32 bytes long:
  while ((c = getchar()) != EOF)
    if (c == 0x81 &&
        getchar() == 0xd3 && getchar() == 0x02 && getchar() == 0x01 &&
        getchar() == 0x01 && getchar() == 0x04 && getchar() == 0x20) {
      for (i = 0; i < 32; i++)
        printf("%02x", getchar());
      printf("\n");
    }
}

Hi dooglus, where did you get the 3081 d302 0101 0420 sequence from? Did you reverse engineer that yourself, or see it elsewhere? I don't think that sequences covers all keys, because I found several in my wallet which had different leading bytes. I've modified your code to extract keys more aggressively - using a smaller sequence - and also backtrack if the conditional fails:

Code:
#include <stdio.h>

int main() {
  int c, i;

/* assume that the 32 bytes following the sequence 0420 are a private key */

  while ((c = getchar()) != EOF) {
    if (c == 0x04) {
      if ((c = getchar()) == 0x20) {
        for (i = 0; i < 32; i++)
          printf("%02x", getchar());
        printf("\n");
        fflush(stdout);
      } else {
        ungetc(c, stdin);  /* push back in case it's 0x04 */
      }
    }
  }
}

The downside of the reduced lead sequence is that the program will cause a lot more false positives, particularly if you use it to scan an entire raw device, rather than (say) a corrupt wallet.dat file. I fed it an old 40GB Windows XP backup image, and it output nearly 600,000 potential keys, so it's really only practical for extracting keys from a known wallet file.

Hope this helps someone, anyway.
WarrEagle
Hero Member
*****
Offline Offline

Activity: 532



View Profile
May 16, 2017, 05:19:00 PM
 #80

Thank you for your contribution, this is a very helpful tool. I have a friend that past away in 2013 supposedly his mom said his laptop has a bunch of BTC on it. Will be checking it out this weekend.

Pages: « 1 2 3 [4] 5 »  All
  Print  
 
Jump to:  

Sponsored by , a Bitcoin-accepting VPN.
Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!