Двумерный массив указателей на функции PVOID
Использую хуки Detours и пытаюсь реализовать указатели на функции в двумерном массиве, чтобы DetourAttach
производить по индексу. Что имеем:
// объявление функции двойника
HIMAGELIST WINAPI MyImageList_Create(
int cx,
int cy,
UINT flags,
int cInitial,
int cGrow
);
// объявление указателя на оригинальную функцию
static HIMAGELIST(WINAPI* actualImageList_Create)(int cx, int cy, UINT flags, int cInitial, int cGrow) = ImageList_Create;
// подключение хука на функцию
DetourAttach(&(PVOID&)actualImageList_Create, MyImageList_Create);
// описание функции двойника
HIMAGELIST WINAPI MyImageList_Create(
int cx,
int cy,
UINT flags,
int cInitial,
int cGrow
)
{
return actualImageList_Create(cx, cy, flags, cInitial, cGrow);
}
Данный пример работает исправно, но неудобен при использовании множества хуков на функции. Необходимо указатели на двойника и оригинальную функции поместить в двух мерный массив, чтобы подключать хук по индексу примерно так:
DetourAttach(functptr[0][0], functptr[0][1]);
Соответственно, в описании функции двойника вызывать оригинальную функцию так же из массива по индексу как-то так:
functptr[0][0](cx, cy, flags, cInitial, cGrow);
Что требуется реализовать:
// объявление функции двойника
HIMAGELIST WINAPI MyImageList_Create(
int cx,
int cy,
UINT flags,
int cInitial,
int cGrow
);
// Объявление целевого массива
PVOID(*functptr[][2]) = { { /*...*/ , (PVOID*)MyImageList_Create} };
// объявление указателя на оригинальную функцию,
// который надо разместить в массиве в первой колонке,
// во второй колонке разместить указатель на функцию двойника
// ...
// подключение хука на функцию
DetourAttach(&(PVOID&)functptr[0][0], functptr[0][1]);
// описание функции двойника
HIMAGELIST WINAPI MyImageList_Create(
int cx,
int cy,
UINT flags,
int cInitial,
int cGrow
)
{
return functptr[0][0](cx, cy, flags, cInitial, cGrow);
}
Описание Detours https://www.codeproject.com/Articles/30140/API-Hooking-with-MS-Detours
Ответы (2 шт):
У меня нет винды, поэтому мог что-то напутать с моделированием виндовых typedefs.
В частности, пользуясь советом enSO, пришлось определить
#define WINAPI __stdcall
#define __stdcall
а HIMAGELIST
, полазив по гуглу, я определил так
struct _IMAGELIST;
typedef struct _IMAGELIST * HIMAGELIST;
-- это ответ --
Я думаю, что прежде всего, для упрощения описания двумерного массива функций functptr[][2]
стоит определить typedef для указателя на функцию, назовем этот тип -- img_foo_t
.
typedef HIMAGELIST (WINAPI *img_foo_t)(int cx, int cy, UINT flags, int cInitial, int cGrow);
После этого у меня получилось скомпилировать вот такой код (с вашими функциями)
// объявление указателя на оригинальную функцию
static HIMAGELIST
(WINAPI *actualImageList_Create)(int cx, int cy,
UINT flags, int cInitial, int cGrow) = ImageList_Create;
int
main (int ac, char *av[])
{
// подключение хука на функцию
// DetourAttach(&(PVOID&)actualImageList_Create, MyImageList_Create);
DetourAttach((PVOID *)&actualImageList_Create, MyImageList_Create);
img_foo_t functptr[][2] = {
{ImageList_Create, MyImageList_Create}
};
DetourAttach((PVOID *)&functptr[0][0], functptr[0][1]);
return 0;
}
Обратите внимание на изменения в передаче первого параметра в DetourAttach
(реально мы передаем адрес переменной с указателем на функцию (как описано в вашей ссылке на Detours API Hooking)).
P.S. Понятно, что для функций ImageList_Create и DetourAttach я использовал заглушки.
Вот таким образом я решил осуществить свои задачи. Код был взят из чужих проектов, поэтому надо что-то почистить и подправить. DetoursHelper.hpp:
#pragma once
namespace MyProject::HookHelper
{
template <size_t hookCount, size_t possibleImportCount>
using DetoursDispatcherDependency = std::array<std::tuple<std::array<std::string_view, possibleImportCount>, LPCSTR, PVOID, PVOID>, hookCount>;
template <size_t hookCount, size_t possibleImportCount>
struct DetoursDispatcher
{
const DetoursDispatcherDependency<hookCount, possibleImportCount>& DetoursDependency{};
//std::array<std::pair<OffsetStorage, std::optional<OffsetStorage>>, hookCount> hookInfoCache{}; // iat mem offset
std::array<std::pair<PVOID, std::optional<HMODULE>>, hookCount> hookTable{}; // iat org value
std::array<size_t, hookCount> hookRef{};
mutable wil::srwlock hookLock{};
PVOID moduleAddress{};
void CacheHookData()
{
/*auto dllPath{ wil::GetModuleFileNameW<std::wstring, MAX_PATH + 1>(reinterpret_cast<HMODULE>(moduleAddress)) };
if (dllPath.empty())
{
return;
}*/
PVOID* functionAddress{ nullptr };
HMODULE* moduleHandle{ nullptr };
auto imageMapper{ ImageMapper(dllPath) };
/*auto initialize_offset_storage = [&](size_t index)
{
auto [possibleImport, functionName, detourFunction, typeFunction] {DetoursDependency[index]};
moduleHandle = GetModuleHandleW(L"user32.dll");
typeFunction = reinterpret_cast<decltype(&detourFunction)>(GetProcAddress(moduleHandle, functionName));
functionAddress = typeFunction;
hookInfoCache[index].first = moduleHandle;
hookInfoCache[index].second = functionAddress;
};*/
auto bind = [&](const std::pair<HMODULE*, PVOID*> value)
{
functionAddress = value.second;
moduleHandle = value.first;
return functionAddress != nullptr;
};
for (size_t i = 0; i < DetoursDependency.size(); i++)
{
auto [possibleImport, functionName, detourFunction, typeFunction] {DetoursDependency[i]};
for (auto importDll : possibleImport)
{
std::string dll{importDll};
// здесь получаю указатель на оригинальную функцию
typeFunction = reinterpret_cast<decltype(&detourFunction)>(GetProcAddress(GetModuleHandleA(dll.c_str()), functionName));
if (typeFunction)
{
OutputDebugStringA(
std::format(
"{} - {} 0x{:x} DetoursHelper\n",
importDll,
functionName,
(DWORD)typeFunction
).c_str()
);
break;
}
}
}
}
bool IsHookEnabled(size_t index) const { auto lock{ hookLock.lock_shared() }; return hookRef[index] > 0; }
bool EnableHook(size_t index, bool enable)
{
/*if (!moduleAddress)
{
return false;
}
auto lock{ hookLock.lock_exclusive() };*/
// защита от повторного вызова
hookRef[index] += enable ? 1 : -1;
bool hookChanged{ false };
if ((enable && hookRef[index] == 1) || (!enable && hookRef[index] == 0))
{
hookChanged = true;
}
auto& [functionAddressOffset, moduleHandleOffset] {hookInfoCache[index]};
auto iatFunctionAddress{ reinterpret_cast<PVOID*>(functionAddressOffset.To(moduleAddress)) };
auto iatModuleAddress{ moduleHandleOffset.has_value() ? std::optional{reinterpret_cast<HMODULE*>(moduleHandleOffset.value().To(moduleAddress))} : std::nullopt };
/*DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)iatFunctionAddress, detourFunction);
DetourTransactionCommit();*/
}
template <size_t index, typename T = PVOID>
[[nodiscard]] __forceinline auto GetOrg() const { auto lock{ hookLock.lock_shared() }; return reinterpret_cast<T>(hookTable[index].first); }
DetoursDispatcher(
const DetoursDispatcherDependency<hookCount, possibleImportCount>& dependency,
PVOID targetDll = nullptr
) : DetoursDependency{ dependency }, moduleAddress{ targetDll }
{
}
DetoursDispatcher() = delete;
};
template <size_t hookCount, size_t possibleImportCount>
DetoursDispatcher(
const DetoursDispatcherDependency<hookCount, possibleImportCount>&,
PVOID, PVOID
) -> DetoursDispatcher<hookCount, possibleImportCount>;
template <typename TDetoursDispatcherDependency>
struct TDetoursDispatcher;
template <size_t hookCount, size_t possibleImportCount>
struct TDetoursDispatcher<DetoursDispatcherDependency<hookCount, possibleImportCount>> { using type = DetoursDispatcher<hookCount, possibleImportCount>; };
}
WinHook.cpp:
using namespace MyProject;
namespace MyProject::WinHooks
{
using namespace std::literals;
typedef int(WINAPI* TypeDrawTextW)(HDC hdc, LPCWSTR lpchText, int cchText, LPRECT lprc, UINT format);
TypeDrawTextW actualDrawTextW = nullptr;
// [еще аналогичные объявления функций...]
// заполнение массива данными
HookHelper::DetoursDispatcherDependency g_DetoursDependency
{
std::tuple
{
std::array
{
"user32.dll"sv,
"ext-ms-win-ntuser-draw-l1-1-0.dll"sv,
"ext-ms-win-ntuser-misc-l1-1-0.dll"sv
},
"DrawTextW",
reinterpret_cast<PVOID>(MyDrawTextW),
reinterpret_cast<PVOID>(actualDrawTextW)
}
/*std::tuple
{
std::array
{
"module.dll"sv,
"module-ntuser-draw-l1-1-0.dll"sv,
"module-win-ntuser-misc-l1-1-0.dll"sv
},
"MoreFunc",
reinterpret_cast<PVOID>(MyMoreFunc),
reinterpret_cast<PVOID>(actualMoreFunc)
}
[...]*/
};
HookHelper::DetoursDispatcher g_DetoursDispatcher
{
g_DetoursDependency
};
}
// кэшируем адреса функций, здесь переменным actualDrawTextW нужно присвоить значения
g_DetoursDispatcher.CacheHookData();
// подключаем хук
g_DetoursDispatcher.EnableHook(index, attach);
// проблема заключается в получении оригинальной функции
// для возврата из функции двойника.
// Нужно реализовать одно из двух:
// либо переменным actualDrawTextW присвоить значения в функции CacheHookData,
// либо вернуть значения как в этом примере:
int WINAPI WinHooks::MyDrawTextW(HDC hdc, LPCWSTR lpchText, int cchText, LPRECT lprc, UINT format)
{
auto actualDrawTextW{ g_DetoursDispatcher.GetOrg<index, decltype(&MyDrawTextW)>() };
return actualDrawTextW(hdc, lpchText, cchText, lprc, format);
}