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

Тут можно читать онлайн Алекс Jenter - Программирование на Visual C++. Архив рассылки - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    Программирование на Visual C++. Архив рассылки
  • Автор:
  • Жанр:
  • Издательство:
    неизвестно
  • Год:
    неизвестен
  • ISBN:
    нет данных
  • Рейтинг:
    4.33/5. Голосов: 91
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

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

Программирование на Visual C++. Архив рассылки - описание и краткое содержание, автор Алекс Jenter, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

РАССЫЛКА ЯВЛЯЕТСЯ ЧАСТЬЮ ПРОЕКТА RSDN, НА САЙТЕ КОТОРОГО ВСЕГДА МОЖНО НАЙТИ ВСЮ НЕОБХОДИМУЮ РАЗРАБОТЧИКУ ИНФОРМАЦИЮ, СТАТЬИ, ФОРУМЫ, РЕСУРСЫ, ПОЛНЫЙ АРХИВ ПРЕДЫДУЩИХ ВЫПУСКОВ РАССЫЛКИ И МНОГОЕ ДРУГОЕ.

Программирование на Visual C++. Архив рассылки - читать онлайн бесплатно полную версию (весь текст целиком)

Программирование на Visual C++. Архив рассылки - читать книгу онлайн бесплатно, автор Алекс Jenter
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Теперь если в коде программы встретится MessageBeepпрепроцессор заменит ее на нашу MyMessageBeep. Очень просто.

Но что если хочется добавить немного своей логики в уже откомпилированный код , изменить работу чужой библиотеки, пересобрать которую нет никакой возможности? Иными словами, заставить уже откомпилированный код вызвать нашу функцию вместо стандартной. Это вполне реально. Давайте поближе рассмотрим, как под Windows процедуры одного модуля используют процедуры другого.

Модификация таблиц импорта/экспорта

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

Код вызова процедуры из другого модуля выглядит примерно так:

call dword ptr [__imp__MessageBeep@4 (004404cc)]

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

• Отыскать таблицу импорта функций для нужного нам модуля

• Отыскать там указатель на перехватываемую функцию

• Снять с этого участка памяти утрибут ReadOnly

• Записать указатель на нашу функцию

• Вернуть защиту обратно

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

// Check args

if (::IsBadStringPtrA(szVictim, –1) || (!IIS_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;

// Locate the victim

IMAGE_DATA_DIRECTORY& impDir =

pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];

PIMAGE_IMPORT_DESCRIPTOR pImpDesc =

MakePtr(PIMAGE_IMPORT_DESCRIPTOR, hModule, impDir.VirtualAddress),

pEnd = pImpDesc + impDir.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR) - 1;

while (pImpDesc < pEnd) {

if (0 == ::lstrcmpiA(MakePtr(LPSTR, hModule, pImpDesc->Name), szVictim)) {

if (0 == pImpDesc->OriginalFirstThunk) {

// no import names table

return E_UNEXPECTED;

}

// Locate the entry

PIMAGE_THUNK_DATA pNamesTable =

MakePtr(PIMAGE_THUNK_DATA, hModule, pImpDesc->OriginalFirstThunk);

if (IS_INTRESOURCE(szEntry)) {

// By ordinal

while(pNamesTable->u1.AddressOfData) {

if (IMAGE_SNAP_BY_ORDINAL(pNamesTable->u1.Ordinal) && WORD(szEntry) == IMAGE_ORDINAL(pNamesTable->u1.Ordinal)) {

hr = S_OK;

break;

}

pNamesTable++;

}

} else {

// By name

while(pNamesTable->u1.AddressOfData) {

if (!IMAGE_SNAP_BY_ORDINAL(pNamesTable->u1.Ordinal)) {

PIMAGE_IMPORT_BY_NAME pName = MakePtr(PIMAGE_IMPORT_BY_NAME, hModule, pNamesTable->u1.AddressOfData);

if (0 == ::lstrcmpiA(LPSTR(pName->Name), szEntry)) {

hr = S_OK;

break;

}

}

pNamesTable++;

}

}

if (SUCCEEDED(hr)) {

// Get address

LPVOID *pProc = MakePtr(LPVOID *, pNamesTable, pImpDesc->FirstThunk - pImpDesc->OriginalFirstThunk);

// Save original handler

if (ppOrig) *ppOrig = *pProc;

// write to write-protected memory

return WriteProtectedMemory(pProc, &pHijacker, sizeof(LPVOID));

}

break;

}

pImpDesc++;

}

return hr;

}

HRESULT WriteProtectedMemory(LPVOID pDest, LPCVOID pSrc, DWORD dwSize) {

// Make it writable

DWORD dwOldProtect = 0;

if (::VirtualProtect(pDest, dwSize, PAGE_READWRITE, &dwOldProtect)) {

::MoveMemory(pDest, pSrc, dwSize);

// Restore protection

::VirtualProtect(pDest, dwSize, dwOldProtect, &dwOldProtect);

return S_OK;

}

return HRESULT_FROM_WIN32(GetLastError());

}

Впрочем, такой способ не будет работать если используется позднее связывание (delay load) или связывание во время исполнения (run-time load) с помощью ::GetProcAddress(). Это можно побороть если перехватить саму ::GetProcAddress(), и подменять возвращяемое значение при необходимости. А можно и подправить таблицу экспорта аналогичным способом:

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.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Алекс Jenter читать все книги автора по порядку

Алекс Jenter - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




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


Отзывы читателей о книге Программирование на Visual C++. Архив рассылки, автор: Алекс Jenter. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x