Различия

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

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

articles:malware-discover [2017/09/05 02:55] (текущий)
Строка 1: Строка 1:
 +====== malware-discover ======
 +<​sub>​{{malware-discover.odt|Original file}}</​sub>​
 +
 +====== контрразведка с soft-ice в руках ======
 +
 +крис касперски ака мыщъх, no-email
 +
 +**антивирусы (даже со всеми апдейтами) далеко не всегда распознают малварь и опытные хакеры доверяют только своим собственному хвосту,​ отладчику ****soft****-****ice**** и другому низкоуровневому инструментарию,​ позволяющему пробурить нору до самого ядра и разоблачить зловредные программы,​ где бы они ни скрывались!**
 +
 +===== введение =====
 +
 +Во времена MS-DOS ручная чистка компьютера — была обычном делом. Количество исполняемых файлов измерялось десятками,​ и существовало не так уж и много мест, пригодных для внедрения малвари (под //​малварью//​ — от английского //​**malware**//​ — здесь и далее по тексту подразумевается вредоносное программное обеспечение — вирусы,​ черви, шпионы и т. д.). С приходом Windows все изменилось. Из крохотного поселка операционная система превратилась в огромный,​ стремительно разрастающийся мегалополис,​ среди сотен тысяч файлов которого может спрятаться и слонопотам.
 +
 +Обнаружить качественно спроектированную и грамотно заложенную закладку усилиями одного человека за разумное время — навряд ли возможно. Намного проще (да и быстрее) переустановить Windows с нуля. К счастью,​ качественная малварь — огромная редкость,​ практически не встречающая в живой природе и в основном приходится сталкиваться с пионерскими поделками,​ оставляющими после себя кучу следов и легко различимыми с помощью soft-ice и сопутствующих ему утилит.
 +
 +Весь вопрос в том — как правильно ими пользоваться. Ну, установили мы soft-ice, нажали <​CTRL-D>,​ увидели черный экран… Дальше-то что?! А вот дальше на сцене появился мыщъх и, плюхнувшись в кресло (предварительно подтолкнув под себя хвост),​ начинает делиться хакерскими секретами.
 +
 +{{malware-discover_Image_0.jpg}}
 +
 +Рисунок 1 Windows – это целый мегалополис
 +
 +===== время тоже оставляет отпечатки =====
 +
 +Чаще всего малварь копирует свою тушу в новый файл со случайным или фиксированным названием,​ реже — внедряется в уже существующие (что требует не только знания устройства PE-формата,​ но и определенных привилегий,​ в частности,​ из-под пользовательского аккаунта системные файлы просто так не заразишь). При этом //​**подавляющее большинство **////​**malware**////​**-писателей забывают скорректировать дату/​время создания файла, выдавая себя с головой.**//​
 +
 +Допустим,​ мы запустили файл сомнительного происхождения и хотим узнать – не натворил ли он чего в системе?​ Пуск  Найти  Файлы и Паки  Параметры Поиска  Файлы созданные за xxx последних дней (в нашем случае за один). Все изменения,​ произошедшие за последние сутки в системе становятся видны как на ладони! Как вариант:​ в FAR'е устанавливаем режим сортировки по дате создания (<​CTRL-F8>​) и заходим во все "​злачные"​ каталоги типа WINNT, System32 и т. д. Файлы, созданные последними,​ будут в самом верху. Прием простой,​ как паровой котел, но чрезвычайно эффективный!
 +
 +{{malware-discover_Image_1.png}}
 +
 +Рисунок 2 поиск файлов,​ созданных за последнее время, с помощью штатных средств Windows – в данном случае мы видим файл hldrrr.exe, "​окопавшийся"​ в каталоге C:​\WINNT\system32
 +
 +Конечно,​ чем позже мы спохватимся,​ тем сложнее отличить "​легальные"​ файлы от "​нелегальных",​ особенно если на компьютер ставится большое количество самого разнообразного программного обеспечения. Но все файлы, устанавливаемые инсталлятором (где он их не размещал — в ProgramFiles,​ WINNT или System32), имеют одну и ту же дату создания с небольшим разбросом по времени (ведь файлы создаются не параллельно,​ а последовательно),​ поэтому их стразу можно исключить из списка подозреваемых. А оставшиеся — подвергнуть тщательному допросу (см. врезку "​признаки вредоносных файлов"​).
 +
 +{{malware-discover_Image_2.png}}
 +
 +Рисунок 3 исследование даты создания файлов при помощи FAR'а
 +
 +Естественно,​ дата создания файла элементарно изменяется средствами win32-API и малвари при желании ничего не стоит замаскироваться. Однако,​ //**на **////​**NTFS**////​**-разделах каждый файл обладает множеством "​невидимых"​ атрибутов,​ до которых нельзя дотянуться через **////​**API**//​. В частности,​ атрибут 30h (**$****FILE****_****NAME****) **помимо стандартных времен создания/​модификации/​последнего обращения,​ хранит время последней модификации данной записи MFT (MasterFileTable – специального мастерфайла,​ содержащего информацию обо всех остальных объектах файловой системы). У "​честных"​ файлов время создания и время последней модификации MFT всегда совпадает,​ а если это не так — мы имеем дело с подделкой. Еще существует атрибут 10h (**$****STANDARD****_****INFORMATION**),​ так же хранящий информацию о времени создания/​модификации/​последнего доступа файла и времени последней модификации MFT, однако,​ в отличии,​ от атрибута 30h, здесь время последней модификации MFT автоматически обновляется всякий раз, когда файлу выделяется новая порция кластеров,​ а потому со временем его создания оно может и не совпадать.
 +
 +Существует не так уж и много утилит,​ отображающих содержимое MFT в удобочитаемом виде. Однаизних — **NtExplorer**от Runtime Software. Грубо говоря,​ это NortonDiskEditor,​ но только под NTFS. К сожалению,​ NtExplorer не поддерживает ни плагинов,​ ни скриптов,​ поэтому,​ быстро вывести список файлов с поддельными датами создания не получается и каждый из них приходится перебирать "​руками",​ что очень сильно напрягает,​ но… NTFS совсем несложная (по нынешним меркам) файловая система,​ а все ее основные структуры давным-давно реконструированы,​ документированы и выложены в Сеть: http://​linux-ntfs.sourceforge.net. Создание программы,​ выполняющий автоматизированный поиск "​поддельных"​ файлов у не займет много времени,​ тем более, что подробное описание NTFS можно найти в моей книге "**la technique de la restitution des données**"​. В общем, дорогу осилит идущий!
 +
 +{{malware-discover_Image_3.png}}
 +
 +Рисунок 4 обнаружение файла с поддельным временем создания при помощи RuntimeNtExplorer — FAR утверждает,​ что файл создан 07.05.2004, в то время как соответствующая ему запись в MFT модифицировалась 18.07.2006
 +
 +===== дерево процессов =====
 +
 +Обычно,​ малварь создает свой собственный процесс (реже — внедряется в чужие),​ при этом у нее возникает вполне естественное желание скрыть этот процесс,​ убрав его из "​Диспетчера Задач"​ и прочих системных утилит. Как это она делает?​ Для предоставления информации о процессах NT поддерживает два механизма:​ набор документированных процедур **TOOLHELP****32** (доставшийся в "​наследство"​ от 9x), реализованных в KERNEL32.DLL,​ и недокументированная функция **NtQuerySystemInformation**,​ экспортируемая NTDLL.DLL, и представляющую собой тонкую "​обертку"​ вокруг системного сервиса 97h, реализованного в NTOSKRNL.EXE. На самом деле, главная функция TOOLHELP32 — CreateToolhelp32Snapshot — полностью опирается на NtQuerySystemInformation,​ так что фактически механизм у нас один, только интерфейсы разные.
 +
 +Малварь может легко перехватить процедуры Process32First/​Process32Next из TOOLHELP32, только это ей ничего не даст, поскольку,​ практически все утилиты ("​Диспетчер Задач",​ FAR и даже примитивный tlist.exe из SDK) работают исключительно через NtQuerySystemInformation (что легко подтверждается установкой точки останова в soft‑ice). Однако,​ перехватить NtQuerySystemInformation с прикладного уровня ничуть не сложнее,​ чем процедуры из набора TOOLHELP32! Существует множество путей как это сделать:​
 +
 +  - **модифицировать ****NTDLL****.****DLL**** на диске**,​ установив в начало функции NtQuerySystemInformation команду перехода на свой обработчик (расположенный где-нибудь в свободном месте внутри NTDLL.DLL), и "​вычищающий"​ из выдаваемой ею информации всякое упоминание о себе. способ простой как барабан,​ но грязный и легко обнаруживаемый путем дизассемблирования NTDLL.DLL или сравнением ее с оригиналом;​ так же малвари придется противостоять SFC и установке ServicePack'​ов некоторые из которых обновляют NTDLL.DLL;
 +  - **модифицировать ****NTDLL****.****DLL****!****NtQuerySystemInformation** в памяти;​ поскольку NT поддерживает механизм copy-on-write,​ автоматически "​расщепляющий"​ страницы памяти при записи,​ модификация NTDLL.DLL приобретает локальный характер,​ ограниченный контекстом процесса-писателя. то есть, чтобы воздействовать на "​Диспетчер Задач",​ в него прежде необходимо внедриться! вот один из возможных сценариев:​ малварь создает свою DLL и прописывает ее в следующую ветку системного реестра:​ **HKLM\Software\Microsoft\Windows NT\CurrentVersion\windows\AppInit_DLLs,​ **в результате чего эта DLL после будет отображаться на _все_ процессы. для большей скрытности можно модифицировать NTDLL.DLL только в контексте тех процессов,​ которые используются для вывода списка задач (taskmng.exe,​ far.exe, tlist.exe и т. д.). //**в этом случае,​ заглянув отладчиком внутрь **////​**NtQuerySystemInformation**////​**,​ мы не найдем никаких следов малвари!**//​ можно, конечно,​ проверить AppInit_DLLs,​ но это не единственный способ внедрения,​ так что задача выявления малвари резко усложняется;​
 +  - **модифицировать таблицу импорта ****taskmng****.****exe**("​Диспетчер Задач"​),​ proclist.dll (плагин FAR'​а,​ ответственный за вывод списка процессов),​ tlist.exe на диске (или в памяти),​ подменив вызовов NtQuerySystemInformation своей собственной функций оберткой. такой перехват легко обнаруживается путем сравнения исполняемых файлов с их образом памяти,​ который может быть получен путем снятия дампа утилитой типа PE‑TOOLS или старым добрым Procdump'​ом,​ к тому же малвари придется дополнительно перехватывать GetProcAddress,​ чтобы отслеживать динамическую загрузку NTDLL.DLL;
 +При наличии прав администратора,​ малварь может проникнуть в NTOSKRNL.EXE и подменить сервис 97h своим собственным обработчиком. Тогда с прикладного уровня обнаружить зловредный процесс уже не удастся и придется спускаться на уровень ядра, подробно рассмотренное в разделе. "​восстановление SST".
 +
 +//​**Soft**////​**-**////​**Ice **////​**– единственная из всех известных мыщъх'​у программ,​ которая не использует **////​**NtQuerySystemInformation**////​** и для отображения списка процессов самостоятельно разбирает базовые структуры операционной системы**//,​ а потому легко выявляет скрытые процессы. ​
 +
 +{{malware-discover_Image_4.png}}
 +
 +Рисунок 5 soft-ice показывает процесс sysrtl, отсутствующий в "​Диспетчере Задач"​
 +
 +Теоретически,​ малварь может внедриться в soft-ice и перехватить любую из его команд (например,​ команду "​PROC"​),​ действуя по той же схеме, что и IceExt/​IceDump (благо,​ что обе утилиты распространяются в исходных текстах),​ но в живой природе такие "​монстры"​ пока что не встречались. Можно надеяться,​ что IceExt, скрывающий soft-ice от большинства защит, скроет его и от малвари,​ однако,​ при этом остается угроза сигнатурного поиска отладчика в памяти;​ к тому же на хакерских форумах не первый год обсуждается гипотетический алгоритм скрытия,​ перехватывающий функции переключения контекста и "​вытирающий"​ себя в промежутках между ними. Однако,​ реализация такого проекта упирается в непреодолимые практические трудности. Формат процессорных структур непостоянен и меняется от одной версии системы к другой,​ к тому же с ними взаимодействуют множество недокументированных функций,​ вызываемых в разное время из различных мест и малварь,​ пытающаяся замаскироваться,​ постоянно обрушивает систему в BSOD, чем сразу себя и разоблачает.
 +
 +Таким образом,​ будем считать,​ что //​**связки из **////​**soft**////​**-**////​**ice**////​** + IceExt для просмотра всех процессов (включая скрытые) вполне достаточно**//​.
 +
 +===== допрос потоков =====
 +
 +В последнее время все чаще и чаще малварь не создает для себя отдельный процесс (который очень легко заметить),​ а предпочитает внедряться в один из уже существующих. Для этого используются два механизма. В первом малварь выделяет в целевом процессе блок памяти функцией VirtualAllocEx,​ копирует себя через WriteProcessMemory и создает удаленный поток посредством CreateRemoteThread. Второй механизм начинается так же, как и первый,​ только вместо создания удаленного потока,​ малварь останавливает текущий поток процесса,​ и изменяет регистр EIP функцией SetThreadContext (естественно,​ предварительно сохранив его оригинальное значение через GetThreadContext),​ передавая управление своей собственной процедуре,​ вызывающей CreateThread,​ восстанавливающей EIP и "​размораживающей"​ ранее остановленный поток. Первый механизм работает только на NT, второй — на всех 32-разядных системах семейства Windows.
 +
 +Как обнаружить такой метод вторжения?​ Естественно,​ количество потоков атакуемого процесса увеличивается на единицу,​ однако,​ это еще не показатель. //​**Никогда и никогда не может сказать точно сколько у приложения должно быть потоков**//​. Даже его непосредственный разработчик! Проведем простой эксперимент. Запустим "​Блокнот"​ и, переключившись на Диспетчер Задач, увидим один-единственный поток. Теперь зайдем в меню "​файл"​ и скажем "​открыть"​. Количество потоков внезапно подскакивает аж по пяти! Закрываем окно открытия файла — один поток исчезает,​ остаются четыре. Что это за ерунда такая?​! Оказывается,​ все дело в динамических библиотеках SHLWAPI.DLL,​ RPCRT4.DLL и OLE32.DLL, "​обслуживающих"​ окно и порождающих свои собственные,​ дочерние,​ потоки. Некоторые драйвера так же могут порождать потоки в чужих приложениях (как правило,​ с целью вызова прикладных API). Нам необходимо как-то научиться отличать "​легальные"​ потоки от "​нелегальных",​ иначе наша борьба с малварью обречена.
 +
 +Вот идея, простая как 3х дюймовая дискета:​ //​**стартовый адрес легального потока лежит в пределах страничного имиджа (в секции .**////​**code**////​** и .**////​**text**////​**),​ а нелегального — в куче, т. е. области динамической памяти,​ выделенной функцией **////​**VirtualAllocEx**////​**.**//​ Чтобы разоблачить нелегалов,​ нам, прежде всего, понадобится карта адресного пространства. soft-ice отображает ее не в самом наглядном виде и лучше воспользоваться OllyDbg или PE-TOOLS.
 +
 +В OllyDbg в меню "​file"​ выбираем "​attach"​ и указываем процесс,​ чьи потоки мы будем исследовать. После успешного присоединения к процессу говорим "​view"​  "​memory"​ или давим <​ALT-M>​. Получаем карту следующего вида:
 +
 +{{malware-discover_Image_5.png}}
 +
 +Рисунок 6 карта памяти "​Блокнота",​ отображенная отладчиком OllyDbg
 +
 +Регионы,​ помеченныекак "​**Priv**"​ (сокращениеот "​private"​) принадлежатблокамдинамическойпамяти,​ "​**map**"​ (сокращениеот "​mapping"​) – проекциямфайлов,​ созданныхфункциямиCreateFileMapping/​MapViewOfFile),​ "​**Imag**"​ (сокращениеот "​imaging"​) – страничнымимиджамисполняемыхфайловилидинамическихбиблиотек.
 +
 +В PE-TOOLS для той же цели необходимо выделить процесс и в контекстом меню выбрать "​dumpregion",​ при этом на экране появится диалоговое окно с картой памяти — не такой подробное как у OllyDbg, но для нашей задачи вполне удовлетворительное.
 +
 +{{malware-discover_Image_6.png}}
 +
 +Рисунок 7 карта памяти "​Блокнота",​ отображенная утилитой PE-TOOLS
 +
 +Для дальнейший экспериментов нам понадобится программа,​ создающая пару потоков — "​честным"​ и "​нечестным"​ путем. Исходный код (с опущенной обработкой ошибок и других исключительных ситуаций) может выглядеть так:
 +
 +#include <​stdio.h>​
 +
 +#include <​windows.h>​
 +
 +// код потока,​ который ничего не делает,​ а только мотает цикл
 +
 +thread(){while(1);​}
 +
 +main()
 +
 +{
 +
 +void *p;// переменная многоцелевого назначения
 +
 +
 +
 +// создаем "​честный"​ поток
 +
 +CreateThread(0,​0,​(void*)&​thread,​0x999,​0,&​p);​
 +
 +
 +
 +// создаем "​нечестный"​ поток так, как это делает malware:
 +
 +// выделяем блок памяти из кучи, копируем туда код потока
 +
 +// ивызываем CreateThread
 +
 +p = VirtualAlloc(0,​ 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);​
 +
 +memcpy(p,​thread,​0x1000);​CreateThread(0,​0,​p,​0x666,​0,&​p);​
 +
 +
 +
 +// ждем нажатия на ENTER
 +
 +gets(&​p);​
 +
 +}
 +
 +Листинг 1 исходный код демонстрационной программы va_thread.c,​ компилируемой с настройками по умолчанию
 +
 +Компилируем,​ запускаем,​ заходим в soft-ice, даем команду "​THREAD -x"​ (вывод детальной информации о потоках) и смотрим полученный результат:​
 +
 +:THREAD -x
 +
 +Extended Thread Info for thread 374
 +
 +KTEB873CFDA0TID:​374Process:​ va_thread(11C)
 +
 +**Start EIP:​KERNEL32!SetUnhandledExceptionFilter+001A (77E878C1)**
 +
 +User Stack: 00030000 - 00130000Stack Ptr:​0012FD24
 +
 +Extended Thread Info for thread 238
 +
 +KTEB:​82007020TID:​238Process:​ va_thread(11C)
 +
 +**Start EIP:​KERNEL32!CreateFileA+00C3 (77E92C50)**
 +
 +User Stack:​00420000 - 00520000Stack Ptr:​FFFFFFFF
 +
 +Extended Thread Info for thread 30C
 +
 +KTEB:​82007AC0TID:​30CProcess:​ va_thread(11C)
 +
 +**Start EIP:​KERNEL32!CreateFileA+00C3 (77E92C50)**
 +
 +User Stack:​00530000 - 00630000Stack Ptr: FFFFFFFF
 +
 +Листинг 2 информация о потоках,​ сообщенная soft-ice (приводится в сокращенном виде)
 +
 +Вот так номер! soft-ice не смог определить истинные стартовые адреса потоков,​ заблудившись в недрах KERNEL32.DLL. Что ж, попробуем другой инструмент — **Process****Explorer** от Марка Руссиновича,​ весьма нехило разбирающегося во внутренностях операционных систем от Microsoft (и даже участвующим в написании книги "​WindowsNTInternals"​. Скачиваем (совершенно бесплатно) Process Explorer,​ запускаем,​ наводим курсор на "​va_thread.exe",​ далее в контекстом меню выбираем пункт "​Properties"​ и в открывшемся диалоговом окне переходим к вкладке "​Threads"​.
 +
 +{{malware-discover_Image_7.png}}
 +
 +Рисунок 8 ProcessExplorer от Марка Руссиновича не смог определить стартовый адрес "​нечестного"​ потока
 +
 +Что мы видим? Адреса двух потоков определены верно. Первый:​ va_thread.exe+0x1405,​ судя по адресу,​ представляет основной поток (адрес совпадает с точкой входа, что легко проверить в hiew'​е). Второй:​ va_thread.exe+0x1000 — это "​честно"​ созданный поток (что опять-таки проверяется по адресу в hiew'​е),​ а вот третий – **KERNEL****32.****DLL****+0****xB****700** – это "​нечестный"​ поток (а чем он еще может быть?​!),​ только его стартовый адрес определен неправильно!
 +
 +Призываем на помощь OllyDbg и пытаемся разобраться в ситуации самостоятельно,​ без всех этих прелестей автоматизации и прочих чудес технического прогресса. Подключившись к процессу va_thread.exe,​ в меню "​view"​ выбираем пункт "​thread"​ и… обнаруживаем не три (как ожидалось),​ а целых четыре потока!
 +
 +IdentEntryData blockLast errorStatusPriority
 +
 +050C7943B7007FFDB000ERROR_SUCCESSActive32 + 0
 +
 +0558000000007FFDC000ERROR_SUCCESSSuspended32 + 0
 +
 +055C000000007FFDE000ERROR_SUCCESSSuspended32 + 0
 +
 +0578000000007FFDD000ERROR_SUCCESSSuspended32 + 0
 +
 +Листинг 3 информация о четырех потоках,​ выданная OllyDbg
 +
 +Стартовый адрес (entry) определен только для одного из потоков — 50Ch да и тот, вероятно,​ служит для связки отлаживаемого процесса с OllyDbg. Стартовые адреса остальных потоков выставлены в ноль, но ведь это же не так!!!
 +
 +Щелкам мышью по потоку c идентификатором 558h (естественно,​ при следующем запуске программы,​ идентификаторы потоков будут другими) и получаем код следующего содержания,​ который (судя по карте памяти),​ принадлежит страничному имиджу,​ следовательно,​ это — легальный поток.
 +
 +40100055PUSH EBP
 +
 +4010018B ECMOV EBP,ESP
 +
 +401003B8 01000000MOV EAX,1
 +
 +40100885C0TEST EAX,EAX
 +
 +40100A74 02JE SHORT va_threa.0040100E
 +
 +40100CEB F5JMP SHORT va_threa.00401003
 +
 +Листинг 4 код потока 558h, находящегося в пределах страничного имиджа
 +
 +Переходим к окну стека, перемещая ползунок на самый низ. На дне стека видим аргумент,​ переданный потоку (второе двойное слово, в данном случае равное — 999h) и… стартовый адрес потока,​ лежащий в третьем двойном слово, и в данном случае равный 401000h, что полностью согласуется с листингом 1. (На самом деле, в зависимости от способа создания потока стартовый адрес может лежать как в третьем,​ так и во втором слове, поэтому автоматические утилиты и путаются).
 +
 +51FFDCFFFFFFFF ​ End of SEH chain
 +
 +51FFE079481F54 ​ SE handler
 +
 +51FFE479432B08 ​ KERNEL32.79432B08
 +
 +51FFE800000000
 +
 +51FFEC00000000
 +
 +51FFF000000000
 +
 +**51****FFF****400401000 ​ ****va****_****threa****.00401000;​ ******** стартовый адрес потока 558****h**
 +
 +51FFF800000999;​  аргумент,​ переданный потоку
 +
 +51FFFC00000000;​  дно пользовательского стека потока
 +
 +Листинг 5 на дне пользовательского стека пока 558h лежит стартовый адрес, вместе с переданным ему аргументом
 +
 +Переходим к следующему потоку — 55Ch. Код выглядит точно так как и раньше (ведь мы запустили два экземпляра одной и той же функции!),​ а вот содержимое дна стека слегка изменилось:​
 +
 +62FFDCFFFFFFFF ​ End of SEH chain
 +
 +62FFE079481F54 ​ SE handler
 +
 +62FFE479432B08 ​ KERNEL32.79432B08
 +
 +62FFE800000000
 +
 +62FFEC00000000
 +
 +62FFF000000000
 +
 +**62****FFF****400520000;​ ******** стартовый адрес потока 55С****h**
 +
 +62FFF800000666;​  аргумент,​ переданный потоку
 +
 +62FFFC00000000;​  дно пользовательского стека потока
 +
 +Листинг 6 на дне пользовательского стека пока 55Ch лежит стартовый адрес, вместе с переданным ему аргументом
 +
 +Как мы помним,​ 666h – это аргументы,​ переданные "​нечестной"​ копии потока,​ а 520000h – его стартовый адрес, принадлежащий (если верить карте памяти) блоку памяти,​ выделенному функцией VirtualAlloc:​
 +
 +AddressSizeOwnerSectionContainsTypeAccessInitial
 +
 +4000001000va_threaPE headerImagRRWE
 +
 +4010004000va_threa.textcodeImagRRWE
 +
 +4050001000va_threa.rdataimportsImagRRWE
 +
 +4060002000va_threa.datadataImagRRWE
 +
 +4100002000MapRR
 +
 +51E0001000PrivRWGuarRW
 +
 +51F0001000stack of thrPrivRWGuarRW
 +
 +**5200001000****Priv********RWE********RWE**
 +
 +62E0001000PrivRWGuarRW
 +
 +Листинг 7 карта памяти процесса va_thread (область памяти,​ принадлежащая потоку 55Ch, выделена полужирным)
 +
 +Последний поток — 578h представляет собой основной поток программы и хранит своей стартовый адрес _не_ в третьем,​ а во втором (!) двойном слове:
 +
 +12FFE0FFFFFFFF ​ End of SEH chain
 +
 +12FFE479481F54 ​ SE handler
 +
 +12FFE879432B18 ​ KERNEL32.79432B18
 +
 +12FFEC00000000
 +
 +12FFF000000000
 +
 +12FFF400000000
 +
 +12FFF800401405 ​ va_threa.<​ModuleEntryPoint>;​  стартовый адрес потока 578h
 +
 +12FFFC00000000;​  дно пользовательского стека потока
 +
 +Листинг 8 поток 578h хранит свой стартовый адрес не в третьем,​ а во втором двойном слове!
 +
 +Свершилось! Мы научились быстро и просто определять стартовые адреса потоков,​ надежно отличая "​левых"​ от "​правых"​. Кстати,​ чтобы каждый раз не сверяться с картой памяти можно использовать следующий трюк. Если при нажатии стартового адреса в контекстом меню OllyDbg присутствует строчка "​FollowinDisassembler"​ – он принадлежит страничному имиджу (т. е. легальному потоку) и, соответственно,​ наоборот.
 +
 +{{malware-discover_Image_8.png}}
 +
 +Рисунок 9 содержимое дна стека "​честного"​ (слева) и "​нечестного"​ потока (справа),​ у "​нечестного"​ отсутствует пункт "​FollowinDisassembler"​ в контекстом меню
 +
 +На самом деле, праздновать победу еще рано. Умная малварь может нас легко обмануть. Самое простое — подменить истинный стартовый адрес так, чтобы он указывал внутрь страничного имиджа целевого процесса (но в этом случае он должен совпадать с началом какой-нибудь процедуры,​ иначе мы тут же разоблачим обман). Более умная малварь использует хитрый способ внедрения — находит в целевом процессе функцию по стандартному прологу PUSH EBP/​MOV EBP,​ ESP (55h/​8Bh ECh),​ вставляет в ее начало jump на выделенный из кучи блок, где размещено ее тело, создает новый поток, начинающийся с jump, и тут же восстанавливает оригинальное содержимое хакнутой функции убирая jump и возвращая стандартный пролог. Еще остается вариант загрузить внутрь процесса динамическую библиотеку,​ принадлежащую малвари и запустить внутри нее новый поток.
 +
 +Во всех этих случаях анализ стартового адреса не даст никакого результата и внедрение зловредного кода останется незамеченным и //​**чтобы быть уверенным на все 100% необходимо трассировать каждый из потоков на предмет проверки его лояльности**//​. Потоки,​ порожденные малварью,​ либо шпионят за клавиатурой,​ либо открывают backdoor, либо рассылают спам. Проблема в том, что потоков (легальных) очень много, а современная малварь пишется уже не на ассемблере,​ а черт знает на чем (DELPHI, VisualBASIC) и полный анализ требует уймы времени,​ однако,​ как говорилось выше, умная малварь — большая редкость и подделкой стартовых адресов потоков никто не занимается.
 +
 +===== восстановление SST =====
 +
 +Для сокрытия своего присутствия в системе,​ малварь нередко внедряется в ядро системы и перехватывает один или несколько сервисов,​ например,​ функции NtQuerySystemInformation,​ про важность которой мы уже говорили. Ловить малварь на такой системе все равно, что бороться с ком. партией под ее руководством.
 +
 +Дизассемблирование NTDDLL.DLL показывает,​ что большинство низкоуровневых функций реализованы как "​переходники"​ к функциям ядра, интерфейс с которым осуществляется либо посредством прерывания INT 2Eh (NT, W2K), либо машинной командой SYSENTER (XP и выше).
 +
 +.text:​77F95BBDpublic ZwQuerySystemInformation
 +
 +.text:​77F95BBDZwQuerySystemInformation proc near
 +
 +.text:​77F95BBDarg_0= byte ptr  4
 +
 +.text:​77F95BBD
 +
 +.text:​77F95BBD B8 97 00 00 00moveax, 97h; NtQuerySystemInformation
 +
 +.text:​77F95BC2 8D 54 24 0leaedx, [esp+arg_0]
 +
 +.text:​77F95BC6 CD 2Eint2Eh
 +
 +.text:​77F95BC8 C2 10 00retn10h
 +
 +.text:​77F95BC8ZwQuerySystemInformation endp
 +
 +Листинг 9 функция ZwQuerySystemInformation в действительности представляет "​переходник"​ к системному сервису 97h
 +
 +Когда происходит вызов прерывания,​ процессор автоматически переключается с прикладного уровня (ring 3) в режим ядра (ring 0), передавая управление функции **KiSystemService**,​ реализованной внутри NTOSKRNL.EXE и опирающейся на Таблицу Системных Дескрипторов,​ она же SDT (SystemDescriptorTable). Собственно,​ дескрипторов в ней всего два — один для системных вызовов,​ другой — для драйвера win32k.sys, куда упрятали весь графический интерфейс. На серверах добавляется и третий дескриптор — IIS, назначение которого ясно из его названия.
 +
 +{{malware-discover_Image_9.png}}
 +
 +Рисунок 10 механизм реализации системных вызовов
 +
 +Дескриптор,​ отвечающий за системные вызовы,​ указывает на SystemServiceTable (Таблица Системных Вызовов),​ представляющую собой простой массив указателей на функции,​ которые _очень_ легко изменить (естественно,​ делать это нужно либо из режима ядра, либо с прикладного уровня,​ обратившись к псевдоустройству PhysicalMemory). Найти таблицу системных вызовов в памяти очень просто. "​Скармливаем"​ NTOSKRNL.EXE функции LoadLibrary и, используя возвращенный ей дескриптор,​ определяем адрес экспортируемой переменной **KeServiceDescriptorTable** через GetProcAddress(или разбираем таблицу экспорта вручную). Первое же двойное слово содержит указатель на SST, поэтому эффективный адрес требуемого системного сервиса по его "​магическому"​ номеру определяется так: addr == *(DWORD *)(**KeServiceDescriptorTable[0] + ****N*********sizeof****(****DWORD****))**,​ где N – номер сервиса,​ а addr – его эффективный адрес.
 +
 +Продемонстрируем эту технику на примере soft-ice:
 +
 +:dd
 +
 +:d KeServiceDescriptorTable
 +
 +0008:​8046AB80 **__804704D8__** 00000000 ​ 000000F8 ​ 804708BC ​ ..G...........G.
 +
 +:d 804704D8
 +
 +0008:​804704D8 804AB3BF ​ 804AE86B ​ 804BDEF3 ​ 8050B034 ​ ..J.k.J...K.4.P.
 +
 +0008:​804704E8 804C11F4 ​ 80459214 ​ 8050C2FF ​ 8050C33F ​ ..L...E...P.?​.P.
 +
 +0008:​804704F8 804B581C ​ 80508874 ​ 8049860A ​ 804FC7E2 ​ .XK.t.P...I...O.
 +
 +:u *(804704D8 + 97*4)
 +
 +ntoskrnl!NtQuerySystemInformation
 +
 +0023:​804BF933PUSHEBP
 +
 +0023:​804BF934MOVEBP,​ ESP
 +
 +0023:​804BF936PUSHFF
 +
 +0023:​804BF938PUSH804043A0
 +
 +0023:​804BF93DPUSHntoskrnl!_except_handler3
 +
 +Листинг 10 протокол работы с soft-ice, демонстрирующий получение адреса системного сервиса 97h
 +
 +Как мы видим, в данном случае,​ функция NtQuerySystemInformation никем не перехвачена,​ что очень хорошо!
 +
 +Чтобы просмотреть содержимое SST в soft-ice достаточно дать команду "​NTCALL"​. На "​стерильной"​ машине _все_ вызовы указывают внутрь NTOSKRNL.EXE,​ а если это не так, то их кто-то перехватил. Это может быть как зловредная малварь,​ так и вполне безобидный драйвер какого-нибудь защитного механизма или, например,​ брандмауэр.
 +
 +Для восстановления SST можно использовать ее копию, хранящуюся внутри NTOSKRNL.EXE,​ правда,​ найти ее на диске значительно сложнее,​ чем в памяти. Проще всего использовать отладочные символы (которые можно бесплатно сгрузить с сервера http://​msdl.microsoft.com/​download/​symbols с помощью библиотеки dbghelp.dll,​ входящей в состав бесплатного пакета DebuggingTools). Адресу SST соответствует метка _KiServiceTable и в моей версии системы она располагается по адресу 4704D8h (в файле):​
 +
 +.data:​004704D8 BF B3 4A 00 _KiServiceTabledd offset _NtAcceptConnectPort@24
 +
 +.data:​004704DC 6B E8 4A 00dd offset _NtAccessCheck@32
 +
 +.data:​004704E0 F3 DE 4B 00dd offset _NtAccessCheckAndAuditAlarm@44
 +
 +Листинг 11 копия таблицы системных вызовом,​ хранящаяся внутри NTOSKRNL.EXE
 +
 +А если отладочных символов нет? Тогда находим все перекрестные ссылки к **KeServiceDescriptorTable** (т. е. просто ищем ее адрес, записанный с учетом обратного порядка байт на x86, задом наоборот). Одна из них ведет к инструкции типа "​mov [mem],​ imm32"​ и представляет собой смещение оригинальной SST (imm32), записываемой в **KeServiceDescriptorTable[0]**. Как нетрудно убедиться дизассемблером,​ изначально SDT пуста и инициализируется на стадии загрузки ядра не экспортируемой функцией **KiInitSystem**.
 +
 +.data:​0046AB80 ; Exported entry 516. KeServiceDescriptorTable
 +
 +.data:​0046AB80 public _KeServiceDescriptorTable
 +
 +.data:​0046AB80 _KeServiceDescriptorTable dd 0
 +
 +Листинг 12 неинициализированная SDT-таблица,​ хранящаяся в NTOSKRNL.EXE
 +
 +Ниже, в качестве примера,​ продемонстрирован поиск SST в hiew'​e:​
 +
 +{{malware-discover_Image_10.png}}
 +
 +Рисунок 11 поиск SST в файле NTOSKRNL.EXE по перекрестным ссылкам
 +
 +Если лень восстанавливать SST вручную,​ можно воспользоваться бесплатной утилитой "​Win2K/​XP SDT Restore"​ от Tan Chew Keong, результат работы которой продемонстрирован ниже:
 +
 +{{malware-discover_Image_11.png}}
 +
 +Рисунок 12 официальный сайт утилиты SDTRestore…
 +
 +{{malware-discover_Image_12.png}}
 +
 +Рисунок 13 …и результат ее работы на зараженной малварью машине
 +
 +Пользуясь SDT Restore,​ следует иметь ввиду, что уже появились rootkit'​ы,​ способные ее обходить. Во-первых,​ для поиска оригинальной SST, утилита SDT Restore использует простой,​ но ненадежный способ,​ обращаясь к KeServiceDescriptorTable[0],​ которую зловредная малварь может и подменить (см. http://​hi-tech.nsys.by/​35/​),​ во-вторых,​ само восстановление SST происходит с прикладного уровня через псевдоустройство PhysicalMemory,​ отображаемое в память посредством native-API функции NtMapViewOfSection,​ легко перехватываемую как с прикладного,​ так и с ядреного уровней,​ после чего перехватчику остается проверить:​ не вызывается ли NtMapViewOfSection с дескриптором PhysicalMemory и если да, то либо заблокировать доступ,​ либо имитировать восстановление,​ не производя его в действительности (см. http://​www.rootkit.com/​newsread.php?​newsid=200).
 +
 +Так же следует учитывать,​ что некоторые защиты "​вешаются"​ на вектора прерываний,​ описанные в таблице IDT, и проверяют перехваченные сервисы,​ например,​ каждый тик таймера. В правильной IDT (просмотреть которую можно одноименной командой в soft-ice) все вектора указывают внутрь NTOSKRNL.EXE или HAL.DLL.
 +
 +:IDT
 +
 +IntTypeSel:​OffsetAttributes Symbol/​Owner
 +
 +IDTbase=80036400 ​ Limit=07FF
 +
 +0000IntG320008:​804625E6DPL=0Pntoskrnl!Kei386EoiHelper+0590
 +
 +0001IntG320008:​80462736DPL=3Pntoskrnl!Kei386EoiHelper+06E0
 +
 +0002IntG320008:​0000144EDPL=0P
 +
 +0003IntG320008:​80462A0EDPL=3Pntoskrnl!Kei386EoiHelper+09B8
 +
 +Листинг 13 просмотр IDT в soft-ice
 +
 +В дополнение к этому, малварь может устанавливать в начало (или даже середину!) некоторых ядерных функций jump на свой обработчик,​ контролирующий целостность перехваченной SST/IDT. Для выявления такого способа перехвата,​ необходимо сравнить образ ядра с файлом NTOSKRNL.EXE,​ что можно осуществить при помощи утилиты PE-TOOLS с плагином eXtremeDumper или сдампить ядро непосредственно из самого soft-ice (что намного надежнее) с установленным расширениями IceExt или IceDump.
 +
 +===== заключение =====
 +
 +Вот два основных пути проникновения малвари на компьютер — файлы, запускаемые самим пользователем и дырявое программное обеспечение (последнее преимущественно относится к IE и линейке NT). И если первое еще можно как-то предотвратить (не открывать никаких потенциально опасных вложений,​ полученных по почте; пользоваться приложениями только от проверенных поставщиков;​ не скачивать crack'​и написанные непонятно кем и неизвестно для чего), то от дыр никуда не уйти. Даже если пересесть с IE на Lynx, останутся дефекты оси, коих в NT ну просто до фига и постоянно обнаруживаются все новые, ранее неизвестные. То есть, это _нам_ они неизвестные,​ а кому-то очень даже хорошо известные и эксплуатируемые.
 +
 +Никто не может чувствовать себя в безопасности,​ если не будет регулярно проверять все закоулки системы своими руками,​ хвостом,​ ну и конечно,​ могучим soft-ice со всей его свитой.
 +
 +===== >>>​ врезка выявление stealth-компонентов =====
 +
 +===== >>>​ врезка сетевые соединения =====
 +
 +===== >>>​ врезка ссылки на программы,​ упомянутые в статье =====
 +
 +  - **NtExplorer**:​
 +    - __http____://​____www____.____runtime____.____org____/​____gdbnt____.____zip__;​
 +  - **OllyDbg**:​
 +    - __http____://​____www____.____ollydbg____.____de__;​
 +  - **Process Explorer**:
 +    - __http://​www.sysinternals.com/​Utilities/​ProcessExplorer.html__;​
 +  - **IceExt**:
 +    - __http://​stenri.pisem.net__;​
 +  - **IceDump**:​
 +    - __http://​programmerstools.org/​system/​files?​file=icedump6.026.zip__;​
 +  - **PE-TOOLS** (base):
 +    - __http://​www.wasm.ru/​baixado.php?​mode=tool&​id=124__;​
 +  - **PE-TOOLS** (updates):
 +    - __http://​neox.iatp.by__;​
 +  - **eXtremeDumper**:​
 +    - __http://​neox.iatp.by/​eXtremeDumper.zip__;​
 +  - **SDT Restore**:
 +    - __http://​www.security.org.sg/​code/​sdtrestore.html__;​
 +