Python поможет понять пример кода

Недавно я пытался выучить Python и столкнулся с чем-то, что мне трудно понять, как именно он работает. В первую очередь это оформление списка.

Список, о котором идет речь, взят из этой статьи по безопасности, в которой говорится о простом инструменте фаззинга: http://blog.securestate.com/post/2009/10/06/How-a-simple-python-fuzzer-brought-down-SMBv2-in-2-seconds.aspx

Фактический рассматриваемый список:

#Negotiate Protocol Request
packet = [chr(int(a, 16)) for a in """
00 00 00 90
ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00
00 00 00 00 00 00 00 00 ff ff ff fe 00 00 00 00
00 6d 00 02 50 43 20 4e 45 54 57 4f 52 4b 20 50
52 4f 47 52 41 4d 20 31 2e 30 00 02 4c 41 4e 4d
41 4e 31 2e 30 00 02 57 69 6e 64 6f 77 73 20 66
6f 72 20 57 6f 72 6b 67 72 6f 75 70 73 20 33 2e
31 61 00 02 4c 4d 31 2e 32 58 30 30 32 00 02 4c
41 4e 4d 41 4e 32 2e 31 00 02 4e 54 20 4c 4d 20
30 2e 31 32 00 02 53 4d 42 20 32 2e 30 30 32 00
""".split()]

Он извлекает из него один байт (я думаю?), Используя следующие строки:

what = packet[:]
where = choice(range(len(packet)))
which = chr(choice(range(256)))
what[where] = which

Я никогда не видел список, разработанный таким образом, и не могу понять, как он выбирает то, что он делает. Что меня больше всего смущает, так это packet = [chr(int(a, 16)) for a in """где он размещает все эти вещи в том, что кажется блоком комментариев... затем делает .split(), 0_о

Я знаю, что это неопределенный вопрос, но если бы кто-нибудь мог мне это объяснить или указать мне какую-то документацию, объясняющую этот стиль построения списка, я был бы исключительно счастлив. Это выглядит как очень эффективный способ хранения / извлечения большого количества байтов.

5 ответов

Решение

Давайте разберем его и упростим для удобства чтения:

    bytes = """
            00 00 00 90
            ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00
            00 00 00 00 00 00 00 00 ff ff ff fe 00 00 00 00
            00 6d 00 02 50 43 20 4e 45 54 57 4f 52 4b 20 50
            52 4f 47 52 41 4d 20 31 2e 30 00 02 4c 41 4e 4d
            41 4e 31 2e 30 00 02 57 69 6e 64 6f 77 73 20 66
            6f 72 20 57 6f 72 6b 67 72 6f 75 70 73 20 33 2e
            31 61 00 02 4c 4d 31 2e 32 58 30 30 32 00 02 4c
            41 4e 4d 41 4e 32 2e 31 00 02 4e 54 20 4c 4d 20
            30 2e 31 32 00 02 53 4d 42 20 32 2e 30 30 32 00
            """
    packet = [chr(int(a, 16)) for a in bytes.split()]

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

bytes.split() разделит пробел и вернет список отдельных частей строки, разделенных пробелами.

print bytes.split()

['00', '00', '00', '90', 'ff', '53', '4d', '42', '72', 
 '00', '00', '00', '00', '18', '53', 'c8', '00', '00' ... ] # and more

Итак, вот это:

packet = [chr(int(a, 16)) for a in bytes.split()]

Это понимание списка:

  • Трещина bytes и получите этот список, как указано выше
  • для каждого элемента в списке (a здесь), выполнить int(a,16) на нем, который получит свое целочисленное значение, выполнив преобразование base-16 в десятичное (т.е. FF было бы 255).
  • Тогда делай chr на это значение, которое вернет вам значение ASCII этого байта.

Так packet будет список байтов в форме ASCII.

print packet
['\x00', '\x00', '\x00', '\x90', '\xff', 'S', 'M', 'B', 'r', '\x00', '\x00', '\x00',
 '\x00', '\x18', 'S', '\xc8', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 
 '\x00', '\x00', '\x00', '\x00', '\x00', '\xff', '\xff', '\xff', '\xfe', '\x00', 
 '\x00', '\x00', '\x00', '\x00', 'm', '\x00', '\x02', 'P', 'C', ' ', 'N', 'E', 'T', 
 'W', 'O', 'R', 'K', ' ', 'P', 'R', 'O', 'G', 'R', 'A', 'M', ' ', '1', '.', '0', 
 '\x00', '\x02', 'L', 'A', 'N', 'M', 'A', 'N', '1', '.', '0', '\x00', '\x02', 'W', 'i', 
 'n', 'd', 'o', 'w', 's', ' ', 'f', 'o', 'r', ' ', 'W', 'o', 'r', 'k', 'g', 'r', 'o', 
 ... more ]

Это

"""
00 00 00 90
ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00
00 00 00 00 00 00 00 00 ff ff ff fe 00 00 00 00
00 6d 00 02 50 43 20 4e 45 54 57 4f 52 4b 20 50
52 4f 47 52 41 4d 20 31 2e 30 00 02 4c 41 4e 4d
41 4e 31 2e 30 00 02 57 69 6e 64 6f 77 73 20 66
6f 72 20 57 6f 72 6b 67 72 6f 75 70 73 20 33 2e
31 61 00 02 4c 4d 31 2e 32 58 30 30 32 00 02 4c
41 4e 4d 41 4e 32 2e 31 00 02 4e 54 20 4c 4d 20
30 2e 31 32 00 02 53 4d 42 20 32 2e 30 30 32 00
"""

это просто многострочная строка.

"""
00 00 00 90
ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00
""".split()

производит разбиение с пробелами вышеупомянутой строки:

['00', '00', '00', '90', 'ff', '53', '4d', '42', '72', '00', '00', '00', '00', '18', '53', 'c8', '00', '00', '00', '00']

И это:

[chr(int(a, 16)) for a in ['00', '00', '00', '90', 'ff', '53', '4d', '42', '72', '00', '00', '00', '00', '18', '53', 'c8', '00', '00', '00', '00']]

это понимание списка, которое проходит через сформированный список и преобразует все значения, применяя chr(int(a,16)) для каждого a,

int(a,16) преобразует строку, содержащую шестнадцатеричное строковое представление, в int,

chr преобразует это целое число в символ

Результат:

>>> [chr(int(a, 16)) for a in ['00', '00', '00', '90', 'ff', '53', '4d', '42', '72', '00', '00', '00', '00', '18', '53', 'c8', '00', '00', '00', '00']]
['\x00', '\x00', '\x00', '\x90', '\xff', 'S', 'M', 'B', 'r', '\x00', '\x00', '\x00', '\x00', '\x18', 'S', '\xc8', '\x00', '\x00', '\x00', '\x00']

   """
content
"""

Формат - это простой способ определения многострочных строковых литералов в Python. Это не блок комментариев.

[chr(int(a, 16)) for a in "00 00 00...".split()] это понимание списка Большая строка разбивается на массив (разделенный пробелами), и для каждого элемента в массиве она преобразуется в шестнадцатеричное число (int(a,16) означает превращение строки a в int, строка a находится в базе 16), а затем возвращает этот символ ascii char (chr(...)) представлен этим целым числом.

packet[:] возвращает поверхностную копию списка packet,

choice(range(len(packet))) возвращает случайное число в диапазоне длины пакета.

chr(choice(range(256))) выбирает случайное число в диапазоне 0,255 и интерпретирует его как символ ascii, а затем последний оператор вставляет этот символ ascii в случайно выбранное место.

Здесь вы сталкиваетесь с парой разных концепций. Просто медленно работайте задом наперед, и вы поймете это.

"""00 00 00 90 ff 53 4d 42 72 00 00 00 00 18 53 c8 00 00 00 00""" - это просто большая строка..Split на нем разбивает его на массив пробелов, поэтому в этот момент у вас есть что-то вроде ['00', '00', '00', '90'....]

Остальная часть этой строки - это понимание списка - это причудливый способ сделать это:

new_list = []
for a in that_list_we_split_above:
    new_list.append( chr( int(a, 16) ) )

функция int преобразует строку в int в базе 16 - http://docs.python.org/library/functions.html

функция chr получает символ ascii, используя это число

так что в конце всей этой ерунды у вас есть список "пакет"

строка, определяющая, где берется длина этого списка, создает новый список с каждым числом от 0 до длины (т. е. каждый возможный индекс этого) и случайным образом выбирает один из них.

строка, для которой выбирается случайное целое число от 0 до 256 и для него получается символ ascii

последняя строка заменяет элемент в списке пакетов по индексу 'where' случайным символом ascii, определенным в котором

tl;dr: иди, найди другой код для изучения - это и запутанно, и не вдохновляет

Рассматриваемый образец кода, по-видимому, заменяет случайно выбранный байт в исходном пакете другим случайным байтом (который, я считаю, является одной из идей размытия).

packet = [chr(int(a, 16)) for a in """
 00 00 00 90 .... """.split()]

Это "разбить строку на пробел, прочитать подстроки как символы, декодированные из целых чисел в шестнадцатеричном формате (второй аргумент для int является основанием).

what = packet[:]

Python идиома для "скопировать packet массив в what".

where = choice(range(len(packet)))

Выберите случайный индекс в пакете.

which = chr(choice(range(256)))

Сделать случайный персонаж.

what[where] = which 

Подставьте его по ранее выбранному индексу.

Другие вопросы по тегам