среда, 26 января 2011 г.
Скрипты для windbg
В данном посте я хочу предствить ряд скриптов, написанных с помощью pykd, которые могут пригодится в повседневной работе многим. Описание их работы есть в wiki на сайте проекта ( ссылка ) и я не буду репостить текст. Допустим вы уже прочитали статью с wiki и уже хотите попробовать. Где взять сами скрипты? Через дистрибутив они не распространяются, единственный способ - скачать из репозитория исходного кода ( ссылка ). В каталоге samples лежат, как не трудно догадаться, разные демонстрационный примеры. А в каталоге snippets - как раз то, что мы ищем. Допустим вы скачали исходный код, куда теперь распаковать каталоги со скриптами? Это не важно - в любой каталог, куда есть доступ. Для удобства использования настоятельно рекомендуется добавить этот путь в переменную окружения $PYTHONPATH. В этом случае, для вызова скрипта не нужно указывать полный путь, даже расширение можно опустить, примерно так:
!py export nt Zw*SetInformation*
Если вы написали полезный скрпит и хотите поделится им - присылайте ссылки на опубликованный код или исходный код и мы опубликуем его на сайте проекта под действующий лицензией.
Почта: pykd.codeplex@hotmail.com
четверг, 20 января 2011 г.
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
print p.Tcb.Alerted[1]
Вот ее прототип:
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;
};
вторник, 18 января 2011 г.
PYKD: Getting Started
Основная задача 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