Малварь как искусство Генерация кода на си. Часть вторая. Исполняем код на лету

Тема в разделе "Технологии создания невидимой малвари", создана пользователем X-Shar, 12 ноя 2017.

↑ ↓
  1. X-Shar :)
    X-Shar
    Ответить в чате

    Администрация

    Регистрация:
    03.06.2012
    Сообщения:
    5.431
    Симпатии:
    57
    Пол:
    Мужской
    Репа:
    +682 / 163 / -34
    Привет.

    Решил сразу вторую часть статьи написать.

    Прочитайте вначале это:Малварь как искусство - Самомодификация и генерация кода на лету в си. Часть 1. Вкуриваем суть.

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

    Теперь давайте запустим какую-нить функцию, причём не просто мат. функцию, а например функцию, которая-бы что-то выводила на экран. :)

    Зачем это нужно:

    1. Если у вас есть какая-то часть кода, которую нужно скрыть (т.е. сплоиты и т.д.).

    2. Хотите скрыть часть кода от реверсера или антивируса.

    Итак приступим:

    Допустим у вас есть код, который нужно скрыть. Для теста мы будем использовать такую функцию:
    Код:
    void demo ()
    {
       
    printf (" HI! \n");
       return 
    0;
    }
    Ну т.е. просто печатает на экран слово "HI!".

    Задача, запустить её из своего кода. Имея бинарный код этой функции.

    Итак приступим:

    1)Как получить бинарный код нужной функции:

    Нужно скопировать секцию кода функции и секцию данных этой функции.

    Вот примерно как это сделать:

    Код:
    #pragma optimize( "", off ) 

    #include "stdafx.h"
    #include "stdio.h"
    #include "string.h"

    void Demo(int (*_printf) (const char *,...) )
    {
      
    char buff1[4];
      
    buff1[0]='H';
      
    buff1[1]='i';
      
    buff1[2]='!';   
      
    buff1[3]='\0';   
      
    _printf(buff1);
      return;
    }

    void _bild()
    {
      
    FILE *f;
      
    void (*_Demo) (int (*) (const char *,...)); 
      
    void (*_Bild) ();
      
    _Demo=Demo;
      
    _Bild=_bild;

      
    f=fopen("Demo32.bin","wb");
      for (
    int a=0;a<func_len;a++)
        
    fputc(((int) buff[a]),f);
      
    fclose(f);

      while (
    1);
    }

    int main(int argccharargv[])
    {
      
    _bild();
      return 
    0;
    }

    #pragma optimize( "", on )
    Программа сохранит в Demo32.bin бинарный код функции. В си-код преобразовать можно так:Информация - Как преобразовать бинарник программы в сишный код

    Немного по коду (собирал на вижуалке):

    1. #pragma optimize( "", off ) - Нужно отключить оптимизацию компилятора и обязательно собирать в режиме релиз (это важно).

    2. Код нашей функции теперь выглядит так:
    Код:
    void Demo(int (*_printf) (const char *,...) )
    {
      
    char buff1[4];
      
    buff1[0]='H';
      
    buff1[1]='i';
      
    buff1[2]='!';   
      
    buff1[3]='\0';   
      
    _printf(buff1);
      return;
    }
    char buff1[4]; - Это данные, т.к. мы не можем скопировать секцию данных, зато можем генерировать эти данные на стеке. :)

    int (*_printf) (const char *,...) - Указатель на printf, т.к. у каждого компьютера это будет разный адрес.

    3. Ну тут думаю понятно, вычисляем длину функции, далее копируем в специальный буфер и этот буфер сохраняем в файл:
    Код:
    int func_len = (unsigned int_Bild
                      
    - (unsigned int_Demo;
      
    char buff[1000];
      
    memcpy (buff_Demofunc_len);

      
    f=fopen("Demo32.bin","wb");
      for (
    int a=0;a<func_len;a++)
        
    fputc(((int) buff[a]),f);
      
    fclose(f);
    2)Ну далее нам нужно преобразовать бинарный код в си-код, как это сделать я сказал выше.
    У меня получилось так:
    Код:
    static char code2[] =
        {
            
    0x550x8b0xec0x510x8d0x450xfc0x500xc70x450xfc0x480x690x210x000xff,
            
    0x550x080x830xc40x040x8b0xe50x5d0xc30xcc0xcc0xcc0xcc0xcc0xcc0xcc
        
    };
    Далее пишем программу запуска кода (тоже вижуалка):
    Код:
    #define _CRT_SECURE_NO_WARNINGS

    #include "stdafx.h"
    #include "stdio.h"
    #include "string.h"
    #include "windows.h"

    int main(int argccharargv[])
    {
        static 
    char buff[1000];

        
    int(*_printf) (const char *, ...);
        
    void(*_Demo) (int(*) (const char *, ...));
              
        static 
    char code2[] =
        {
            
    0x550x8b0xec0x510x8d0x450xfc0x500xc70x450xfc0x480x690x210x000xff,
            
    0x550x080x830xc40x040x8b0xe50x5d0xc30xcc0xcc0xcc0xcc0xcc0xcc0xcc
        
    };
      
        
    int code_size sizeof(code2);
        
    memcpy(buffcode2sizeof(code2));

        
    _printf printf;    
        
    _Demo = (void(*) (int(*) (const char *, ...)))&buff[0];

        
    DWORD oldprotect;
        
    VirtualProtect(_Demosizeof(code2), PAGE_EXECUTE, &oldprotect);

        
    _Demo(_printf);

        while (
    1);
        
        return 
    0;
    }
    Немного по коду:

    1) Код, который будем запускать:
    Код:
    static char code2[] =
        {
            
    0x550x8b0xec0x510x8d0x450xfc0x500xc70x450xfc0x480x690x210x000xff,
            
    0x550x080x830xc40x040x8b0xe50x5d0xc30xcc0xcc0xcc0xcc0xcc0xcc0xcc
        
    };
    2)Указатели на printf и на нашу функцию:
    Код:
        int(*_printf) (const char *, ...);
        
    void(*_Demo) (int(*) (const char *, ...));
        
    _printf printf;   
        
    _Demo = (void(*) (int(*) (const char *, ...)))&buff[0];
    3)В общем-то делаем разрешение на запуск и запускаем:
    Код:
     DWORD oldprotect;
        
    VirtualProtect(_Demosizeof(code2), PAGE_EXECUTE, &oldprotect);
        
    _Demo(_printf);
    Получаем:

    upload_2017-11-12_0-7-17.

    Таким образом можно запускать сплоиты. Шифрованный код и т.д.

    Как видите нет ничего сложного ! :)