Фундаментальные основы хакерства. Учимся идентифицировать конструкторы и деструкторы - «Новости» » Самоучитель CSS
Меню
Наши новости
Учебник CSS

Невозможно отучить людей изучать самые ненужные предметы.

Введение в CSS
Преимущества стилей
Добавления стилей
Типы носителей
Базовый синтаксис
Значения стилевых свойств
Селекторы тегов
Классы
CSS3

Надо знать обо всем понемножку, но все о немногом.

Идентификаторы
Контекстные селекторы
Соседние селекторы
Дочерние селекторы
Селекторы атрибутов
Универсальный селектор
Псевдоклассы
Псевдоэлементы

Кто умеет, тот делает. Кто не умеет, тот учит. Кто не умеет учить - становится деканом. (Т. Мартин)

Группирование
Наследование
Каскадирование
Валидация
Идентификаторы и классы
Написание эффективного кода

Самоучитель CSS

Вёрстка
Изображения
Текст
Цвет
Линии и рамки
Углы
Списки
Ссылки
Дизайны сайтов
Формы
Таблицы
CSS3
HTML5

Новости

Блог для вебмастеров
Новости мира Интернет
Сайтостроение
Ремонт и советы
Все новости

Справочник CSS

Справочник от А до Я
HTML, CSS, JavaScript

Афоризмы

Афоризмы о учёбе
Статьи об афоризмах
Все Афоризмы

Видео Уроки


Наш опрос



Наши новости

      
      
  • 24 марта 2016, 16:20
13-07-2020, 12:39
Фундаментальные основы хакерства. Учимся идентифицировать конструкторы и деструкторы - «Новости»
Рейтинг:
Категория: Новости

В этой статье речь пойдет об известных каждому программисту функциях работы с объектами класса — конструкторах и деструкторах, а также о том, как обнаружить их в коде исследуемой программы.

Читай также:



  • Проверка аутентичности и базовый взлом защиты

  • Знакомство с отладчиком

  • Продолжаем осваивать отладчик

  • Новые способы находить защитные механизмы в чужих программах

  • Выбираем лучший редактор для вскрытия исполняемых файлов Windows

  • Мастер-класс по анализу исполняемых файлов в IDA Pro

  • Учимся искать ключевые структуры языков высокого уровня

  • Идентификация стартового кода и виртуальных функций приложений под Win64

  • Какие бывают виртуальные функции и как их искать


Объекты в куче



Конструктор в силу своего автоматического вызова при создании нового экземпляра объекта — первая по счету функция. Так какие же могут возникнуть сложности в его идентификации? Камень преткновения в том, что конструктор факультативен, то есть может присутствовать в объекте, а может и не присутствовать. Поэтому совсем не факт, что первая вызываемая функция — именно конструктор!



Заглянув в описание языка C++, можно обнаружить, что конструктор не возвращает никакого значения, что нехарактерно для обычных функций, однако все же не настолько редко встречается, чтобы однозначно его идентифицировать. Как же тогда быть?



Выручает то обстоятельство, что по стандарту конструктор не должен автоматически вызывать исключения, даже если выделить память под объект не удалось. Реализовать это требование можно множеством различных способов, но все знакомые автору компиляторы просто помещают перед вызовом конструктора проверку на нулевой указатель, передавая ему управление только при удачном выделении памяти для объекта. Напротив, все остальные функции объекта вызываются всегда, даже при неуспешном выделении памяти. Точнее, пытаются вызываться, но нулевой указатель (возвращаемый в случае ошибки выделения памяти) при первой же попытке обращения вызывает исключение, передавая бразды правления обработчику соответствующей исключительной ситуации.



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



Деструктор, как и конструктор, факультативен, то есть последняя вызываемая функция объекта может и не быть деструктором. Тем не менее отличить деструктор от любой другой функции очень просто — он вызывается только при результативном создании объекта (то есть успешном выделении памяти) и игнорируется в противном случае. Это документированное свойство языка — следовательно, обязательное к реализации всеми компиляторами. Таким образом, в код помещается такое же «кольцо», как и у конструктора, но никакой путаницы не возникает, так как конструктор вызывается всегда первым (если он есть), а деструктор — последним (опять-таки если он присутствует).



Особый случай представляет объект, целиком состоящий из одного конструктора (или деструктора), — попробуй-ка разобраться, с чем мы имеем дело. Но разобраться можно! За вызовом конструктора практически всегда присутствует код, обнуляющий this РІ случае неудачного выделения памяти, Р° Сѓ деструктора этого нет. Далее, деструктор обычно вызывается РЅРµ непосредственно РёР· материнской процедуры, Р° РёР· функции-обертки, вызывающей РїРѕРјРёРјРѕ деструктора Рё оператор delete, который освобождает занятую объектом память. Так что отличить конструктор от деструктора вполне можно.



Между тем современные компиляторы для создания оптимального по быстродействию и размеру кода могут впихнуть все элементы в функцию main. Для лучшего понимания сказанного рассмотрим демонстрацию конструктора и деструктора (пример myClass1):



#include
class MyClass {

public:
MyClass(void);
void demo(void);
~MyClass(void);
};

MyClass::MyClass()
{
printf("Constructorn");
}

MyClass::~MyClass()
{
printf("Destructorn");
}

void MyClass::demo(void)
{
printf("MyClassn");
}

int main()
{
MyClass *zzz = new MyClass();
zzz->demo();
delete zzz;
}
[/code]

Фундаментальные основы хакерства. Учимся идентифицировать конструкторы и деструкторы - «Новости»
Вывод приложения myClass1

В результате компиляции примера myClass1 с помощью VC++’17 с настройкой вывода проекта Release будет выглядеть так:



main proc near
push rbx
sub rsp, 20h
mov ecx, 1
; size
call operator new(unsigned __int64)
lea rcx, _Format
; "Constructorn"
mov [rsp+28h+arg_0], rax
mov rbx, rax
call printf
lea rcx, aMyclass
; "MyClassn"
call printf
lea rcx, aDestructor ; "Destructorn"
call printf
mov edx, 1
; __formal
mov rcx, rbx
; block
call operator delete(void *,unsigned __int64)
xor eax, eax
add rsp, 20h
pop rbx
retn
main endp
[/code]

Как раз упомянутый случай! Компилятор все сделал достоянием функции main, РІ отдельности РЅРµ создав РЅРё конструктора, РЅРё деструктора, РЅРё метода класса. После выделения памяти РѕРЅ тут Р¶Рµ вызывает функцию для вывода строки символов! РўРѕ Р¶Рµ РїСЂРѕРёСЃС…РѕРґРёС‚ СЃ очисткой памяти. Р’РѕС‚ это магия! Здесь интересным для нас может быть только оператор new: его устройство мы подробно рассмотрели в предыдущей статье.


Цитирование статьи, картинки - фото скриншот - Rambler News Service.
Иллюстрация к статье - Яндекс. Картинки.
Есть вопросы. Напишите нам.
Общие правила  поведения на сайте.

В этой статье речь пойдет об известных каждому программисту функциях работы с объектами класса — конструкторах и деструкторах, а также о том, как обнаружить их в коде исследуемой программы. Читай также: Проверка аутентичности и базовый взлом защиты Знакомство с отладчиком Продолжаем осваивать отладчик Новые способы находить защитные механизмы в чужих программах Выбираем лучший редактор для вскрытия исполняемых файлов Windows Мастер-класс по анализу исполняемых файлов в IDA Pro Учимся искать ключевые структуры языков высокого уровня Идентификация стартового кода и виртуальных функций приложений под Win64 Какие бывают виртуальные функции и как их искать Объекты в куче Конструктор в силу своего автоматического вызова при создании нового экземпляра объекта — первая по счету функция. Так какие же могут возникнуть сложности в его идентификации? Камень преткновения в том, что конструктор факультативен, то есть может присутствовать в объекте, а может и не присутствовать. Поэтому совсем не факт, что первая вызываемая функция — именно конструктор! Заглянув в описание языка C , можно обнаружить, что конструктор не возвращает никакого значения, что нехарактерно для обычных функций, однако все же не настолько редко встречается, чтобы однозначно его идентифицировать. Как же тогда быть? Выручает то обстоятельство, что по стандарту конструктор не должен автоматически вызывать исключения, даже если выделить память под объект не удалось. Реализовать это требование можно множеством различных способов, но все знакомые автору компиляторы просто помещают перед вызовом конструктора проверку на нулевой указатель, передавая ему управление только при удачном выделении памяти для объекта. Напротив, все остальные функции объекта вызываются всегда, даже при неуспешном выделении памяти. Точнее, пытаются вызываться, но нулевой указатель (возвращаемый в случае ошибки выделения памяти) при первой же попытке обращения вызывает исключение, передавая бразды правления обработчику соответствующей исключительной ситуации. Таким образом функция, окольцованная проверкой нулевого указателя, и есть конструктор, а не что-либо иное. Теоретически, впрочем, подобная проверка может присутствовать и при вызове других функций, конструктором не являющихся, но. Во всяком случае, автору на практике с таким еще не приходилось встречаться. Деструктор, как и конструктор, факультативен, то есть последняя вызываемая функция объекта может и не быть деструктором. Тем не менее отличить деструктор от любой другой функции очень просто — он вызывается только при результативном создании объекта (то есть успешном выделении памяти) и игнорируется в противном случае. Это документированное свойство языка — следовательно, обязательное к реализации всеми компиляторами. Таким образом, в код помещается такое же «кольцо», как и у конструктора, но никакой путаницы не возникает, так как конструктор вызывается всегда первым (если он есть), а деструктор — последним (опять-таки если он присутствует). Особый случай представляет объект, целиком состоящий из одного конструктора (или деструктора), — попробуй-ка разобраться, с чем мы имеем дело. Но разобраться можно! За вызовом конструктора практически всегда присутствует код, обнуляющий this РІ случае неудачного выделения памяти, Р° Сѓ деструктора этого нет. Далее, деструктор обычно вызывается РЅРµ непосредственно РёР· материнской процедуры, Р° РёР· функции-обертки, вызывающей РїРѕРјРёРјРѕ деструктора Рё оператор delete, который освобождает занятую объектом память. Так что отличить конструктор от деструктора вполне можно. Между тем современные компиляторы для создания оптимального по быстродействию и размеру кода могут впихнуть все элементы в функцию main. Для лучшего понимания сказанного рассмотрим демонстрацию конструктора и деструктора (пример myClass1): Вывод приложения myClass1 В результате компиляции примера myClass1 с помощью VC ’17 с настройкой вывода проекта Release будет выглядеть так: Как раз упомянутый случай! Компилятор все сделал достоянием функции main, РІ отдельности РЅРµ создав РЅРё конструктора, РЅРё деструктора, РЅРё метода класса. После выделения памяти РѕРЅ тут Р¶Рµ вызывает функцию для вывода строки символов! РўРѕ Р¶Рµ РїСЂРѕРёСЃС…РѕРґРёС‚ СЃ очисткой памяти. Р’РѕС‚ это магия! Здесь интересным для нас может быть только оператор new: его устройство мы подробно рассмотрели в предыдущей статье.
Просмотров: 484
Комментариев: 0:   13-07-2020, 12:39
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь. Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

 
Еще новости по теме:



Другие новости по теме: