pykd/docs/ru/tutorial.txt
SND\kernelnet_cp 6ece37ff95 [0.3.x] branch : docs
git-svn-id: https://pykd.svn.codeplex.com/svn@87944 9b283d60-5439-405e-af05-b73fd8c4d996
2017-11-03 14:36:27 +04:00

126 lines
8.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

!! Введение
!!!! Шаг 1. Начало работы
Для установки лучше всего воспользоваться автоматическим инсталлятором. Он установит pykd в нужно место, а также установит и зарегистрирует все необходимые компоненты.
Если установка завершилась без ошибок, пора познакомится с pykd. Для этого стартуем windbg и начинаем отладочную сессию ( открываем процесс, дамп или устанавливаем соединение с отладчиком ядра ). Теперь можно загрузить pykd. Для этого выполняем команду:
.load pykd.pyd
Если во время загрузки случится какая либо ошибка - windbg выдаст сообщение. Отсутствие каких либо сообщений свидетельствует об удачной загрузки расширения.
Теперь можно начинать работу. Выполним команду !pycmd. После ее выполнения отладчик перейдет в режим ввода пользовательских данных. Весь пользовательский ввод будет обрабатываться интерпретатором python.
{{
0:000> !pycmd
Python 2.6.6 (r266:84297, Aug 24 2010, 18:13:38) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> print "Hello world!"
Hello world!
>>>
}}
Тут самое время ознакомится с синтаксисом python, если кто еще не знаком. Уверяю, это не должно занять много времени: python очень прост в освоении.
Давайте вспомним базовые основы синтаксиса python:
{{
>>> def printHello():
... i = 0
... while i < 4:
... print "Hello #%d" % i
... i += 1
...
>>> printHello()
Hello #0
Hello #1
Hello #2
Hello #3
>>>
}}
Обратите внимание: вложенность блоков задается количеством лидирующих пробелов. Это, так сказать, "фирменная" особенность python. Пока этих знаний нам будет вполне достаточно. Двигаемся дальше.
!!!! Шаг 2. Доступ к регистрам.
Любой отладчик должен предоставлять три базовые возможности: чтение регистров процессора, чтение памяти и управление режимом отладки. Начнем с регистров. С pykd это делается довольно просто:
{{
>>> print hex(reg("eip"))
0x778ecb60
>>> print hex(reg("esp"))
0x1ef0e0
>>> print hex(reg("esp")+4)
0x1ef0e4
}}
В данном случае, мы используем функцию PYKD *reg*. Она осуществляет чтение регистров процессора по имени. Пытливый читатель может спросить: как мы используем функции из PYKD без импортирования самого модуля? На самом деле, модуль конечно надо импортировать. Просто PYKD это сделал автоматически при конструировании консоли Python.
Давайте напишем небольшой пример и посмотрим, куда указывает текущий счетчик инструкций:
{{
>>> print findSymbol(reg("eip"))
ntdll!LdrpDoDebuggerBreak+30
}}
Функция *findSymbol* пытается для данного адреса найти т.н. отладочный символ. В данном случае мы видим, что счетчика инструкций равен смещению 0x30 относительно функции LdrpDoDebuggerBreak, т.е мы попросту находимся внутри функции LdrpDoDebuggerBreak, находящейся в модуле ntdll. Мы это смогли выяснить, поскольку у нас есть отладочная информация для модуля ntdll.dll ( соответствующий pdb файл ). Если у вас по какой то причине символы не показываются, необходимо проверить настройки путей к символам в windbg.
!!!! Шаг 4. Доступ к памяти
Для доступа к памяти PYKD предлагает большой набор функций. Их можно разделить на 3 группы:
* Чтение значения из памяти:
*ptrByte*
*ptrWord*
*ptrDWord*
*ptrQWord*
И другие, с полным набором можно ознакомится в [справке по API|PYKD 0.2. API Reference]
Все функции принимают в качестве параметра адрес и возвращают значение, хранящееся по данному адресу.
* Чтение массивов
*loadBytes*
*loadWords*
*loadDWords*
*loadQWords*
Все функции принимают в качестве параметров указатель на начало массива и его длину в элементах. Возвращают объект *list* c элементами массива
* Чтение строк
*loadCStr*
*loadWStr*
Функции читают из памяти 0-терминированные строки возвращают python строки.
Давайте модифицируем предыдущий пример и выведем аргументы функции. Будем считать, что функция имеет соглашение о вызове stdcall и ее параметры адресуются регистром ebp
{{
>>> def printFunc():
... print findSymbol( reg("eip") )
... params = [ ptrDWord( reg("ebp") + 4*(i+1) ) for i in range(0,3) ]
... print "var1: %x var2: %x var3: %x" % ( params[0], params[1], params[2] )
...
>>> print printFunc()
ntdll32!LdrpDoDebuggerBreak+2c
var1: 774b1383 var2: fffdd000 var3: fffde000
None
>>>
}}
Обратите внимание на конструкцию:
{{
params = [ ptrDWord( reg("ebp") + 4*(i+1) ) for i in range(0,3) ]
}}
Это т.н генератор списка - специальная конструкция python, которую можно использовать для инициализации списков. Это конструкция эквивалентна следующей
{{
[ ptrDWord( reg("ebp") + 4) ), ptrDWord( reg("ebp") + 8) ), ptrDWord( reg("ebp") + 0xC) ) ]
}}
!!!! Шаг 5. Доступ к памяти с учетом типа.
При отладке программ мы чаще всего сталкиваемся с типизированными переменными. PYKD имеет богатые возможности для доступа к переменным с учетом типа. По сути, эта главная "фишка" всего проекта: доступ к полям структур и классов осуществляется очень похожим на исходный код способом. Например, допустим у нас есть следующий код на Си:
{{
struct STRUCT_A {
int filed1;
char field2;
};
STRUCT_A a = { 100, 2}
}}
Теперь во время отладки мы хотим проверить состояние переменной 'a' c помощью PYKD:
{{
a = typedVar( "module!STRUCT_A", getOffset("module!a") )
if a.field1!=100 or a.field2!=2:
print "ERROR! a is not poperly initialized!"
}}