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

Кто просматривает этот контент: "Тема" (Всего пользователей: 0; Гостей: 2)

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
5 693
Репутация
222
Jabber
Telegram
#1
Привет.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

CODE:
#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 argc, char* argv[])
{
  _bild();
  return 0;
}

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

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

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

2. Код нашей функции теперь выглядит так:
CODE:
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. Ну тут думаю понятно, вычисляем длину функции, далее копируем в специальный буфер и этот буфер сохраняем в файл:
CODE:
int func_len = (unsigned int) _Bild
                  - (unsigned int) _Demo;
  char buff[1000];
  memcpy (buff, _Demo, func_len);

  f=fopen("Demo32.bin","wb");
  for (int a=0;a<func_len;a++)
    fputc(((int) buff[a]),f);
  fclose(f);
2)Ну далее нам нужно преобразовать бинарный код в си-код, как это сделать я сказал выше.
У меня получилось так:
CODE:
static char code2[] =
    {
        0x55, 0x8b, 0xec, 0x51, 0x8d, 0x45, 0xfc, 0x50, 0xc7, 0x45, 0xfc, 0x48, 0x69, 0x21, 0x00, 0xff,
        0x55, 0x08, 0x83, 0xc4, 0x04, 0x8b, 0xe5, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc
    };
Далее пишем программу запуска кода (тоже вижуалка):
CODE:
#define _CRT_SECURE_NO_WARNINGS

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

int main(int argc, char* argv[])
{
    static char buff[1000];

    int(*_printf) (const char *, ...);
    void(*_Demo) (int(*) (const char *, ...));
          
    static char code2[] =
    {
        0x55, 0x8b, 0xec, 0x51, 0x8d, 0x45, 0xfc, 0x50, 0xc7, 0x45, 0xfc, 0x48, 0x69, 0x21, 0x00, 0xff,
        0x55, 0x08, 0x83, 0xc4, 0x04, 0x8b, 0xe5, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc
    };
  
    int code_size = sizeof(code2);
    memcpy(buff, code2, sizeof(code2));

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

    DWORD oldprotect;
    VirtualProtect(_Demo, sizeof(code2), PAGE_EXECUTE, &oldprotect);

    _Demo(_printf);

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

1) Код, который будем запускать:
CODE:
static char code2[] =
    {
        0x55, 0x8b, 0xec, 0x51, 0x8d, 0x45, 0xfc, 0x50, 0xc7, 0x45, 0xfc, 0x48, 0x69, 0x21, 0x00, 0xff,
        0x55, 0x08, 0x83, 0xc4, 0x04, 0x8b, 0xe5, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc
    };
2)Указатели на printf и на нашу функцию:
CODE:
    int(*_printf) (const char *, ...);
    void(*_Demo) (int(*) (const char *, ...));
    _printf = printf;   
    _Demo = (void(*) (int(*) (const char *, ...)))&buff[0];
3)В общем-то делаем разрешение на запуск и запускаем:
CODE:
 DWORD oldprotect;
    VirtualProtect(_Demo, sizeof(code2), PAGE_EXECUTE, &oldprotect);
    _Demo(_printf);
Получаем:

upload_2017-11-12_0-7-17.png

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

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