четверг, 11 марта 2010 г.

Gray Hat Python Глава 01 v. 0.6



Как и обещал, выкладываю перевод первой главы весьма интересной книги "Gray Hat Python". Перевод пока весьма сыроват, но зато он есть. Буду рад замечаниям в переводе, вопросам и техническим уточнениям. И так, поехали.

Глава 1. Настройка вашего рабочего окружения.

Прежде чем вы начнете совершенствоваться в искусстве программирования в Серой Шляпе на языке Python, вам следует пройти самую неинтересную часть этой книги - настройки вашей будущей рабочей среды разработки. Весьма важно, чтобы вы имели хорошую и удобную среду разработки, которая позволит вам провести время в поглощении крайне интересной информации в данной книге, а не спотыкаться и набивать шишки, пытаясь заставить ваш код выполняться.


Эта глава быстро покрывает тему установки и настройки Python 2.5 (на момент перевода версия Python уже 2.6, как будет работать с 3 версией без понятия, но всё равно для всех примеров в книге будет использоваться Python именно версии 2.5. прим. пер.), конфигурирования вашего рабочего окружения Eclipse, и основы написания Си-совместимого кода на Python. Как только вы настроите окружение и поймете основы,
мир будет для вас устрицей, а эта книга покажет вам, как её открыть.

1.1. Требования к системе.

Я предполагаю, что вы используете 32-битную ОС, основанную на базе Windows (XP, Vista, 7). Windows имеет широкий спектр инструментов и хорошо поддается для программирования на Python. Все главы этой книги ориентированны в первую очередь на Windows, и большинство примеров будут работать только с ОС Windows.

Однако, будет несколько примеров, которые вы можете запустить на дистрибутиве Linux. Для разработки под Linux я рекомендую вам скачать 32-битный дистрибутив Linux'a как VMware устройства. Проигрыватель VMware устройств бесплатен, и позволяет вам быстро перемещать файлы с вашей рабочей системы на виртуальную Linux машину. Если у вас завалялся лишний компьютер, можете попробовать свои силы и установить полноценную Linux систему. Для целей книги использовался основанный на Red Hat Linux дистрибутив, вроде Fedora Core 7 или Centos 5. Конечно, в качестве альтернативы, вы можете запустить Linux и сэмулировать на нём Windows. Это дело вашего вкуса.


/==============================================\
Бесплатные образы для VMware.
На сайте VMware есть каталог бесплатных устройств. Эти устройства позволяют обратному разработчику (реверс инженеру) или исследователю уязвимостей разместить вредоносную программу (malware) или приложения на виртуальной машине, сокращая к минимуму риски для физической инфраструктуры и предоставляют изолированный "черновик" для работы. Вы можете посетить страницу виртуальных устройств по адресу и скачать плеер по адресу .
\==============================================/


1.2 Получение и установка Python 2.5

Среда Python устанавливается быстро и безболезненно как на Linux так и на Windows. Пользователям Windows облегчит жизнь установщик, который позаботится обо всех настройках, однако на Linux вы будете собирать и устанавливать Python из исходных кодов (Однако на очень многих дистрибутивах Linux Python 2.5 установлен "из коробки").

1.2.1 Установка Python в Windows.

Пользователи Windows могут получить установщик с официального сайта Python . Только дважды щелкните мышкой по файлу установщика и следуйте далее шаг за шагом по этапам установки. Установщик создаст каталог C:\Python25/. В этом каталоге будут установлены файл python.exe - интерпретатор команд Python, а так же все стандартные библиотеки.

Примечание: Вместо этого вы можете установить отладчик Immunity Debugger, который содержит не только сам отладчик, но и установщик Python 2.5. В последних главах книги вы будете использовать Immunity Debugger для многих задач, поэтому вы можете "убить двух зайцев" одной установкой. Чтобы скачать и установить Immunity Debugger, посетите

1.2.2 Установка Python в Linux
Для установки Python 2.5 в ОС Linux, вам следует скачать и скомпилировать исходные коды. Это дает вам полный контроль над настройками в процессе установки Python в ОС на базе Red Hat. Процесс установки подразумевает, что вы будете выполнять все следующие команды от имени пользователя root(суперпользователя).

Первым шагом будет загрузка и распаковка исходного кода Python 2.5. В командном терминале (консоли) вводите следующее:
----------------------------------------------------------
# cd /usr/local
# wget http://python.org/ftp/pyton/2.5.1/Python-2.5.1.tgz
# tar -zxvf Python-2.5.1.tgz
# mv Python-2.5.1 Python25
# cd Python25

----------------------------------------------------------

Вы только что скачали и распаковали исходный код в /usr/local/Python25. Следующим шагом будет компиляция исходного кода и проверки работоспособности интерпретатора Python:

----------------------------------------------------------
# ./configure --prefix=/usr/local/Python25
# make && make install
# pwd

/usr/local/Python25
#python
Python 2.5.1 (r251:54863, Mar 14 2012, 07:39:18)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on Linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
----------------------------------------------------------

Теперь вы находитесь в интерактивной оболочке Python, которая предоставляет вам полный доступ к интерпретатору Python и любой встроенной библиотеке. Быстрая проверка покажет, что команды интерпретируются верно:

-----------------------------------------------------------
>>> print "Hello World!"
Hello World!
>>> exit()
#
-----------------------------------------------------------

Отлично! Все работает, как вам надо. Чтобы застраховаться, что ваше пользовательское окружение находит, где находится интерпретатор Pyton, автоматически, вам следует изменить файл /root/.bashrc . Лично я использую текстовый редактор nano для всех моих работ с текстом, но вы вольны выбрать любой текстовый редактор, с которым вам комфортно работать. Откройте файл /root/.bashrc и в конце файла добавьте следующую строку:

-----------------------------------------------------------
export PATH=/urs/local/Pyton25/:$PATH
-----------------------------------------------------------

Эта строка укажет окружению Linux что пользователь root может иметь доступ к интерпретатору Python без указания полного пути к нему. Если вы закончите сессию root и затем войдете под root снова, когда вы введете python в любом месте в командной строке, вы незамедлительно окажетесь в интерпретаторе Python.

====================================================
Примечание переводчика: В Windows можно сделать то же самое. Для этого нужно щелкнуть правой кнопкой мыши на "Мой компьютер" -> "Свойства" -> "Дополнительно" -> "Переменные среды" -> Выбрать переменную "Path" -> "Изменить" -> В строке "Значение переменной" в конце дописать ;C:\Python25. Далее проверяем в командной строке. Вводим python и смотрим, запустился ли интерпретатор, как в случае с Linux или нет.
====================================================

И так, теперь у вас полностью рабочие интерпретаторы Python как в Windows так и в Linux. Настало время настроить вашу интегрированную среду разработки (IDE). Если у вас есть IDE в которой вам комфортно работать, то можете пропустить следующий раздел.


1.3. Настройка среды Eclipse и PyDev

Как правило для быстрой разработки и отладки Python приложений, абсолютно необходимо использовать полноценную IDE. Взаимодействие популярной среды разработки Eclipse и модуля PyDev к нему дает вам в руки огромное число мощных возможностей, которые не предлагают большинство других средств разработки. Кроме того, Eclipse запускается одинаково в Windows, Linux, и Mac, а так же имеет отличную группу поддержки и разработки. Давайте быстро пройдем все этапы как установить и настроить Eclipse и PyDev:

1. Скачиваете архив Eclipse Classic для вашей платформы с сайта .

2. Распаковываете его в C:\Eclipse

3. Запускаете C:\Eclipse\eclipse.exe

4. При первом запуске Eclipse спросит вас где хранить ваше рабочее место, вы можете принять предлагаемое место по умолчанию, и поставить галочку в графу Use this as default and do not ask again. Щелкните на OK.

5. Как только Eclipse запустится выберите Help > Install new Software....

6. Переходите к полю Work with:.

7. Кликните на кнопку Add...

8. В поле Name введите описывающую строку, вроде PyDev Update. Убедитесь, что поле URL содержит http://pydev.org/updates и щёлкните OK. Затем щелкните Finish, и вас выбросит в установщик обновлений Eclipse.

9. Диалог обновлений появится через несколько мгновений. Когда он появится, выберите PyDev и нажмите Next для продолжения.

10. Затем прочитайте и примите лицензионное соглашение для PyDev. Если вы согласны с ним, то выберите I accept the terms in the license agreement.

11. Щелкните Next и наконец Finish. Вы увидите, как Eclipse установит PyDev дополнение.

12. В конце кликните Yes в диалоговом меню, которое появится после установки PyDev. Это перезагрузит Eclipse, и запустит его с вашим новеньким PyDev.


На следующей стадии конфигурирования Eclipse вы убедитесь, что PyDev может найти правильный интерпретатор Python для последующего использования, когда вы будете запускать скрипты в PyDev:

1. Когда запустится Eclipse, выберите Window > Preferences.

2. Разверните ветвь PyDev, и выберите Interpreter - Python.

3. Нажмите кнопку New....

4. Укажите путь в Browse C:\Python25]python.exe и кликните Open.

5. Следующее диалоговое окно покажет вам список включенных библиотек для интерпретатора. Оставьте все как есть и кликните OK.

6. Затем кликните OK еще раз, чтобы закончить настройку интерпретатора.


Теперь у вас есть установленный и работоспособный PyDev, настроенный для использования свежеустановленного интерпретатора Python 2.5. Прежде чем начнете программировать, вам следует создать новый PyDev проект. Этот проект будет содержать все исходные файлы, данные далее в этой книге. Чтобы настроить новый проект, следуйте следующим образом:

1. Выберите File > New > Project.

2. Разверните ветку PyDev, и выберите PyDev Project. Кликните Next для продолжения.

3. Назовите Gray Hat Python. Щёлкните Finish.

Вы заметите, что экран Eclipse перегруппирует себя, и вы увидите проект Gray Hat Python проект в наверху слева. Теперь щелкните правой кнопкой мыши папу src и выберите New > PyDev Module. В графе Name введите chapter1-test, и кликните на Finish. Вы увидите, что панель вашего проекта обновится, и в этот список будет добавлен файл chapter1-test.py.

Чтобы запустить скрипт Python в среде Eclipse, только кликните кнопку Run As (зеленый кружок с белой стрелкой внутри) на панели инструментов. Чтобы заново запустить последний запущенный скрипт нажмите Ctrl+F11. Когда вы запустите скрипт в Eclipse, вместо командной строки Windows, вы увидите панель внизу среды Eclipse, обозначенной, как Console. Весь вывод ваших скриптов будет отображаться на панели Console. Вы так же можете обратить внимание, что текстовый редактор уже открыл chapter1-test.py и уже ожидает немного сладкого нектара Python.


1.3.1. Лучшие друзья Хакера: ctypes.

Модуль ctypes для Python является безусловно одной из самых мощных библиотек, доступных разработчику на Python. Библиотека ctypes позволяет вам вызывать функции в динамически подключаемых библиотеках (dll) и имеет богатые возможности для создания комплексных типов данных языка Си и полезных функций для низкоуровневой работы с памятью. Это необходимо для того, чтобы вы понимали основы того, как использовать библиотеку ctypes, так как вы будете полагаться на эту библиотеку в значительной степени на протяжении всей книги.


1.3.2 Использование динамических библиотек.

Первый шаг на пути использования ctypes это понимание, как запускать и получать доступ к функциям в динамически подключаемых библиотеках. Динамически подключаемая библиотека (dynamically linked library) - это скомпилированный бинарный файл, который подключаются к основному процессу во время его выполнения по мере надобности. На платформе Windows эти бинарные файлы называются динамически подключаемые библиотеки, а на платформе Linux - разделяемые объекты (eng. shared objects(SO)). В обоих случаях эти бинарные файлы предоставляют функции через экспортированные имена, какие получают возможность запуска по реальным адресам в памяти. Обычно во время выполнения вам приходится решать, какой будет порядок адресов функций для вызова этих функций, однако с ctypes вся эта грязная работа уже сделана.//Еще не один раз перечитать и по-человечески дописать весь абзац, прим.

Есть три различных способа загрузки dll в ctypes: cdll(), windll(), и oledll(). Разница между ними в том, каким образом вызываются функции этих библиотек, и какие они возвращают значения. Метод cdll() используется для запуска библиотек, которые экспортируют функции, используя стандартное соглашение вызова cdecl. Метод windll() загружает библиотеки, которые экспортируют функции, используя соглашение вызова stdcall, которое является родным соглашением в Microsoft Win32 API. Ну а метод oledll() работает так же, как windll(), однако, он предполагает, что экспортированная функция возвращает Windows код ошибки HRESULT, который используется специально для сообщений об ошибках, возвращаемых функциями Объектной Модели Компонентов (MS Component Object Model, COM).

В качестве небольшого примера, вы возьмете функцию printf() из библиотеки времени исполнения языка C (С runtime) в Windows и Linux, и используете её для вывода в тестовом сообщении. В Windows C runtime находится в msvcrt.dll, находящемся в папке C:\WINDOWS\System32\, а в Linux это libc.so.6, которая по умолчанию находится в /lib/. Создайте следующий скрипт Python или в Eclipse, или в вашей обычной рабочей директории Python, и введите следующий код:

chapter1-printf.py Код для Windows
-----------------------------------------------------------
from ctypes import *

msvcrt = cdll.msvcrt
message_string = "Hello world!\n"
msvcrt.printf("Testing: %s", message_string)
-----------------------------------------------------------

Этот скрипт выводит следующее:
-----------------------------------------------------------
C:\Python25\python chapter1-printf.py
Testing: Hello world!
C:\Python25>
-----------------------------------------------------------

Под Linux этот пример будет немного отличаться, но делать будет то же самое. Перейдите в Linux и создайте chapter1-printf.py в вашей директории /root/

/==============================================\
Понимание соглашений вызовов.

Соглашение вызовов описывает как правильно вызывать определенную функцию. Оно включает в себя порядок того, как выделяются параметры функции, какие параметры функции помещаются в стек или переходят в регистры, и как раскручивается стек при возвращении функцией значения. Вам надо научиться понимать два соглашения вызовов: cdecl и stdcall. В соглашении cdecl параметры помещаются в стек справа налево, и вызывающий функцию ответственен за очистку стека от аргументов. Это соглашение используется в большинстве C-систем на архитектуре x86.

Вот пример вызова функции с помощью cdecl:

На языке C
-----------------------------------------------------------
int python_rocks(reason_one, reason_two, reason_tree);
-----------------------------------------------------------

На ассемблере x86:
-----------------------------------------------------------
push reason_tree
push reason_two
push reason_one
call python_rocks
add esp, 12
-----------------------------------------------------------

Вы можете ясно увидеть, как передаются аргументы функции. Последняя линия выделяет (увеличивает) стеку 12 байт (у функции 3 параметра, и каждый параметр стека занимает 4 байта, поэтому в сумме дает 12 бит), которых как раз хватает для этих параметров.

Пример соглашения stdcall, которые используются в Win32 API демонстрируется тут:

На языке C:
-----------------------------------------------------------
int my_socks(color_one, color_two, color_tree);
-----------------------------------------------------------

На языке ассемблера x86
-----------------------------------------------------------
push color_tree
push color_two
push color_one
call my_socks
-----------------------------------------------------------
В данном случае вы видите, что порядок параметров такой же, но очистка стека не проводится вызывающим функцию, а функцией перед возвращением ей полученных значений.

Для обеих соглашений важно запомнить, что возвращенные значения функции хранятся в регистре EAX.
\==============================================/


chapter1-printf.py пример для Linux
-----------------------------------------------------------
from ctypes import *

libc = CDLL("libc.so.6")
message_string = "Hello world!\n"
libc.printf("Testing: %s", message_string)
-----------------------------------------------------------

Данный скрипт в Linux будет выводить следующее:
-----------------------------------------------------------
#python /root/chapter1-printf.py
Testing: Hello world!
#
-----------------------------------------------------------

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


1.3.3 Конструирование типов данных C


Создание типа данных языка C в Python - это словно откровенная сексуальность в этом гиковском, странном способе (Дословно: Creating a C datatype in Python is just downright sexy, in that nerdy, weird way. кто предложит перевод лучше, будет молодцом ). Наличие этих особенностей позволяет вам полностью использовать компоненты, написанные на C и C++, которые значительно увеличивают мощь языка Python. Кратко просмотрите таблицу 1-1, для понимания того, как взаимосвязаны типы данных C и Python и результирующий тип ctypes.



Видите, как хорошо типы данных конвертируются туда и обратно? Используйте эту таблицу для удобства, в случае, если вы забудете преобразование типов. Типы из ctypes могут быть инициализированы со значением, но оно должно быть надлежащего типа и размера. Для демонстрации, откройте вашу оболочку Python и введите несколько следующих примеров:
-----------------------------------------------------------
C:\Python25>python.exe
Python 2.5 (r25:51908, Sep 19 2006, 09:52:17) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import *
>>> c_int()
c_long(0)
>>> c_char_p("Hello, world!")
c_char_p('Hello, world!')
>>> c_ushort(-5)
c_ushort(65531)
>>>
>>> seitz = c_char_p("loves the python")
>>> print seitz
c_char_p('loves the python')
>>> print seitz.value
loves the python
>>> exit()
-----------------------------------------------------------

Последний пример описывает вам как переменной seitz присваивается указатель на строку "loves the python". Для доступа к содержимому указателя используется метод seitz.value, который называется разыменовыванием указателя.


1.3.4 Передача параметров по ссылке.

Очень часто в C и C++ есть функции, которые ожидают указатель, как один из параметров. Причина в том, что функция может как записывать в этот участок памяти, или, если при передаче по значению параметр слишком велик. В любом случае, ctypes обладает функционалом чтобы сделать именно это, используя функцию byref(). Когда функция ожидает указатель, в качестве параметра, вы вызываете её так: fuction_main(byref (parametr) ).


1.3.5 Определение структур и объединений.

Структуры и объединения - важные типы данных, которые часто используются как Win32 API, так и с libc в Linux. Структура - это простая группа переменных, которые могут быть одного или разных типов данных. Вы можете получить доступ к любой содержащейся в структуре переменной, используя точечную нотацию (dot notation), например такую: beer_recipe.amt_barley. Это даст доступ к переменной amt_barley, находящейся в структуре beer_recipe. Следующий пример определит структуру (или struct как их обычно называют для упрощения) как в C так и в Python.

Код на C.
-----------------------------------------------------------
structure beer_recipe
{
    int amt_barley;
    int amt_water;
};
-----------------------------------------------------------

Код на Python.
-----------------------------------------------------------
class beer_recipe(Structure):
    _fields_ = [
    ("amt_barley",c_int),
    ("amt_water",c_int),
    ]
-----------------------------------------------------------

Как видите, ctypes делает очень легким создание C-совместимой структуры. Замечу, что это не полный рецепт пива, и я не советую вам пить смесь ячменя и воды.

Объединения, это почти тоже самое, что и структуры. Однако в объединении все участвующие переменные находятся по одному адресу в памяти. Следующий пример демонстрирует объединение, которое позволяет вам отобразить число тремя разными способами.


Код на C

-----------------------------------------------------------
union {
    long barley_long;
    int barley_int;
     char barley_char[8];
}barley_amount;
-----------------------------------------------------------

Код на Python
-----------------------------------------------------------
class barley_amount(Union):
    _fields_=[
    ("barley_long", c_long),
    ("barley_int", c_int),
    ("barley_char", c_char * 8),
    ]
-----------------------------------------------------------

Если вы присвоите переменной barley_int из объединения barley_amount значение 66, то затем вы сможете использовать переменную barley_char для отображения символа представляющего это число. Для демонстрации создадим новый файл chapter1-unions.py и вобъем следующий код.

chapter1-unions.py
-----------------------------------------------------------
from ctypes import *

class barley_amount(Union):
    _fields_=[
    ("barley_long", c_long),
    ("barley_int", c_int),
    ("barley_char", c_char * 8),
    ]
value = raw_input("Enter the amount of barley to put into the beer vat:")
my_barley = barley_amount(int(value))
print "Barley amount as a long: %ld" %my_barley.barley_long
print "Barley amount as an int: %d" %my_barley.barley_long
print "Barley amount as a char: %s" %my_barley.barley_char
-----------------------------------------------------------
Вывод будет следующим
-----------------------------------------------------------
C:\Python25> python chapter1-unions.pyEnter the amount of barley to put into the beer vat:66
Barley amount as a long: 66
Barley amount as an int: 66
Barley amount as a char: B

C:\Python25>
-----------------------------------------------------------

Как видите, присвоив объединению одно значение, вы можете получить три разных представления этого значения. Если вас смущает вывод значения переменной barley_char, а именно буква 'B', то это лишь эквивалент ASCII (американский стандарт кодировки) десятичного 66.

Переменная barley_char из этого объединения - отличный пример того, как определять массив в ctypes. В ctypes массив определяется путем умножения типа на количество элементов, которые вы хотите выделить в массиве. В предыдущем примере, 8-элементный массив символов был определен для переменной barley_char из объединения.

Теперь у вас есть рабочее окружение Python на двух отдельных системах, и теперь вы понимаете как взаимодействовать с низкоуровневыми библиотеками. Настало время для того, чтобы начать применять эти знания для создания широкого списка инструментов для помощи в реверс-инженерии и хакинге программ. Надеваем шлем.

5 комментариев:

  1. Ну всё отлично! жду дальше

    ОтветитьУдалить
  2. Спасибо за труды!

    ОтветитьУдалить
  3. Книга просто супер !! Спасибо вам что вы взялись её переводить !!!

    ОтветитьУдалить
  4. это словно откровенная сексуальность в этом гиковском, странном способе (Дословно: Creating a C datatype in Python is just downright sexy, in that nerdy,

    >
    это словно откровенное сексуальное извращение :)

    с уважением mindgames

    ОтветитьУдалить