Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

articles:asm.inject [2017/09/05 02:55] (текущий)
Строка 1: Строка 1:
 +====== asm.inject ======
 +<​sub>​{{asm.inject.odt|Original file}}</​sub>​
 +
 +====== ручная троянизация приложений под windows ======
 +
 +крис касперски ака мыщъх, FreeBSD@smtp.ru
 +
 +**время тупых троянов давно прошло. сегодня уже никто не пытается сокрушить диск или удалить все файлы под чистую. такой троян будет слишком заметен,​ а потому навряд ли получит большое распространение. гораздо заманчивее внедрить на компьютер бакдор или шпион для перехвата паролей,​ электронных кошельков,​ номеров кредитных карт и т. д. как это слелать?​ а вот как!**
 +
 +===== введение =====
 +
 +Крупные компании и синдикаты пишут свои собственные программы (например,​ привлекательные хранители экрана) с закладками внутри. Соблазненный народ так и прет, а синдикат пожинает урожай.
 +
 +Но так то синдикат! Написать такую программу в одиночку практически нереально,​ даже есть хвост разорвать,​ поэтому,​ хакеры предпочитают модифицировать уже существующие. Например,​ можно выпустить "​новую"​ версию AVP Pro, или выложить на варезный сайт взломанную софтину,​ которую тут же утянет голодный народ. А файлобменные сети? Да через них не меньше половины всего Интернет-траффика проходит! Стоит только забросать туда программу и уже никто не сможет ее удалить!
 +
 +Разумеется,​ это не руководство к немедленному действию. Скорее — предостережение. Чтобы научиться разоблачать троянизированные приложения,​ необходимо научиться троянизировать самому. Сухая теория еще никого не доводила до добра. Хочешь научиться самообороне — учись драться.
 +
 +Наши эксперименты будут носить совершенно невинный характер. Мы возьмем стандартный notepad.exe и будем над ним издеваться,​ предварительно разорвав лицензионное соглашение от Microsoft на мелкие куски. Оно нам больше не понадобится. Модификация notepad'​а аннулирует все льготы,​ обязательства и гарантии со стороны Microsoft. Свежую Windows со скидкой уже не получишь! Ну и больно надо! Поставим Linux! Но это потом, а пока…
 +
 +{{asm.inject_Image_0.png?​552}}
 +
 +Рисунок 1 текст дрозофилы,​ набранный в редакторе WinAsmStudio
 +
 +===== что нам понадобиться =====
 +
 +Большинство хакерских статей,​ рассказывающих о троянизации приложений,​ предлагает напрямую править их в HIEW'​е или любом другом HEX-редакторе. Но это порочная практика (живодерство сплошное)! И к тому же полноценную программу в HIEW'​е не напишешь,​ а если и напишешь,​ то потом не изменишь,​ ведь чтобы добавить одну-единственную команду зачастую приходится перебивать весь код целиком.
 +
 +Поступим умнее! Наберем программу в своем любимом редакторе,​ например,​ TASMED, WinAsm Studio или FAR'е и откомпилируем ее FASM'​ом. Полученный двоичный файл легко вставляется HEX-редактором в любой экзек. Ну… или почти любой.
 +
 +Еще нам потребуется IDA Pro или другой приличный дизассемблер,​ которым мы будем исследовать подопытный файл. Отладчик — Soft-Ice, MS DBG, OllyDbg. Он поможет найти ошибки во внедряемом коде. Крайне маловероятно,​ что написанная нами программа заработает с первого раза, поэтому без отладчика далеко не уплывешь.
 +
 +Остальные ингредиенты (пиво/​квас/​сигареты) по вкусу, но пива побольше.
 +
 +===== куда податься?​ =====
 +
 +Проще всего внедряться в свободное место готового файла, который мы будем звать дрозофилой,​ а сам внедряемый код — бациллой. Если свободного места ни хрена нет, можно раздвинуть последнюю секцию и внедриться в нее, но это намного сложнее,​ поэтому такой способ здесь не рассматривается,​ а всех любопытствующих мы отсылаем к "​пути воина — техника внедрение в PE-файлы",​ который можно отыскать на сайте www.wasm.ru.
 +
 +Типичный PE-заголовок вместе с таблицей секций и OLD-EXE заголовком занимает чуть больше 200h байт, а минимальное физическое выравнивание внутри файла (File Alignment),​ которое только поддерживает Windows, как раз и составляет 200h! Таким образом,​ в нашем распоряжении оказывается практически 200h незанятых байт или даже больше того! Для ускорения загрузки файла большинство линкеров выравнивает адрес начала первой секции не по File Alignment,​ а по Section Alignment,​ который никак не меньше 1000h. Как следствие — наши "​владения"​ увеличиваются аж до E00h байт. Для ассемблерных программ это целый материк,​ на котором и слона разместить можно, ну если не слона, то полноценную бациллу — точно! В упакованных файлах,​ заголовок прижат к первой секции практически вплотную,​ поэтому,​ перед началом внедрения их необходимо распаковать.
 +
 +Отроем notepad.exe в редакторе HTE и будем прокручивать его до тех пор, пока не врежемся в напаханную целину сплошных нулей. В нашел случае она начинается с адреса 2F0h (именно 2F0h, а не 2EFh, поскольку последний нуль служит завершителем строки WINSPOOL.DRV и трогать его нежелательно). Из любви к круглым цифрам,​ выберем 300h, хотя, выравнивать начало внедряемого кода совершенно необязательно.
 +
 +{{asm.inject_Image_1.png?​553}}
 +
 +Рисунок 2 поиск места для внедрения бациллы в редакторе HTE
 +
 +Теперь необходимо определить базовый адрес загрузки файла. Он содержится в заголовке. Не выходя из HTE нажмем <F6> (mode) и выберем "​pe/​header"​. Там, вразделе "​optional header: NT fields",​ будетполе "image base". Это и есть базовый адрес, в нашем случае равный 1000000h. Так же необходимо убедиться,​ что заголовок действительно распахнут на всю ширину (он лежит в том же разделе в поле "size of headers"​) и в нашем случае равен 600h. Это значит,​ что при загрузке файла в память отображаются только первые 600h байт от его начала,​ а поскольку мы начинаем внедрение с 300h байта, размер бациллы не может превышать 600h –300h == 300h байт. Плохо! Очень плохо! Но при желании это поле можно увеличить до 1000h. Главное,​ чтобы оно не превышало Section Alignment,​ указанного ниже. Так же необходимо убедиться,​ что файл не содержит перемещаемых элементов,​ которые могут испортить всю малину. Смотрим,​ если поле "​baserelocationtable"​ в разделе "​optionalheader:​ directories"​ не равно нулю, лучше всего отказаться от внедрения. При большом желании можно внедриться и в перемещаемые файлы, это лишь чуть-чуть труднее,​ однако,​ не будем лезть в дебри и для начала разберемся с малым.
 +
 +Контрольную сумму (checksum) править необязательно. Windows все равно ее игнорирует. Антивирусы,​ кстати говоря,​ тоже. Я всегда говорил,​ что они тупые создания! Впрочем,​ для перестраховки это поле можно обнулить или рассчитать новую контрольную сумму с помощью утилиты editbin, поставляемой с компилятором Microsoft Visual C++.
 +
 +{{asm.inject_Image_2.png?​553}}
 +
 +Рисунок 3 основные поля дрозофилы,​ ответственные за внедрение бациллы
 +
 +Так же можно внедряться в конец кодой секции,​ в хвосте которой "​пасется"​ до FFFFh свободных байт, оставленных для выравнивания,​ однако,​ чаще всего их количество не превышает 50h, чего для полноценной программы явно недостаточно,​ но на всякий случай будем иметь эту заначку ввиду. ​
 +
 +Берем все тот же HTE, привычным движением руки давим <​F6>​(mode),​ "​pe/​header"​ и смотрим атрибуты секции .text (в некоторых случаях она называется CODE или как-то еще). Как быстро перейти в конец секции .text? Очевидно,​ необходимо переместиться на начало следующей секции (в нашем случае эта секция .data), а затем вернуться на один байт назад.
 +
 +Переводим HTE в режим страничного имиджа (<​F6>,​ "​pe/​image"​),​ давим <F5> (goto) и говорим "​section("​.data"​)",​ заставляя редактор перейти к началу секции "​.data"​. Переводим курсор на несколько строк вверх и… здравствуй,​ хвост секции .text! Нулевые байты (которым соответствует ассемблерная команда add [eax],​al) никем не заняты и могут использоваться по нашему усмотрению. В данном случае здесь содержится 38h байт. Хм, не слишком-то длинный хвост. Бывают хвосты и подлиннее!
 +
 +{{asm.inject_Image_3.png?​553}}
 +
 +Рисунок 4 незанятый хвост секции .text, готовый к внедрению бациллы
 +
 +===== системные вызовы и библиотечные функции =====
 +
 +Бацилла (если это только не вещь в себе по типу океана Соляриса),​ должна как-то взаимодействовать с внешним миром: открывать файлы, устанавливать сетевые соединения,​ выводить ругательные сообщения и т. д. Обычно для этого используется прямой вызов API-функций. Но это не лучший вариант. Намного удобнее использовать высокоуровневые библиотечные функции,​ доставшиеся бацилле в наследство от дрозофилы. Согласитесь,​ намного удобнее открывать файл с помощью _fopen, чем CreateFile. Одних только аргументов в последнем случае потребуется миллион!
 +
 +Библиотечные функции легко распознаются при помощи IDA Pro. Вот, например:​
 +
 +{{asm.inject_Image_4.png?​552}}
 +
 +Рисунок 5 библиотечные функции,​ автоматически распознанные IDA Pro
 +
 +Мы видим, что адрес функции _fopen равен 401988h, значит,​ ее вызов будет выглядеть приблизительно так:
 +
 +pushaRb; "​rb"​ указатель на строку с режимом открытия файла
 +
 +pushaName; указатель на имя файла (аргументы заносятся справа налево)
 +
 +call401988hl вызываем функции _fopen
 +
 +addesp, 8; удаляем аргументы из стека
 +
 +Листинг 1 пример вызова стандартной библиотечной функции языка Си
 +
 +Однако,​ использовать библиотечные функции можно только после того, как отработает Start-Up (стартовый код), иначе у нас ничего не получается. В этом нам вновь поможет IDA Pro, распознающая функцию main (WinMain) языков Си/Си++ и процедуру Begin на Паскаль. В notepad'​е ее вызов расположен по адресу 1006571h. Здесь находится call 100299Eh,​ где 100299Eh – адрес WinMain. Для внедрения дрозофилы,​ достаточно изменить call 100299Eh на свой адрес, в смысле адрес свой бациллы.
 +
 +{{asm.inject_Image_5.png?​552}}
 +
 +Рисунок 6 функция WinMain в стартовом коде
 +
 +А что делать,​ если библиотечные функции не распознаны или среди них нет той, что нужна нам? Тогда можно обратиться к импорту дрозофилы и поискать там. В IDA Pro этоделаетсятак:​ View  Open Subview  Imports:​
 +
 +{{asm.inject_Image_6.png?​552}}
 +
 +Рисунок 7 функции,​ импортируемые из USER32.DLL
 +
 +Вот, например,​ адрес функции MessageBoxW равен 01001204h. На самом деле, это еще не сам адрес, а только указатель на него, инициализируемый на стадии загрузки,​ а потому вызов функции будет выглядеть так:
 +
 +xoreax,eax; обнуляем eax
 +
 +push30h; uType
 +
 +pushlpCaption;​ lpCaption
 +
 +pushlpText; lpText
 +
 +pusheax; hWnd
 +
 +calldword [1001204h]; вызываемфункции MessageBoxW
 +
 +Листинг 2 пример вызова API-функции из импорта дрозофилы
 +
 +Но в некоторых случаях,​ в импорте искомой функции нет функции. Что тогда? Есть два пути: использовать связку LoadLibrary\GetProcAddress или сканировать импорт вручную. Оба этих способа уже рассматривались в статье "​техника написания переносимого shell-кода",​ опубликованной в таком-то номере журнала,​ так что не будет здесь повторятся.
 +
 +===== память в кредит =====
 +
 +Кодовая секция недоступна для записи. Где же дрозофила будет хранить свои переменные?​ Проще всего воспользоваться стандартной Сишной функций malloc или API-функций VirtualAlloc,​ причем выделенную память можно даже не освобождать — при закрытии приложения Windows это сделает самостоятельно.
 +
 +Еще проще выделить на стеке. Команда SUB ESP,​ n – выделяет n байт, а ADD ESP,​ n – возвращает их обратно. Однако,​ типичный объем стека составляет всего несколько мегабайт,​ а этого количества не всегда достаточно,​ так что на практике оба способа приходится комбинировать друг с другом.
 +
 +===== внедрение не во сне, а на яву =====
 +
 +Вот и подошли вплотную к внедрению. Создадим бациллу,​ выводящую простое диалоговое окно перед запуском дрозофилы. Открываем FAR или любой другой редактор и пишем. А что мы, собственно,​ пишем?
 +
 +Поскольку это не совсем обычный файл, транслятор должен знать с какого адреса начинать ассемблирование. Мы решили внедряться в дрозофилу со смещения 300h, так? Базовый адрес загрузки равен 1000000h, следовательно,​ первый байт бациллы соответствует адресу 1000300h. Так и запишем:​ "​ORG 1000300h"​. ORG – это директива,​ отвечающая за базирование файла.
 +
 +Еще необходимо указать "​USE32",​ чтобы FASM знал, что это 32-разрядный код. Вот, собственно,​ и все отличия от нормальных файлов. Дальше можно кодить как обычно. Ах да, чуть было не забыл. Ведь это notepad.exe под Windows NT и, следовательно,​ ASCII-функций в нем нет, а импортировать их вручную нам лениво. Поскольку,​ FASM не поддерживает уникода,​ перекодировку приходится осуществлять самостоятельно. В FAR'е для этого можно набросать следующий макрос:​ "'​ Right '​ ,​ 0 ,"​ (одинарная кавычка,​ стрелка влево, одинарная кавычка,​ запятая,​ ноль, запятая),​ который будет преобразовывать ASCII строки в UNICODE. Правда,​ только на английском языке. Для русского все намного более заморочено. Проще всего взять notepad.exe,​ записать в нем строку,​ сохранить,​ как уникод,​ и вставить получившийся файл в исходный текст при помощи db.
 +
 +Законченный текст программы может выглядеть например так:
 +
 +org1000300h;​ адрес начала бациллы в памяти
 +
 +use32; 32-разрядный код
 +
 +pushad; сохраняем все регистры
 +
 +xor eax,eax; EAX := 0
 +
 +pusheax; uType (диалог с кнопкой ОК)
 +
 +pushcaption;​ указатель на заголовок
 +
 +pushtext; указатель на текст в окне
 +
 +pusheax; hWnd (нет владельца)
 +
 +call dword [1001204h]; MessageBoxW
 +
 +popad; восстанавливаем регистры
 +
 +jmp 100299Eh; передаем управление WinMain
 +
 +ret; возвращаемся в стартовый код
 +
 +caption db '​h',​0,'​e',​0,'​l',​0,'​l',​0,'​o',​0,​0,​0
 +
 +text db '​I',​0,'​ ',​0,'​l',​0,'​o',​0,'​v',​0,'​e',​0,'​ ',​0,'​y',​0,'​o',​0,'​u',​0,​0,​0
 +
 +Листинг 3 исходный текст простейшей бациллы,​ признающийся в любви
 +
 +Ассемблируем программу FASM'​ом и на выходе получаем двоичный файл (для определенности пусть это будет inject.bin). Запускаем HTE, открываем notepad.exe и тут же открываем inject.bin (<F3> (open), "​inject.bin). При помощи shift'​а выделяем весь код бациллы и ждем <​Ctrl-Ins>​ для копирования в буфер обмена. Переключаемся на notepad.exe (<​Alt-2>​),​ находясь в hex-режиме подводим курсор к смещению 300h и нажимаем <​Shift-Ins>,​ чтобы вставить. Сохраняем изменения по <F2> и… открываем пиво. Первый этап внедрения завершен. Теперь можно послушать BurningPoint,​ собраться с мыслями и немного расслабиться.
 +
 +{{asm.inject_Image_7.png?​553}}
 +
 +Рисунок 8 вставка бациллы в дрозофилу
 +
 +И вот наступает последний решительный этап: перехват управления у WinMain, точка вызова которой,​ как мы помним,​ лежит по адресу 1006571h. Переводим HTE в дизассемблерный режим (<F6> (mode), pe/image), жмем <F5> (goto) и говорим:​ "​1006571h"​. Теперь нажимаем <​Ctrl-A>​ (Assemble) и вводим "​CALL 1000300h",​ где 1000300h — адрес начала бациллы. Кстати говоря,​ HIEW для этой цели непригоден,​ поскольку неправильно ассемблирует код и все летит к черту. Во всяком случае,​ версия 6.09 ведет себя именно так, а более поздние не проверял. Зачем платить деньги за коммерческий HIEW, когда есть и бесплатные HEX-редакторы не хуже!?
 +
 +HTE все ассемблирует правильно,​ но переходить к бацилле по перекрестной ссылке наотрез отказывается,​ считая,​ что ее нет. Ну нет — и не надо. Нажимаем <F2> (save), чтобы изменения возымели силу и выходим по <​F10>​.
 +
 +{{asm.inject_Image_8.png?​553}}
 +
 +Рисунок 9 перехват управления у WinMain
 +
 +C замираем сердца запускам notepad.exe и… Оторвать мыщъх'​у хвост это работает,​ выдавая симпатичное диалоговое окно:
 +
 +{{asm.inject_Image_9.png?​115}}
 +
 +Рисунок 10 сообщения от бациллы
 +
 +===== обход антивирусов =====
 +
 +И все бы было у нас хорошо,​ если бы антивирусы ни ругались на инфицированный файл. А они ругаются,​ причем матом, что портит нам весь бизнес и создает угрозу отрыва хвоста и детородного органа вместе с ним:
 +
 +{{asm.inject_Image_10.png?​552}}
 +
 +Рисунок 11 реакция антивирусов на бациллу
 +
 +Вернемся к адресу 1006571h, в котором происходит передача управления на бациллу и посмотрим,​ что тут можно предпринять:​
 +
 +100656a ! ff1594100001calldword ptr [KERNEL32.dll:​GetModuleHandleA]
 +
 +1006570 ! 50pusheax
 +
 +1006571 ! e88a9dffffcall1000300h
 +
 +1006576 ! 894598mov[ebp-68h],​ eax
 +
 +1006579 ! 50pusheax
 +
 +100657a ! ff1568110001calldword ptr [MSVCRT.dll:​exit]
 +
 +Листинг 4 окрестности точки в которой происходит перехват управления
 +
 +Очевидно,​ антивирус отслеживает команду CALL, эмулируя ее выполнение. А как на счет передачи управления через ret? Интересно,​ сможет ли он с ним справиться?​ Давайте заменим CALL 1000300h на PUSH 1000300h/​RET. Это ведь несложно. Правда,​ возникает одна проблема,​ — "​чистый"​ CALL на байт короче и этого самого байта нам как раз не хватает! К счастью,​ следом за CALL'​ом расположена команда MOV [EBP-68h],​ EAX,​ копирующая код возврата в локальную переменную,​ а кому он сейчас нужен? Поэтому мы можем смело оттяпать от нее один байт и перекрыть оставшиеся два байта операциями NOP. (Как вариант,​ можно перенести часть Start-Up кода внутрь бациллы,​ но в нашем случае это излишне).
 +
 +Подводим курсор к 1006571h, жмем <​Ctrl-A>​ и пишем PUSH 1000300h/​RET/​NOP/​NOP. К сожалению,​ HTE позволяет ассемблировать только одну команду за раз, поэтому жать <​Ctrl‑A>​ приходится многократно. Еще необходимо в теле бациллы заменить JMP 100299Eh/​RET на CALL 100299Eh/​JMP 1006579h (мы ведь заменили CALL на эквивалент JMP'​а,​ поэтому,​ для достижения гармонии необходимо проделать обратную ему операцию).
 +
 +Сохраняем изменения по <F2>, выходим и… Бацилла по прежнему работает как миленькая,​ но антивирус уже не ругается. Обиделся,​ наверное. Или уснул.
 +
 +{{asm.inject_Image_11.png?​552}}
 +
 +Рисунок 12
 +
 +Вообще-то,​ это не самый надежный антивирусный прием, зато самый простой! Остальные можно найти в статье "​техника выживания в мутной воде или как обуть антивирус",​ опубликованной в таком-то номере хакера.
 +
 +===== заключение =====
 +
 +Созданная нами бацилла предельно проста и пользы от нее немного. Но ведь и вреда никакого! Более сложные программы пишутся аналогичным способом и каждый из нас сможет справится с этой задачей самостоятельно,​ так что не будем охлаждать творческий стимул и выдавать на гора кучу готовых полуфабрикатов.
 +
 +