Перед сборкой
- Создать копию исходного файла для восстановления
echo F|xcopy SourceProg.cpp tmp.cpp
- Выполнить обфускацию на уровне исходного кода начиная с заданной строки
python obfuscator.py SourceProg.cpp 237
СБОРКА
После сборки
- Выполнить зашифрование участка исполняемого файла между заданными адресами на случайном ключе
encrypter.exe $(TargetPath) 33FA0 34EDA
- Восстановить исходный файл из копии
del SourceProg.cpp
echo F|xcopy tmp.cpp SourceProg.cpp
del tmp.cpp
Выполнение
- Установить права чтения, записи и исполнения для зашифрованного участка кода, в котором содержится полезная нагрузка
void getRWX(void* startAddr)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(
(void*)startAddr,
&mbi,
sizeof(mbi));
VirtualProtect(
mbi.BaseAddress,
mbi.RegionSize,
PAGE_EXECUTE_READWRITE,
&mbi.Protect);
}
- Расшифровать участок кода в процессе выполнения
- Выполнить расшифрованную полезную нагрузку программы
Для обеспечения полиморфизма используется два модуля: обфускатор (obfuscator.py) и шифровальщик (encrypter.exe). Затем зашифрованный код расшифровывается в процессе выполнения программы.
Обфускатор производит модификацию исходного кода программы, состоящую в добавлении ассемблерных инструкций, не изменяющих общую логику. С некоторой вероятностью могут быть добавлены следующие инструкции:
NOP
PUSH, POP со случайным регистром общего назначения
INC, DEC со случайным регистром общего назначения
или их комбинации. Обфусцируются функции, которые не могут быть зашифрованы: функция main() и функции, необходимые для расшифрования.
Шифровальщик выполняет операцию XOR с однобайтовым случайным ключом для участка исполняемого файла, в котором содержится код полезной нагрузки.
В процессе выполнения вычисляется ключ и производится обратное преобразование зашифрованного участка кода. Код любой функции начинается с операции PUSH EBP, код операции 0x55. Таким образом, ключ можно получить так: key=b_0⨁0x55, где b_0 – начальный байт зашифрованной функции.