Мониторинг обменных курсов валют
18c0693f

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


Должен честно сказать, что почти не поддерживал функций подключения, экспортируемых по порядковому значению, потому что подобная попытка весьма чревата ошибками (из-за того, что разные версии MFC DLL используют различные порядковые значения). Однако если абстрагироваться от проблем, связанных с версиями, то процесс подключения по порядковому значению почти идентичен подключению по имени. Сравните функцию HookordinaiExport, показанную в листинге 14-4, с функцией HookimportedFunctionsByName, рассмотренной в главе 12, и вы увидите, что обе функции выполняют много одинаковых действий.

Листинг 14-4. Функция HookordinaiExport 

BOOL BUGSUTILJ3LLINTERFACE _stdcall

HookordinaiExport ( HMODULE hModule , 

LPCTSTR szImportMod, 

DWORD dwOrdinal ,

 PROC pHookFunc , 

PROC * ppOrigAddr )

{

// Проверить параметры с помощью утверждений.

 ASSERT ( NULL != hModule);

ASSERT ( FALSE == IsBadStringPtr ( szImportMod, MAX_PATH)); 

ASSERT ( 0 != dwOrdinal);

ASSERT ( FALSE = IsBadCodePtr ( pHookFunc));

 // Выполнить проверку ошибок для параметров.

if ( ( NULL == hModule ' ) | |

 ( TRUE == IsBadStringPtr ( szImportMod, MAX_PATH)) || 

( 0 == dwOrdinal ) I I ( TRUE == IsBadCodePtr ( pHookFunc) ) )

 {

SetLastErrorEx ( ERROR_INVALID_PARAMETER, SLE_ERROR);

 return ( FALSE); 

}

if ( NULL != ppOrigAddr)

{

ASSERT ( FALSE ==

IsBadWritePtr ( ppOrigAddr, sizeof ( PROG))); 

if ( TRUE == IsBadWritePtr ( ppOrigAddr, sizeof ( PROC)))

 {

SetLastErrorEx ( ERROR_INVALID_PARAMETER, SLE_ERROR);

 return ( FALSE);

 }

 }

// Получить конкретный дескриптор импорта.

 PIMAGE_IMPORT_DESCRIPTOR plmportDesc =

GetNamedlmportDescriptor ( hModule, szImportMod);

 if ( NULL == plmportDesc) 

{

// Запрошенный модуль не был импортирован. Не возвращать ошибку,

 return ( TRUE); 

}

// Получить информацию об исходных переходниках для этого DLL

. // Невозможно использовать информацию переходников, хранящуюся в


 // pImportDesc->FirstThunk, т. к. загрузчик уже изменил этот массив 

// при установке всех импортов. Исходный переходник обеспечивает

 // доступ к именам функций.

 PIMAGE_THUNK_DATA pOrigThunk =

MakePtr ( PIMAGE_THUNK_DATA

hModule , 

pImportDesc->OriginalFirstThunk );

// Получить массив p!mportDesc->FirstThunk, в котором будут

 // выполняться подключения и вся черная работа.

PIMAGE_THUNK_DATA pRealThunk = MakePtr ( PIMAGE_THUNK_DATA ,

hModule , 

pImportDesc->FirstThunk );

// Флажок будет устанавливаться из переходника,

// что облегчает его поиск.

DWORD dwCompareOrdinal = IMAGE JDRDINAL_FLAG | dwOrdinal;

// Цикл поиска подключаемых функций.

while ( NULL != pOrigThunk->ul.Function)

{

// Отыскивать только функции, которые импортируются по

 // порядковому значению, а не по имени, 

if ( IMAGE__ORDINAL_FLAG ==

( pOrigThunk->ul.Ordinal & IMAGE_ORDINAL_FLAG))

 {

// Найдена ли функция подключения? 

if ( dwCompareOrdinal == pOrigThunk->ul.Ordinal) . 

{

// Функция для подключения найдена. Теперь нужно

 // изменить защиту памяти на "read-write" (для записи),

 // прежде чем перезаписывать указатели функций. Заметьте,

 // что ничего не записывается в реальную область 

// переходников!

MEMORY_BASIC__IN FORMATION mbi_thunk ; 

VirtualQuery ( pRealThunk , 

 &mbi_thunk , 

sizeof ( MEMORY_BASIC_INFORMATION) ); 

if ( FALSE == VirtualProtect ( mbi_thunk.BaseAddress,

rabi_thunk.RegionSize ,

 PAGE_READWRITE ,

&mbi_thunk.Protect ))

 {

ASSERT ( !"VirtualProtect failed!");

 // Здесь приходится фиксировать неуспешное 

// выполнение функции (возвращая FALSE),

 // предварительно указав причину ошибки.

 SetLastErrorEx ( ERROR__INVALID_PARAMETER,

SLE^ERROR );

return ( FALSE); 

}

// Сохранить исходные адреса, если требуется

 if ( NULL != ppOrigAddr)



 {

*ppOrigAddr = (PROC)pRealThunk->ul.Function; 

}

// Microsoft имеет два различных определения 

// РIМАСЕ_ТШ№С_ОАТА-полей для будущей поддержки Win64

 // Будет использован самый последний набор заголовков

//из W2K RC2 Platform SDK, с которыми будут иметь дело

 // заголовки из Visual C++ 6 Service Pack 3.

// Подключить функцию (DWORD*)SpRealThunk->ul.Function; 

*pTemp = (DWORD)(pHookFunc); 

DWORD dwOldProtect;

// Изменить защиту обратно к тому состоянию, которое

 // предшествовало переписыванию указателя функции.

 VERIFY ( VirtualProtect ( mbi_thunk.BaseAddress,

mbi_thunk.RegionSize ,

 mbi_thunk.Protect , 

sdwOldProtect )); 

// Жизнь прекрасна! 

SetLastError ( ERROR_SUCCESS);

 return ( TRUE);

 } 

}

// Инкремент обеих таблиц. pOrigThunk++; pRealThunk++;

 }

// Ничего не было подключено. Технически это не ошибка. Это просто

 // означает, что модуль импортирован, а функция — нет.

 SetLastError ( ERROR_SDCCESS);

 return ( FALSE); 

}

Для реализации обработки AfxTrace без ее подключения, пришлось бы просматривать стек при каждом вызове, чтобы вернуться к реальному вызову функции OutputDebugstring. Дополнительная работа на каждом вызове была бы медленнее, по сравнению с прямым подключением AfxTrace. Кроме того, если бы я игнорировал AfxTrace, то утилита LIMODS была бы, в основном, бесполезна для MFC-программистов. И, наконец, я предпочел создавать утилиту LIMODS настолько полной, насколько это возможно, причем я был вынужден дважды проверять версии MFC DLL.






Самый выгодный курс обмена валюты