Продолжим наш разговор о простой
обфускации кода с С. Эти приемы довольно
просты, однако позволяют в определенной
степени запутать читающего код. Кроме того
они помогут лучше узнать возможности языка.
Первую часть статьи можно найти тут: http://www.xakep.ru/post/29820/default.asp

Массивы — неисчерпаемое поле для
развлечений и запутывания. Например можно
использовать разделение и слияние. Если в
цикле надо обработать массив, то можно
разделить его на два и передавать
управление от одного к другому в ходе
работы. На самом деле возможности неограниченны
и все дело только в фантазии разработчика. С
другой стороны можно соединять массивы в
нужном порядке:

A1|A2|A3| + |B1|B2|B3|B4|B5|B6| = |A1|B1|B2|A2|B3|B4…

Многомерные массивы обычно сложны для
начинающих, но их можно использовать и для
обмана продвинутых кодеров — если найти им
правильно применение. Чем больше
размерность массива, чем больше [] в коде,
тем более сложен код для понимания.
Многомерные массивы можно как разбавлять
излишками, так и сворачивать, уменьшая
размерность. Комплексность данных
усложняет понимание.

Другой метод работы, похожий на
сворачивание и разворачивание — инверсия. Горизонтальный
массив можно переводить в вертикальный, а
вертикальный — в горизонтальный. Это
конечно гораздо проще чем изменение
размерности, но тоже может пригодится. 

Так же в массивах можно применять
реорганизацию — написать математическую
функцию, которая однозначно будет
переопределять оригинальный индекс i в
новый j. В цикле таким образом надо будет
читать не i-sq элемент массива, а j = f (i). 

Ну и напоследок — указатели. Известно, что:

array[i] == *(array + i)

По другом можно сделать так:

array[i] == *(array + i) == *(i + array) = i[array]

На самом деле это все одно и тоже и вполне
допускается синтаксисом языка. Используя
такие знания можно составлять такие
выражения: 

i++[array—]++;

Это все, конечно, больше напоминает Brainfuck,
чем обычный язык С, но на самом деле это все
работает!

Дальше мы рассмотрим некоторые отдельные
приемы, которыми можно воспользоваться для
своих грязных нужд.

Например строки — это те же массивы, а
значит можно делать так:

"i’m a baad string!"[i++]

или

i++["i’m a baad index!"]

Другую хорошую штуку можно провернуть со
строками из единственного символа (обычно
используются в качестве разделителя при
парсинге текста), их можно использовать как
скалярные величины:

strtok(str, &((char*) {0x2a}))

Строки можно шифровать простыми
алгоритмами и использовать для работы лишь
часть:

main(l,a,n,d)char**a;{
for(d=atoi(a[1])/10*80-
atoi(a[2])/5-596;n=»@NKA\
CLCCGZAAQBEAADAFaISADJABBA^\
SNLGAQABDAXIMBAACTBATAHDBAN\
ZcEMMCCCCAAhEIJFAEAAABAfHJE\
TBdFLDAANEfDNBPHdBcBBBEA_AL\
H E L L O, W O R L D! «
[l++-3];)for(;n—>64;)
putchar(!d+++33^
l&1);}

Помните, практически все можно
использовать для обфускации — конструкции
switch, числа разной системы (например
десятеричные и шестнадцатеричные),
логические операции — ?, |, ^, >>, >>,
прямые операции с памятью. Например к
переменным, переданным через командную
строку  можно обращаться так:

int main(int argc, …)
{
printf("My name is %s\n", *(char**)*(&argc+1));
return 0;

Вы же помните, что аргументы хранятся в
стеке?

Ну и напоследок — учитесь у мастеров,
найдите в сети участников International Obfuscated C Code
Contest (IOCCC) и попытайтесь разобраться в их
коде, участвуйте в конференциях. И когда вы
поймете что делает такая программа:

main(o,O){while(O=(o++-1)["NdlLQHGFW/"])putchar(O^26+(o|1));}

вы станете настоящим мастером…

Оставить мнение

Check Also

Энкодеры msfvenom. Разбираемся с кодированием боевой нагрузки при бинарной эксплуатации

Генерация полезной нагрузки — неотъемлемая часть эксплуатации. При использовании модулей M…