Контрразведка с soft-ice в руках

         

Дерево процессов


Обычно, малварь создает свой собственный процесс (реже— внедряется в чужие), при этом у нее возникает вполне естественное желание скрыть этот процесс, убрав его из "Диспетчера Задач" и прочих системных утилит. Как это она делает? Для предоставления информации о процессах NT поддерживает два механизма: набор документированных процедур TOOLHELP32 (доставшийся в "наследство" от 9x), реализованных в KERNEL32.DLL, и недокументированная функция NtQuerySystemInformation, экспортируемая NTDLL.DLL, и представляющую собой тонкую "обертку" вокруг системного сервиса 97h, реализованного в NTOSKRNL.EXE. На самом деле, главная функция TOOLHELP32 — CreateToolhelp32Snapshot — полностью опирается на NtQuerySystemInformation, так что фактически механизм у нас один, только интерфейсы разные.

Малварь может легко перехватить процедуры Process32First/Process32Next

из TOOLHELP32, только это ей ничего не даст, поскольку, практически все утилиты ("Диспетчер Задач", FAR и даже примитивный tlist.exe из SDK) работают исключительно через NtQuerySystemInformation

(что легко подтверждается установкой точки останова в soft?ice). Однако, перехватить NtQuerySystemInformation

с прикладного уровня ничуть не сложнее, чем процедуры из набора TOOLHELP32! Существует множество путей как это сделать:

q       модифицировать NTDLL.DLL на диске, установив в начало функции NtQuerySystemInformation

команду перехода на свой обработчик (расположенный где-нибудь в свободном месте внутри NTDLL.DLL), и "вычищающий" из выдаваемой ею информации всякое упоминание о себе. способ простой как барабан, но грязный и легко обнаруживаемый путем дизассемблирования NTDLL.DLL или сравнением ее с оригиналом; так же малвари придется противостоять SFC и установке ServicePack'ов некоторые из которых обновляют NTDLL.DLL;

q       модифицировать 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, но это не единственный способ внедрения, так что задача выявления малвари резко усложняется;

q       модифицировать таблицу импорта taskmng.exe ("Диспетчер Задач"), proclist.dll (плагин FAR'а, ответственный за вывод списка процессов), tlist.exe на диске (или в памяти), подменив вызовов NtQuerySystemInformation

своей собственной функций оберткой. такой перехват легко обнаруживается путем сравнения исполняемых файлов с их образом памяти, который может быть получен путем снятия дампа утилитой типа PE?TOOLS или старым добрым Procdump'ом, к тому же малвари придется дополнительно перехватывать GetProcAddress, чтобы отслеживать динамическую загрузку NTDLL.DLL;

При наличии прав администратора, малварь может проникнуть в NTOSKRNL.EXE и подменить сервис 97h своим собственным обработчиком. Тогда с прикладного уровня обнаружить зловредный процесс уже не удастся и придется спускаться на уровень ядра, подробно рассмотренное в разделе. "восстановление SST".

Soft-Ice – единственная из всех известных мыщъх'у программ, которая не использует NtQuerySystemInformation и для отображения списка процессов самостоятельно разбирает базовые структуры операционной системы, а потому легко выявляет скрытые процессы.




Допрос потоков


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



Контрразведка с soft-ice в руках


крис касперски ака мыщъх, no-email

антивирусы (даже со всеми апдейтами) далеко не всегда распознают малварь и опытные хакеры доверяют только своим собственному хвосту, отладчику soft-ice и другому низкоуровневому инструментарию, позволяющему пробурить нору до самого ядра и разоблачить зловредные программы, где бы они ни скрывались!



функция ZwQuerySystemInformation


Когда происходит вызов прерывания, процессор автоматически переключается с прикладного уровня (ring 3) в режим ядра (ring 0), передавая управление функции KiSystemService, реализованной внутри NTOSKRNL.EXE и опирающейся на Таблицу Системных Дескрипторов, она же SDT (System Descriptor Table). Собственно, дескрипторов в ней всего два — один для системных вызовов, другой — для драйвера win32k.sys, куда упрятали весь графический интерфейс. На серверах добавляется и третий дескриптор — IIS, назначение которого ясно из его названия.



исходный код демонстрационной


Компилируем, запускаем, заходим в soft-ice, даем команду "THREAD -x" (вывод детальной информации о потоках) и смотрим полученный результат:

:THREAD -x

              Extended Thread Info for thread 374

KTEB          873CFDA0             TID:          374    Process: va_thread(11C)

Start EIP:    KERNEL32!SetUnhandledExceptionFilter+001A (77E878C1)

User Stack:   00030000 - 00130000 Stack Ptr:    0012FD24

              Extended Thread Info for thread 238

KTEB:         82007020             TID:          238    Process: va_thread(11C)

Start EIP:    KERNEL32!CreateFileA+00C3 (77E92C50)

User Stack:   00420000 - 00520000  Stack Ptr:    FFFFFFFF

              Extended Thread Info for thread 30C

KTEB:         82007AC0             TID:          30C    Process: va_thread(11C)

Start EIP:    KERNEL32!CreateFileA+00C3 (77E92C50)

User Stack:   00530000 - 00630000  Stack Ptr:    FFFFFFFF



информация о потоках, сообщенная soft-ice (приводится в сокращенном виде)


Вот так номер! soft-ice не смог определить истинные стартовые адреса потоков, заблудившись в недрах KERNEL32.DLL. Что ж, попробуем другой инструмент — Process Explorer от Марка Руссиновича, весьма нехило разбирающегося во внутренностях операционных систем от Microsoft (и даже участвующим в написании книги "Windows NT Internals". Скачиваем (совершенно бесплатно) Process Explorer, запускаем, наводим курсор на "va_thread.exe", далее в контекстом меню выбираем пункт "Properties" и в открывшемся диалоговом окне переходим к вкладке "Threads".



информация о четырех потоках, выданная OllyDbg


Стартовый адрес (entry) определен только для одного из потоков — 50Ch да и тот, вероятно, служит для связки отлаживаемого процесса с OllyDbg. Стартовые адреса остальных потоков выставлены в ноль, но ведь это же не так!!!

Щелкам мышью по потоку c идентификатором 558h (естественно, при следующем запуске программы, идентификаторы потоков будут другими) и получаем код следующего содержания, который (судя по карте памяти), принадлежит страничному имиджу, следовательно, это — легальный поток.

401000 55            PUSH EBP

401001 8B EC         MOV EBP,ESP

401003 B8 01000000   MOV EAX,1

401008 85C0          TEST EAX,EAX

40100A 74 02         JE SHORT va_threa.0040100E

40100C EB F5         JMP SHORT va_threa.00401003



код потока 558h, находящегося в пределах страничного имиджа


Переходим к окну стека, перемещая ползунок на самый низ. На дне стека видим аргумент, переданный потоку (второе двойное слово, в данном случае равное — 999h) и… стартовый адрес потока, лежащий в третьем двойном слово, и в данном случае равный 401000h, что полностью согласуется с листингом 1. (На самом деле, в зависимости от способа создания потока стартовый адрес может лежать как в третьем, так и во втором слове, поэтому автоматические утилиты и путаются).

51FFDC FFFFFFFF  End of SEH chain

51FFE0 79481F54  SE handler

51FFE4 79432B08  KERNEL32.79432B08

51FFE8 00000000

51FFEC 00000000

51FFF0 00000000

51FFF4 00401000  va_threa.00401000 ; ß стартовый адрес потока 558h

51FFF8 00000999                   ; ß

аргумент, переданный потоку

51FFFC 00000000                   ; ß дно пользовательского стека потока



на дне пользовательского


Переходим к следующему потоку — 55Ch. Код выглядит точно так как и раньше (ведь мы запустили два экземпляра одной и той же функции!), а вот содержимое дна стека слегка изменилось:

62FFDC FFFFFFFF  End of SEH chain

62FFE0 79481F54  SE handler

62FFE4 79432B08  KERNEL32.79432B08

62FFE8 00000000

62FFEC 00000000

62FFF0 00000000

62FFF4 00520000                   ; ß стартовый адрес потока 55Сh

62FFF8 00000666                   ; ß

аргумент, переданный потоку

62FFFC 00000000                   ; ß дно пользовательского стека потока



на дне пользовательского


Как мы помним, 666h – это аргументы, переданные "нечестной" копии потока, а 520000h – его стартовый адрес, принадлежащий (если верить карте памяти) блоку памяти, выделенному функцией VirtualAlloc:

Address       Size   Owner         Section       Contains      Type   Access        Initial

400000 1000   va_threa             PE header     Imag   R             RWE

401000 4000   va_threa      .text  code          Imag   R             RWE

405000 1000   va_threa      .rdata imports              Imag   R             RWE

406000 2000   va_threa      .data  data          Imag   R             RWE

410000 2000                                     Map    R             R

51E000 1000                                     Priv   RW     Guar   RW

51F000 1000                       stack of thr  Priv   RW     Guar   RW

520000 1000                                     Priv   RWE           RWE

62E000 1000                                     Priv   RW     Guar   RW



карта памяти процесса


Последний поток — 578h представляет собой основной поток программы и хранит своей стартовый адрес _не_ в третьем, а во втором (!) двойном слове:

12FFE0 FFFFFFFF  End of SEH chain

12FFE4 79481F54  SE handler

12FFE8 79432B18  KERNEL32.79432B18

12FFEC 00000000

12FFF0 00000000

12FFF4 00000000

12FFF8 00401405  va_threa.<ModuleEntryPoint>
    ; ß

стартовый адрес потока 578h

12FFFC 00000000                          ; ß дно пользовательского стека потока



поток 578h хранит свой стартовый адрес не в третьем, а во втором двойном слове!


Свершилось! Мы научились быстро и просто определять стартовые адреса потоков, надежно отличая "левых" от "правых". Кстати, чтобы каждый раз не сверяться с картой памяти можно использовать следующий трюк. Если при нажатии стартового адреса в контекстом меню OllyDbg присутствует строчка "Follow in Disassembler" – он принадлежит страничному имиджу (т. е. легальному потоку) и, соответственно, наоборот.



протокол работы с soft-ice, демонстрирующий получение адреса системного сервиса 97h


Как мы видим, в данном случае, функция NtQuerySystemInformation никем не перехвачена, что очень хорошо!

Чтобы просмотреть содержимое SST в soft-ice достаточно дать команду "NTCALL". На "стерильной" машине _все_ вызовы указывают внутрь NTOSKRNL.EXE, а если это не так, то их кто-то перехватил. Это может быть как зловредная малварь, так и вполне безобидный драйвер какого-нибудь защитного механизма или, например, брандмауэр.

Для восстановления SST можно использовать ее копию, хранящуюся внутри NTOSKRNL.EXE, правда, найти ее на диске значительно сложнее, чем в памяти. Проще всего использовать отладочные символы (которые можно бесплатно сгрузить с сервера http://msdl.microsoft.com/download/symbols с помощью библиотеки dbghelp.dll, входящей в состав бесплатного пакета Debugging Tools). Адресу SST соответствует метка _KiServiceTable

и в моей версии системы она располагается по адресу 4704D8h (в файле):

.data:004704D8 BF B3 4A 00 _KiServiceTable      dd offset _NtAcceptConnectPort@24

.data:004704DC 6B E8 4A 00               dd offset _NtAccessCheck@32

.data:004704E0 F3 DE 4B 00               dd offset _NtAccessCheckAndAuditAlarm@44



копия таблицы системных вызовом, хранящаяся внутри 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



неинициализированная SDT-таблица, хранящаяся в NTOSKRNL.EXE


Ниже, в качестве примера, продемонстрирован поиск SST в hiew'e:



просмотр IDT в soft-ice


В дополнение к этому, малварь может устанавливать в начало (или даже середину!) некоторых ядерных функций jump на свой обработчик, контролирующий целостность перехваченной SST/IDT. Для выявления такого способа перехвата, необходимо сравнить образ ядра с файлом NTOSKRNL.EXE, что можно осуществить при помощи утилиты PE-TOOLS с плагином eXtreme Dumper или сдампить ядро непосредственно из самого soft-ice (что намного надежнее) с установленным расширениями IceExt или IceDump.



поиск файлов, созданных


Конечно, чем позже мы спохватимся, тем сложнее отличить "легальные" файлы от "нелегальных", особенно если на компьютер ставится большое количество самого разнообразного программного обеспечения. Но все файлы, устанавливаемые инсталлятором (где он их не размещал — в Program Files, WINNT или System32), имеют одну и ту же дату создания с небольшим разбросом по времени (ведь файлы создаются не параллельно, а последовательно), поэтому их стразу можно исключить из списка подозреваемых. А оставшиеся — подвергнуть тщательному допросу (см. врезку "признаки вредоносных файлов").



soft-ice показывает процесс sysrtl, отсутствующий в "Диспетчере Задач"


Теоретически, малварь может внедриться в soft-ice и перехватить любую из его команд (например, команду "PROC"), действуя по той же схеме, что и IceExt/IceDump (благо, что обе утилиты распространяются в исходных текстах), но в живой природе такие "монстры" пока что не встречались. Можно надеяться, что IceExt, скрывающий soft-ice от большинства защит, скроет его и от малвари, однако, при этом остается угроза сигнатурного поиска отладчика в памяти; к тому же на хакерских форумах не первый год обсуждается гипотетический алгоритм скрытия, перехватывающий функции переключения контекста и "вытирающий" себя в промежутках между ними. Однако, реализация такого проекта упирается в непреодолимые практические трудности. Формат процессорных структур непостоянен и меняется от одной версии системы к другой, к тому же с ними взаимодействуют множество недокументированных функций, вызываемых в разное время из различных мест и малварь, пытающаяся замаскироваться, постоянно обрушивает систему в BSOD, чем сразу себя и разоблачает.

Таким образом, будем считать, что связки из soft-ice + IceExt для просмотра всех процессов (включая скрытые) вполне достаточно.



карта памяти "Блокнота", отображенная отладчиком OllyDbg


Регионы, помеченные как "Priv" (сокращение от "private") принадлежат блокам динамической памяти, "map" (сокращение от "mapping") – проекциям файлов, созданных функциями CreateFileMapping/MapViewOfFile), "Imag" (сокращение от "imaging") – страничным имиджам исполняемых файлов или динамических библиотек.

В PE-TOOLS для той же цели необходимо выделить процесс и в контекстом меню выбрать "dump region", при этом на экране появится диалоговое окно с картой памяти — не такой подробное как у OllyDbg, но для нашей задачи вполне удовлетворительное.



исследование даты создания файлов при помощи FAR'а


Естественно, дата создания файла элементарно изменяется средствами win32-API и малвари при желании ничего не стоит замаскироваться. Однако, на NTFS-разделах каждый файл обладает множеством "невидимых" атрибутов, до которых нельзя дотянуться через API. В частности, атрибут 30h ($FILE_NAME) помимо стандартных времен создания/модификации/последнего обращения, хранит время последней модификации данной записи MFT (Master File Table – специального мастерфайла, содержащего информацию обо всех остальных объектах файловой системы). У "честных" файлов время создания и время последней модификации MFT всегда совпадает, а если это не так — мы имеем дело с подделкой. Еще существует атрибут 10h ($STANDARD_INFORMATION), так же хранящий информацию о времени создания/модификации/последнего доступа файла и времени последней модификации MFT, однако, в отличии, от атрибута 30h, здесь время последней модификации MFT автоматически обновляется всякий раз, когда файлу выделяется новая порция кластеров, а потому со временем его создания оно может и не совпадать.

Существует не так уж и много утилит, отображающих содержимое MFT в удобочитаемом виде. Одна из них — NtExplorer от Runtime Software. Грубо говоря, это Norton Disk Editor, но только под NTFS. К сожалению, NtExplorer не поддерживает ни плагинов, ни скриптов, поэтому, быстро вывести список файлов с поддельными датами создания не получается и каждый из них приходится перебирать "руками", что очень сильно напрягает, но… NTFS совсем несложная (по нынешним меркам) файловая система, а все ее основные структуры давным-давно реконструированы, документированы и выложены в Сеть: http://linux-ntfs.sourceforge.net. Создание программы, выполняющий автоматизированный поиск "поддельных" файлов у не займет много времени, тем более, что подробное описание NTFS можно найти в моей книге "la technique de la restitution des données". В общем, дорогу осилит идущий!



карта памяти "Блокнота", отображенная утилитой 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);

}



Process Explorer от Марка


Что мы видим? Адреса двух потоков определены верно. Первый: va_thread.exe+0x1405, судя по адресу, представляет основной поток (адрес совпадает с точкой входа, что легко проверить в hiew'е). Второй: va_thread.exe+0x1000 — это "честно" созданный поток (что опять-таки проверяется по адресу в hiew'е), а вот третий – KERNEL32.DLL+0xB700 – это "нечестный" поток (а чем он еще может быть?!), только его стартовый адрес определен неправильно!

Призываем на помощь OllyDbg и пытаемся разобраться в ситуации самостоятельно, без всех этих прелестей автоматизации и прочих чудес технического прогресса. Подключившись к процессу va_thread.exe, в меню "view" выбираем пункт "thread" и… обнаруживаем не три (как ожидалось), а целых четыре потока!

Ident  Entry         Data block    Last error    Status        Priority

050C   7943B700      7FFDB000      ERROR_SUCCESS Active        32 + 0

0558   00000000      7FFDC000      ERROR_SUCCESS Suspended     32 + 0

055C   00000000      7FFDE000      ERROR_SUCCESS Suspended     32 + 0

0578   00000000      7FFDD000      ERROR_SUCCESS Suspended     32 + 0



содержимое дна стека


На самом деле, праздновать победу еще рано. Умная малварь может нас легко обмануть. Самое простое — подменить истинный стартовый адрес так, чтобы он указывал внутрь страничного имиджа целевого процесса (но в этом случае он должен совпадать с началом какой-нибудь процедуры, иначе мы тут же разоблачим обман). Более умная малварь использует хитрый способ внедрения — находит в целевом процессе функцию по стандартному прологу PUSH EBP/MOV EBP, ESP

(55h/8Bh ECh), вставляет в ее начало jump на выделенный из кучи блок, где размещено ее тело, создает новый поток, начинающийся с jump, и тут же восстанавливает оригинальное содержимое хакнутой функции убирая jump и возвращая стандартный пролог. Еще остается вариант загрузить внутрь процесса динамическую библиотеку, принадлежащую малвари и запустить внутри нее новый поток.

Во всех этих случаях анализ стартового адреса не даст никакого результата и внедрение зловредного кода останется незамеченным и чтобы быть уверенным на все 100% необходимо трассировать каждый из потоков на предмет проверки его лояльности. Потоки, порожденные малварью, либо шпионят за клавиатурой, либо открывают backdoor, либо рассылают спам. Проблема в том, что потоков (легальных) очень много, а современная малварь пишется уже не на ассемблере, а черт знает на чем (DELPHI, Visual BASIC) и полный анализ требует уймы времени, однако, как говорилось выше, умная малварь — большая редкость и подделкой стартовых адресов потоков никто не занимается.



механизм реализации системных вызовов


Дескриптор, отвечающий за системные вызовы, указывает на System Service Table (Таблица Системных Вызовов), представляющую собой простой массив указателей на функции, которые _очень_ легко изменить (естественно, делать это нужно либо из режима ядра, либо с прикладного уровня, обратившись к псевдоустройству 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:804BF933 PUSH   EBP

0023:804BF934 MOV    EBP, ESP

0023:804BF936 PUSH   FF

0023:804BF938 PUSH   804043A0

0023:804BF93D PUSH   ntoskrnl!_except_handler3



поиск SST в файле NTOSKRNL.EXE по перекрестным ссылкам


Если лень восстанавливать SST вручную, можно воспользоваться бесплатной утилитой "Win2K/XP SDT Restore" от Tan Chew Keong, результат работы которой продемонстрирован ниже:



и результат ее работы на зараженной малварью машине


Пользуясь 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

Int    Type   Sel:Offset    Attributes Symbol/Owner

IDTbase=80036400  Limit=07FF

0000   IntG32 0008:804625E6 DPL=0         P      ntoskrnl!Kei386EoiHelper+0590

0001   IntG32 0008:80462736 DPL=3         P      ntoskrnl!Kei386EoiHelper+06E0

0002   IntG32 0008:0000144E DPL=0         P

0003   IntG32 0008:80462A0E DPL=3         P      ntoskrnl!Kei386EoiHelper+09B8



Восстановление SST


Для сокрытия своего присутствия в системе, малварь нередко внедряется в ядро системы и перехватывает один или несколько сервисов, например, функции NtQuerySystemInformation, про важность которой мы уже говорили. Ловить малварь на такой системе все равно, что бороться с ком. партией под ее руководством.

Дизассемблирование NTDDLL.DLL показывает, что большинство низкоуровневых функций реализованы как "переходники" к функциям ядра, интерфейс с которым осуществляется либо посредством прерывания INT2Eh (NT, W2K), либо машинной командой SYSENTER (XP и выше).

.text:77F95BBD       public ZwQuerySystemInformation

.text:77F95BBD       ZwQuerySystemInformation proc near

.text:77F95BBD       arg_0  = byte ptr  4

.text:77F95BBD

.text:77F95BBD B8 97 00 00 00     mov    eax, 97h      ; NtQuerySystemInformation

.text:77F95BC2 8D 54 24 0  lea    edx, [esp+arg_0]

.text:77F95BC6 CD 2E       int    2Eh

.text:77F95BC8 C2 10 00    retn   10h

.text:77F95BC8       ZwQuerySystemInformation endp



Время тоже оставляет отпечатки


Чаще всего малварь копирует свою тушу в новый файл со случайным или фиксированным названием, реже— внедряется в уже существующие (что требует не только знания устройства PE-формата, но и определенных привилегий, в частности, из-под пользовательского аккаунта системные файлы просто так не заразишь). При этом подавляющее большинство malware-писателей забывают скорректировать дату/время создания файла, выдавая себя с головой.

Допустим, мы запустили файл сомнительного происхождения и хотим узнать – не натворил ли он чего в системе? Пуск à Найти à

Файлы и Паки à

Параметры Поиска à

Файлы созданные за xxx последних дней (в нашем случае за один). Все изменения, произошедшие за последние сутки в системе становятся видны как на ладони! Как вариант: в FAR'е устанавливаем режим сортировки по дате создания (<CTRL-F8>) и заходим во все "злачные" каталоги типа WINNT, System32 и т. д. Файлы, созданные последними, будут в самом верху. Прием простой, как паровой котел, но чрезвычайно эффективный!



>>> Врезка ссылки на программы, упомянутые в статье


q       NtExplorer:

o        http://www.runtime.org/gdbnt.zip;

q       OllyDbg:

o        http://www.ollydbg.de;

q       Process Explorer:

o        http://www.sysinternals.com/Utilities/ProcessExplorer.html;

q       IceExt:

o        http://stenri.pisem.net;

q       IceDump:

o        http://programmerstools.org/system/files?file=icedump6.026.zip;

q       PE-TOOLS (base):

o        http://www.wasm.ru/baixado.php?mode=tool&id=124;

q       PE-TOOLS (updates):

o        http://neox.iatp.by;

q       eXtremeDumper:

o        http://neox.iatp.by/eXtremeDumper.zip;

q       SDT Restore:

o        http://www.security.org.sg/code/sdtrestore.html;



была обычном делом. Количество исполняемых


Во времена MS-DOS ручная чистка компьютера — была обычном делом. Количество исполняемых файлов измерялось десятками, и существовало не так уж и много мест, пригодных для внедрения малвари (под малварью — от английского malware — здесь и далее по тексту подразумевается вредоносное программное обеспечение — вирусы, черви, шпионы и т. д.). С приходом Windows все изменилось. Из крохотного поселка операционная система превратилась в огромный, стремительно разрастающийся мегалополис, среди сотен тысяч файлов которого может спрятаться и слонопотам.
Обнаружить качественно спроектированную и грамотно заложенную закладку усилиями одного человека за разумное время — навряд ли возможно. Намного проще (да и быстрее) переустановить Windows с нуля. К счастью, качественная малварь — огромная редкость, практически не встречающая в живой природе и в основном приходится сталкиваться с пионерскими поделками, оставляющими после себя кучу следов и легко различимыми с помощью soft-ice и сопутствующих ему утилит.
Весь вопрос в том — как правильно ими пользоваться. Ну, установили мы soft-ice, нажали <CTRL-D>, увидели черный экран… Дальше-то что?! А вот дальше на сцене появился мыщъх и, плюхнувшись в кресло (предварительно подтолкнув под себя хвост), начинает делиться хакерскими секретами.


Вот два основных пути проникновения


Вот два основных пути проникновения малвари на компьютер— файлы, запускаемые самим пользователем и дырявое программное обеспечение (последнее преимущественно относится к IE и линейке NT). И если первое еще можно как-то предотвратить (не открывать никаких потенциально опасных вложений, полученных по почте; пользоваться приложениями только от проверенных поставщиков; не скачивать crack'и написанные непонятно кем и неизвестно для чего), то от дыр никуда не уйти. Даже если пересесть с IE на Lynx, останутся дефекты оси, коих в NT ну просто до фига и постоянно обнаруживаются все новые, ранее неизвестные. То есть, это _нам_ они неизвестные, а кому-то очень даже хорошо известные и эксплуатируемые.
Никто не может чувствовать себя в безопасности, если не будет регулярно проверять все закоулки системы своими руками, хвостом, ну и конечно, могучим soft-ice со всей его свитой.