Чтение онлайн

на главную - закладки

Жанры

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

HRESULT ApiHijackExports(HMODULE hModule, LPSTR szEntry, LPVOID pHijacker, LPVOID *ppOrig) {

 // Check args

 if ((!IS_INTRESOURCE(szEntry) && ::IsBadStringPtrA(szEntry, -1)) || ::IsBadCodePtr(FARPROC(pHijacker))) {

return E_INVALIDARG;

 }

 PIMAGE_DOS_HEADER pDosHeader = PIMAGE_DOS_HEADER(hModule);

 if (::IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER)) || IMAGE_DOS_SIGNATURE != pDosHeader->e_magic) {

return E_INVALIDARG;

 }

 PIMAGE_NT_HEADERS pNTHeaders =

MakePtr(PIMAGE_NT_HEADERS, hModule, pDosHeader->e_lfanew);

 if (::IsBadReadPtr(pNTHeaders, sizeof(IMAGE_NT_HEADERS)) || IMAGE_NT_SIGNATURE != pNTHeaders->Signature) {

return E_INVALIDARG;

 }

 HRESULT hr = E_UNEXPECTED;

 IMAGE_DATA_DIRECTORY& expDir =

pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];

 PIMAGE_EXPORT_DIRECTORY pExpDir =

MakePtr(PIMAGE_EXPORT_DIRECTORY, hModule, expDir.VirtualAddress);

 LPDWORD pdwAddrs = MakePtr(LPDWORD, hModule, pExpDir->AddressOfFunctions);

 LPWORD pdwOrd = MakePtr(LPWORD, hModule, pExpDir->AddressOfNameOrdinals);

 DWORD dwAddrIndex = -1;

 if (IS_INTRESOURCE(szEntry)) {

// By ordinal

dwAddrIndex = WORD(szEntry) - pExpDir->Base;

hr = S_OK;

 } else {

// By name

LPDWORD pdwNames = MakePtr(LPDWORD, hModule, pExpDir->AddressOfNames);

for (DWORD iName = 0; iName < pExpDir->NumberOfNames; iName++) {

if (0 == ::lstrcmpiA(MakePtr(LPSTR, hModule, pdwNames[iName]), szEntry)) {

dwAddrIndex = pdwOrd[iName];

hr = S_OK;

break;

}

}

 }

 if (SUCCEEDED(hr)) {

if (pdwAddrs[dwAddrIndex] >= expDir.VirtualAddress && pdwAddrs[dwAddrIndex] < expDir.VirtualAddress + expDir.Size) {

// We have a redirection

LPSTR azRedir = MakePtr(LPSTR, hModule, pdwAddrs[dwAddrIndex]);

ATLASSERT(!IsBadStringPtrA(azRedir, -1));

LPSTR azDot = strchr(azRedir, '.');

int nLen = azDot - azRedir;

LPSTR azModule = (LPSTR)alloca(nLen);

memcpy(azModule, azRedir, nLen);

azModule[nLen] = '\x0';

// Try to patch redirected function

return ApiHijackExports(

::GetModuleHandle(azModule), azDot + 1, pHijacker, ppOrig);

}

if (ppOrig)

*ppOrig = MakePtr(LPVOID, hModule, pdwAddrs[dwAddrIndex]);

DWORD dwOffset = DWORD_PTR(pHijacker) - DWORD_PTR(hModule);

// write to write-protected memory

hr = WriteProtectedMemory(pdwAddrs + dwAddrIndex, &dwOffset, sizeof(LPVOID));

 }

 return hr;

}

Имейте

в виду, под Windows9x нельзя честно подменить экспорты для разделяемых библиотек, таких как user32.dll, kernel32.dll и gdi32.dll. Это связано с тем, что область памяти начиная с адреса 7FC00000h и выше совместно используестя всеми процессами в системе, и модификация сказалась бы на каждом из них. А это нежелательно, поскольку память, занимаемая нашей функцией-перехватчиком, наоборот, принадлежит только нашему процессу. Во всех остальных процессах в системе ::GetProcAddress, после подмены таблицы экспорта, вернула бы неправильный указатель. Тем не менее, если нельзя, но очень хочется, то можно. Для этого нам придется вручную создать новый дескриптор в GDT (вот тут-то у Windows9x проблем не возникает) и используя этот дескриптор произвести необходимые изменения. Но будьте готовы к тому, что понадобится написать свою разделяемую библиотеку, установить ее в системе и проверять ID процесса при каждом обращении. Рабочий пример есть на internals.com.

Модификация самого обработчика

Эти два способа работают в 99% случаев. Последний процент – это подмена функции, вызываемой внутри чужого модуля, т.е. когда и вызаваемая и вызывающая процедура находятся в одном и том же, да к тому же чужом, модуле. В этом случае, вызов будет сделан напрямик, а не через таблицы импорта/экспорта. Тут уже ничего сделать нельзя. Почти. Можно изменить саму функцию-обработчик, с тем чтобы перенаправить вызовы в нашу собственную. Делается это довольно просто: в начало исходного обработчика прописывается команда безусловного перехода на нашу процедуру, а если нужно вызвать оригинал, то нужно просто сохранить первые 5 байт затертых командой перехода, добавить после них опять-таки команду безусловного перехода на изначальный код +5 байт. Разумется, эти пять байт кода не дожны содержать команд перехода или вызова. Кроме того, может понадобиться больше чем 5 байт, ведь команда перехода посреди длинной инструкции работать не будет. Это случается крайне редко. Обычно код функции, как его генерит компилятор для I86 выглядит примерно так: инициализация стека, загрузка в регистры параметров функции, их проверка и переход в случае неудовлетворительных результатов. Этого вполне хватает чтобы вставить наш маленький перехватчик. Но бывает и так:

CSomeClass::Release:

FF152410E475 call dword ptr [InterlockedDecrement]

85C0 test eax,eax

Или даже

CSomeClass::NonImplemented:

C20400 ret 4

Что, впрочем, можно распознать и вернуть код ошибки если инструкции ret, jmp или call встретится слишком рано. Но вот такой случай распознать не получится:

SomeFunction:

33C0 xor eax,eax

SomeFunction2:

55 push ebp

8BEC mov ebp,esp

Иными словами, модификация SomeFunction приведет к неизвестным изменениям в SomeFunction2, и, возможно, краху всей системы.

Все это сильно усложняет нам задачу. Нужно дизассемблировать эти байты и проверить каждую инструкцию. Чтобы немного облегчить нам жизнь, фирма Майкрософт разработала специальный SDK для такого рода трюков: Microsoft Detours. С этим SDK задача подмены чужой функции реализуется удивительно просто:

Поделиться:
Популярные книги

Белые погоны

Лисина Александра
3. Гибрид
Фантастика:
фэнтези
попаданцы
технофэнтези
аниме
5.00
рейтинг книги
Белые погоны

Черный дембель. Часть 1

Федин Андрей Анатольевич
1. Черный дембель
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Черный дембель. Часть 1

Лишняя дочь

Nata Zzika
Любовные романы:
любовно-фантастические романы
8.22
рейтинг книги
Лишняя дочь

Темный Лекарь 5

Токсик Саша
5. Темный Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Темный Лекарь 5

Последний из рода Демидовых

Ветров Борис
Фантастика:
детективная фантастика
попаданцы
аниме
5.00
рейтинг книги
Последний из рода Демидовых

Чиновникъ Особых поручений

Кулаков Алексей Иванович
6. Александр Агренев
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Чиновникъ Особых поручений

Попаданка в академии драконов 4

Свадьбина Любовь
4. Попаданка в академии драконов
Любовные романы:
любовно-фантастические романы
7.47
рейтинг книги
Попаданка в академии драконов 4

Боги, пиво и дурак. Том 6

Горина Юлия Николаевна
6. Боги, пиво и дурак
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Боги, пиво и дурак. Том 6

Курсант: Назад в СССР 10

Дамиров Рафаэль
10. Курсант
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Курсант: Назад в СССР 10

Сделай это со мной снова

Рам Янка
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Сделай это со мной снова

Болотник 2

Панченко Андрей Алексеевич
2. Болотник
Фантастика:
попаданцы
альтернативная история
6.25
рейтинг книги
Болотник 2

Камень Книга двенадцатая

Минин Станислав
12. Камень
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
5.00
рейтинг книги
Камень Книга двенадцатая

Небо для Беса

Рам Янка
3. Самбисты
Любовные романы:
современные любовные романы
5.25
рейтинг книги
Небо для Беса

Надуй щеки! Том 4

Вишневский Сергей Викторович
4. Чеболь за партой
Фантастика:
попаданцы
уся
дорама
5.00
рейтинг книги
Надуй щеки! Том 4