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

Хэширование строк в C

atavism

HalReturnToBorderline
Premium
Регистрация
03.05.2020
Сообщения
150
Реакции
85
Депозит
0.0016
Немного туплю по этому поводу. Додумался вот до вот такого варианта:
C:
#define HASH_STRING(function, ...) (function)(__VA_ARGS__)

Где "function" - наша хеширующая функция. Ну, к примеру:
C:
int hashString(WCHAR *str) {
    ULONG i = 0;
    ULONG hash = 0;

    while (i = *str++) {
        hash = (i + (hash << 6) + (hash << 16) - hash) ^ 0xF0000000L;
    }

    return hash;
}

В итоге получается что-то похожее:
C:
#define Secret HASH_STRING(hashString, L"Hashed");

Однако, строки все равно остаются и подсчет хэша происходит после появляения самой строки (насколько понимаю из-за механизма макроподстановки функций):
1638830445100.png


Может, есть более простые и действенные методы хеширования? Можно, конечно и без функции работать, а чисто на макросе, но тогда в моем понимании я буду очень ограничен. Благодарю!
 
Решение
Не знаю, зачем, но я запилил пример простого хеширования на С-макросах, о котором говорил. Просто захотелось проверить, могу ли я до сих пор циклический алгоритм преобразовать в рекурсивный. Ну решение тупое, некрасивое и костыльное, конечно, но, судя по асм листингу, вроде работает (для того, чтобы constant folding работал и вся эта чушь препроцессора свернулась в одну константу, нужна включенная оптимизация). Может пригодиться кому, я хз:
C:
#include <stdint.h>
#include <stdio.h>

#define FNV_32_PRIME 0x01000193
#define FNV_32_SEED  0x811c9dc5

#define HASH00(S) FNV_32_SEED
#define HASH01(S) (HASH00(S) * FNV_32_PRIME ^ (uint32_t)S[0])
#define HASH02(S) (HASH01(S) * FNV_32_PRIME ^ (uint32_t)S[1])
#define HASH03(S) (HASH02(S) *...
Пожалуйста, обратите внимание, что пользователь заблокирован
В чистом Си нереально зашифровать строки макропроцессором. По крайней мере, мне не удалось. Нужен или С++11 либо нестандартные варианты (у GCC вроде было или там можно дописать).
 
Пожалуйста, обратите внимание, что пользователь заблокирован
В чистом Си нереально зашифровать строки макропроцессором
Да и хешировать тоже тяжело, можно "рекурсивным" макросом (HASH_STRING10 вызывает HASH_STRING09 и тд) по длине строки, но это такой костыль, что мне даже стыдно о нем упоминать. Нужно либо перейти на плюсы, где давно появился constexpr, либо использовать внешний препроцессор для исходников, как, например, я показывал в конкурсной статье.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Однако, строки все равно остаются и подсчет хэша происходит после появляения самой строки
Так может не использовать вообще строки, а все хеши посчитать, выписать заранее и резолв адресов делать по хешу? Это конечно если импортов не много.
 
Вынеси строки в отдельный файл *.h и шифруй их внешним сотфом перед компиляцией, почти тоже что макропроцессор =)

 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Не знаю, зачем, но я запилил пример простого хеширования на С-макросах, о котором говорил. Просто захотелось проверить, могу ли я до сих пор циклический алгоритм преобразовать в рекурсивный. Ну решение тупое, некрасивое и костыльное, конечно, но, судя по асм листингу, вроде работает (для того, чтобы constant folding работал и вся эта чушь препроцессора свернулась в одну константу, нужна включенная оптимизация). Может пригодиться кому, я хз:
C:
#include <stdint.h>
#include <stdio.h>

#define FNV_32_PRIME 0x01000193
#define FNV_32_SEED  0x811c9dc5

#define HASH00(S) FNV_32_SEED
#define HASH01(S) (HASH00(S) * FNV_32_PRIME ^ (uint32_t)S[0])
#define HASH02(S) (HASH01(S) * FNV_32_PRIME ^ (uint32_t)S[1])
#define HASH03(S) (HASH02(S) * FNV_32_PRIME ^ (uint32_t)S[2])
#define HASH04(S) (HASH03(S) * FNV_32_PRIME ^ (uint32_t)S[3])
// Продолжить до максимально возможной длины строки

uint32_t fnv32(const char* str) {
    uint32_t hval = FNV_32_SEED;

    while (*str) {
        hval *= FNV_32_PRIME;
        hval ^= (uint32_t)*str++;
    }

    return hval;
}

int main(int argc, char** argv) {
    printf("HASH MACRO: %X\n", HASH04("ABCD"));
    printf("HASH FUNC:  %X\n", fnv32("ABCD"));
    return 0;
}
 
Решение
Пожалуйста, обратите внимание, что пользователь заблокирован
Тоже стало интересно и запилил небольшой пример на CTL масмовском. Воспроизводил этот алгоритм.

Собственно, вот тестовый код макроса для подсчета хеша.

Код:
HashAPIName macro apiStr

hash = 35h
const1 =  0AB10F29Fh
    ; цикл с хешированием
    forc char, apiStr
        ; было неправильно
        ; hash = hash + (hash * const1 + '&char') AND 0FFFFFFh
        ; правильно
        hash = hash + ((hash * const1 + '&char') AND 0FFFFFFh)
    ; конец цикла
    endm
     ; вернуть хэш
    exitm <hash>
; конец макроса
endm

; Передаем CT потом в printf через edx
CT   dword  HashAPIName(<CreateThread>)

В дизасме строк нет, передается только хэш. Компайл тайм мать его.

apihash.png


Правда есть одна проблема, конечный хэш обрезается на байт почему-то (маска тут не причем). Догадки есть, но пока не решил.

Питоновский прототип для проверки был такой:
Python:
f_names  = ["CreateThread", "CreateProcess"]

def GetHashFromString(string, hash):
    for c in string:
        hash += (hash * 0xab10f29f + ord(c)) & 0xffffff
        print("Char value: " + c + "\t\t", "Hex value: " + hex(ord(c)) + "\t\t", "Hash value: " + hex(hash))
    return hash

for proc in f_names:
    print("\n" + proc + " hash\t", hex(GetHashFromString(proc, 0x35)) + "\n")

В итоге прога на макросе возвращает значение 0x44e304 (на скрине видно), а питухон 0x544e304. Хэш в асме начинает плыть после второй итерации.
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Правда есть одна проблема, конечный хэш обрезается на байт почему-то (маска тут не причем).
Так правильное значение питон выдает или макрос? Разница скорее всего в том, что в макросе сначала считается сложение с предыдущим значением хеша, а потом AND 0xffffff, а в питоне наоборот. Скобки попробуй правильно поставить в макросе.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Так правильное значение питон выдает или макрос? Разница скорее всего в том, что в макросе сначала считается сложение с предыдущим значением хеша, а потом AND 0xffffff, а в питоне наоборот. Скобки попробуй правильно поставить в макросе.
В статье, что в линке на павершелле и С значение такое же как на питоне. Т.е. где-то в макросе ошибка, либо какая-то интовая магия. Вроде скобки норм проставил, в упор не вижу ошибки.

Все. Надо было

hash = hash + ((hash * const1 + '&char') AND 0FFFFFFh)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Убери это, оно тебе первый байт обнуляет
Я не понимаю. Если бы ты удосужился посмотреть алгоритм хеширования, который он реализовывал, то понял бы, что он просто неправильно скобки расставил в первый раз, как бы алгоритму нужно обнулять старший байт. И он уже решил эту проблему:
hash = hash + ((hash * const1 + '&char') AND 0FFFFFFh)
 


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