понедельник, 19 декабря 2011 г.

wincheck rc8.3

download mirror
Changelog:
  • add -kt option to dump all KTIMERs. Works on 32 & 64bit windows
  • add checking of FS_FILTER_CALLBACKS
  • add checking of callbacks which can be installed with ExRegisterAttributeInformationCallback function
  • add checking of KPRCB.WorkerRoutine (32bit only)

воскресенье, 18 декабря 2011 г.

make_pdmp.pl

по многочисленным просьбам - запчасть от моей системы тестирования, которая ездит по директориям, качает .pdb и делает .pdmp файлы
Модуль PEIdent я в силу врожденной паранойи выкусил - нечего вам знать какие файлы оно у меня знает, бгг
Батник get_pdb.bat идентичен приведенному ранее

про тестирование

а вот например меня тут давеча спросили - поскольку wincheck для извлечения смещений структур и адресов всякого использует статический анализ кода, то как происходит проверка стат. анализатора на куче версий windows ? Это хороший вопрос тащемта, тем более что ничего внятного про такую задачу в этих ваших интернетах по моему не написано и пришлось как обычно все делать на коленке самому.
Правильный ответ - Максимальная Автоматизация всего процесса с помощью адовой смеси perl/bat скриптов

Получаем pdb

Как известно microsoft в отличие от практически всех остальных софтоклепательных компаний предоставляет .pdb файлы от почти всех своих системных модулей. Было бы глупо не воспользоваться такой шикарной возможностью при создании эталонных данных для тестов. Соотв-но обработка любого файла начинается с получения его .pdb файла и последующего дампа этого .pdb с помощью пропатченной мною версии pdbdump

Cуществует множество способов получить .pdb. На мой вкус самый простой - использовать программу symchk.exe из Debugging Tools for Windows:
"C:\Program Files\Debugging Tools for Windows (x86)\symchk.exe" %1  /s SRV*%tmp%\ida\*http://msdl.microsoft.com/download/symbols /v 2>log

В файле log интересна следующая строчка:
DbgSizeOfImage      0x0001d000
DbgChecksum         0x0001df9b
PdbFilename         C:\DOCUME~1\USER\LOCALS~1\Temp\ida\6to4svc.pdb\FD2DAD64D03E4365A5116D01DCB424031\6to4svc.pdb 

PdbSignature        {FD2DAD64-D03E-4365-A511-6D01DCB42403}

Простой perl script парзит данный log, и в случае успеха копирует скачанный .pdb файл рядом с исходным бинарным, после чего запускает pdbdump, перенаправляя его вывод в файл с именем исходного PE файла и расширением .pdmp

Формирование эталонных данных

Для проведения тестов нужны файлы с эталонными данными, которые мне лениво набивать для каждого файла вручную, поэтому они также генерятся полуавтоматически. Эти данные хранятся в файле с именем исходного PE файла и расширением .et. Файл .et выглядит примерно так (взято из 32/win7/nosp/ntkrnlpa.et):
KiDebugRoutine 1689BC
KdDebuggerDataBlock 128C08

M DbgkLkmd_cblist 12DB20
PspLegoNotifyRoutine 369EE0

EPROCESS.ObjectTable F4


Для получения .et файла нужно натравить на .pdmp файл perl script make_et.pl, который распарзит выход pdbdumpа и извлечет всякие нужные адреса и смещения нужных полей в нужных структурах и сохранит их . Этот скрипт крайне прост и практически не отличается от ранее публиковавшегося. Здесь есть один тонкий момент - некоторых имен в .pdb файле может не быть. Так например в pdb от ntkrnlpa.exe от windows 7 нет переменной DbgkLkmd_cblist - она должна быть добавлена вручную. Соотв-но скрипт сначала зачитывает из уже имеющегося файла .et все строчки с символом M в начале строки (флажок, означающий что данная строчка была добавлена вручную) и сохраняет их в новой версии .et файла. Так гарантируется что однажды вручную добавленные поля никогда не будут потеряны. Как вы можете догадаться, эта функциональность также была добавлена благодаря моей выдающейся лени например

Собственно тесты

Это самая скучная часть повествования. Из общей с wincheck кодовой базы была написана специальная программа с оригинальным именем test.exe, которая делает ровно то же что и анализатор в wincheck, только еще умеет распечатать результаты в stdout. Есс-но что программа имеет 32 и 64 битные версии. Далее запускается еще один perl script, который рекурсивно ездит с помощью модуля File::Find по директориям с тестовыми данными, находит все .et файлы, запускает test.exe для исходного PE файла и сравнивает получившиеся результаты с эталонными данными. Все не найденное или не совпавшее с эталонными данными пишется в лог.
Скрипт этот имеет два режима работы - проверить вообще все, либо (что бывает значительно чаще) совершенно конкретный модуль. Откуда он знает какой файл относится к какому модулю ? Ему говорит об этом отдельный perl package PEIdent, ф-ции в котором выглядят примерно так:

sub is_hal
{
  my $fname = lc(shift);
  return ($fname eq 'hal.dll')      ||

         ($fname eq 'halapic.dll')  ||
         ($fname eq 'halmps.dll')   ||
         ($fname eq 'halacpi.dll')  ||
         ($fname eq 'halaacpi.dll') ||
         ($fname eq 'halmacpi.dll')
 ;
}

Думаю что основная идея из этого кусочка понятна. Далее можно формировать кортежи из двух указателей на ф-ции - is_XX & do_XX, вторая вызывается если первая вернула не ноль. Еще далее из этих кортежей можно составить список кортежей, по которому можно пройтись с именем .exe/.dll/.sys файла, найти его тип модуля, вызвать нужную ф-цию для обработки. В эти списки можно добавить кортежи только для отдельных типов модулей или для всех pe файлов и так далее

Добавление нового эталонного значения

Изредка возникает необходимость добавить еще одно (или не одно) поле в .et файлы для определенного модуля. Поскольку лень моя чудовищна - это делается с помощью все того же make_et.pl. К нему дописывается еще одна (или не одна) строчка - имя переменной, которую мы хотим получить из .pdmp или поле и структура. Этот скрипт точно так же обходит рекурсивно директорию с тестовыми данными и делает свое грязное дело по изменению .et файлов, генерируя при этом отчет - для какого файла что не нашлось. По моему это единственное место когда требуется ручное вмешательство с помощью анализа кода в IDA Pro

Добавление нового файла

Бывает также иногда необходимость добавить либо файлы с какой-либо версии windows, либо совершенно новый тип модуля. Если нужно добавить новый тип модуля для анализа - правится PEIdent и прочие использующие его скрипты. Затем просто запускаются два скрипта:
  1. make_pdmp.pl - рекурсивно ездит по директориям с тестовыми данными, ищет файлы, у которых отсутствуют .pdb/.pdmp файлы, скачивает все недостающее и вызывает pdbdump, при этом пишется два лога - для тех файлов, скачать .pdb к которым не удалось, и для всех вновь добавленных. Я думал что можно было бы make приспособить для этого дела - но тогда пришлось бы руками в нем прописывать все добавленные файлы с полными путями. Ручной рекурсивный обход дерева каталогов оказался намного проще
  2. все тот же make_et.pl для получения эталонных данных для вновь добавленных файлов
Как следует из описания если нужно просто добавить некоторое количество файлов (например давеча я добавил файлы от 32битной w2k3 sp1) - их нужно просто скопировать в нужную директорию и запустить простой .bat файл

Организация каталогов

Чтобы не потеряться в куче файлов - .exe/.dll/.sys, а также соотв-щих им .pdb/.pdmp/.et (размер этого добра сейчас составляет что-то около 6Gb) - нужна правильная организация каталогов. Директорий с тестовыми данными две - одна для 32бит, другая для 64 (и на самом деле эти директории могут лежать на разных машинах). В каждой директории есть папки с именем версии windows, откуда был взят набор файлов, примерно такие:
32/w2k/sp4
32/xp/sp1
32/xp/sp2
32/xp.64/sp1
и так далее

В каждой папке лежит весь наборчик файлов данной битности от данной версии windows. Благодаря тому что любой скрипт для манипуляции с файлами ездит по директориям рекурсивно - всегда можно задать директорию, в которой нужно отработать - например тестировать только xp версии, скачать pdb от 32/w2k3/sp1 etc etc

Должен заметить что подобная организация тестов значительно ЗНАЧИТЕЛЬНО МЕГАЗНАЧИТЕЛЬНО экономит время тестирования/поиска багов/добавления новых переменных/новых типов модулей/новых версий windows

суббота, 17 декабря 2011 г.

KTIMERs with DPC per processor

а вот например как всем давно известно (c) начиная с windows 7 KTIMERs хранятся в KPRCB per processor (в поле KPRCB.TimerTable). Соотв-но я сегодня отладил таки код, вытаскивающий все KTIMERs для всех камней и вот что получилось на моей восьмиголовой windows 7 64bit:

AffinityMask

а вот например windows7 (и соотв-но w2008r2) могут поддерживать более 64 камней
А как известно ф-ция SetThreadAffinityMask в качестве маски имеет аргумент типа DWORD_PTR, что позволяет задать маску ровно для 64 камней. Если же на машине больше - то предлагают использовать всякие ритуальные пляски с бубном типа SetThreadIdealProcessorEx и заданием т.н. processor group.
Предположим (потому что у меня банально нету такого железа) что мы запущены на машине, где больше 64 камней. Количество камней я как-нть из kernel-mode узнать могу (KeNumberProcessors например). Соотв-но дальше я хочу свой поток подключить к каждому имеющемуся камню и достать всякое из KPRCB например. Ясно что я должен использовать кроме subj еще и processor group. А вот дальше непонятно - а сколько таких групп в системе ? А сколько в каждой камней (а системы бывают например на 96 камней - не кратные 64) ? А как можно провернуть такой трюк в kernel mode ?
Кто-нть имел подобный опыт ?

Update: вдумчивое разглядывание msdn подсказывает, что нужные ф-ции называются примерно так:
Наверняка все реализовано через какие-нть плохо документированные Information Classes NtQuerySystemInformation

вторник, 13 декабря 2011 г.

определение версии KPRCB 2

я тут писал уже как-то про сие невинное занятие, но внезапно выяснилось что метод не работает например под windows 8 - под ней KeIsExecutingDpc выглядит так:
  mov     eax, large fs:2354h
  and     eax, 10001h
  retn

это дает нам смещение на DpcRoutineActive равным 0x2234, что неверно

Но есть и еще один способ - например можно узнать смещение поля WorkerRoutine. В экспортируемой ф-ции KiIpiServiceRoutine есть примерно такой кусочек кода:
  mov     eax, [edx+2170h]
  mov     edx, [esp+24h+arg_0]
  mov     [esi+2128h], edx
  call    eax

0x2170 - это и есть наше искомое смещение. К недостаткам метода относится его применимость только для 32 бит, потому что под 64битными системами ф-ция KiIpiServiceRoutine не экспортируется
Также работает он только начиная с xp - под w2k ф-ция KiIpiServiceRoutine пуста

илита вирмейкинга недовольна

wincheckом:
Например есть у нас детектор типо wincheck. Вроде кошерная поделка, анализирует стопяцот внутренних структур, как юзермодных, так и нейтивных. Но это аверское дерьмо выпиливается через маршрутизацию. Что толку от мониторинга LdrpDllNotificationList, если я юзаю ShowSnaps и S/W переключение на код
это успех (c) ящетаю. Особенно угарно что wincheck на всю катушку использует анализ графа codeflow - не GPE™ понятно, а более пригодную для использования самописную либу, но идея таки да, ровно та же самая, бгг