mirror of
https://github.com/8damon/Blackbird-Platform
synced 2026-06-21 13:41:12 +00:00
665 lines
20 KiB
C++
665 lines
20 KiB
C++
#include "ws.h"
|
|
|
|
#ifndef _WINSOCKAPI_
|
|
#define _WINSOCKAPI_
|
|
#endif
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#ifndef NOMINMAX
|
|
#define NOMINMAX
|
|
#endif
|
|
|
|
#include <Windows.h>
|
|
#include <TlHelp32.h>
|
|
#include <intrin.h>
|
|
|
|
#include <cstring>
|
|
|
|
#pragma intrinsic(_ReturnAddress)
|
|
|
|
namespace
|
|
{
|
|
using WsasendFn = INT(WSAAPI *)(SOCKET, LPWSABUF, DWORD, LPDWORD, DWORD, LPWSAOVERLAPPED,
|
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE);
|
|
|
|
using WsarecvFn = INT(WSAAPI *)(SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, LPWSAOVERLAPPED,
|
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE);
|
|
|
|
using SendFn = int(WSAAPI *)(SOCKET, const char *, int, int);
|
|
|
|
using RecvFn = int(WSAAPI *)(SOCKET, char *, int, int);
|
|
|
|
using ConnectFn = int(WSAAPI *)(SOCKET, const sockaddr *, int);
|
|
|
|
using WsaConnectFn = int(WSAAPI *)(SOCKET, const sockaddr *, int, LPWSABUF, LPWSABUF, LPQOS, LPQOS);
|
|
|
|
using GetAddrInfoWFn = INT(WSAAPI *)(PCWSTR, PCWSTR, const ADDRINFOW *, PADDRINFOW *);
|
|
|
|
struct HookEntry
|
|
{
|
|
const char *ModuleName;
|
|
const char *FunctionName;
|
|
void **OriginalFunction;
|
|
void *HookFunction;
|
|
};
|
|
|
|
static WsasendFn g_OriginalWsasend = nullptr;
|
|
static WsarecvFn g_OriginalWsarecv = nullptr;
|
|
static SendFn g_OriginalSend = nullptr;
|
|
static RecvFn g_OriginalRecv = nullptr;
|
|
static ConnectFn g_OriginalConnect = nullptr;
|
|
static WsaConnectFn g_OriginalWsaConnect = nullptr;
|
|
static GetAddrInfoWFn g_OriginalGetAddrInfoW = nullptr;
|
|
static WinsockHookCallback g_ActiveCallback = nullptr;
|
|
static bool g_HooksInstalled = false;
|
|
static __declspec(thread) bool g_InHook = false;
|
|
|
|
struct PatchedIatSlot
|
|
{
|
|
ULONG_PTR *Slot;
|
|
void *HookFunction;
|
|
};
|
|
|
|
static PatchedIatSlot g_PatchedSlots[512]{};
|
|
static std::size_t g_PatchedSlotCount = 0;
|
|
|
|
static bool ModuleImportsWinsock(HMODULE moduleHandle)
|
|
{
|
|
if (moduleHandle == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto *base = reinterpret_cast<std::uint8_t *>(moduleHandle);
|
|
auto *dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(base);
|
|
if (dosHeader == nullptr || dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto *ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(base + dosHeader->e_lfanew);
|
|
if (ntHeaders == nullptr || ntHeaders->Signature != IMAGE_NT_SIGNATURE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
IMAGE_DATA_DIRECTORY &importDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
|
|
if (importDirectory.VirtualAddress == 0 || importDirectory.Size == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto *importDescriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(base + importDirectory.VirtualAddress);
|
|
|
|
for (; importDescriptor->Name != 0; ++importDescriptor)
|
|
{
|
|
const char *importedModuleName = reinterpret_cast<const char *>(base + importDescriptor->Name);
|
|
if (importedModuleName != nullptr && _stricmp(importedModuleName, "WS2_32.dll") == 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void TrackPatchedSlot(ULONG_PTR *slot, void *hookFunction)
|
|
{
|
|
if (slot == nullptr || hookFunction == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (std::size_t i = 0; i < g_PatchedSlotCount; ++i)
|
|
{
|
|
if (g_PatchedSlots[i].Slot == slot)
|
|
{
|
|
g_PatchedSlots[i].HookFunction = hookFunction;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (g_PatchedSlotCount < RTL_NUMBER_OF(g_PatchedSlots))
|
|
{
|
|
g_PatchedSlots[g_PatchedSlotCount].Slot = slot;
|
|
g_PatchedSlots[g_PatchedSlotCount].HookFunction = hookFunction;
|
|
++g_PatchedSlotCount;
|
|
}
|
|
}
|
|
|
|
INT WSAAPI WsasendHook(SOCKET socketHandle, LPWSABUF buffers, DWORD bufferCount, LPDWORD bytesSent, DWORD flags,
|
|
LPWSAOVERLAPPED overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completionRoutine)
|
|
{
|
|
if (!g_InHook && g_ActiveCallback != nullptr && buffers != nullptr && bufferCount > 0)
|
|
{
|
|
g_InHook = true;
|
|
void *caller = _ReturnAddress();
|
|
|
|
for (DWORD i = 0; i < bufferCount; ++i)
|
|
{
|
|
if (buffers[i].buf == nullptr || buffers[i].len == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
WinsockHookBuffer bufferView{};
|
|
bufferView.Data = buffers[i].buf;
|
|
bufferView.Length = buffers[i].len;
|
|
|
|
WinsockHookContext context{};
|
|
context.Operation = WinsockOperation::WsaSend;
|
|
context.Socket = socketHandle;
|
|
context.Buffers = &bufferView;
|
|
context.BufferCount = 1U;
|
|
context.Caller = caller;
|
|
|
|
g_ActiveCallback(context);
|
|
}
|
|
|
|
g_InHook = false;
|
|
}
|
|
|
|
if (g_OriginalWsasend == nullptr)
|
|
{
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
return g_OriginalWsasend(socketHandle, buffers, bufferCount, bytesSent, flags, overlapped, completionRoutine);
|
|
}
|
|
|
|
INT WSAAPI WsarecvHook(SOCKET socketHandle, LPWSABUF buffers, DWORD bufferCount, LPDWORD bytesReceived,
|
|
LPDWORD flags, LPWSAOVERLAPPED overlapped,
|
|
LPWSAOVERLAPPED_COMPLETION_ROUTINE completionRoutine)
|
|
{
|
|
if (g_OriginalWsarecv == nullptr)
|
|
{
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
const INT result =
|
|
g_OriginalWsarecv(socketHandle, buffers, bufferCount, bytesReceived, flags, overlapped, completionRoutine);
|
|
|
|
if (result != 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
if (!g_InHook && g_ActiveCallback != nullptr && buffers != nullptr && bufferCount > 0 &&
|
|
bytesReceived != nullptr && *bytesReceived > 0)
|
|
{
|
|
g_InHook = true;
|
|
void *caller = _ReturnAddress();
|
|
|
|
std::size_t remaining = static_cast<std::size_t>(*bytesReceived);
|
|
|
|
for (DWORD i = 0; i < bufferCount && remaining > 0; ++i)
|
|
{
|
|
if (buffers[i].buf == nullptr || buffers[i].len == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const std::size_t bufLen =
|
|
(remaining < buffers[i].len) ? remaining : static_cast<std::size_t>(buffers[i].len);
|
|
|
|
WinsockHookBuffer bufferView{};
|
|
bufferView.Data = buffers[i].buf;
|
|
bufferView.Length = bufLen;
|
|
|
|
WinsockHookContext context{};
|
|
context.Operation = WinsockOperation::WsaRecv;
|
|
context.Socket = socketHandle;
|
|
context.Buffers = &bufferView;
|
|
context.BufferCount = 1U;
|
|
context.Caller = caller;
|
|
|
|
g_ActiveCallback(context);
|
|
|
|
remaining -= bufLen;
|
|
}
|
|
|
|
g_InHook = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int WSAAPI SendHook(SOCKET socketHandle, const char *buffer, int length, int flags)
|
|
{
|
|
if (!g_InHook && g_ActiveCallback != nullptr && buffer != nullptr && length > 0)
|
|
{
|
|
g_InHook = true;
|
|
|
|
WinsockHookBuffer bufferView{};
|
|
bufferView.Data = buffer;
|
|
bufferView.Length = static_cast<std::size_t>(length);
|
|
|
|
WinsockHookContext context{};
|
|
context.Operation = WinsockOperation::Send;
|
|
context.Socket = socketHandle;
|
|
context.Buffers = &bufferView;
|
|
context.BufferCount = 1U;
|
|
context.Caller = _ReturnAddress();
|
|
|
|
g_ActiveCallback(context);
|
|
|
|
g_InHook = false;
|
|
}
|
|
|
|
if (g_OriginalSend == nullptr)
|
|
{
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
return g_OriginalSend(socketHandle, buffer, length, flags);
|
|
}
|
|
|
|
int WSAAPI RecvHook(SOCKET socketHandle, char *buffer, int length, int flags)
|
|
{
|
|
if (g_OriginalRecv == nullptr)
|
|
{
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
const int result = g_OriginalRecv(socketHandle, buffer, length, flags);
|
|
|
|
if (result > 0 && !g_InHook && g_ActiveCallback != nullptr && buffer != nullptr)
|
|
{
|
|
g_InHook = true;
|
|
|
|
WinsockHookBuffer bufferView{};
|
|
bufferView.Data = buffer;
|
|
bufferView.Length = static_cast<std::size_t>(result);
|
|
|
|
WinsockHookContext context{};
|
|
context.Operation = WinsockOperation::Recv;
|
|
context.Socket = socketHandle;
|
|
context.Buffers = &bufferView;
|
|
context.BufferCount = 1U;
|
|
context.Caller = _ReturnAddress();
|
|
|
|
g_ActiveCallback(context);
|
|
|
|
g_InHook = false;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int WSAAPI ConnectHook(SOCKET socketHandle, const sockaddr *name, int nameLength)
|
|
{
|
|
if (!g_InHook && g_ActiveCallback != nullptr && name != nullptr && nameLength > 0)
|
|
{
|
|
g_InHook = true;
|
|
|
|
WinsockHookBuffer bufferView{};
|
|
bufferView.Data = name;
|
|
bufferView.Length = static_cast<std::size_t>(nameLength);
|
|
|
|
WinsockHookContext context{};
|
|
context.Operation = WinsockOperation::Connect;
|
|
context.Socket = socketHandle;
|
|
context.Buffers = &bufferView;
|
|
context.BufferCount = 1U;
|
|
context.Caller = _ReturnAddress();
|
|
context.Args[0] = static_cast<std::uint64_t>(name->sa_family);
|
|
context.Args[1] = static_cast<std::uint64_t>(nameLength);
|
|
|
|
g_ActiveCallback(context);
|
|
|
|
g_InHook = false;
|
|
}
|
|
|
|
if (g_OriginalConnect == nullptr)
|
|
{
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
return g_OriginalConnect(socketHandle, name, nameLength);
|
|
}
|
|
|
|
int WSAAPI WsaConnectHook(SOCKET socketHandle, const sockaddr *name, int nameLength, LPWSABUF callerData,
|
|
LPWSABUF calleeData, LPQOS sqos, LPQOS gqos)
|
|
{
|
|
if (!g_InHook && g_ActiveCallback != nullptr && name != nullptr && nameLength > 0)
|
|
{
|
|
g_InHook = true;
|
|
|
|
WinsockHookBuffer bufferView{};
|
|
bufferView.Data = name;
|
|
bufferView.Length = static_cast<std::size_t>(nameLength);
|
|
|
|
WinsockHookContext context{};
|
|
context.Operation = WinsockOperation::WsaConnect;
|
|
context.Socket = socketHandle;
|
|
context.Buffers = &bufferView;
|
|
context.BufferCount = 1U;
|
|
context.Caller = _ReturnAddress();
|
|
context.Args[0] = static_cast<std::uint64_t>(name->sa_family);
|
|
context.Args[1] = static_cast<std::uint64_t>(nameLength);
|
|
|
|
g_ActiveCallback(context);
|
|
|
|
g_InHook = false;
|
|
}
|
|
|
|
if (g_OriginalWsaConnect == nullptr)
|
|
{
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
return g_OriginalWsaConnect(socketHandle, name, nameLength, callerData, calleeData, sqos, gqos);
|
|
}
|
|
|
|
INT WSAAPI GetAddrInfoWHook(PCWSTR nodeName, PCWSTR serviceName, const ADDRINFOW *hints, PADDRINFOW *result)
|
|
{
|
|
if (!g_InHook && g_ActiveCallback != nullptr && nodeName != nullptr && nodeName[0] != L'\0')
|
|
{
|
|
g_InHook = true;
|
|
|
|
std::size_t chars = 0;
|
|
while (nodeName[chars] != L'\0' && chars < 31)
|
|
{
|
|
++chars;
|
|
}
|
|
|
|
WinsockHookBuffer bufferView{};
|
|
bufferView.Data = nodeName;
|
|
bufferView.Length = chars * sizeof(wchar_t);
|
|
|
|
WinsockHookContext context{};
|
|
context.Operation = WinsockOperation::GetAddrInfoW;
|
|
context.Socket = INVALID_SOCKET;
|
|
context.Buffers = &bufferView;
|
|
context.BufferCount = 1U;
|
|
context.Caller = _ReturnAddress();
|
|
context.Args[0] = (hints != nullptr) ? static_cast<std::uint64_t>(hints->ai_family) : 0ull;
|
|
context.Args[1] = (serviceName != nullptr && serviceName[0] != L'\0')
|
|
? reinterpret_cast<std::uint64_t>(serviceName)
|
|
: 0ull;
|
|
|
|
g_ActiveCallback(context);
|
|
|
|
g_InHook = false;
|
|
}
|
|
|
|
if (g_OriginalGetAddrInfoW == nullptr)
|
|
{
|
|
return EAI_FAIL;
|
|
}
|
|
|
|
return g_OriginalGetAddrInfoW(nodeName, serviceName, hints, result);
|
|
}
|
|
|
|
static HookEntry g_HookEntries[] = {
|
|
{"WS2_32.dll", "WSASend", reinterpret_cast<void **>(&g_OriginalWsasend),
|
|
reinterpret_cast<void *>(&WsasendHook)},
|
|
{"WS2_32.dll", "WSARecv", reinterpret_cast<void **>(&g_OriginalWsarecv),
|
|
reinterpret_cast<void *>(&WsarecvHook)},
|
|
{"WS2_32.dll", "send", reinterpret_cast<void **>(&g_OriginalSend), reinterpret_cast<void *>(&SendHook)},
|
|
{"WS2_32.dll", "recv", reinterpret_cast<void **>(&g_OriginalRecv), reinterpret_cast<void *>(&RecvHook)},
|
|
{"WS2_32.dll", "connect", reinterpret_cast<void **>(&g_OriginalConnect),
|
|
reinterpret_cast<void *>(&ConnectHook)},
|
|
{"WS2_32.dll", "WSAConnect", reinterpret_cast<void **>(&g_OriginalWsaConnect),
|
|
reinterpret_cast<void *>(&WsaConnectHook)},
|
|
{"WS2_32.dll", "GetAddrInfoW", reinterpret_cast<void **>(&g_OriginalGetAddrInfoW),
|
|
reinterpret_cast<void *>(&GetAddrInfoWHook)},
|
|
};
|
|
|
|
bool PatchImportAddressTableForModule(HMODULE moduleHandle, bool install)
|
|
{
|
|
if (moduleHandle == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto *base = reinterpret_cast<std::uint8_t *>(moduleHandle);
|
|
|
|
auto *dosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(base);
|
|
if (dosHeader == nullptr || dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto *ntHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(base + dosHeader->e_lfanew);
|
|
if (ntHeaders == nullptr || ntHeaders->Signature != IMAGE_NT_SIGNATURE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
IMAGE_DATA_DIRECTORY &importDirectory = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
|
|
|
if (importDirectory.VirtualAddress == 0 || importDirectory.Size == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto *importDescriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(base + importDirectory.VirtualAddress);
|
|
|
|
bool anyPatched = false;
|
|
|
|
for (; importDescriptor->Name != 0; ++importDescriptor)
|
|
{
|
|
const char *importedModuleName = reinterpret_cast<const char *>(base + importDescriptor->Name);
|
|
|
|
bool moduleMatches = false;
|
|
for (const auto &hookEntry : g_HookEntries)
|
|
{
|
|
if (_stricmp(importedModuleName, hookEntry.ModuleName) == 0)
|
|
{
|
|
moduleMatches = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!moduleMatches)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
auto *thunkIat = reinterpret_cast<PIMAGE_THUNK_DATA>(base + importDescriptor->FirstThunk);
|
|
|
|
PIMAGE_THUNK_DATA thunkOriginal = nullptr;
|
|
if (importDescriptor->OriginalFirstThunk != 0)
|
|
{
|
|
thunkOriginal = reinterpret_cast<PIMAGE_THUNK_DATA>(base + importDescriptor->OriginalFirstThunk);
|
|
}
|
|
|
|
for (; thunkIat->u1.Function != 0; ++thunkIat)
|
|
{
|
|
const char *functionName = nullptr;
|
|
|
|
if (thunkOriginal != nullptr)
|
|
{
|
|
if (IMAGE_SNAP_BY_ORDINAL(thunkOriginal->u1.Ordinal))
|
|
{
|
|
++thunkOriginal;
|
|
continue;
|
|
}
|
|
|
|
auto *importByName =
|
|
reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(base + thunkOriginal->u1.AddressOfData);
|
|
|
|
functionName = reinterpret_cast<const char *>(importByName->Name);
|
|
++thunkOriginal;
|
|
}
|
|
|
|
if (functionName == nullptr)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (auto &hookEntry : g_HookEntries)
|
|
{
|
|
if (_stricmp(importedModuleName, hookEntry.ModuleName) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (std::strcmp(functionName, hookEntry.FunctionName) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
auto *functionSlot = reinterpret_cast<ULONG_PTR *>(&thunkIat->u1.Function);
|
|
|
|
DWORD oldProtection = 0;
|
|
if (!VirtualProtect(functionSlot, sizeof(ULONG_PTR), PAGE_READWRITE, &oldProtection))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (install)
|
|
{
|
|
if (*hookEntry.OriginalFunction == nullptr)
|
|
{
|
|
*hookEntry.OriginalFunction = reinterpret_cast<void *>(*functionSlot);
|
|
}
|
|
|
|
*functionSlot = reinterpret_cast<ULONG_PTR>(hookEntry.HookFunction);
|
|
TrackPatchedSlot(functionSlot, hookEntry.HookFunction);
|
|
anyPatched = true;
|
|
}
|
|
else
|
|
{
|
|
if (*hookEntry.OriginalFunction != nullptr)
|
|
{
|
|
*functionSlot = reinterpret_cast<ULONG_PTR>(*hookEntry.OriginalFunction);
|
|
anyPatched = true;
|
|
}
|
|
}
|
|
|
|
VirtualProtect(functionSlot, sizeof(ULONG_PTR), oldProtection, &oldProtection);
|
|
}
|
|
}
|
|
}
|
|
|
|
return anyPatched;
|
|
}
|
|
|
|
bool PatchLoadedModules(bool install, HMODULE specificModule = nullptr)
|
|
{
|
|
if (specificModule != nullptr)
|
|
{
|
|
return PatchImportAddressTableForModule(specificModule, install);
|
|
}
|
|
|
|
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
|
|
if (snapshot == INVALID_HANDLE_VALUE)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
MODULEENTRY32W moduleEntry{};
|
|
moduleEntry.dwSize = sizeof(moduleEntry);
|
|
bool anyPatched = false;
|
|
|
|
if (Module32FirstW(snapshot, &moduleEntry))
|
|
{
|
|
do
|
|
{
|
|
anyPatched |= PatchImportAddressTableForModule(moduleEntry.hModule, install);
|
|
} while (Module32NextW(snapshot, &moduleEntry));
|
|
}
|
|
|
|
CloseHandle(snapshot);
|
|
return anyPatched;
|
|
}
|
|
} // namespace
|
|
|
|
bool KeSetWinsockHook(WinsockHookCallback callback) noexcept
|
|
{
|
|
if (callback == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
g_ActiveCallback = callback;
|
|
|
|
if (g_HooksInstalled)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
g_PatchedSlotCount = 0;
|
|
|
|
const bool patched = PatchLoadedModules(true);
|
|
if (!patched)
|
|
{
|
|
g_ActiveCallback = nullptr;
|
|
return false;
|
|
}
|
|
|
|
g_HooksInstalled = true;
|
|
return true;
|
|
}
|
|
|
|
bool KeIsWinsockHookRequired() noexcept
|
|
{
|
|
const HMODULE moduleHandle = GetModuleHandleW(nullptr);
|
|
if (moduleHandle == nullptr)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return ModuleImportsWinsock(moduleHandle);
|
|
}
|
|
|
|
bool KeRefreshWinsockHooks(HMODULE moduleHandle) noexcept
|
|
{
|
|
if (!g_HooksInstalled)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return PatchLoadedModules(true, moduleHandle);
|
|
}
|
|
|
|
void KeRemoveWinsockHook() noexcept
|
|
{
|
|
if (!g_HooksInstalled)
|
|
{
|
|
g_ActiveCallback = nullptr;
|
|
return;
|
|
}
|
|
|
|
(void)PatchLoadedModules(false);
|
|
|
|
g_ActiveCallback = nullptr;
|
|
g_HooksInstalled = false;
|
|
g_PatchedSlotCount = 0;
|
|
}
|
|
|
|
bool KeCheckWinsockHookIntegrity(std::uint32_t *mismatchCount) noexcept
|
|
{
|
|
std::uint32_t mismatches = 0;
|
|
|
|
if (g_HooksInstalled)
|
|
{
|
|
for (std::size_t i = 0; i < g_PatchedSlotCount; ++i)
|
|
{
|
|
ULONG_PTR *slot = g_PatchedSlots[i].Slot;
|
|
void *expectedHook = g_PatchedSlots[i].HookFunction;
|
|
if (slot == nullptr || expectedHook == nullptr)
|
|
{
|
|
++mismatches;
|
|
continue;
|
|
}
|
|
|
|
if (*slot != reinterpret_cast<ULONG_PTR>(expectedHook))
|
|
{
|
|
++mismatches;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mismatchCount != nullptr)
|
|
{
|
|
*mismatchCount = mismatches;
|
|
}
|
|
|
|
return mismatches == 0;
|
|
}
|