В начале 2012 года я впервые услышал о криптовалюте Bitcon. Сразу было решено — майнингу быть. Зарегистрировался на https://mining.bitcoin.cz и начал майнить. Везде, где читал про Bitcoin, авторы настойчиво рекомендовали шифровать кошелек. Хакеры, спецслужбы, вирусы и т.д. — все норовят стянуть ваш wallet.dat. Вот и я поддался и решил зашифровать свой. Процесс шифрования происходил поздно вечером, спустя пару дней после начала майнинга и в состоянии небольшого алкогольного опьянения. Итак, прошло 3 месяца до того момента, когда я решил впервые воспользоваться намайненым, и каково же было мое удивления, когда ни один из паролей, которыми я пользовался, не подошел. Срочно был создан новый wallet.dat без пароля, а этот отложен до лучших времен. Я надеялся, что с распространением Bitcoin найдутся «добрые» люди, которые напишут взломщик кошелька, и я восстановлю свой пароль. Но время шло, и такого решения все не было, хотя в Интернете было множество постов на форумах с призывами о помощи восстановления забытых паролей, когда человек знал свой пароль, но мог ошибиться в нескольких символах в нескольких местах.
Было принято решение — писать подборщик паролей самому. В одном из сообщений на форуме я наткнулся на 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 [email protected] — 900 паролей в минуту;
- intel q9650 — 520 паролей в минуту.
Надеюсь, мой опыт поможет кому-то еще восстановить свой пароль. Удачи.
Релоцировались? Теперь вы можете комментировать без верификации аккаунта.