Python3 обрабатывает не-ASCII символы странным образом

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

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

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

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

xff преобразуется в xc3xbf

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

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

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

Всего 2 ответа


В 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')"

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

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

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

b'xff'

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

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

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


Есть идеи?

10000