Базы данныхИнтернетКомпьютерыОперационные системыПрограммированиеСетиСвязьРазное
Поиск по сайту:
Подпишись на рассылку:

Назад в раздел

Написание самомодифицирующегося кода под Windows 95

div.main {margin-left: 20pt; margin-right: 20pt} Написание самомодифицирующегося кода под Windows 95 Краткий обзор

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

Windows 95 имеет большую степень защиты кода программы, чем DOS. Обычно приложения получают доступ к сегменту данных и стеку, но они не имеют права изменять собственный сегмент кода. Однако это не значит, что сделать это невозможно - достаточно "попросить" Windows, вызвав функцию VirtualProtect(). В качестве параметра в функцию передаются адрес первого байта блока памяти, к которому мы хотим получить доступ, количество байтов в блоке, а также флаг, определяющий, какой тип доступа нам нужен (т.е. чтение, запись, выполнение и т.д.). Также в функцию передается адрес переменной, в которой сохраняется предыдущее состояние защиты указанного блока, которое мы обязаны восстановить, когда проделаем необходимые манипуляции.

Следующий фрагмент Wn32-кода показывает эту технику "в деле". Ассемблерный оператор после метки myloop - "mov dword ptr a, 0x12345678". Предшествующие операторы изменяют его на "mov dword prt a, 0x87654321". Попробуйте поместить приведенный код в функцию CC++ и по шагам пройти ее в отладчике:

LPVOID address; // Получаем адрес слова, которое нужно изменить _asm mov dword ptr address, offset [myloop+3] // Получаем разрешение модифицировать участок кода result = VirtualProtect(address, 4, PAGE_WRITECOPY, &oldprotect); // Изменяем ассемблерный код. Это эквивалентно *(LPVOID) address = 0x87654321 _asm mov ebx, dword ptr address _asm mov dword ptr [ebx], 0x87654321 // Все сделано result = VirtualProtect(address, 4, PAGE_EXECUTE, &oldprotect); mylopp: _asm mov dword ptr a, 0x12345678 Создаем новый фрагмент кода

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

typedef LONG (* FunctionType) (LONG, LONG); FunctionType ComputeSum;

Итак, ComputeSum - переменная типа FunctionType, определяющего указатель на функцию следующего вида:

LONG Function(LONG, LONG);

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

ComputeSum = (FunctionType) new BYTE[11];

Теперь можно заполнить выделенную область опкодами:

((LPBYTE) ComputeSum)[0] = 0x55; // push ebp ((LPBYTE) ComputeSum)[1] = 0x8B; // mov ebp, esp ((LPBYTE) ComputeSum)[2] = 0xEC; ((LPBYTE) ComputeSum)[3] = 0x8B; // mov eax, [bp+8] ((LPBYTE) ComputeSum)[4] = 0x45; ((LPBYTE) ComputeSum)[5] = 0x08; ((LPBYTE) ComputeSum)[6] = 0x03; // add eax, [bp+12] ((LPBYTE) ComputeSum)[7] = 0x45; ((LPBYTE) ComputeSum)[8] = 0x0C; ((LPBYTE) ComputeSum)[9] = 0x5D; // pop ebp ((LPBYTE) ComputeSum)[10] = 0xC3; // ret eax

Наконец, можно вызвать функцию VirtualProtect(). Все наши команды на месте, нам нужно просто разрешить выполнить их. Следующая команда сделает это:

VirtualProtect(ComputeSum, 11, PAGE_EXECUTE, &oldprotect);

Как и раньше, переменная oldprotect должна быть типа DWORD. Итак, сейчас у нас есть указатель на обычную функцию, которую можно вызвать, например, так:

sum = ComputeSum(1, 2); sum = ComputeSum(val1, val2);

Единственная деталь, о которой не нужно забывать - освободить память, выделенную для нашей функции оператором new. Перед этим не помешает восстановить статус защиты выделенного блока памяти:

VirtualProtect(ComputeSum, 11, oldprotect, &oldprotect); delete (LPBYTE) ComputeSum;

И в заключение небольшое замечание: если вы хотите, чтобы ваша "мутирующая" программа выполнялась правильно и под Windows NT, после модификаций сегмента кода нужно вызывать функцию FlushInstructionCache(). Для Windows 95 это необязательное требование, т.к. эта операционная система поддерживает только один процессор, однако для совместимости со старшими версиями Windows вы должны использовать FlushInstructionCahce();

Удачного программирования!



  • Главная
  • Новости
  • Новинки
  • Скрипты
  • Форум
  • Ссылки
  • О сайте




  • Emanual.ru – это сайт, посвящённый всем значимым событиям в IT-индустрии: новейшие разработки, уникальные методы и горячие новости! Тонны информации, полезной как для обычных пользователей, так и для самых продвинутых программистов! Интересные обсуждения на актуальные темы и огромная аудитория, которая может быть интересна широкому кругу рекламодателей. У нас вы узнаете всё о компьютерах, базах данных, операционных системах, сетях, инфраструктурах, связях и программированию на популярных языках!
     Copyright © 2001-2024
    Реклама на сайте