среда, 26 января 2011 г.

Скрипты для windbg

Целью проекта pykd является интеграция python в windbg. А целью интеграции python в windbg - замена стандартного скриптового движка на более удобный. А удобный скриптовый движок нам нужен, чтобы быстро и легко автоматизировать свои действия. По-моему, так?

В данном посте я хочу предствить ряд скриптов, написанных с помощью pykd, которые могут пригодится в повседневной работе многим. Описание их работы есть в wiki на сайте проекта ( ссылка ) и я не буду репостить текст. Допустим вы уже прочитали статью с wiki и уже хотите попробовать. Где взять сами скрипты? Через дистрибутив они не распространяются, единственный способ - скачать из репозитория исходного кода ( ссылка ). В каталоге samples лежат, как не трудно догадаться, разные демонстрационный примеры. А в каталоге snippets - как раз то, что мы ищем. Допустим вы скачали исходный код, куда теперь распаковать каталоги со скриптами? Это не важно - в любой каталог, куда есть доступ. Для удобства использования настоятельно рекомендуется добавить этот путь в переменную окружения $PYTHONPATH. В этом случае, для вызова скрипта не нужно указывать полный путь, даже расширение можно опустить, примерно так:
!py export nt Zw*SetInformation*

Если вы написали полезный скрпит и хотите поделится им - присылайте ссылки на опубликованный код или исходный код и мы опубликуем его на сайте проекта под действующий лицензией.

Почта: pykd.codeplex@hotmail.com

четверг, 20 января 2011 г.

typedVar

При разработке pykd мы старались не трансиловать механически функционал из Debug Engine, а реализвать API, удобный при повседневной работе в windbg. А что делает пользователь в отладчике чаще всего? Конечно, просматривает значение переменных! Соответственно, для автоматизации его работу в первую очередь нужна функция для удобной и быстрой работы с переменными. Для этого мы реализовали функцию typedVar.

Вот ее прототип:

typedVar( string moduleName, string typeName, long address )


moduleName - имя модуля, содержащего тип
typeName - имя типа переменной
address - виртуальный адрес переменной

Функция создает объект типа typedVarClass и динамически добавляет ему аттрибуты, с именами соответствующими именам полей структуры заданного типа. Если поле является сложным типом - операция повторяется рекурсивно. В результате, мы в python е получаем объект, с которым можем работать в той же манере, как и в Си:

p = typedVar( "nt", "_ETHREAD", threadAddr )
print "Wait time: %d" % p.Tcb.WaitTime

Данный код выведет значение счетчика ожидания потока, адрес которого задан в переменной threadAddr. Массивы тоже будут корректно обработаны. Обращаться к элементу массива можно также в стиле Си:

print p.Tcb.Alerted[1]

В работе часто приходится иметь дело с связанными списками структур. Конечно, можно в цикле вызвать ф. typedVar для получения значений списка. В pykd для этого реализована специальная функция: typedVarList.

Вот ее прототип:

typedVarList( long head_address, string moduleName, string typeName, fieldName)


head_address - адрес головы списка
moduleName - имя модуля, содержащего тип элемента списка
typeName - имя типа элемента списка
fieldName - имя поля, содержащего указатель на следующий элемент списка.

Функция возвращает питоновский лист, каждый элемент которого имеет тип typedVarClass. Соответственно, для элементов этого списка справедливо все, что сказано выше. Проиллюстрируем на примере, как это работает:

nt = loadModule( "nt" )
processList = typedVarList( nt.PsActiveProcessHead, "nt", "_EPROCESS", "ActiveProcessLinks" )
for process in processList:
dprintln( "".join( [ chr(i) for i in process.ImageFileName.values() ] ) )

Данный код выведет на экран список процессов

Третья полезная функция для работы с переменными: containingRecord. Это аналог макроса CONTAINING_RECORD.

Вот ее прототип:

containingRecord( long field_address, string moduleName, string typeName, fieldName)


field_address - адрес поля структуры.
moduleName - имя модуля, содержащего тип
typeName - имя типа элемента списка
fieldName - имя поля, адрес которого задан переменной field_address

Битовые поля

Функция typedVar не поддерживает работу с битовымии полями в полном объеме. Если в структуре объявлено битовое поле:

struct A {
int a : 10;
int b : 20;
};

Мы в питоне получим, что obj.a = obj.b. Т.е структура битового поля не сохраняется и придется дополнительно накладывать битовые маски. Интересно, что команда dt в windbg правильно отображает битовые поля. Так что тут есть над чем поработать!

вторник, 18 января 2011 г.

PYKD: Getting Started

Логично в самом начале жизни блога написать о том, как начать работу с PYKD.
Основная задача pykd - подружить windbg и python. А поэтому разумным кажется требование иметь на машине предустановленные версии этих продуктов. Если вы еще читаете это, я уверен, что у вас уже установлен windbg или по крайней мере, вы знаете о чем идет речь. На установке python остановимся чуть подробнее. Какую версию выбрать? 1) Разрядность ( 32 или 64 бита ) должна совпадать с разрядностью windbg 2) Версия python должна поддерживаться pykd. В настоящее время поддерживается только 2.6.х ( для других версий 2.x можно собрать самостоятельно ). Таким образом, мы однозначно определяем, какой именно пакет скачать с www.python.org.

Переходим к установке pykd. К сожалению, в настоящее время автоматический инсталлятор отсутствует и придется все делать вручную. Загружаем архив с последней версией: ссылка. В архиве два каталога - x64 и x86, в которых лежат сборки pykd.pyd соответствующей разрядности. Выбираем нужную версию и копируем ее. Только вот куда? В принципе, можно в любой каталог, из которого возможнен запуск исполняемых файлов. Наиболее удобным является подкаталог winext, расположенный в каталоге установки windbg. При выборе этого каталога при последующей загрузке расширения в windbg достаточно будет просто указать имя. В других случаях придется указывать полный путь.

Можно начинать работу? Не совсем. Для работы pykd необходимо, чтобы на машине был установлен Microsoft Visual C++ 2005 SP1 Redistributable Package нужной версии и разрядности. Загрузить его можно с сайта Microsoft или со страницы загрузки: ссылка, файл vcredist_x86 или vcredist_x64. С выбором нужного, надеюсь, понятно. Вот теперь - можно начинать!

Запускаем отладчик windbg и открываем любую отладочную сессию: начинаем отладку пользоватеьского процесса, загружаем креш-дамп или подключаемся к отладчику ядра удаленной машины. Далее необходимо загрузить расширение. Если вы установили его по рекомендованному пути, сделать это просто:
.load pykd.pyd
Проверим, что все заработало, вводим команду !pycmd для перехода в режим интерпретатора python
1>!pycmd
>>> print "hello world!"
hello world!
>>>
Для выхода из режима интерпретатора просто вводим пустую строку. Если у вас получилось вывести на экран приветственную строку, значит с установкой и настройкой все получилось. Теперь пора подумать, какую из этого можно извлечь пользу. Сам по себе интерпретатор python кончено очень занимательная штука, но нам он нужен для управления отладчиком. Поскольку pykd.pyd является не только расширением для windbg, но и модулем python, он нам в этом и поможет:
1>!pycmd
>>> from pykd import *
>>> eax = reg("eax")
>>> print eax
125
>>>
Мы использовали функцию reg, реализованную в модуле pykd. Полный список API приведен здесь.
Сессия интерпретатора питона длится, пока pykd не будет выгружен. Поэтому можно много позже сделать
1>!pycmd
>>> print eax
125
и получить сохраненное в контексте python значение.

Кроме глобальной сессии интерпретора python есть возможность выполнить скрипт в изолированной среде:
1>!py myscript.py "hello script"
hello from script
На сайте проекта приведены как небольшие демонстрационные примеры таких скриптов, так и скрипты, которые вы можете использовать в своей работе. Здесь можно получить подробную информацию.

И так, вы попробовали и:
1) вам понравилось. Тогда помогите проекту: примите участие в разработке, написании документации, пришлите свой полезный скрипт, киньте ссылку коллеге - он то наверняка сидит без дела целыми днями в инете. Да просто напишите нам свое мнение - для нас это будет очень ценно.
2) не понравилось. Очень вам просим, напишите, что именно! Это очень важно для нас.

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

Release 0.0.14

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

В класс typedVarClass добавлен метод получения аттрибутов __getattr__. Получение аттрибута трактуется как вычисление адреса переменной(функции) модуля.
Сравните два фрагмента кода. В старой редакции для получения адреса переменной необходимо было явно вызывать функцию getOffset:

# Old version
nt = loadModule( "nt" )
nt.PsActiveProcessHead = getOffset( "nt", "PsActiveProcessHead" )
processList = typedVarList( nt.PsActiveProcessHead, "nt", "_EPROCESS", "ActiveProcessLinks" )

Теперь в этом нет нужды, при обращении к аттрибуту экземпляра класса модуля, эта функция будет вызвана автоматически

# New version
nt = loadModule( "nt" )
#nt.PsActiveProcessHead = getOffset( "nt", "PsActiveProcessHead" )
processList = typedVarList( nt.PsActiveProcessHead, "nt", "_EPROCESS", "ActiveProcessLinks" )

При использовании команды !pycmd часто возникает желание распечатать содержимое переменной, полученной через вызов typedVar. До этого единственным способом было явное обращение к аттрибутам ( соответствующим полям стурктуры ). Оператор print - не работал. Поэтому в класс typedVarClass был добавлен метод __str__, возвращающий текстовое представление класса:

p = typedVarList( "nt", "_EPROCESS", processAddr )
print p

суббота, 1 января 2011 г.

Оставить отзыв

Если у вас есть любые предложения, жалобы или слова благодарности, оставьте комментарий к этому сообщению.