Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР #78, ИЮНЬ 2005 г.

Охота на ведьм

Николай «GorluM» Андреев

Хакер, номер #078, стр. 078-104-2


1) перечисляем все модули нашей программы;

2) в каждом модуле ищем таблицу импорта;

3) с помощью GetProcAddress проверяем правильность каждого адреса функций в таблице;

4) если адрес, возвращенный GetProcAddress (или ее аналогом), и адрес, взятый из таблицы, не совпали — громко орем и выводим на экран всю возможную информацию (о лечении я пока молчу, ибо бесполезно лечить одну только нашу программу).

Правда, есть небольшой нюанс. GetProcAddress, возвращающая адрес функции по ее имени и хэндлу модуля, тоже может быть перехвачена (даже не может, а обязана). А это значит, доверять ей нельзя и придется написать собственный аналог, который перехватывать никто не станет и не сможет. Что ж, с основной идеей разобрались, можно начинать кодить.

[кодим помаленьку]

Перечислить все модули определенного процесса (в данном случае нашего) можно тучей разных способов: тут и библиотека psapi сгодится, и даже сама NtQuerySystemInformation. Я, правда, привык пользоваться ToolHelp-функциями. Они удобные, если приноровиться их юзать. Сначала получаешь снимок нужной тебе системной информации с помощью CreateToolhelp32Snapshot, а затем бегаешь по нему с помощью Module32First\Module32Next или аналогов. К примеру, чтобы выполнить функцию Test для каждого хэндла модуля текущего процесса (нашего детектора), нужно написать вот такой несложный код:

MODULEENTRY32 me = {sizeof(me)};

HANDLE m_Snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,

GetCurrentProcessId());

if (m_Snap == INVALID_HANDLE_VALUE) return;

if (!Module32First(m_Snap, &me)) return;

do Test(me.hModule);

while (Module32Next(m_Snap, &me));

CloseHandle(m_Snap);

Функция Test — это второй, третий и четвертый шаги нашего алгоритма. В ней мы должны найти таблицу импорта и проверить подлинность каждой записи. Но, как ты понимаешь, для работы с таблицей надо знать ее формат. Он уже описывался всеми, кем только можно, и отыскать в Сети подробный мануал тебе труда не составит (wasm.ru, к примеру, располагает подобной информацией).

Разобравшись с форматом таблицы импорта и вообще с PE (я не знаю, как можно программировать под windows без таких основ), можно приступить к кодингу нашей функции Test. Первое, что она должна сделать, — найти импорт в модуле, чей хэндл был передан ей в единственном параметре. Осуществить это можно двумя способами:

1) с помощью функции библиотеки imagehlp, сразу возвращающей нужный нам указатель на первую структуру таблицы:

PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(hModule,
TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);

2) вручную, покопавшись в PE-заголовках модуля. Хэндл модуля — это указатель на первый байт образа библиотеки, загруженной в адресное пространство процесса. Мы без проблем можем найти все необходимые данные:

Назад на стр. 078-104-1  Содержание  Вперед на стр. 078-104-3