книги хакеры / Защита_от_взлома_сокеты,_эксплойты,_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 671 |
|
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 |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ка COM-сервера – это не простая задача. Тут-то и приходит на помощь новая возможность, появившаяся в Visual C++.NET, – атрибуты C++.
Назначение атрибута C++ – автоматически вставить в ваш исходный текст некоторый код, решающий конкретную задачу. Атрибуты C++ реализуются провайдерами атрибутов, и таким провайдером в случае ATL служит библиотека atlprov.dll.
Применение атрибутов ATL намного сокращает объем кода, который надо написать для получения компонента. В частности, вам уже не нужно возиться со сценариями реестра и определением интерфейса на языке IDL. Кроме того, провайдер атрибутов включает поддержку для написания ATL-сервера, клиента OLE DB, программирования показателей производительности и Web-сервисов.
Кодирование с использованием атрибутов ATL очень напоминает составление описания на языке IDL. На самом деле, многие атрибуты имеют такой же синтаксис, как в IDL. Подобно IDL, атрибуты объявляются в квадратных скобках и предшествуют некоторым конструкциям (объявлению класса, структуры, интерфейса, функции и так далее).
Чтобы начать пользоваться атрибутами ATL в своей программе, необходимо определить константу _ATL_ATTRIBUTES перед заголовочным файлом atlbase.h. В результате файл atlbase.h включает дополнительный файл atlplus.h, который и содержит необходимые для работы с атрибутами объявления.
Рассмотрим типичный пример программы, которая реализует полнофункциональный COM-сервер в виде DLL, предоставляющий клиентам один COM-объект.
1 #include <windows.h>
2
3 #define _ATL_ATTRIBUTES
4 #define _ATL_APARTMENT_THREADED
5
6 #include <atlbase.h>
7 #include <atlcom.h>
8
9 [module(type=dll, name="HotFixChecker")];
10
11[object, uuid("EAA203CA-24D4-4C49-9A76-1327068987D8")]
12__interface IHotFixChecker
13{
14HRESULT IsHotFixInstalled([in] BSTR bstrQNumber,
15[out, retval] VARIANT_BOOL *pbInstalled);
16};
17
18[coclass
19uuid("FC9CBC60-4648-4E66-9409-610AD30689C7"),
|
|
|
|
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 673 |
|
to |
|
|
|
|
|
|
||||
w Click |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
m |
w Click |
|
|
|
|
|
|
|
m |
|||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
||
|
w |
|
|
|
|
|
|
|
|
o |
|
|
w |
|
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
g |
.c |
|
|
. |
|
|
|
|
g |
.c |
|
||||||
|
|
p |
|
-xcha |
Как видите, атрибут важный и делающий очень много. |
|
|
p |
|
-x cha |
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
e |
|
|||||||||||
|
|
|
df |
|
|
n |
e |
|
|
|
|
df |
|
|
n |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Если вы хотите переопределить часть поведения, реализуемого этим атрибутом, НЕ ставьте в конце точку с запятой, а объявите вслед за атрибутом класс модуля. Например, так:
[module(type=dll, name="HotFixChecker")] class CHFChecker
{
public:
int DllMain(DWORD dwReason, PVOID p)
{
return __super::DllMain(dwReason, p);
}
int RegisterServer(BOOL bRegTypeLib)
{
return __super::RegisterServer(bRegTypeLib);
}
};
Ключевое слово __super языка C++ просит компилятор автоматически найти базовый класс.
Ниже приведен список допустимых параметров атрибута module:
[module(type=dll,
name=string,
uuid=uuid,
version=1.0,
lcid=integer,
control=boolean,
helpstring=string,
helpstringdll=string,
helpfile=string,
helpcontext=integer,
hidden=boolean,
restricted=boolean,
custom=string, resource_name=string
) ];
Атрибут interface
Идем дальше. Если вы когда-нибудь писали определения интерфейсов на языке IDL, то без сомнения узнали следующий атрибут:
[object, uuid("EAA203CA-24D4-4C49-9A76-1327068987D8")] __interface IHotFixChecker
{
HRESULT IsHotFixInstalled([in] BSTR bstrQNumber, [out, retval] VARIANT_BOOL *pbInstalled);
};
|
|
|
|
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 |
|
|
674 Глава 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 |
|
|
|
|
|
Атрибут object идентичен одноименному атрибуту в IDL, поэтому много-x cha |
|
|
|
|
|
говорить о нем нет смысла. Он информирует компилятор о том, что далее следует определение интерфейса объекта, а в квадратных скобках заданы параметры. В данном случае указан лишь IID интерфейса.
Ключевое слово __interface очень полезно для объявления интерфейсов, которые должны удовлетворять некоторым требованиям, например, предъявляемым COM. Употребление этого слова налагает на члены интерфейса следующие ограничения:
разрешено наследовать произвольному числу базовых интерфейсов;
запрещено наследовать базовому классу;
запрещено включать конструкторы и деструкторы;
разрешены только открытые, чисто виртуальные методы;
запрещено наличие данных-членов;
запрещено включать статические методы.
Таким образом, это ключевое слово может оказаться полезным не только для реализации COM-объектов.
COM-интерфейсы описаны внутри блока, вводимого словом __interface. Как и в случае IDL, определение интерфейса должно быть однозначным, все параметры следует помечать атрибутом [in] или [out].
Атрибут coclass
[coclass uuid("FC9CBC60-4648-4E66-9409-610AD30689C7"), vi_progid("HotFixChecker")
]
Этот синтаксис очень напоминает применяемый в IDL, но есть несколько расширений. Атрибут coclass применяется к объявлению класса, в котором будет реализована функциональность компонента. Поэтому нужно лишь описать характеристики класса компонента в предшествующем ему атрибуте. В данном случае мы задаем CLSID и ProgID компонента. Вот некоторые особенности работы этого атрибута:
вставляет блок coclass в библиотеку типов;
вставляет код для регистрации CLSID и ProgID компонента.
Еще один важный параметр, который можно задать в атрибуте coclass, – это потоковая модель компонента. В зависимости от нее вставляется код, выводящий ваш класс из подходящей конкретизации CComObjectRootEx. Параметр может задаваться так: threading=apartment èëè threading=free.
Объявление класса, следующего за этим атрибутом – как раз то место, куда провайдер атрибутов и помещает большую часть кода. Так, в рассматри-
|
|
|
|
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 |
|
|
|
|
|
|
Добавление СОМ расширений в программу RPCDUMP 675 |
|
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 |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
базовые классы:
public CComCoClass<CHotFixChecker, &__uuidof(CHotFixChecker)>, public CComObjectRootEx<CComSingleThreadModel>,
public IProvideClassInfoImpl<&__uuidof(CHotFixChecker)>
Как вы знаете, CComCoClass наделяет компонент способностью создавать фабрику класса. CComObjectRootEx реализует подсчет ссылок в зависимости от заданной потоковой модели. IProvideClassInfoImpl реализует интерфейс, позволяющий клиентам получать указатель на интерфейс ITypeInfo.
Следующий важный кусок, автоматически вставляемый в код компонента, – это карта COM:
BEGIN_COM_MAP(CHotFixChecker)
COM_INTERFACE_ENTRY(IHotFixChecker),
COM_INTERFACE_ENTRY(IProvideClassInfo)
END_COM_MAP()
Поскольку атрибуты наделены «интеллектом», ATL знает, что наш класс предоставляет только один интерфейс IHotFixChecker и, естественно, он включен в карту.
Компиляция COM-сервера
После компиляции кода, сгенерированного с помощью атрибутов, мы полу- чим DLL, содержащую библиотеку классов и обладающую способностью к авторегистрации, то есть по существу вполне работоспособный COM-сервер.
Добавление COM расширений в программу RPCDUMP
Утилита RPCDump распечатывает содержимое карты оконечных точек RPC на удаленном компьютере. Это полезно для разных целей, в том числе для поиска потенциально небезопасных RPC-интерфейсов. В частности, этот инструмент можно применять для защиты ПК от сетевых вторжений. Но прежде чем останавливать сетевые службы на ПК, нужно знать, что именно данный компьютер предоставляет. Специалисты по сетевой безопасности часто используют программу отображения портов (port mapper) для выявления открытых TCP и UDP-портов. Описываемая утилита эквивалентна сканеру портов в плане определения служб RPC, предоставляемых конкретной машиной.
|
|
|
|
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 |
|
|
|
676 Глава 13. Написание компонентов для задач, связанных с безопасностью |
|
|
|
|
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 |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
проверить, все ли RPC-интерфейсы удовлетворяют принятой политике. Типы RPC-привязок ncacn_np и ncacn_ip_tcp определяют удаленно дос-
тупные оконечные точки RPC, аналогичные сокетам. Если распечатать карту оконечных точек RPC, то результат может выглядеть примерно так:
nacan_ip_tcp:127.0.0.1[1025] ncacn_np:\\\\MYCOMPUTER[\\PIPE\atsvc] ncacn_np:\\\\MYCOMPUTER[\\pipe\Ctx_WinStation_API_service] ncacn_np:\\\\MYCOMPUTER[\\PIPE\DAV RPC SERVICE] ncacn_np:\\\\MYCOMPUTER[\\PIPE\winreg]
Из этой распечатки видно, что порт 1025 соответствует оконечной точке RPC, равно как и именованные каналы Ctx_WinStation_API_service, DAV RPC SERVICE и winreg. И все они доступны для дистанционного манипулирования. Имея это в виду, можете закрыть столько служб, доступных через RPC, сколько необходимо для доведения безопасности ПК до желаемого уровня.
Типичная относящаяся к безопасности утилита на платформе Win32, представляет собой консольное приложение, которому большая часть, если не все, аргументы передаются в командной строке. Результаты своей работы такая программа выводит на стандартный вывод. Памятуя об этом, мы покажем, как добавить COM-расширение к существующей утилите RPCDump, которую написал Тодд Сабин (Todd Sabin). В этом примере мы будем пользоваться ATL-атрибутами, имеющимися в языке Visual C++.NET.
Но сначала сформулируем критерии успешности нашей попытки интеграции с существующим COM-приложением:
сохранить семантику командной строки;
минимизировать изменения в исходном тексте утилиты.
Основные шаги, необходимые для добавления COM-расширения в утилиты типа RPCDump, таковы:
добавить возможность работы в качестве внепроцессного COM-серве- ра путем применения ATL-атрибутов;
перехватить управление точками входа;
определить интерфейсы COM-объектов;
реализовать COM-объекты, предоставляемые утилитой;
добавить процедуры интеграции с утилитой.
Программа RPCDump состоит из единственного файла RPCdump.c. После добавления COM-расширений файлов станет три: RPCdump.c, COMSupport.cpp и COMSupport.h. Для добавления COM-расширений в исходную программу надо будет добавить или изменить в ней всего семь строк кода.
|
|
|
|
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 |
|
|
|
|
|
|
Добавление СОМ расширений в программу RPCDUMP 679 |
|
to |
|
|
|
|
|
|
||||
w Click |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
m |
w Click |
|
|
|
|
|
|
|
m |
|||||||
w |
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
||
|
w |
|
|
|
|
|
|
|
|
o |
|
|
w |
|
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
g |
.c |
|
|
. |
|
|
|
|
g |
.c |
|
||||||
|
|
p |
|
|
|
|
|
|
|
|
|
p |
|
-x cha |
|
|
|
||||||
|
|
|
|
-xchêîéa |
ATL в нужный момент: WinMain и RegisterServer. Если бы мы не стали их |
|
|
e |
|
||||||||||||||
|
|
|
df |
|
|
n |
e |
|
|
|
|
df |
|
|
n |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
переопределять, то сохранилось бы поведение по умолчанию.
Функция WinMain (строка 18) решает две важных задачи. Во-первых, если приложение загружено как автономная программа, то вызывается исходная точка входа rpcdump_main (строки 20–27). В этом случае функция IsComRequest (вызываемая из WinMain в строке 20) возвращает FALSE, и тогда после вызова rpcdump_main приложение завершается (строка 26).
Обратите внимание на пару макросов BEGIN_ENTRYPOINT() и END_ENTRYPOINT() перед вызовом rpcdump_main. Они расширяются следующим образом:
#define BEGIN_ENTRYPOINT() __try { #define END_ENTRYPOINT() } \ __except(EXCEPTION_EXECUTE_HANDLER) {}
Это означает, что мы перехватываем все исключения, так что управление обязательно вернется в WinMain. Бывают случаи, когда функция rpcdump_main намеренно возбуждает исключение. Мы еще вернемся к этому при рассмотрении файла COMSupport.h.
Если же утилита загружена в результате запроса от COM, то она не должна как-то взаимодействовать с пользователем. Поэтому необходимо закрыть предоставляемое системой по умолчанию окно консоли, вызвав функцию FreeConsole в строке 31.
Примечание
Подавить неявную загрузку окна консоли можно, объявив, что при ложение будет пользоваться графической подсистемой, а затем в случае необходимости открыть консоль путем обращения к функ ции AllocConsole. Но такой подход вступает в противоречие с поряд ком использования оригинальной утилиты и, стало быть, не удовлет воряет нашим требованиям.
В строке 38 мы получаем индекс в локальную память потока (Thread Local Storage – TLS), а в строке 40 освобождаем его. TLS – это механизм, позволяющий сохранить значения типа DWORD, связанные с данным потоком и только с ним. Для получения памяти, в которой их можно сохранить, нужно вызвать функцию TlsAlloc. В нашем случае локальная память нужна для хранения указателя на структуру TOOL_CALL_CONTEXT. Ее назначение мы объясним ниже при рассмотрении процедур интеграции с приложением и кокласса CRPCDump.
|
|
|
|
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 |
|
|
680 Глава 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 |
|
|
|
|
|
Функция IsComRequest (строка 5) определяет, было ли приложение вызва--x cha |
|
|
|
|
|
но средой исполнения COM, анализируя наличие флага -COMSERVER в командной строке. Почему такой метод работает, объяснено ниже в разделе «Поток управления».
Метод RegisterServer (строка 46) вызывается инфраструктурой ATL, если приложение должно зарегистрировать себя в качестве COM-сервера, то есть в командной строке есть флаг /RegServer.
Поскольку в данном проекте для регистрации класса компонента применяются средства ATL, а один аспект регистрации нужно реализовать нестандартно, нам приходится переопределить этот метод. Нестандартность заключается в добавлении строки «-COMSERVER» к значению по умолчанию для ключа LocalServer32. Стандартно это значение содержит путь к файлу EXE-сервера и используется средой исполнения COM для запуска сервера при поступлении запроса от клиента. Таким образом, когда клиент запрашивает наш COMобъект, сервер будет загружен, а в его командной строке будет присутствовать флаг «-COMSERVER».
Поток управления
Следующий шаг – интегрировать в RPCDump поток управления из файла COMSupport.cpp.
Как вы помните, ATL-атрибут module определяет в качестве точки входа в EXE-сервер функцию _tWinMain (см. рис. 13.4). Но она не вызывается при входе, потому что в параметрах проекта сказано, что это консольное приложение, значит, должна быть вызвана функция с именем main. Раз ATL не предоставляет такой функции, нам придется реализовать ее самостоятельно, как показано в примере 13.2.
Пример 13.2. Перехват потока управления в точке входа
1 int main(int argc, char *argv[])
2 {
3// Сохранить аргументы
4g_argc = argc;
5 g_argv = argv;
6
7 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
8
9STARTUPINFO si = {0};
10GetStartupInfo(&si);
11LPTSTR lpCmdLine = GetCommandLine();
13 // функция _tWinMain вставлена ATL-атрибутом module
14 // В конечном итоге управление попадет в CConsoleApp::WinMain