Python3 обрабатывает не-ASCII символы странным образом - PullRequest
1 голос
/ 16 мая 2019

Я пытался решить pwnable с помощью Python 3. Для этого мне нужно напечатать некоторые символы, не входящие в диапазон ASCII.

Python 3 преобразует эти символы в какой-то странный Unicode.

Например, если я печатаю "\xff" в Python 3, я получаю это:

root@kali:~# python3 -c 'print("\xff")' | xxd
00000000: c3bf 0a                                  ...

\xff преобразуется в \xc3\xbf

Но в Python 2 он работает, как и ожидалось, вот так:

root@kali:~# python -c 'print("\xff")' | xxd
00000000: ff0a                                     ..

Так как же это можно напечатать в Python 3?

Ответы [ 2 ]

2 голосов
/ 16 мая 2019

В Python 2 str и bytes были одинаковыми, поэтому, когда вы писали '\xff', результат содержал фактический байт 0xFF.

В Python 3 str ближе к объекту unicode в Python 2 и не является псевдонимом для bytes. \xff больше не является запросом на вставку байта, а скорее является запросом на вставку символа Unicode, код которого может быть представлен в 8 битах. Строка печатается с вашей кодировкой по умолчанию (возможно, UTF-8), в которой символ 0xFF кодируется как байты \xc3\xbf. \x - это в основном однобайтовая версия \u, когда она появляется в строке. Это все то же самое, что и раньше, когда оно появляется в bytes.

Теперь для решения. Если вам просто нужно несколько байтов, сделайте

b'\xff'

Это будет работать так же, как в Python 2. Вы можете записать эти байты в двоичный файл, но затем не сможете печатать напрямую, поскольку все, что вы печатаете, конвертируется в str. Проблема печати заключается в том, что все кодируется в текстовом режиме. К счастью, sys.stdout имеет атрибут buffer, который позволяет вам выводить bytes напрямую:

sys.stdout.buffer.write(b'\xff\n')

Это будет работать, только если вы не замените sys.stdout чем-то необычным, у которого нет buffer.

1 голос
/ 16 мая 2019

В Python 2 print '\xff' записывает строку байтов непосредственно в терминал, так что вы получаете печатаемый байт.

В Python 3 print('\xff') кодирует символ Unicode U + 00FF для терминала, используя кодировку по умолчанию ... в вашем случае UTF-8.

Чтобы напрямую выводить байты на терминал в Python 3, вы не можете использовать print, но вы можете использовать следующее, чтобы пропустить кодирование и написать строку байтов:

python3 -c "import sys; sys.stdout.buffer.write(b'\xff')"
...