Динамическое запутывание с помощью самоизменяющегося кода - PullRequest
2 голосов
/ 27 декабря 2010

Вот что я пытаюсь сделать:

предположим, у вас есть две функции

void f1(int *v)
{
   *v = 55;
}
void f2(int *v)
{
   *v = 44;
}

char *template;
template = allocExecutablePages(...);

char *allocExecutablePages (int pages)
{
    template = (char *) valloc (getpagesize () * pages);
    if (mprotect (template, getpagesize (),
        PROT_READ|PROT_EXEC|PROT_WRITE) == -1) {
            perror (“mprotect”);
    }
}

Я хотел бы сделать сравнение между f1 и f2 (так скажите, что идентично и чтоэто не так) (поэтому получите строки сборки этих функций и проведите сравнение строк за строкой) И затем поместите эти строки в мой шаблон.

Есть ли способ в C сделать это?

Спасибо

Обновление

Спасибо за все, что вы ответили, ребята, но, возможно, я неправильно объяснил свою потребность.

В основном я пытаюсь написать небольшой метод запутывания.Идея состоит в том, чтобы позволить двум или более функциям совместно использовать одно и то же место в памяти.Устанавливается область памяти (которую мы будем называть шаблоном), содержащая некоторые байты машинного кода из функций, более конкретно, те, которые у них всех общие.Перед выполнением определенной функции сценарий редактирования используется для исправления шаблона необходимыми байтами машинного кода для создания полной версии этой функции.Когда собирается выполняться другая функция, назначенная тому же шаблону, процесс повторяется, на этот раз с другим сценарием редактирования.Чтобы проиллюстрировать это, предположим, что вы хотите запутать программу, которая содержит две функции f1 и f2.Первый (f1) имеет следующие байты машинного кода

Address Machine code
0          10
1          5
2          6
3          20
and the second one (f2) has
Address Machine code
0          10
1          9
2          3
3          20
At obfuscation time, one will replace f1 and f2 by the template
Address Machine code
0           10
1           ?
2           ? 
3           20
and by the two edit scripts e1 = {1 becomes 5, 2 becomes 6} and e2 = {1
becomes 9, 2 becomes 3}.


#include <stdlib.h>
#include <string.h>

typedef unsigned int uint32;
typedef char * addr_t;

typedef struct {
uint32 offset;
char value;
} EDIT;

EDIT script1[200], script2[200];
char *template;
int template_len, script_len = 0;
typedef void(*FUN)(int *);
int val, state = 0;

void f1_stub ()
{
if (state != 1) {
patch (script1, script_len, template);
state = 1;
}
((FUN)template)(&val);
}

void f2_stub () {
if (state != 2) {
patch (script2, script_len, template);
state = 2;
}
((FUN)template)(&val);
}

int new_main (int argc, char **argv)
{
f1_stub ();
f2_stub ();
return 0;
}

void f1 (int *v) { *v = 99; }
void f2 (int *v) { *v = 42; }

int main (int argc, char **argv)
{
int f1SIZE, f2SIZE;
/* makeCodeWritable (...); */
/* template = allocExecutablePages(...); */
/* Computed at obfuscation time */
diff ((addr_t)f1, f1SIZE,
(addr_t)f2, f2SIZE,
script1, script2,
&script_len,
template,
&template_len);
/* We hide the proper code */
memset (f1, 0, f1SIZE);
memset (f2, 0, f2SIZE);
return new_main (argc, argv);
}

Так что теперь мне нужно написать функцию diff.он будет принимать адреса двух моих функций и генерирует шаблон с соответствующим скриптом.

Поэтому я хотел бы сравнить байты с байтами двух моих функций

Извините за мойпервый пост который был не очень понятен!

спасибо

Ответы [ 4 ]

2 голосов
/ 27 декабря 2010

Вы хотите сделать это во время выполнения или во время авторства?

Вы, вероятно, можете указать вашему компилятору C производить вывод на ассемблере, например, gcc имеет опцию -S, которая будет выводить в file.sВаш комплект компилятора может также иметь программу типа objdump, которая может декомпилировать объектный файл или весь исполняемый файл.Однако вы, как правило, хотите оставить оптимизации для современного компилятора, а не делать это самостоятельно.

Во время выполнения оператор & может взять адрес функции, и вы можете прочитать ее, хотя вы должны быть готовыдля возможности встретиться с инструкцией ветвления до чего-либо интересного, так что вам действительно нужно программно «понять» хотя бы подмножество набора команд.То, с чем вы столкнетесь при чтении указателей на функции, конечно, будет зависеть от машины, ABI, компилятора, флагов оптимизации и т. Д.

1 голос
/ 27 декабря 2010

Если вы используете Visual Studio, перейдите на

Project Properties -> Configuration -> C/C++ -> Output Files -> Assembler output

или используйте переключатели компилятора /FA, /FAc, /FAs, /FAcs. Нижний регистр c означает выходной машинный код, s - исходный код рядом с кодом сборки. И не забудьте отключить оптимизацию компилятора.

1 голос
/ 27 декабря 2010

Поместите функции в t1.c и t2.c, используйте gcc -S для генерации вывода сборки:

gcc -S t1.c
gcc -S t2.c

Теперь сравните t1.s и t2.s.

0 голосов
/ 28 декабря 2010

Прочитав некоторые ответы и комментарии, я не уверен, что полностью понимаю ваш вопрос, но, возможно, вы ищете вызов gcc, подобный следующему:
gcc -S -xc - -o -

Это говорит gcc вводить код C из stdin и выводить сборку в stdout.

Если вы используете редактор в стиле vi, вы можете выделить тело функции в визуальном режиме и затем запустить команду:
:'<,'>!gcc -S -xc - -o - 2> /dev/null
... и это заменит тело функции на сборку (задача "stderr> / dev / null" - пропустить ошибки о # include).

В противном случае вы могли бы использовать этот вызов gcc как часть конвейера в скрипте.

...