В начале 2012 года я впервые услышал о крипто валюте Bitcon. Сразу было решено — майнингу быть. Зарегистрировался на mining.bitcoin.cz и начал майнить. Везде где читал про Bitcoin авторы настойчиво рекомендовали шифровать кошелек. Хакеры, спецслужбы, вирусы и т.д. все норовят стянуть ваш wallet.dat. Вот и я поддался и решил зашифровать свой. Процесс шифрования происходил поздно вечером, спустя пару дней после начала майнинга и в состоянии небольшого алкогольного опьянения. Итак прошло 3 месяца до того момента когда я решил первый раз воспользоваться намайненым и каково же было мое удивления когда ни один из паролей которыми я пользовался не подошел. Срочно был создан новый wallet.dat без пароля а этот отложен до лучших времен. Я надеялся что с течением распространения Bitcoin найдутся «добрые» люди который напишут взломщик кошелька и я восстановлю свой пароль. Но время шло и такого решения все не было хотя в Интернете было множество постов на форумах с призывами о помощи восстановления забытых паролей, когда человек знал свой пароль но мог ошибиться в нескольких символах в нескольких местах.
Было принято решение писать подборщик паролей самому. В одном из сообщений на форуме bitcointalk.org/index.php?topic=85495.0;all я наткнулся на ruby скрипт который перебирает пароли для открытия кошелька. Разобравшись в коде выяснилось что алгоритм очень прост.
Далее я буду описывать что и как делал я, но поняв суть процесса написать свой подборщик паролей сможет любой программист.
Итак у меня есть старый wallet.dat за март 2012, есть клиент того времени bitcoin-0.5.2-win32-setup.exe. Для простоты было решено поставить Windows XP на виртуальную машину и все эксперименты проводить в ней. После установки Windows и клиента Bitcoin в ней был выключен сетевой адаптер виртуальной машины и первый раз запущен c:\Program Files\Bitcoin\bitcoin-qt.exe. Зачем выключать сетевой адаптер? При старте клиента кошелька он лезет в Интернет и скачивает всю цепочку транзакций, а это на текущий момент 14Gb — процесс долгий и не нужный в данном случае. В c:\Documents and Settings\Администратор\Application Data\Bitcoin\ появился новый wallet.dat. Далее закрываем bitcoin-qt.exe. Заменяем только что созданный wallet.dat на свой старый с забытым паролем. Теперь нужно положить в c:\Documents and Settings\Администратор\Application Data\Bitcoin\ рядом с wallet.dat файл bitcoin.conf со следующим содержимым:
rcpuse=zeta
rpcpassword=somerandomcrap
daemon=1
Далее идем в c:\Program Files\Bitcoin\daemon\ там находится файл bitcoind.exe. Он то нам и нужен. Замечу что клиент bitcoin-qt.exe должен быть выключен. Итак создаем bat файл со следующим содержимым:
bitcoind.exe -daemon
Запускаем его. Клиент запустился в режиме демона причем консольное окно не должно исчезнуть а как бы зависнуть. Сворачиваем его.
Теперь немного теории. Процесс подбора состоит в запуске еще одного экземпляра bitcoind.exe с параметрами командной строки:
bitcoind.exe walletpassphrase some_pass 20
где some_pass это новый пароль который пытается открыть кошелек. Процесс возвращает код в зависимости от результата. 0 если пароль подошел, во всех остальных случаях число будет отлично от 0. Например если bitcoind.exe сейчас не работает как демон будет выдано сообщение в консоль:
error: couldn't connect to server
если bitcoind.exe работает как демон то мы увидим:
error: {"code":-14,"message":"Error: The wallet passphrase entered was incorrect."}
Зная это, дело остается за малым — написать программу генерирующую новые пароли, запускающую bitcoind.exe с параметром walletpassphrase далее через пробел новый пароль потом пробел и число 20. Смотрим вернувший код и либо генерируем новый пароль либо сообщаем что пароль найден.
Свою реализацию я писал на с++. Вот часть кода запуска:
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
std::string sFull= " walletpassphrase "+sPass+" 20";
if(!CreateProcess("bitcoind.exe", sFull.c_str(), NULL, NULL,FALSE, 0,NULL,NULL,&si,&pi))
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD exitCode=0;
// Get the exit code.
GetExitCodeProcess(pi.hProcess, &exitCode);
if (exitCode==0)
resTry=pswSuccess;
else
{
if (exitCode==87)
resTry=pswTryAgain;
}
Поскольку обычно я использую несколько вариантов паролей отличающихся в конце был составлен список возможных вариантов начал, список символов которые могут быть в конце и суть перебора была брать начало фразы и брутфорсить конец фразы. Было создано несколько копий виртуальных машин с разными началами и процесс пошел. Поскольку сколько бы занял процесс перебора не известно — было решено написать клиент-сервер приложение где сервер генерит пароли и шлет клиентам клиенты пробуют и либо просят новую порцию паролей либо сообщают что пароль найден. К слову сказать как раз когда я заканчивал писать это приложение и тестировал его — мой пароль был найден. И все же я закончил его и вот результаты нескольких компов:
intel i7 2600K - 1900 паролей в минуту
intel i5 2500K - 920 паролей в минуту
amd a8-3870@3.4Gh - 900 паролей в минуту
intel q9650 - 520 паролей в минуту
Надеюсь мой опыт поможет кому то еще восстановить свой пароль. Удачи.