Нет, мне нужно чтобы человек (или машина) вооруженный отладчиком при отладке кода этого замучился. Иначе будет очень просто по-шагам поисполнять и получить результат. Так нельзя.
То есть это разновидность защиты гениального кода от хакеров? Вы уверены, что код стоит того чтобы его защищать?
У меня есть классические знания по криптографии. И даже есть опыт обширный в написании, но это имеет мало отношения к вопросу:
Тут именно крипто не важен. Не важна криптостойкость. Тем более, что тут и шифротекст и ключ фактически лежат вместе, поэтому можно забыть про криптографию вовсе.
Мне нужно получить число A из числа B.
- Генерируем число R := B - A
- Генерируем алгоритм:
function algo1() {
return B - R; // B-R = B-B+A = A
}
Это одно из возможных решений, оно примитивное и нам не подходит.
Нужно уметь генерировать функции вроде algo1, но посложнее.
Такая вот задача, что скажете?
Да для защиты, вернее для того, чтобы посмотрев на два бинарника нельзя было сказать, что эти два бинарника - одно и то же.
Если у нас рандомный алгоритм, который оперирует с рандомным большим числом в const unsigned char *Source;, то и весь код, полученный компиляцией такого алгоритма с пришитым к нему рандомным же массивом будет непохож на такой же, но с другим алгоритмом и начальным числом.
Можно было бы написать один алгоритм и просто разбавлять его ничего не значащими конструкциями. Но такой подход устарел и нам не подходит.
Наш гениальный алгоритм вычисляет нужное нам число, а потом делает “jmp” прямо в вычисленное число.
Если я правильно понял, вам нужно сгенерить хеш вашего кода, из которого можно будет восстановить исходный текст. Чтобы придумать что-то заведомо стойкое нужны глубокие знания предмета, как уже сказали.
Если пробовать что-то простенькое “на коленке” - можно например сделать XOR каждого байта кода с неким “ключом” длиной в один или несколько байт
Да, такие защиты взламываются уже годов с 90х, со времен ДОСа - просто позволяется алгоритму запуститься на столько-то шагов, а потом сохраняется вся память на диск. С большой вероятность. распакованное число будет найдено.
Это, конечно, требует пошагово исполнять код (благо на интеле есть оладочный механизмы для этого) но тем не менее.
Но если количество шагов, требуемое для распаковки числа велико, то таким методом результат получить сложно. Похожие решения используются в антивирусах, в эвристических анализаторах кода. Там тоже пошагово исполняется подозрительный код и изучается результат. Но количество шагов опять же ограничено - если за разумное время ничего не расшифровалось, то антивирус такой файл отбрасывает
Пусть взламывается. Ничего страшного. Лишь бы бинарники (т.е. скомпилированный алгоритм + исходный хэш) были непохожи друг на дружку.
Вот с этим затык.
придумать генератор алгоритмов.
придумать генератор “простеньких алгоритмов на коленке”, которые при этом друг на дружку непохожи.
PS:
нутром чую, без матана не обойтись, но доказать не могу :))))
Да, прекрасный вариант.
Второй вариант - намудрить с FFT, чтобы в конце получить искомое. Хороший вариант.
Но.
Но это мы их выдумываем. А надо - чтобы программа сама выдумывала. Разные.
Что-то я опять потерялся, что вы создаете. Ваша манера отвечать самому себе запутывает.
То есть вам уже недостаточно одного алгоритма хеширования, вам целый генератор подавай?
Именно так:
const char *generate_new_algorithm(const char *Result, const char *RandomNumber);
А на выходе: вариант с XOR, вариант с sin(), вариант с игрой жизнь (ну ладно, это перебор), вариант с чем угодно.
Все, до чего додумался я - это придумать вручную 10-20 шаблонов и разбавлять их рандомными, ничего не значащими инструкциями.
Но это плохо и шаблоны эти будут видны в коде. Это тоже устаревший подход.
Ну хоть чатжпт меня не бросил :))
Ага, теперь понял — ты хочешь программу-генератор, которая сама придумывает Си-код (не просто выполняет вычисления), а на выходе пишет строку кода, которая преобразует один массив
A[]в другой массивB[].То есть задача такая:
- дан массив
input[](например, случайные числа),- дан массив
output[](какой должен получиться),- требуется найти/синтезировать алгоритм, который преобразует
input → output,- и результат работы генератора — это именно кусок Си-кода.
Как к этому можно подойти
- Прямое уравнивание (символика)
- Рассматриваешь задачу как поиск функции
f, гдеoutput[i] = f(input, i).- Если есть небольшие массивы, можно попробовать подобрать линейные/полиномиальные зависимости.
- Генератор кода тогда просто пишет
for (...) out[i] = ...;.
- Поиск в пространстве программ (program synthesis)
- Существуют методы вроде генетического программирования или enumerative search, где перебираются все возможные маленькие программы (из арифметических операций, циклов и условий).
- Проверка — это запуск кандидата и сравнение результата с эталонным
output.- Как только совпало — программа-решение найдена.
- Комбинирование шаблонов
- Задать “кирпичики”:
+,-,^,*, сдвиги, индексация.- Генератор случайным образом строит выражения.
- Потом проверяешь, подходит ли для всего массива.
- Оптимизационный подход
- Задачу можно свести к поиску формул через SAT/SMT-решатели (например, Z3).
- Там описываешь «у меня есть такие операции, хочу, чтобы результат совпадал».
- Решатель либо находит формулу, либо доказывает, что её нет в ограничениях.
купи Guardant и не морочь нам голову.
Знакомые говорят - “решето” :). Фиговая у них защита от отладки, поговаривают.
Вы это все в рантайме собрались проделывать? А памяти хватит чтоб завернуть ФФТ на 64 килобита?
Да, на есп32, там у нас хватает ресурсов.
Если нам математики не врут (есть такая надежда) весь твой код есть в последовательности чисел при расчете числа ПИ, осталось найти после какого знака после запятой он начинается )))
PS никто не мешает тебе сложить его кусками
Заливаете контроллер эпоксидкой в форме параллелепипеда.
Обматываете получившийся кирпичик конденсаторной лентой (два листа фольги с диэлектриком посередине).
Помещаете в корпус и заливаете эпоксидкой снова.
Все необходимые контакты кроме тех что для программирования (считывания кода) выведены наружу.
Расшифровка кода простейшим алгоритмом (да хоть xor) по ключу из флешки на борту.
При включении контроль емкости защитной обкладки. Если отличается от номинала, уничтожение ключа. Номинал емкости запоминается при первом включении после сборки (например, рвется контрольный контакт выведенный наружу, который обозначает начало эксплуатации).
Имея несколько таких устройств и зная примерную идею защиты все равно вскрыть код можно, но очень геморно. Если там не идея на миллиарды, после первых окирпиченных устройств интерес пропадет.
Устойчивая криптография обойдется дороже. И без применения аппаратных средств не эффективна.
ну да, если даже в STM (блюпилл) защита от чтения простыми средствами вскрывается влёт, не говоря о PUYA )))
Я сомневаюсь, что там идея на миллионы в коде. Если ее защитой занимается человек не имеющий базовых знаний в криптографии.
Но в качестве темы пообсуждать дендрофекальные способы ароматизировать код - вполне себе занятие, главное чтобы хобби удовольствие приносило.
поставить STM32 верхних ядер, внутри функция, ты ей вопрос она ответ, закрыть, там есть даже с 1 мегабайтом флэша, так что вполне надёжно будет, но я весьма далёк от этого ежели что, ИМХО