Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги хакеры / Защита_от_взлома_сокеты,_эксплойты,_shell_код_Фостер_Дж_

.pdf
Скачиваний:
14
Добавлен:
19.04.2024
Размер:
3.68 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

Глава 1

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Написание безопасных программ

Описание данной главы:

Введение

С/С++

Java

C#

Perl

Python

Резюме

Обзор изложенного материала

Часто задаваемые вопросы

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

32 Глава 1. Написание безопасных программ

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

 

e

 

 

 

 

 

 

n

Введение

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

История языков программирования коротка, но динамична. Еще не так давно передовым считался язык ассемблера. Но с тех пор программирование прошло длинный путь, на котором обогатилось новыми идеями и технологиями: от объектов до инструментов визуального программирования. Сегодня существует три основных парадигмы программирования: процедурная (например, C и Pascal), функциональная (Lisp и ML) и объектно-ориентиро- ванная (Java, C++ и Smalltalk). Логическое или декларативное программирование (например, Prolog) остается уделом академических исследований.

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

âклассы. Экземпляры классов, именуемые объектами, содержат данные и методы, выполняющие те или иные действия над этими данными. Объекты взаимодействуют, посылая друг другу сообщения, в которых содержатся запросы на выполнение определенных действий.

Понимать особенности языков программирования необходимо как прикладным программистам, так и специалистам по безопасности, занятым тестированием приложений. У каждого языка есть специфические характеристики, которые нужно учитывать при попытке взлома программы. Например, программисты, привыкшие писать «эксплойты», основанные на переполнении буфера в программах на языке C, могут впасть в растерянность, когда для аудита будет представлено приложение, написанное на Java. Прочи- тав эту главу, вы получите общее представление о такого рода аспектах безопасности, связанных с ними рисках и о том, какие дефекты возможны в программах на языках C, C++, Java и C#.

На заре распространения операционной системы UNIX в конце 60-х и

â70-õ годах на авансцену вышли интерпретируемые языки, призванные сократить время разработки небольших задач. Они позволяли энтузиастам программирования создавать сценарии, то есть наборы интерпретируемых инструкций, которые компьютер мог выполнить. Такие утомительные проблемы как управление памятью и работа с низкоуровневыми системными

командами, теперь выполнялись «за кулисами», что позволило снизить слож-

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

С/С++ 33

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

p

 

-x cha

 

 

 

 

 

 

 

-xchностьa

и объем кода, необходимого для решения конкретной задачи. Безус-

 

 

e

 

 

 

 

df

 

 

n

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ловно, языки сценариев стали мечтой ленивого программиста. Почитаемым предком всех интерпретируемых языков является язык

управления заданиями (JCL – job control language). В системе OS/360 этот язык использовался для организации данных, поступающих с перфокарт, в пригодные для работы наборы символов. Если принять во внимание возможности языка и его примитивную природу, то накладные расходы были просто гигантскими. Первым получившим широкое распространение языком сценариев стал язык интерпретатора команд sh в системе UNIX. Первона- чально он предназначался для администраторов и позволял быстро создавать сценарии для управления сетью и системой в целом.

По мере того как производительность и функциональность платформы росла безумными темпами, число интерпретируемых языков превысило число полномасштабных компилируемых языков программирования. Сценарии превратились в весьма развитую технологию, свидетельством чему могут служить широкие возможности, заложенные в такие языки, как PHP, Python, Perl и Javascript. Современные языки сценариев уже содержат объект- но-ориентированные средства, создание классов, управление памятью, создание сокетов, рекурсию, динамические массивы и регулярные выражения. Есть даже интерпретируемые языки, позволяющие разрабатывать графические интерфейсы, например, популярный язык TCL/Tk.

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

C/C++

Язык программирования C создал Деннис Ричи из компании Bell Labs в 1972 году. С тех пор C стал одним из основных языков профессиональных программистов и главным языком в операционной системе UNIX. В 1980 году Бьярн Страуструп из той же компании Bell Labs приступил к включению в C объектноориентированных механизмов, в частности, инкапсуляции и наследования. Так в 1983 году появился язык «C with Classes», который позднее получил название C++. Имея схожий с C синтаксис и обладая преимуществами объектной ориентированности, язык C++ быстро приобрел широкую популярность.

Языки C и C++ так широко распространены благодаря своей выразительной мощи, а также потому, что именно их предпочитают преподавать в университетах. Хотя новые языки, к примеру, C# и Java, постепенно набирают популярность, но программисты, умеющие писать на C и C++, будут востребованы еще много лет.

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

34 Глава 1. Написание безопасных программ

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

 

e

 

 

 

 

df

 

 

n

 

Характеристики языка

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Поскольку высокоуровневые языки C и C++ являются компилируемыми, то написанный на них текст не понятен процессору. Специальная программа- компилятор транслирует этот текст в машинный код, который процессор может исполнить. В отличие от интерпретируемых языков, к числу которых относится Java, не существует никакого байт-кода или промежуточного языка. Программы, написанные на C или C++, транслируются непосредственно в команды, доступные процессору. У такого подхода есть недостаток – зависимость от платформы. Код должен быть скомпилирован именно для той системы, на которой будет исполняться.

ßçûê C

Язык C знаменит своей универсальностью, сочетаемой с простотой. Число зарезервированных слов в нем невелико, но функциональность тем не менее весьма высока. Небольшое число зарезервированных слов не мешает программисту выразить то, что он хочет. К услугам программистов на C имеются разнообразные операторы и возможность создавать собственные типы данных. Простота языка позволяет научиться его основам легко и быстро.

Мощь языка C происходит от отсутствия в нем ограничений; программист может получать доступ к данным и манипулировать ими на уровне битов. Широко распространено также использование указателей, то есть прямых ссылок на ячейки памяти. В более поздних языках, например, в Java эта возможность удалена. C – это процедурный язык. Написанная на нем программа состоит из функций, представляющих собой автономные конструкции для решения отдельных задач. Модульность позволяет использовать код повторно. Группы функций можно объединить в библиотеки, допускающие импорт в другие программы, что заметно сокращает время разработки.

C также очень эффективный язык. Некоторые алгоритмы возможно реализовать машинно-зависимым способом, воспользовавшись особенностями архитектуры микропроцессора. Программа на C транслируется непосредственно в машинный код, поэтому исполняется быстрее программы на «интерпретируемом» языке типа Java. Такое быстродействие оказывается существенным для многих приложений, особенно работающих в реальном масштабе времени, но у него есть и обратная сторона: код, написанный на C, не является платформенно-независимым. При переносе на новую платформу части программы иногда приходится переписывать. Из-за дополнительных усилий не всегда существует версия конкретной C-программы для новой операционной системы или набора микросхем.

Тем не менее, язык C очень полюбился программистам. Программы на нем могут выглядеть просто и элегантно, обладая в то же время большими

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

С/С++ 35

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

p

 

-x cha

 

 

 

 

 

 

 

-xchвозможностями.a

Особенно хорошо язык C подходит для работы в системе

 

 

e

 

 

 

 

df

 

 

n

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

ßçûê C++

Язык C++ является расширением C. Синтаксис и набор операторов схожи с тем, что есть в C, но при этом добавлены черты, характерные для объектноориентированного программирования, а именно:

Инкапсуляция. За счет использования классов объектно-ориентиро- ванный код имеет очень хорошую организацию и обладает высокой модульностью. Данные и методы для выполнения операций над ними инкапсулированы в структуру класса;

Наследование. Объектно-ориентированная организация и инкапсуляция позволяют без труда реализовать повторное использование или «наследование» ранее написанного кода. Наследование экономит время, так как программисту не нужно заново кодировать уже имеющуюся функциональность;

Сокрытие данных. Объекты, то есть экземпляры класса могут содержать данные, которые не могут быть изменены иначе как с помощью методов самого этого класса. Программист на C++ может скрыть данные, назначив им атрибут «private» (закрытый);

Абстрактные типы данных. Программист может определить класс, который можно представлять себе как обобщение структуры (struct), имеющейся в языке C. Класс описывает определенный программистом тип данных вместе с операциями, применимыми к объектам этого типа.

В отличие от Java, язык C++ не является полностью объектно-ориентиро- ванным. На нем можно писать программы в стиле C, не пользуясь объектноориентированными расширениями.

Безопасность

Языки C и C++ разрабатывались до стремительного наступления Интернета, поэтому первоочередное внимание безопасности не уделялось. Типичной уязвимостью для программ, написанных на этих языках, является переполнение буфера. Об этой проблеме многие узнали из статьи Элиаса Леви (Elias Levy) (опубликованной под псевдонимом «Aleph One») «Smashing the Stack for Fun and Profit» (Манипуляции со стеком для забавы и пользы). С помощью описанной там техники атакующий может обнаружить участок программы, в котором значение считывается в область фиксированного размера, а затем

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

36 Глава 1. Написание безопасных программ

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

 

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

-xcha

 

 

 

 

 

p

 

 

 

 

 

 

 

 

 

 

 

 

 

передать программе более длинное значение, вызвав тем самым переполне--x cha

 

e

 

 

 

 

df

 

 

n

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ние стека или «кучи», и как следствие получить доступ к защищенной области памяти.

Âязыках C и C++ нет механизма автоматического контроля выхода за границы, что и делает их уязвимыми для атак методом переполнения стека. Ответственность за реализацию такого контроля для каждой переменной, счи- тываемой из внешнего источника, возлагается на программиста. В языках C#

èJava риска переполнения буфера нет, так как контроль выхода за границы производится автоматически.

ÂС++ включены средства для сокрытия данных. Внутренние методы и данные класса можно объявить закрытыми, так что они будут доступны только внутри этого класса и больше нигде. Поскольку C – это чисто процедурный язык, то механизмы сокрытия данных в нем отсутствуют, поэтому злонамеренный пользователь может получить доступ к внутренним структурам программы непредусмотренным способом.

Атакуя программу, написанную на C или C++, противник может также получить доступ к критически важным областям памяти. Дело в том, что в обоих языках активно применяются указатели, позволяющие обратиться к произвольному адресу в памяти. В Java и C# вместо этого используются ссылочные переменные. Кроме того, в Java реализована модель «песочницы» (sandbox), в соответствии с которой программы, работающие внутри «песоч- ницы», не могут читать или модифицировать внешние данные. Такой концепции в языках C и C++ нет.

Пример «Здравствуй, мир!»

Программу «Здравствуй, мир!» (Hello, world!) часто приводят в пример, как простейшую из возможных программ на данном языке. Начинающие программисты на этом примере осваивают базовую структуру языка, учатся пользоваться компилятором и запускать программу на выполнение. Ниже приведен текст такой программы на языке C.

Пример 1.1. Здравствуй, мир!

1#include <stdio.h>

2int main( void ) {

3printf("%s", "Hello, world!");

4return 0;

5}

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

мах, например, «printf». Данная программа состоит всего из одной функции

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

r

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

С/С++

37

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

 

p

 

-x cha

 

 

 

 

 

 

 

-xcháåça

 

аргументов (о чем говорит ключевое слово void), возвращающей целое

 

 

e

 

 

 

 

df

 

 

n

e

 

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

число. Предложение printf в строке 3 печатает строку на так называемый стандартный вывод. Конструкция «%s» говорит о том, что будет напечатана переменная строкового типа, а надпись «Hello, world!» – это и есть выводимая строка. О типах и функциях мы будем еще подробно говорить ниже в этой главе.

Типы данных

Типы данных служат в языках программирования для определения переменных до их инициализации. Тип определяет, как переменная будет размещена

âпамяти и какие данные она может содержать. Интересно отметить, что, хотя типы данных часто применяются для описания размера переменной,

âстандарте языка не определены точные размеры каждого типа. Поэтому программист должен хорошо представлять себе платформу, для которой он пишет код. Говорят, что переменная является экземпляром (instance) некоторого типа данных. В языках C и C++ имеются следующие стандартные типы данных:

Int. Òèï int служит для представления целых чисел. В большинстве систем для хранения целого числа выделяется 4 байта;

Float. Типом float представляют числа с плавающей точкой. В большинстве систем под них отводится 4 байта;

Double. Òèï double служит для представления чисел с плавающей точ- кой двойной точности. Как правило, на ПК переменные такого типа занимают 8 байтов;

Char. Òèï char служит для представления символов. В большинстве систем для каждого символа выделяется 1 байт.

Существуют также модификаторы, изменяющие размер и интерпретацию описанных выше типов. К ним относятся short, long, signed и unsigned. Знаковые (signed) типы могут представлять как положительные, так и отрицательные значения. Беззнаковые (unsigned) типы позволяют представить только неотрицательные значения. По умолчанию все числовые типы знаковые. На рис. 1.1 приведена классификация типов данных в языках C/C++.

Языки C/C++ позволяют программисту определить собственные типы данных с помощью ключевого слова typedef. Оно часто применяется, чтобы сделать программу понятнее. Так, следующие ниже примеры эквивалентны, но использование typedef более наглядно показывает, что хотел сказать программист.

Пример 1.2. Конструкция typedef

Áåç typedef

int weight( void ){ int johnweight;

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

38 Глава 1. Написание безопасных программ

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

double

Типы с плавающей точкой

float

Предопределенные

типы

char

Целочисленные

типы

int

Рис. 1.1. Классификация типов данных в языках C/C++

johnweight = 150; return johnweight;

}

Ñ typedef

int weight( void ){

 

typedef int weight;

/* вес в фунтах */

weight johnweight = 150;

 

return johnweight;

 

}

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

-x

 

n

e

 

 

 

 

 

cha

 

 

 

 

Из этих примеров видно, что использование typedef проясняет смысл программы и позволяет связать с типом данных некоторые дополнительные характеристики. Комментарий к строке 7 говорит о том, что все переменные типа weight будут хранить значения веса в фунтах. Глядя на строку 8 мы видим, что переменная johnweight – это, вероятнее всего, вес. В примере без применения typedef можно лишь сказать, что johnweight – это целое число. По мере увеличения размера программы преимущества typedef становятся более очевидными. В предыдущем примере оба метода приводят к ясному коду, но, если программа состоит из нескольких сотен строк, то объявление переменной как имеющей тип weight может многое сказать о ее природе.

В языке C имеются следующие конструкции для организации структур данных:

Массивы. Массив – это индексированная последовательность данных одного типа;

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

 

 

 

 

 

 

-xcha

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

С/С++ 39

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

-x cha

 

 

 

Указатели. Указатель – это переменная, ссылающаяся на другую пере-

df

 

e

 

 

 

 

 

 

n

 

 

 

 

менную;

Структуры. Структура (struct) – это запись, содержащая данные разных типов;

Объединения. Объединение (union) содержит только одно значение, но в разные моменты исполнения программы у него могут быть разные типы. Какой именно тип хранится в данный момент, определяет поле селектора;

Перечисления. Перечисление (enum) позволяет определить переменную, способную принимать значения из небольшого множества.

Для создания сложных типов данных, состоящих из нескольких элементов, применяется ключевое слово struct. Часто в структурах употребляются типы, ранее определенные с помощью слова typedef. В примере 1.3 продемонстрирована структура данных.

Пример 1.3. Структура struct

1struct person{

2

String name;

/* тип String должен быть где-то определен */

3

Height

h;

/*

òèï

Height

должен

áûòü

ãäå-òî

определен

*/

4

Weight

w;

/*

òèï

Weight

должен

áûòü

ãäå-òî

определен

*/

5}

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

int combinedweight = John.w + Tom.w;

Ущерб и защита

Создание дерева атак

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

Продолжение

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

40 Глава 1. Написание безопасных программ

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

 

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

 

.

 

 

 

 

g

 

 

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

p

 

 

 

 

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

df

-x

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

Построив дерево атак, припишите каждому узлу некоторую вероят

 

 

cha

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ность. Поднимаясь снизу вверх, от «листьев» к «корню», можно дать

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

вероятностную оценку безопасности системы в целом.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Поток управления

В языках C и C++ для управления потоком выполнения программы применяются циклы. В программах часто встречаются участки, которые надо повторить либо заранее известное число раз, либо до тех пор, пока не будет выполнено некоторое условие. Циклы как раз и предназначены для решения подобного рода задач. Имеется три основных вида циклов: for, while и do...while.

Пример 1.4. Цикл «for»

1for( начальное_выражение; проверяемое_условие; операция ){

2 [блок предложений];

3}

Из всех циклов чаще всего используется for. В начале выполнения цикла программа вычисляет начальное выражение и проверяет следующее за ним условие. Если условие истинно, выполняется тело цикла («блок предложений»). В конце цикла производится операция, указанная на третьем месте в заголовке, после чего снова проверяется условие. Цикл продолжается, пока условие не станет ложным.

Особенно хорошо цикл for подходит для выполнения итераций. Если нужно выполнить блок предложений пять раз, то можно написать такой простой цикл:

for( i = 0 ; i < 5 ; i++ ){ [блок предложений];

}

Пример 1.5. Цикл «while»

while( условие ){ [блок предложений];

}

При выполнении цикла while проверяется условие, стоящее в начале цикла. Если оно истинно, выполнение цикла продолжается, иначе прекращается. Цикл повторяется, пока условие не станет ложным.