Всем привет ! :)
Осень, дерьмовая погода и настроение жесть.
Что-бы как-то поднять настроение, решил
Гуглил, находил книги Криса, который говорил про исполнение кода на стеке, но чот так и не получилось у меня.
Ибо грёбанная винда, блокирует доступ к стеку, хотя возможно руки вырасли из жопы. Но не суть в принципе можно сделать что-то такое в кучи.
Давайте разбираться, итак как её, ах-да теория. Короче немного тут будет:
В си есть прикольная штука, называется указатель на функцию. Смысл такой, ты делаешь какой-то абстрактный тип данных, и говоришь, "Это функция" и далее можешь использовать этот тип данных вызывая различные функции, с разным функционалом, например:
Код:
typedef LONG (*FunctionPointer) (LONG, LONG);
Далее например если у вас есть функция например функция сложения а+в, вы можете вызвать её. При помощи этого указателя, вот пример:
FunctionPointer Summa; //Объявляем переменную с типом FunctionPointer (наш указатель на функцию)
Допустим есть функция, которая складывает два числа:
int tst_summ (LONG a, LONG b)
{
return a+b;
}
Далее мы можем вызвать нашу функцию например так:
Summa = tst_summ;
Result = Summa (1,2);
Ну думаю понятно, что это нужно когда например в разных ситуациях выполнялся разный код, например я это использую как абстрактный тип данных при написании драйверов для различных девайсов. Например, функции чтения с различных устройств (флешки, диски и т.д.) всегда разные, но при этом можно сделать удобный интерфейс для взаимодействия, т.е. пользователь будет дёргать одну функцию, например read, а она уже будет вызывать нужную функцию чтения для нужно флешки. :)
Ну это ладно с теорией почти закончено, а что если мы вообще не будет никак заполнять функцию, а заполним её в процессе работы программы, или например пошифруем тело нашей функции, а далее выполним код в процессе выполнения программы ?
Как можно это сделать:
Итак, давайте вначале в этой статье, немного о простом. А в следующей части уже зашифруем код и исполним его в своей программе. Это нужно например для скрытия своей вредоносной нагрузки, или шеллов. А может и вовсе просто хотите скрыть код от палева. :)
Итак теперь немного про ассемблер и машинный код:
Все вы знаете, что ассемблерные команды преобразуются в машинный код после компиляции, это можно посмотреть в любом отладчике, открыв нативную программу, например в оледбг:
Тут левая крайняя колонка, это адрес, правее как раз машинный код, право крайняя колонка это ассемблерный код.
Итак как вы думаете что будет, если мы создадим указатель на функцию, в которой генерируются эти машинные коды ? :)
Ога, они исполнятся в программе.
Давайте попробуем это реализовать, простая функция сложения двух чисел:
1)Создаём абстрактный тип данных:
Код:
typedef LONG (*FunctionPointer) (LONG, LONG);
2)Выделяем память для функции, которую будем генерировать "на лету":
Код:
FunctionPointer Summa;
Summa = (FunctionPointer) malloc (11);
3)Заполняем выделенную память опкодами:
Код:
((LPBYTE) Summa)[0] = 0x55; // push bp
((LPBYTE) Summa)[1] = 0x8B; // mov ebp, esp
((LPBYTE) Summa)[2] = 0xEC;
((LPBYTE) Summa)[3] = 0x8B; // mov eax, [bp+8]
((LPBYTE) Summa)[4] = 0x45;
((LPBYTE) Summa)[5] = 0x08;
((LPBYTE) Summa)[6] = 0x03; // add eax, [bp+12]
((LPBYTE) Summa)[7] = 0x45;
((LPBYTE) Summa)[8] = 0x0C;
((LPBYTE) Summa)[9] = 0x5D; // pop ebp
((LPBYTE) Summa)[10] = 0xC3; // ret eax
Код:
DWORD oldprotect;
VirtualProtect(Summa, 11, PAGE_EXECUTE, &oldprotect);
4)В общем-то и всё, можно запускать нашу функцию:
Код:
int sum = Summa(1, 2);
printf (" Summa = %d \n", sum);
Получаем:
Код программы на си (можно собрать как консольное приложение в вижуалке):
Код:
#include "stdafx.h"
#include "windows.h"
typedef LONG (*FunctionPointer) (LONG, LONG);
int _tmain(int argc, _TCHAR* argv[])
{
FunctionPointer Summa;
Summa = (FunctionPointer) malloc (11);
((LPBYTE) Summa)[0] = 0x55; // push ebp
((LPBYTE) Summa)[1] = 0x8B; // mov ebp, esp
((LPBYTE) Summa)[2] = 0xEC;
((LPBYTE) Summa)[3] = 0x8B; // mov eax, [bp+8]
((LPBYTE) Summa)[4] = 0x45;
((LPBYTE) Summa)[5] = 0x08;
((LPBYTE) Summa)[6] = 0x03; // add eax, [bp+12]
((LPBYTE) Summa)[7] = 0x45;
((LPBYTE) Summa)[8] = 0x0C;
((LPBYTE) Summa)[9] = 0x5D; // pop ebp
((LPBYTE) Summa)[10] = 0xC3; // ret eax
DWORD oldprotect;
VirtualProtect(Summa, 11, PAGE_EXECUTE, &oldprotect);
int sum = Summa(1, 2);
printf (" Summa = %d \n", sum);
while (1);
return 0;
}
Всё работает ! :)
В следующей части, зашифруем код и исполним его после расшифровки на "лету".
Всем удачи ! :)