Сегодня мы разберем один из самых простых и действенных методов скрытия вызовов WinAPI.Для полного понимания, как работает данный метод необходимо знать как устроен PE-формат.
Как работает данный метод?
Мы будем пробегаться по таблице экспорта системной библиотеки в которой содержится нужная API-функция, хешируя каждое название функции в таблице экспорта.Если хэши одной из функций и нашей функции будут совпадать - то мы нашли указатель на нужную нам функцию.В данном примере я буду использовать алгоритм хеширования CRC-32.У него есть пару минусов:
В реальных условиях желательно использовать другой алгоритм.
Теперь приступим к реализации, напишем функцию получения функции по хешу(все комментарии в коде):
Заголовочный файл:
CPP-файл:
Теперь протестируем:
Функция успешно вызвалась
Теперь взглянем на IAT
user32!MessageBoxA там не отображается.
Собственна все)
Как работает данный метод?
Мы будем пробегаться по таблице экспорта системной библиотеки в которой содержится нужная API-функция, хешируя каждое название функции в таблице экспорта.Если хэши одной из функций и нашей функции будут совпадать - то мы нашли указатель на нужную нам функцию.В данном примере я буду использовать алгоритм хеширования CRC-32.У него есть пару минусов:
- Скорость алгоритма не самая высокая.
- Приходится таскать в бинарнике достаточно громоздкую таблицу:
В реальных условиях желательно использовать другой алгоритм.
Теперь приступим к реализации, напишем функцию получения функции по хешу(все комментарии в коде):
Заголовочный файл:
Код:
#pragma once
#include <Windows.h>
LPVOID GetFuncByHash(LPCSTR pszLibrary, UINT uHash);
CPP-файл:
Код:
#include "cApiHash.h"
#include "cCRC32.h"
LPVOID GetFuncByHash(LPCSTR pszLibrary, UINT uHash) {
//Загружаем библиотеку
HINSTANCE hLibrary = GetModuleHandleA(pszLibrary);
if (!hLibrary)
return NULL;
//Получаем DOS-заголовок и проверяем его на валидность
PIMAGE_DOS_HEADER pDOSHdr = (PIMAGE_DOS_HEADER)hLibrary;
if (pDOSHdr->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
//Получаем PE-заголовок и проверяем его на валидность
PIMAGE_NT_HEADERS pNTHdr = (PIMAGE_NT_HEADERS)((LPBYTE)hLibrary + pDOSHdr->e_lfanew);
if (pNTHdr->Signature != IMAGE_NT_SIGNATURE)
return NULL;
if ((pNTHdr->FileHeader.Characteristics & IMAGE_FILE_DLL) == NULL ||
pNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == NULL ||
pNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == NULL)
return NULL;
//Получаем смещение таблицы экспорта
PIMAGE_EXPORT_DIRECTORY pIED = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)hLibrary +
pNTHdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PDWORD pdwAddress = (PDWORD)((LPBYTE)hLibrary + pIED->AddressOfFunctions);
PDWORD pdwNames = (PDWORD)((LPBYTE)hLibrary + pIED->AddressOfNames);
PWORD pwOrd = (PWORD)((LPBYTE)hLibrary + pIED->AddressOfNameOrdinals);
//Разбираем таблицу экспорта
for (DWORD i = 0; i < pIED->AddressOfFunctions; i++)
{
LPSTR pszFuncName = (LPSTR)((LPBYTE)hLibrary + pdwNames[i]);
UINT32 u32FuncHash = cCRC32::Hash(pszFuncName, lstrlenA(pszFuncName));
//Если хеши совпадают - возвращаем указатель
if (u32FuncHash == uHash)
return (LPVOID)((LPBYTE)hLibrary + pdwAddress[pwOrd[i]]);
}
}
Теперь протестируем:
Код:
#include <Windows.h>
#include "cApiHash.h"
//Прототип функции которую хотим вызвать
typedef int(WINAPI* _MessageBoxA)(
HWND hWND,
LPCSTR pszText,
LPCSTR pszCaption,
UINT uType
);
VOID WINAPI Entry(VOID) {
_MessageBoxA fpMessageBoxA = (_MessageBoxA)GetFuncByHash("user32.dll", 0x572D5D8E);
fpMessageBoxA(NULL, "Hello xss.pro", "xss.pro", MB_OK);
}
Функция успешно вызвалась
Теперь взглянем на IAT
user32!MessageBoxA там не отображается.
Собственна все)
Вложения
Последнее редактирование: