Вопрос по – Примеры метаморфического кода

33

Я понимаю концепциюполиморфный а такжеМетаморфические код, но я недавно прочитал страницу Википедии на обоих (по какой-либо причине я не делал это раньше!). Теперь я действительно хочу попробовать написать метаморфический код для себя.

Я не владею языком, увлекаюсь многими. Я знаю немного PHP, MySQL, c / c ++, Java, скриптов Bash, Visual Basic 6, VBScripting, Perl, JavaScript.

Может кто-нибудьprovide an example of metamorphic code на любом из этих языков. Я хотел бы увидеть рабочий пример, даже когда результат программы просто «Hello World», чтобы понять на примере, как это происходит (я изо всех сил пытаюсь теоретизировать, как эти методы могут быть достигнуты только с помощью ментального мышления). Любой язык подойдет, это просто предпочтительные.

Кроме того, поиск в Интернете дал лишь ограниченное количество примеров в c / c ++ (даже не полных рабочих примеров, более частичных фрагментов кода), потому что другие языки, которые я предложил, недостаточно низки, чтобы иметь силу / гибкость, необходимая для создания метаморфического кода?

@ J0e3gan +1 от меня, да, я кратко просмотрел Symantec PDF, мне нужно прочитать его еще раз. И да, я нахожу квины очень интересными. Я уже понимаю их концепцию, и их легче найти (например, через поисковую систему). Я не включил в свой вопрос непосредственно вопросы, связанные с квин, но я согласен, что они актуальны (и увлекательно!: D) jwbensley
Еще один полезный совет для поли / метаморфического программирования: используйтеcompiled язык как C / C ++. Не используйте интерпретируемый язык, такой как PHP, Perl, VB и т. Д. recursion.ninja
Может быть, вы заметили столько же, но есть примеры метаморфоза ассемблера в связанной с ВикипедиейSymantec PDF в нижней частиMetamorphic Code статья. Кроме того, существует больше примеров кода дляquines, которые выглядят как хорошее место для начала, поскольку метаморфический код кажется (более) понятным по сравнению с хайвинами. J0e3gan

Ваш Ответ

3   ответа
47

что, по моему мнению, классифицировалось бы как метаморфический код, написанный на C. Я боюсь, что у меня нет большого опыта написания переносимого кода на C, поэтому для компиляции на других платформах может потребоваться некоторая модификация (I '; м, используя старую версию Borland на Windows). Кроме того, он опирается на целевую платформу x86, поскольку включает в себя генерацию машинного кода. Теоретически он должен компилироваться на любой ОС x86.

How it works

Каждый раз, когда программа запускается, она генерирует случайно измененную копию с другим именем файла. Он также распечатывает список смещений, которые были изменены, чтобы вы могли видеть, что они действительно что-то делают.

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

Жесткое кодирование списка смещений, очевидно, нереально для того, что другие люди должны иметь возможность компилировать, поэтому последовательности генерируются таким образом, чтобы их было легко идентифицировать при поиске по объектному коду, надеюсь, без совпадения с ложными срабатываниями. ,

Каждая последовательность начинается с операции push в определенном регистре, набора инструкций, которые изменяют этот регистр, и затем операции pop, чтобы восстановить регистр до его начального значения. Для простоты, в оригинальном источнике все последовательности простоPUSH EAX, восемьNOPс иPOP EAX, Однако во всех последующих поколениях приложения последовательности будут полностью случайными.

Explaining the code

Я разделил код на несколько частей, чтобы попытаться объяснить его шаг за шагом. Если вы хотите скомпилировать его самостоятельно, вам просто нужно объединить все части вместе.

Сначала некоторые довольно стандартные включает в себя:

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

Далее у нас есть определения для различных кодов операций x86. Обычно они объединяются с другими значениями для создания полной инструкции. Например,PUSH определить (0x50) само собойPUSH EAX, но вы можете получить значения для других регистров, добавив смещение в диапазоне от 0 до 7. То же самое дляPOP а такжеMOV.

#define PUSH 0x50
#define POP  0x58
#define MOV  0xB8
#define NOP  0x90

Последние шесть являются префиксными байтами нескольких двухбайтовых кодов операций. Второй байт кодирует операнды и будет объяснен более подробно позже.

#define ADD  0x01
#define AND  0x21
#define XOR  0x31
#define OR   0x09
#define SBB  0x19
#define SUB  0x29

const unsigned char prefixes[] = { ADD,AND,XOR,OR,SBB,SUB,0 };

JUNK это макрос, который вставляет нашу последовательность нежелательных операций в любое место кода. Как я объяснял ранее, он изначально просто записываетPUSH EAX, NOP, а такжеPOP EAX. JUNKLEN это числоNOPs в этой последовательности - не полная длина последовательности.

И если вы не знаете,__emit__ является псевдофункцией, которая вставляет литеральные значения непосредственно в объектный код Я подозреваю, что это может быть чем-то, что вам нужно перенести, если вы используете другой компилятор.

#define JUNK __emit__(PUSH,NOP,NOP,NOP,NOP,NOP,NOP,NOP,NOP,POP)
#define JUNKLEN 8

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

unsigned char *code;
int codelen;

Далее у нас есть простая функция, которая будет считывать наш объектный код в память. Я никогда не освобождаю эту память, потому что мне все равно.

Обратите внимание наJUNK вызовы макросов вставляются в случайных точках. Вы увидите больше всего этого в коде. Вы можете вставить их почти где угодно, но если вы используете настоящий компилятор C (в отличие от C ++), он будет жаловаться, если вы попытаетесь поместить их до или между объявлениями переменных.

void readcode(const char *filename) {
  FILE *fp = fopen(filename, "rb");    JUNK;
  fseek(fp, 0L, SEEK_END);             JUNK;
  codelen = ftell(fp);
  code = malloc(codelen);              JUNK;
  fseek(fp, 0L, SEEK_SET);
  fread(code, codelen, 1, fp);         JUNK;
}

Еще одна простая функция - снова выписать приложение после его изменения. Для нового имени файла мы просто заменяем последний символ исходного имени на цифру, которая увеличивается каждый раз. Не предпринимается никаких попыток проверить, существует ли файл и не перезаписываем ли мы критически важный компонент операционной системы.

void writecode(const char *filename) {
  FILE *fp;
  int lastoffset = strlen(filename)-1;
  char lastchar = filename[lastoffset];
  char *newfilename = strdup(filename);  JUNK;
  lastchar = '0'+(isdigit(lastchar)?(lastchar-'0'+1)%10:0);
  newfilename[lastoffset] = lastchar;
  fp = fopen(newfilename, "wb");         JUNK;
  fwrite(code, codelen, 1, fp);          JUNK;
  fclose(fp);
  free(newfilename);
}

Эта следующая функция записывает случайную инструкцию для нашей ненужной последовательности.reg Параметр представляет регистр, с которым мы работаем, - который будет помещен в любой конец последовательности.offset смещение в коде, где будет записана инструкция. А такжеspace дает количество байтов, которые мы оставили в нашей последовательности.

В зависимости от того, сколько у нас места, мы можем ограничиться тем, какие инструкции мы можем выписать, в противном случае мы выбираем случайным образом, является ли этоNOP, MOV или один из других.NOP это просто один байт. MOV составляет пять байтов: наш код операции MOV (сreg добавлен параметр) и 4 случайных байта, представляющих число, перемещенное в регистр.

Для двухбайтовых последовательностей первый - это просто один из наших префиксов, выбранных случайным образом. Второй байт в диапазоне0xC0 в0xFF где младшие 3 бита представляют основной регистр, т. е. для него должно быть установлено значение нашегоreg параметр.

int writeinstruction(unsigned reg, int offset, int space) {
  if (space < 2) {
    code[offset] = NOP;                         JUNK;
    return 1;
  }
  else if (space < 5 || rand()%2 == 0) {
    code[offset] = prefixes[rand()%6];          JUNK;
    code[offset+1] = 0xC0 + rand()%8*8 + reg;   JUNK;
    return 2;
  }
  else {
    code[offset] = MOV+reg;                     JUNK;
    *(short*)(code+offset+1) = rand();
    *(short*)(code+offset+3) = rand();          JUNK;
    return 5;
  }
}

Теперь у нас есть эквивалентная функция для чтения одной из этих инструкций. Предполагая, что мы уже определилиreg отPUSH а такжеPOP Операции на любом конце последовательности, эта функция может попытаться проверить, является ли инструкция в данномoffset является одной из наших нежелательных операций и что первичный регистр соответствует заданномуreg параметр.

Если он находит правильное совпадение, он возвращает длину инструкции, в противном случае он возвращает ноль.

int readinstruction(unsigned reg, int offset) {
  unsigned c1 = code[offset];
  if (c1 == NOP)
    return 1;                     JUNK;
  if (c1 == MOV+reg)
    return 5;                     JUNK;
  if (strchr(prefixes,c1)) {
    unsigned c2 = code[offset+1]; JUNK;
    if (c2 >= 0xC0 && c2 <= 0xFF && (c2&7) == reg)
      return 2;                   JUNK;
  }                               JUNK;
  return 0;
}

Эта следующая функция является основным циклом, который ищет и заменяет ненужные последовательности. Это начинается с поискаPUSH код операции с последующимPOP код операции в том же регистре восемь байтов позже (или что-то ещеJUNKLEN был установлен в).

void replacejunk(void) {
  int i, j, inc, space;
  srand(time(NULL));                                 JUNK;

  for (i = 0; i < codelen-JUNKLEN-2; i++) {
    unsigned start = code[i];
    unsigned end = code[i+JUNKLEN+1];
    unsigned reg = start-PUSH;

    if (start < PUSH || start >= PUSH+8) continue;   JUNK;
    if (end != POP+reg) continue;                    JUNK;

Если регистр оказываетсяESPмы можем безопасно пропустить это, потому что мы никогда не будем использоватьESP в нашем сгенерированном коде (стековые операции наESP нуждаются в особом рассмотрении, которое не стоит усилий).

    if (reg == 4) continue; /* register 4 is ESP */

После того, как мы подобрали подходящее PUSH иPOP Затем мы попытаемся прочитать промежуточные инструкции. Если мы успешно сопоставим ожидаемую длину байтов, мы считаем, что совпадение может быть заменено.

    j = 0;                                           JUNK;
    while (inc = readinstruction(reg,i+1+j)) j += inc;
    if (j != JUNKLEN) continue;                      JUNK;

Затем мы выбираем один из 7 регистров случайным образом (как было объяснено до того, как не рассмотримESP) и выпишитеPUSH а такжеPOP операции для этого регистра на любом конце последовательности.

    reg = rand()%7;                                  JUNK;
    reg += (reg >= 4);
    code[i] = PUSH+reg;                              JUNK;
    code[i+JUNKLEN+1] = POP+reg;                     JUNK;

Тогда все, что нам нужно сделать, это заполнить промежуточное пространство, используя нашwriteinstruction функция.

    space = JUNKLEN;
    j = 0;                                           JUNK;
    while (space) {
      inc = writeinstruction(reg,i+1+j,space);       JUNK;
      j += inc;
      space -= inc;                                  JUNK;
    }

И здесь мы показываем смещение, которое мы только что исправили.

    printf("%d\n",i);                                JUNK;
  }
}                                                                             

Наконец у нас есть основная функция. Это просто вызывает функции, описанные ранее. Мы читаем в коде, заменяем мусор, затем снова записываем его.argv[0] Аргумент содержит имя файла приложения.

int main(int argc, char* argv[]) {

  readcode(argv[0]);     JUNK;
  replacejunk();         JUNK;
  writecode(argv[0]);    JUNK;

  return 0;
}

И это все, что нужно сделать.

Some final notes

Очевидно, что при запуске этого кода вам необходимо убедиться, что у пользователя есть соответствующие разрешения для записи файла в том же месте, что и исходный код. Затем, после того как новый файл создан, вам, как правило, необходимо переименовать его, если вы находитесь в системе, где важно расширение файла, или установить его атрибуты исполнения, если это необходимо.

Наконец, я подозреваю, что вы, возможно, захотите запустить сгенерированный код через отладчик, а не просто выполнять его напрямую и надеяться на лучшее. Я обнаружил, что если я скопировал сгенерированный файл поверх исходного исполняемого файла, отладчик с радостью позволил мне просмотреть его, все еще просматривая исходный код. Затем, когда вы доберетесь до точки в коде, который говоритJUNKВы можете открыть окно сборки и посмотреть на сгенерированный код.

В любом случае, я надеюсь, что мои объяснения были достаточно ясными, и это был тот пример, который вы искали. Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать в комментариях.

Bonus update

В качестве бонуса я думал, что я также включу пример метаморфического кода на языке сценариев. Это сильно отличается от примера C, так как в этом случае нам нужно изменить исходный код, а не двоичный исполняемый файл, что немного проще, я думаю.

В этом примере я широко использовал phpgoto функция. Каждая строка начинается с метки и заканчиваетсяgoto указывая на метку следующей строки. Таким образом, каждая строка, по сути, самодостаточна, и мы можем с радостью перетасовать их и при этом заставить программу работать точно так же, как раньше.

Условия и структуры цикла немного сложнее, но их просто нужно переписать в виде условия, которое переходит на одну из двух разных меток. Я включил в код маркеры комментариев, в которых должны были бы быть циклы, чтобы было легче следить за ними.

Пример кода на ideone.com

Все, что делает код, это повторяет перемешанную копию самой себя, так что вы можете легко протестировать ее на ideone, просто вырезав и вставив вывод обратно в поле исходного кода и запустив его снова.

Если бы вы хотели, чтобы он мутировал еще больше, было бы довольно легко сделать что-то вроде замены всех меток и переменных другим набором случайных строк при каждом запуске кода. Но я подумал, что лучше постараться сделать все как можно проще. Эти примеры предназначены только для демонстрации концепции - на самом деле мы не пытаемся избежать обнаружения. :)

Error: User Rate Limit Exceeded jwbensley
Error: User Rate Limit Exceeded__emit__Error: User Rate Limit Exceeded__volatile__Error: User Rate Limit Exceeded jwbensley
Error: User Rate Limit Exceeded jwbensley
Error: User Rate Limit Exceededstackoverflow.com/questions/731428/…Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
26

Publically available metamorphic code samples are limited by several factors:

1) Expertise: Metamorphic coding is an extremely advanced technique in computer programming. The number of programmers capable of coding coherent and clean metamorphic code suitable for sampling is a very small number.

2) Financial Incentives: Metamorphic coding has limited use in commercial application. Because of this the number of programmers who have sufficient skill to create metamorphic code have no professional exposure/incentive to create/learn metamorphic coding techniques.

3) Legitamicy: Metamorphic coding has large applications in potent virus creation. Hence any responsible professional who created metamorphic code would have ethical issues freely distributing samples as an ametuer hacker may be able to use the code to enhance a malicious attack. Conversely, any hacker who was competent enough to create metamorphic code would have no incentive to advertise his skill, should one o,f his attacks be uncovered as he would then be on a very short list of suspects based on competency.

4) Secrecy: Lastly, and probably the most realist reason metamorphic code is so difficult to find is because any programmer who demonstrates competency in metamorphic programming, and is not apprehended by authorities for cyber crimes, is likely to be recruited by a government security agency, private security firm, or anti-virus company and the programmer's subsequent research/knowledge is then subject to a non-disclosure agreement to maintain a competitive edge.

Why only C/C++ examples?

Вы упоминаете только нахождениеC/C++ примеры кода поли / метаморфического программирования и предполагают, что только языки, близкие к аппаратному, могут быть поли / метаморфическими. Это верно для самых строгих определений поли / метаморфического кода. Интерпретируемые языки могут иметь поли / метаморфическое поведение, но для выполнения полагаться на статически соблюдаемый интерпретатор, следовательно, большую часть «сигнатуры во время выполнения». не является изменчивым Только скомпилированные языки низкого уровня предлагают вычислительную гибкость, чтобы иметь легко изменяемую «подпись во время выполнения».

Вот некоторые «полиморфные» PHP-код, который я написал. PHP, являющийся интерпретируемым языком, а не скомпилированным языком, делает истинный полиморфизм невозможным.

PHP Code:

<?php
// Programs functional Execution Section
system("echo Hello World!!\\n");
// mutable malicious payload goes here (if you were devious)

// Programs Polymorphic Engine Section
recombinate();
?>
<?php

function recombinate() {
  $file      = __FILE__;                    //assigns file path to $file using magic constant
  $contents  = file_get_contents($file);    //gets file contents as string
  $fileLines = explode("\n", $contents);    //splits into file lines as string array
  $varLine   = $fileLines[2];               //extracts third file line as string
  $charArr   = str_split($varLine);         //splits third line into char array
  $augStr    = augmentStr($charArr);        //recursively augments char array
  $newLine   = implode("",$augStr);         //rebuilds char array into string
  $fileLines[2] = $newLine;                 //inserts string back into array
  $newContents  = implode("\n",$fileLines); //rebuilds array into single string
  file_put_contents($file,$newContents);    //writes out augmented file
  sleep(1);                                 //let the CPU rest
  $pid = pcntl_fork();                      //forks process
  if($pid) {                                //if in parent:
    exit(0);                                //exit parent process
  }                                         //WARNING: creates 'Zombie' child process
  else {                                    //else in child process
    system("nohup php -f " .$file . " 2> /dev/null"); //executes augmented file
    exit(0);                                //exits exit child process
  }
}

function augmentStr($inArr) {
  if (mt_rand(0,6) < 5) {               //determines mutability
    /*$startIndex & $endIndex define mutable parts of file line as Xs
     * system("echo XXXXX ... XXXXX\\n");
     * 01234567890123            -7654321
     */
    $startIndex  = 13;
    $endIndex    = count($inArr)-7;
    $targetIndex = mt_rand($startIndex,$endIndex);     //choose mutable index
    $inArr[$targetIndex] = getSafeChar(mt_rand(0,62)); //mutate index
    $inArr = augmentStr($inArr);               //recurse
  }
  return $inArr;
}

function getSafeChar($inNum) {      //cannot use escaped characters
  $outChar;                 //must be a standard PHP char
       if ($inNum >=  0 && $inNum <= 9 ) { $outChar = chr($inNum + 48); }
  else if ($inNum >= 10 && $inNum <= 35) { $outChar = chr($inNum + 55); }
  else if ($inNum >= 36 && $inNum <= 61) { $outChar = chr($inNum + 61); }
  else if ($inNum == 62)                 { $outChar = " ";              }
  else                                   { $outChar = " ";              }
  return $outChar;
}

?>

WARNING: Создаетпроцесс зомби, знать, как убить процесс зомби, прежде чем запускать код

Information Finding Techniques:

Эта статья содержит более конкретную информацию, чем в Википедии. Эта статья, однако, не содержит истинного исходного кода. Если вам нужен мой совет, хотя вряд ли найдется пример исходного кода, вы можете найти достаточноacademic documentation создать свой собственный метаморфический код. Рассмотрим это, чтобы начать (Google ученый):

При чтении академических статей / работ обязательно ознакомьтесь с источниками в конце документа, поскольку эти источники также могут содержать ценную информацию.

Best of luck in your quest for knowledge!

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded jwbensley
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded jwbensley
2

This answer is not finished, I will continue to expand on it over time, until this question's answer is complete

Scripted Example - PHP

Я сделал свою собственную копию PHP-скрипта, которую предоставил Джеймс Холдернесс, чтобы я сам смог увидеть, продемонстрировав, как может работать метаморфический скрипт. Полное описание кода здесь;http://null.53bits.co.uk/index.php?page=php-goto-replicator

Проще говоря, после первоначального выполнения сценария он копирует себя в новый файл со случайным именем файла со строками кода в новом случайном порядке, затем он создает новый процесс, который выполняет новую копию файла сценария и оригинал Копировать выходы. Теперь запущена новая копия скрипта, которая является копией исходного файла, но со случайным именем файла и строками кода в другом порядке. Это вечный процесс; переупорядочение и репликация, затем выполнение нового экземпляра (процесса), убившего предыдущий.

Я стремился немного расширить PHP-ответ Джеймса Холдернесса в пример работающего самовоспроизводящегося и изменяющегося кода.

Это необработанный код PHP, который я придумал;

<?php goto a01;
a01: $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';    goto a02;
a02: $randomString = __DIR__."/";                                                       goto a03;
a03: $i = 0;                                                                            goto a04;
a04: if ($i < 10)                                                                       goto a05; else goto a07;
a05:   $randomString .= $characters[rand(0, strlen($characters) - 1)];                  goto a06;
a06:   $i++;                                                                            goto a04;
a07: $randomString .= ".php";                                                           goto a08;
a08: $ARGS=Array("-f",$randomString);                                                   goto a09;
a09: $handle_out = fopen("$randomString", "w");  goto l01;
l01: $filename = __FILE__;                       goto l02;
l02: $contents = file_get_contents($filename);   goto l03;
l03: $lines = explode("\n",$contents);           goto l04;
l04: $collection = array();                      goto l05;
l05: $pattern = '%^[^:]+:.*goto [^;]+;$%';       goto l06;
l06: $i = 0;                                     goto l07;
l07: if ($i < count($lines)-1)                   goto l08; else goto l23;
l08:   $line = $lines[$i];                       goto l09;
l09:   $line = trim($line);                      goto l10;
l10:   if (substr($line,0,2) != '//')            goto l11; else goto l22;
l11:     if (preg_match($pattern, $line) === 1)  goto l12; else goto l13;
l12:       $collection[] = $line;                goto l22;
l13:       shuffle($collection);                 goto l14;
l14:       $j = 0;                               goto l15;
l15:       if ($j < count($collection))          goto l16; else goto l19;
l16:         echo $collection[$j]."\n";          goto l17;
l17:         fwrite($handle_out, $collection[$j]."\n");    goto l18;
l18:         $j++;                               goto l15;
l19:       $collection = array();                goto l20;
l20:       fwrite($handle_out, $line."\n");      goto l21;
l21:       echo $line."\n";                      goto l22;
l22:   $i++;                                     goto l07;
l23: fclose($handle_out);                        goto f01;
f01: $pid = pcntl_fork();                        goto f02;
f02: if ($pid == -1)                             goto f03; else goto f04;
f03:   die("Could not fork a new child\n");      goto f03;
f04: if ($pid)                                   goto f05; else goto f06;
f05:   exit(0);                                  goto f05;
f06: $sid = posix_setsid();                      goto f07;
f07: if ($sid < 0)                               goto f08; else goto f09;
f08:   die("Child posix_setsid error\n");        goto f08;
f09: sleep(10);                                  goto f10;
f10: pcntl_exec(PHP_BINARY, $ARGS);
l24: exit(0);                                    goto l24;
?>

Похожие вопросы