книги хакеры / Защита_от_взлома_сокеты,_эксплойты,_shell_код_Фостер_Дж_
.pdf
|
|
|
|
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 |
|
|
|
|
|
|
Библиотека ATL 661 |
|
to |
|
|
|
|
|
|
||||
w Click |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
m |
w Click |
|
|
|
|
|
|
|
m |
|||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
||
|
w |
|
|
|
|
|
|
|
|
o |
|
|
w |
|
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
g |
.c |
|
|
. |
|
|
|
|
g |
.c |
|
||||||
|
|
p |
|
|
|
|
|
|
|
|
|
p |
|
-x cha |
|
|
|
||||||
|
|
|
|
-xchэлементa |
массива DWORD, функция может модифицировать значение, на ко- |
|
|
e |
|
||||||||||||||
|
|
|
df |
|
|
n |
e |
|
|
|
|
df |
|
|
n |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
торое указывает p, или только читать его. Если бы вместо DWORD* мы указали тип PVOID, то оставалось бы только гадать, что делает функция. При программировании на C++ не так важно указывать точный тип. Но когда речь идет о вызове метода из другого адресного пространства, ситуация радикально меняется.
Поскольку определения интерфейсов должны быть строго типизированы, в COM применяется специальный язык (IDL) для описания как интерфейсов, так и COM-объектов. Следовательно, в любом проекте для реализации COM-объекта, поддерживающего различные контексты загрузки и потоковые модели, обязательно будет присутствовать файл с определениями всех интерфейсов.
Такие файлы имеют расширение .IDL и передаются компилятору MIDL, который создает несколько других файлов, описывающих интерфейсы, предоставляемые вашим сервером. Сначала составим описание интерфейса на языке IDL, а затем посмотрим, во что его преобразует MIDL.
1[object, uuid("85C5B433-C053-435f-9E4A-8C48557E1D4B")]
2 interface IWarpEngine : IUnknown
3{
4 HRESULT Engage([in] VARIANT_BOOL vbEngage);
5};
Это описание типичного интерфейса на языке IDL. Рассмотрим его подробнее.
В первой строке указаны атрибуты интерфейса:
Данный интерфейс принадлежит объекту (слово object);
IID интерфейса равен 85C5B433-C053-435f-9E4A-8C48557E1D4B.
Во второй строке говорится, что интерфейс называется IWarpEngine. В языке C++ можно указывать наследование; то же позволяет и IDL – можно сообщить, что один интерфейс наследует другому. Следующий пример типичен для описания любого интерфейса, совместимого с автоматизацией, который должен наследовать интерфейсу IDispatch.
Как и в случае определения класса, внутри объявления интерфейса пере- числяются методы. В фигурных скобках указаны названия всех методов и свойств, поддерживаемых данным интерфейсом.
Семантика функции Engage в примере выше очевидна из ее описания: она возвращает значение типа HRESULT и принимает в качестве параметра VARIANT_BOOL. Относительно ее использования не возникает никаких сомнений, в этом и состоит смысл IDL.
Свойства COM-класса описываются на IDL следующим образом:
|
|
|
|
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 |
|
|
|
|
|
|
Библиотека ATL 663 |
|
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 |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
те что-то необычное. Как правило, достаточно задать лишь имя IDL-файла:
midl.exe SpaceShip.idl
В результате успешной компиляции в том же каталоге появляются несколько новых файлов, перечисленных в таблице 13.2.
Таблица 13.2. Список файлов, сгенерированных компилятором MIDL
Имя файла |
Назначение |
Spaceship.h |
Этот файл следует включить в ATL проект, так как он |
|
содержит определения всех абстрактных классов |
|
в синтаксисе C++, которые предстоит реализовать |
|
в вашем коклассе. Помимо этого, здесь же находятся |
|
ссылки на CLSID, IID и LIBID, сгенерированные MIDL. Если |
|
хотите назвать файл иначе, воспользуйтесь флагом /h |
Spaceship_i.c |
Этот файл содержит реальные значения тех GUID, на |
|
которые ссылается файл SpaceShip.h. Если хотите |
|
назвать файл иначе, воспользуйтесь флагом /iid |
Spaceship.tlb |
Этот файл содержит откомпилированную библиотеку |
|
типов. При желании можно восстановить исходный IDL |
|
файл из tlb файла. Этот файл можно распространять |
|
независимо от модуля или включить его в состав |
|
ресурсов. Обычно ему назначается первый порядковый |
|
номер в разделе ресурсов |
Dlldata.c |
Этот файл содержит информацию о точках входа для |
|
заглушки и заместителя, которые необходимы при |
|
удаленном вызове интерфейсов |
Spaceship_p.c |
Этот файл содержит код заглушки и заместителя для |
|
вызова методов интерфейса объекта, находящегося |
|
в отдельном процессе, например, в EXE файле |
Регистрация класса
Как вы уже знаете, любой COM-объект должен быть предварительно зарегистрирован. Если объект реализован в виде DLL, то регистрация выполняется, когда клиент обращается к точке входа DllRegisterServer. Если же объект представлен в виде EXE-файла, то для регистрации нужно запустить этот файл с флагом /regserver. Сама же процедура регистрации мало отличается.
Регистрация компонентов, созданных без применения ATL, – это муторное занятие, сводящееся к многократным вызовам функций для работы с реестром. Напротив, ATL существенно упрощает дело, позволяя ассоциировать с каждым коклассом так называемый сценарий реестра. Формат таких сценариев был изобретен задолго до появления ATL.
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
||
|
|
|
C |
|
E |
|
|
|
|
|
|
|
C |
|
E |
|
|
|
||||||
|
|
X |
|
|
|
|
|
|
|
|
|
X |
|
|
|
|
|
|
||||||
|
- |
|
|
|
|
|
d |
|
|
|
- |
|
|
|
|
|
d |
|
||||||
|
F |
|
|
|
|
|
|
|
i |
|
|
|
F |
|
|
|
|
|
|
|
i |
|
||
|
|
|
|
|
|
|
|
t |
|
|
|
|
|
|
|
|
|
|
t |
|
||||
P |
D |
|
|
|
|
|
|
|
|
o |
|
P |
D |
|
|
|
|
|
|
|
|
o |
||
|
|
|
|
NOW! |
r |
|
|
|
|
|
NOW! |
r |
||||||||||||
|
|
|
|
|
BUY |
|
|
|
|
|
|
|
|
BUY |
|
|
||||||||
|
|
|
|
to |
|
|
666 Глава 13. Написание компонентов для задач, связанных с безопасностью |
|
|
|
|
to |
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
w |
|
|
|
|
|
|
|
|
|
m |
|
w |
|
|
|
|
|
|
|
|
|
m |
||
w Click |
|
|
|
|
|
|
o |
|
w Click |
|
|
|
|
|
|
o |
||||||||
|
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
||
|
. |
|
|
|
|
|
|
.c |
|
|
|
. |
|
|
|
|
|
|
.c |
|
||||
|
|
p |
df |
|
|
|
|
e |
|
|
|
|
p |
df |
|
|
|
|
e |
|
||||
|
|
|
|
|
g |
|
|
|
|
|
|
|
|
|
g |
|
|
|
||||||
|
|
|
|
|
n |
|
|
|
|
|
|
|
|
|
|
n |
|
|
|
|
||||
|
|
|
|
-xcha |
|
|
|
|
|
Затем нажмите кнопку Import, найдите среди файлов проекта сценарий-x cha |
|
|
|
|
|
реестра и нажмите OK. Visual Studio попросит указать тип импортируемого ресурса. Принято обозначать RGS-сценарии строкой REGISTRY, поэтому введите эту строку и нажмите OK. Осталось лишь переименовать ресурс так, чтобы он ассоциировался с вашим коклассом. После всего этого сценарий реестра окажется в одном файле с компонентом и найти его можно будет по имени, которое, кстати, указано и в сгенерированном файле resource.h.
Покончив с шагом 1, можно перейти к шагу 2, на котором мы ассоциируем сценарий реестра с коклассом. Для этого предназначен макрос DECLARE_REGISTRY_RESOURCE_ID, которому передается идентификатор ресурса.
Макрос DECLARE_REGISTRY_RESOURCE_ID расширяется в вызов следующей статической функции:
#define DECLARE_REGISTRY_RESOURCE_ID(x) \
static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\ { }; // Код опущен
Функция UpdateRegistry строит массив пар имя/значения, который регистратор ATL использует для расширения таких макросов препроцессора, как %MODULE%. Если у вас возникнет желание передать нестандартное значе- ние, то надо будет лишь переписать функцию UpdateRegistry с учетом своих требований. Основное назначение этой функции – передать информацию об именах, а также идентификатор ресурса сценария глобальной функции UpdateRegistryFromResource, которая и выполняет основную часть работы по регистрации класса.
Реализация внутрипроцессного COM-сервера
При разработке COM-сервера у вас есть выбор: написать весь код вручную, воспользоваться встроенными в Visual Studio мастерами или применить смешанный подход. Общее правило – поступать так, как диктует конкретный проект. Если вы делаете что-то необычное, то желательно получить больший контроль над проектом, и тогда лучше писать вручную. Но на каком бы решении вы ни остановились, надо понимать, что требуется от модуля и как этого добиться.
Глобальная переменная _AtlModule
В любом приложении, которое пишется с применением библиотеки ATL, вне зависимости от типа сервера, должна быть определена глобальная переменная с именем _AtlModule. Меняется от проекта к проекту ее òèï, который зависит от выбранного вида проекта. Например, при реализации сервера в виде DLL эта переменная должна иметь тип CAtlDllModuleT, а для сервера в виде EXE-
|
|
|
|
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 |
|
|
|
|
|
|
Библиотека ATL 667 |
|
to |
|
|
|
|
|
|
||||
w Click |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
m |
w Click |
|
|
|
|
|
|
|
m |
|||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
||
|
w |
|
|
|
|
|
|
|
|
o |
|
|
w |
|
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
g |
.c |
|
|
. |
|
|
|
|
g |
.c |
|
||||||
|
|
p |
|
|
|
|
|
|
|
|
|
p |
|
-x cha |
|
|
|
||||||
|
|
|
|
-xchфайлаa |
– òèï CAtlExeModuleT. Именно тип переменной _AtlModule и включает |
|
|
e |
|
||||||||||||||
|
|
|
df |
|
|
n |
e |
|
|
|
|
df |
|
|
n |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
в приложение нужную функциональность.
Объявить один лишь класс модуля при работе с ATL нельзя; он должен быть производным от создаваемого вами класса. Это позволяет включить в модуль некоторые константные свойства, не вызывая никаких функций инициализации. Приведем пример:
class CMyApplicationModule :
public CAtlDllModuleT< CMyApplicationModule >
{
public: DECLARE_LIBID(LIBID_MyApplicationModule)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_MYAPPLICATIONMODULE, "{4DD88301-0C57-416B-953C-3829095440C05}")
}
CMyApplicationModule _AtlModule;
Предыдущий фрагмент содержит скелет объявления и определения любого внутрипроцессного COM-сервера. Класс CMyApplicationModule наследует входящему в ATL шаблонному классу CAtlDllModuleT, который предоставляет всю свойственную DLL функциональность и принимает в качестве параметраимя класса CMyApplicationModule.
Следующие две строки сообщают классу CMyApplicationModule константную информацию, а именно: GUID библиотеки типов (LIBID), хранящийся в переменной LIBID_MyApplicationModule, и идентификатор ресурса, в котором находится сценарий реестра. Кроме того, макрос DECLARE_REGISTRY_APPID_RESOURCEID, как следует из его названия, передает классу модуля идентификатор приложения APPID, который будет нужен во время регистрации.
Функции, экспортируемые из DLL
Выше мы уже говорили, что COM-объекты, реализованные в виде DLL, должны экспортировать четыре функции, чтобы среда исполнения могла их корректно загрузить. Функции называются DllGetClassObject, DllCanUnloadNow, DllRegisterServer и DllUnregisterServer. Поддержка, предоставляемая ATL, позволяет переместить весь связанный с ними стандартный код в библиотеку. Чтобы понять, как это делается, рассмотрим следующий код, сгенерированный мастером:
STDAPI DllGetClassObject(
REFCLSID rclsid,
REFIID riid,