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

Долой импорт!

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

Хакер, номер #080, стр. 080-116-2


[всем известный поиск ядра]

HMODULE GetKernel()

{

__asm {

mov eax, dword ptr fs:[30h]

mov eax, dword ptr [eax+0ch]

mov esi, dword ptr [eax+1ch]

lodsd

mov eax, dword ptr [eax+08h]

}

}

Имея ядро, можно найти в нем с помощью собственной функции GetProcAddress адрес LoadLibrary, подгрузить с ее помощью любую нужную библиотеку и искать уже в ней адрес необходимой для работы программы функции (как вариант, можно найти адрес GetModuleHandle). Геморрой, конечно, но он просто автоматизируется, а исследователю жизнь все-таки усложняет. В итоге, со всеми извращениями запуск API-функции, к примеру, MessageBox'а на Си выглядит следующим образом:

[я не такой уж и извращенец, честное слово!]

typedef int (WINAPI * tMessageBoxA)

(HWND, LPCSTR, LPCSTR, UINT);

typedef HMODULE (WINAPI * tLoadLibraryA)

(LPCSTR);

HMODULE hKernel32 = GetKernel();

tLoadLibraryA pLoadLibraryA = GetProcAddressEx

(hKernel32, "LoadLibraryA"); // 0xC8AC8026

HMODULE hUser32 = pLoadLibraryA ("user32.dll");

tMessageBox pMessageBox = GetProcAddressEx

(hUser32, "MessageBoxA" ); // 0xABBC680D

pMessageBox(0, "Hello world", "", 0);

Упс, наврал... Не со всеми извращениями. Ведь тут поиск осуществляется по имени, а нас это, как я уже говорил, не устраивает. Будем переделывать поиск, чтобы искал по хэшу.

[ищем функции по хэшу]

Хэш - это некоторое число, которое считается от строки. Хэш-функция, соответственно, функция, которая будет это число считать. Его ведь можно кучей разных способов получать. Она у нас будет очень простенькая, я ее выдрал из замечательных программ z0mbie и переписал на Си.

[хэш-функция]

DWORD CalcHash(char *str)

{

DWORD hash = 0;

char* copystr = str;

while(*copystr) {

hash = ((hash << 7) & (DWORD)(-1))|(hash >> (32-7));

hash = hash^(*copystr);

copystr++;

}

return hash;

}

Число, полученное в результате подсчета, почти уникально. Конечно, это я очень хреново выразился. Я хотел сказать, что вероятность того, что от двух разных строк ты получишь одно число - очень мала. А на пространстве имен функций какой-нибудь одной библиотеки вообще равна нулю. Потому-то и можно искать функцию в таблице экспорта, сравнивая не имена, а числа. Это позволяет хранить не палевное название API в программе, а всего лишь 4 байта хэша, которые влезают в любой регистр и могут просто жить в какой-нибудь инструкции, прямо в коде, а не в данных. Меня это обстоятельство радует безумно. Я вообще данные в программе не люблю.

Чтобы иметь возможность искать имя по хэшу, достаточно немного модифицировать функцию GetProcAddressEx. Второй параметр ее станет DWORD'ом вместо указателя на строку, а внутри вместо сравнения имен:

if (lstrcmp((char*)RVATOVA(hModule, *pdwNamePtr), lpProcName) == 0)

Будет сравнение второго параметра (hash) и подсчитанного хэша от рассматриваемого в конкретный момент имени функции:

if (CalcHash((char*)RVATOVA(hModule, *pdwNamePtr)) == hash)

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