Может быть, мой вопрос кажется немного странным, но я не смог найти какие-либо обучающие материалы по этой теме. Если есть - посоветуйте, пожалуйста.
Заранее спасибо.
Заранее спасибо.
Подскажешь, что лучше под чистые C/C++ LLVM или GIMPLE?Смотря для какого языка, и на уровне чего это сделать. Тебе нужно найти и использовать библиотеку, которая сможет разобрать программу, модифицировать ее и записать обратно. Например, более менее универсальное решение для большинства языков на уровне абстрактного синтаксического дерева: https://xss.pro/threads/106900/ - но у каждого языка скорее всего найдется библиотека, которая будет разбирать язык лучше общего решения: типа libclang для C/C++, Roslyn для C#, Esprima для JS, ast для Python и тд. Можно писать обфускаторы на базе более низкоуровневого представления, типа LLVM или GIMPLE для C/C++/итд или MSIL для дотнетов (dnlib, Mono.Cecil или AsmResolver).
Мне для С/С++ всегда хватало манипуляций на уровне AST, то есть работа только на уровне исходных текстов. Это проще, и для большинства вещей вполне хватает.Подскажешь, что лучше под чистые C/C++ LLVM или GIMPLE?
Большое спасибоМне для С/С++ всегда хватало манипуляций на уровне AST, то есть работа только на уровне исходных текстов. Это проще, и для большинства вещей вполне хватает.
GIMPLE - это промежуточное представления у GCC/MinGW, тоже SSA, как и LLVM. Но чтобы до него добраться и что-то поменять нужно писать плагин к компилятору. Вот очень старое видео на тему, но там довольно неплохо рассказывается концепт:
По поводу LLVM, я экспериментировал с этим, но так и не доделал, тк переключился на обработку сорсов. Плюс LLVM (в отличии от GIMPLE) в том, что ты можешь сдампить LLVM IR, модифицировать его и скомпилировать, без необходимости оформлять это в виде плагина к компилятору. На тему LLVM есть несколько презентаций на тытрубе, например вот это:
Спасибо. Меня по большей части плюсы интересовали.Смотря для какого языка, и на уровне чего это сделать. Тебе нужно найти и использовать библиотеку, которая сможет разобрать программу, модифицировать ее и записать обратно. Например, более менее универсальное решение для большинства языков на уровне абстрактного синтаксического дерева: https://xss.pro/threads/106900/ - но у каждого языка скорее всего найдется библиотека, которая будет разбирать язык лучше общего решения: типа libclang для C/C++, Roslyn для C#, Esprima для JS, ast для Python и тд. Можно писать обфускаторы на базе более низкоуровневого представления, типа LLVM или GIMPLE для C/C++/итд или MSIL для дотнетов (dnlib, Mono.Cecil или AsmResolver).
Работать с LLVM-IR приятнее за счёт более богатого тулчейна - есть LLVM-C, который можно использовать из любого ЯП. Дока по IR так же очень подробная, нет ограничения по ЯП, которые можно обфусицировать/морфить - можно поддерживать любой ЯП, умеющий собираться в байткод LLVM. Так же JIT, который можно использовать для автоматических тестов обработанного кода.Подскажешь, что лучше под чистые C/C++ LLVM или GIMPLE?
a ^ b выглядит примерно так:%global_var% + %stack_var% * %random_winapi_res% + %stack_var% * ~(%operand_a% ^ %operand_b%) + %global_var% * ~%random_winapi_res%, где:%global_var% - рандомная глобальная переменная%stack_var% - рандомная переменная на стеке%random_winapi_res% - рандомный результат выполнения винапи, не влияющий на результат (напримерGetCurrentProcessId())%operand_a% - исходный операнд A - результат вызова винапи с известным результатом (условный lstrlenW(L"sssss") = 5)%operand_b% - исходный операнд BДля ветвлений есть инструкция "br": https://mapping-high-level-construc...n/latest/control-structures/if-then-else.html - но в любом случае тебе придется разобраться с "phi", а это довольно странная вещь. Я бы тебе посоветовал для ускорения процесса смотреть, как clang делает, и делать также. То есть, накодил на С/С++ for+switch для control flow flattening, скомпилил clang'ом в LLVM IR, посмотрел, что получилось, и сделал также.Как правильно генерировать if/switch/loop брэнчи?
Проблема не в том как вставить ту или иную инструкцию, а скорее куда и каким образом, чтоб это выглядело как легитимный код - не ясна сама логика. Возможно вопрос очень глупый, но у меня не было опыта написания обфускатором-морфером.Для ветвлений есть инструкция "br"
Дельный совет - уже использую.накодил на С/С++ for+switch для control flow flattening, скомпилил clang'ом в LLVM IR, посмотрел, что получилось, и сделал также
switch_key, прыгаем в диспатчер (после окончания обработки функции нужно пофиксить стек). Достаточно эффективный метод для запутывания CFG (при условии что switch_key нельзя предугадать статически), но проблема в том что результат выполнения, по сути, всегда одинаковый (если не проходиться несколько раз) - нужно добавлять фейковые базовые блоки и прыгать туда, но каким кодом наполнить эти фейк-блоки?Так а в чем проблема? Одинаковый и одинаковый.но проблема в том что результат выполнения, по сути, всегда одинаковый
Ну теме же неявными предикатами и наполни. Можешь еще добавить кучу функций с предикатами, которые никогда не выполняются, и вставлять вызовы этих функций с рандомными параметрами.но каким кодом наполнить эти фейк-блоки
Хотелось бы добиться максимальной уникальности, иначе морфер не морфер.Так а в чем проблема? Одинаковый и одинаковый.
Кстати, как вариант. Можно прямо в предикаты встроить генерацию фейк-базовых блоков, на подобии:Ну теме же неявными предикатами и наполни.
int a = 10;
int res = 0;
if (true) {
res = a ^ 5;
} else {
res = a + 42;
}
assert_eq(res, 15);