• XSS.stack #1 – первый литературный журнал от юзеров форума

Python и utf-16-le

Lawsons

CD-диск
Пользователь
Регистрация
01.03.2020
Сообщения
14
Реакции
5
Работаю с C и питоном. Имеется определенный алгоритм хеширования, которым в теле С программы обрабатываются некоторые строки. Питон скрипт запускается билд эвентом. С ANSI строками всё в порядке, однако с Unicode - проблема.

Пытаюсь обработать строку следующим образом в C:

C:
DWORD dwHash = MyHash(lpModuleName, strlenW(lpModuleName) * 2, 123);

И следующим образом в питоне:

Python:
Ntdll = Hash(b'Test'.decode('utf-16-le', errors='replace'), 123)

Результат отличается. Подскажите пожалуйста, как решить проблему. Перепробовал уже множество методов.
 
Во-первых, убери хэширование. Откуда нам знать, может ты в нем накосячил, а не в кодировках. Сравнивай хэшируемые данные. Или уточни, что за хэширование такое. Кроме того, хэшируются всегда байты, а в python-листинге у тебя на вход твоей функции подается unicode (ты ведь третий питон используешь?)

Во-вторых, покажи пример строки. Судя по тому, что ты задал аргумент errors, у тебя были какие-то ошибки перекодировки?
 
Последнее редактирование:
Во-первых, убери хэширование. Откуда нам знать, может ты в нем накосячил, а не в кодировках. Сравнивай хэшируемые данные. Или уточни, что за хэширование такое. Кроме того, хэшируются всегда байты, а в python-листинге у тебя на вход твоей функции подается unicode (ты ведь третий питон используешь?)

Во-вторых, покажи пример строки. Судя по тому, что ты задал аргумент errors, у тебя были какие-то ошибки перекодировки?
Алгоритм хеширования - murmur3.

Для использования в C юзаю эту либу. ( hash x86 )

Для питона - следующий код:

Python:
def Hash(data, seed = 0):
    c1 = 0xcc9e2d51
    c2 = 0x1b873593

    length = len(data)
    h1 = seed
    roundedEnd = (length & 0xfffffffc)  # round down to 4 byte block
    for i in range(0, roundedEnd, 4):
      # little endian load order
      k1 = (ord(data[i]) & 0xff) | ((ord(data[i + 1]) & 0xff) << 8) | \
           ((ord(data[i + 2]) & 0xff) << 16) | (ord(data[i + 3]) << 24)
      k1 *= c1
      k1 = (k1 << 15) | ((k1 & 0xffffffff) >> 17) # ROTL32(k1,15)
      k1 *= c2

      h1 ^= k1
      h1 = (h1 << 13) | ((h1 & 0xffffffff) >> 19)  # ROTL32(h1,13)
      h1 = h1 * 5 + 0xe6546b64

    # tail
    k1 = 0

    val = length & 0x03
    if val == 3:
        k1 = (ord(data[roundedEnd + 2]) & 0xff) << 16
    # fallthrough
    if val in [2, 3]:
        k1 |= (ord(data[roundedEnd + 1]) & 0xff) << 8
    # fallthrough
    if val in [1, 2, 3]:
        k1 |= ord(data[roundedEnd]) & 0xff
        k1 *= c1
        k1 = (k1 << 15) | ((k1 & 0xffffffff) >> 17)  # ROTL32(k1,15)
        k1 *= c2
        h1 ^= k1

    # finalization
    h1 ^= length

    # fmix(h1)
    h1 ^= ((h1 & 0xffffffff) >> 16)
    h1 *= 0x85ebca6b
    h1 ^= ((h1 & 0xffffffff) >> 13)
    h1 *= 0xc2b2ae35
    h1 ^= ((h1 & 0xffffffff) >> 16)

    return h1 & 0xffffffff

Проблема сугубо в Unicode строками. Если я хеширую анси строки - результат одинаков. Если пробую работать с юникодом - не одинаков.

Пример строки:

C:
LPWSTR lpModuleName = L"ntdll.dll";

По поводу ошибок перекодировки - да. При попытке запуска скрипта без указания параметра errors получаю следующее:

UnicodeDecodeError: 'utf-16-le' codec can't decode byte 0x64 in position 2: truncated data
 
Пример строки:
C:
LPWSTR lpModuleName = L"ntdll.dll";
То есть в питоне, если раньше ты делал
Ntdll = Hash(b'Test'.decode('utf-16-le', errors='replace'), 123)
С этой строкой получается
Python:
Ntdll = Hash(b'ntdll.dll'.decode('utf-16-le', errors='replace'), 123)
правильно?

UTF16 кодирует каждый codepoint двумя байтами. Байтовая строка b'ntdll.dll' содержит нечетное количество байт. Это про конкретную ошибку.

Если говорить в целом, то
1) не пиши хэш-функцию с нуля, проверь есть ли на pypi готовые пакеты, а они есть https://pypi.org/project/murmurhash3/
2) в питоне хэшируются всегда байты, а не юникодовые строки. Потому что у юникодовой строки может быть множество различных представлений. Ты должен вызывать hash_function('unicode string'.encode('some encoding')), но тебе скорее всего придется исправить свою функцию. Разберись, как устроены байты и юникодовые строки в питоне.
3) используй type hinting или докстринги, чтобы было понятно, какой тип данных принимает на вход функция и что она возвращает.


Пример того как все должно работать
Python:
import binascii
import mmh3
binascii.hexlify(mmh3.hash_bytes('ntdll.dll'.encode('utf-16-le')))
# returns b'64235c61223f09dbdb0baae225494d11'
mmh3.hash('ntdll.dll'.encode('utf-16-le'))
# returns-2024649801
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх