恍兮惚兮 dc7eaafcc7 .
2024-12-16 15:48:47 +08:00

343 lines
9.6 KiB
C++

#include "MinHook.h"
void HIJACK();
void detachall();
std::unordered_map<uint64_t, std::pair<JITTYPE, uintptr_t>> emuaddr2jitaddr;
std::unordered_map<uintptr_t, std::pair<JITTYPE, uint64_t>> jitaddr2emuaddr;
HMODULE hLUNAHOOKDLL;
WinMutex viewMutex;
CommonSharedMem *commonsharedmem;
Synchronized<std::map<uint64_t, std::pair<std::string, HookParam>>> delayinserthook;
namespace
{
AutoHandle<> hookPipe = INVALID_HANDLE_VALUE,
mappedFile = INVALID_HANDLE_VALUE,
mappedFile3 = INVALID_HANDLE_VALUE;
TextHook (*hooks)[MAX_HOOK];
int currentHook = 0;
}
DWORD WINAPI Pipe(LPVOID)
{
for (bool running = true; running; hookPipe = INVALID_HANDLE_VALUE)
{
DWORD count = 0;
BYTE buffer[PIPE_BUFFER_SIZE] = {};
AutoHandle<> hostPipe = INVALID_HANDLE_VALUE;
while (!hostPipe || !hookPipe)
{
// WinMutex connectionMutex(CONNECTING_MUTEX, &allAccess);
// std::scoped_lock lock(connectionMutex);
WaitForSingleObject(AutoHandle<>(CreateEventW(&allAccess, FALSE, FALSE, (std::wstring(PIPE_AVAILABLE_EVENT) + std::to_wstring(GetCurrentProcessId())).c_str())), INFINITE);
hostPipe = CreateFileW((std::wstring(HOST_PIPE) + std::to_wstring(GetCurrentProcessId())).c_str(), GENERIC_READ | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
hookPipe = CreateFileW((std::wstring(HOOK_PIPE) + std::to_wstring(GetCurrentProcessId())).c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
}
DWORD mode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
*(DWORD *)buffer = GetCurrentProcessId();
WriteFile(hookPipe, buffer, sizeof(DWORD), &count, nullptr);
WriteFile(hookPipe, LUNA_VERSION, sizeof(LUNA_VERSION), &count, nullptr);
ReadFile(hostPipe, &curr_lang, sizeof(SUPPORT_LANG), &count, nullptr);
ConsoleOutput(TR[PIPE_CONNECTED]);
HIJACK();
host_connected = true;
while (running && ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE, &count, nullptr))
switch (*(HostCommandType *)buffer)
{
case HOST_COMMAND_NEW_HOOK:
{
auto info = *(InsertHookCmd *)buffer;
static int userHooks = 0;
NewHook(info.hp, ("UserHook" + std::to_string(userHooks += 1)).c_str());
}
break;
case HOST_COMMAND_INSERT_PC_HOOKS:
{
auto info = *(InsertPCHooksCmd *)buffer;
if (info.which == 0)
PcHooks::hookGdiGdiplusD3dxFunctions();
else if (info.which == 1)
PcHooks::hookOtherPcFunctions();
}
break;
case HOST_COMMAND_SET_LANGUAGE:
{
auto info = *(SetLanguageCmd *)buffer;
curr_lang = info.lang;
}
break;
case HOST_COMMAND_REMOVE_HOOK:
{
auto info = *(RemoveHookCmd *)buffer;
RemoveHook(info.address, 0);
}
break;
case HOST_COMMAND_FIND_HOOK:
{
auto info = *(FindHookCmd *)buffer;
if (*info.sp.text)
SearchForText(info.sp.text, info.sp.codepage);
else
SearchForHooks(info.sp);
}
break;
case HOST_COMMAND_DETACH:
{
running = false;
}
break;
}
}
if (dont_detach)
{
host_connected = false;
return Pipe(0);
}
else
{
MH_Uninitialize();
for (auto &hook : *hooks)
hook.Clear();
FreeLibraryAndExitThread(GetModuleHandleW(LUNA_HOOK_DLL), 0);
}
}
void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T *buffer, int len)
{
memcpy(&buffer->tp, &tp, sizeof(tp));
memcpy(&buffer->hp, &hp, sizeof(hp));
WriteFile(hookPipe, buffer, sizeof(TextOutput_T) + len, DUMMY, nullptr);
}
void HostInfo(HOSTINFO type, LPCSTR text, ...)
{
HostInfoNotif buffer;
va_list args;
va_start(args, text);
buffer.type = type;
vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
Synchronized<std::unordered_map<uintptr_t, std::wstring>> modulecache;
std::wstring &querymodule(uintptr_t addr)
{
auto &re = modulecache.Acquire().contents;
if (re.find(addr) != re.end())
return re.at(addr);
WCHAR fn[MAX_PATH];
if (GetModuleFileNameW((HMODULE)addr, fn, MAX_PATH))
{
re[addr] = wcsrchr(fn, L'\\') + 1;
}
else
{
re[addr] = L"";
}
return re[addr];
}
void NotifyHookFound(HookParam hp, wchar_t *text)
{
if (hp.jittype == JITTYPE::PC)
if (!(hp.type & MODULE_OFFSET))
if (AutoHandle<> process = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()))
if (MEMORY_BASIC_INFORMATION info = {}; VirtualQueryEx(process, (LPCVOID)hp.address, &info, sizeof(info)))
{
auto mm = querymodule((uintptr_t)info.AllocationBase);
if (mm.size())
{
hp.type |= MODULE_OFFSET;
hp.address -= (uint64_t)info.AllocationBase;
wcsncpy_s(hp.module, mm.c_str(), MAX_MODULE_SIZE - 1);
}
}
HookFoundNotif buffer(hp, text);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
void NotifyHookRemove(uint64_t addr, LPCSTR name)
{
if (name)
ConsoleOutput(TR[REMOVING_HOOK], name);
HookRemovedNotif buffer(addr);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
void NotifyHookInserting(uint64_t addr, wchar_t hookcode[])
{
HookInsertingNotif buffer(addr);
wcscpy(buffer.hookcode, hookcode);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
{
hLUNAHOOKDLL = hModule;
viewMutex = WinMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(GetCurrentProcessId()), &allAccess);
if (GetLastError() == ERROR_ALREADY_EXISTS)
return FALSE;
DisableThreadLibraryCalls(hModule);
auto createfm = [](AutoHandle<> &handle, void **ptr, DWORD sz, std::wstring &name)
{
handle = CreateFileMappingW(INVALID_HANDLE_VALUE, &allAccess, PAGE_EXECUTE_READWRITE, 0, sz, (name).c_str());
*ptr = MapViewOfFile(handle, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, sz);
memset(*ptr, 0, sz);
};
hooks = (decltype(hooks))new TextHook[MAX_HOOK];
VirtualProtect((LPVOID)hooks, sizeof(TextHook) * MAX_HOOK, PAGE_EXECUTE_READWRITE, DUMMY);
createfm(mappedFile3, (void **)&commonsharedmem, sizeof(CommonSharedMem), EMBED_SHARED_MEM + std::to_wstring(GetCurrentProcessId()));
MH_Initialize();
CloseHandle(CreateThread(nullptr, 0, Pipe, nullptr, 0, nullptr)); // Using std::thread here = deadlock
}
break;
case DLL_PROCESS_DETACH:
{
MH_Uninitialize();
detachall();
delete[] hooks;
UnmapViewOfFile(commonsharedmem);
}
break;
}
return TRUE;
}
int HookStrLen(HookParam *hp, BYTE *data)
{
if (data == 0)
return 0;
if (hp->type & CODEC_UTF16)
return wcsnlen((wchar_t *)data, TEXT_BUFFER_SIZE) * 2;
else if (hp->type & CODEC_UTF32)
return strlenEx((uint32_t *)data) * 4;
else
return strnlen((char *)data, TEXT_BUFFER_SIZE);
}
static std::mutex maplock;
void jitaddrclear()
{
std::lock_guard _(maplock);
emuaddr2jitaddr.clear();
jitaddr2emuaddr.clear();
}
void jitaddraddr(uint64_t em_addr, uintptr_t jitaddr, JITTYPE jittype)
{
std::lock_guard _(maplock);
emuaddr2jitaddr[em_addr] = {jittype, jitaddr};
jitaddr2emuaddr[jitaddr] = {jittype, em_addr};
}
bool NewHook_1(HookParam &hp, LPCSTR lpname)
{
if (hp.emu_addr)
ConsoleOutput("%p => %p", hp.emu_addr, hp.address);
if (++currentHook >= MAX_HOOK)
{
ConsoleOutput(TR[TOO_MANY_HOOKS]);
return false;
}
if (lpname && *lpname)
strncpy_s(hp.name, lpname, HOOK_NAME_SIZE - 1);
wcscpy_s(hp.hookcode, HOOKCODE_LEN, HookCode::Generate(hp, GetCurrentProcessId()).c_str());
if (!(*hooks)[currentHook].Insert(hp))
{
ConsoleOutput(TR[InsertHookFailed], WideStringToString(hp.hookcode).c_str());
(*hooks)[currentHook].Clear();
return false;
}
else
{
NotifyHookInserting(hp.address, hp.hookcode);
return true;
}
}
void delayinsertadd(HookParam hp, std::string name)
{
delayinserthook->insert(std::make_pair(hp.emu_addr, std::make_pair(name, hp)));
ConsoleOutput(TR[INSERTING_HOOK], name.c_str(), hp.emu_addr);
}
void delayinsertNewHook(uint64_t em_address)
{
auto &&_delayinserthook = delayinserthook.Acquire();
if (_delayinserthook->find(em_address) == _delayinserthook->end())
return;
auto h = _delayinserthook->at(em_address);
_delayinserthook->erase(em_address);
NewHook(h.second, h.first.c_str());
}
bool NewHook(HookParam hp, LPCSTR name)
{
if (hp.address || hp.jittype == JITTYPE::PC)
return NewHook_1(hp, name);
if (hp.jittype == JITTYPE::UNITY)
{
auto spls = strSplit(hp.function, ":");
if (spls.size() != 5)
{
ConsoleOutput("invalid");
return false;
}
int argcount;
try
{
argcount = std::stoi(spls[4]);
}
catch (...)
{
argcount = -1;
}
hp.address = tryfindmonoil2cpp(spls[0].c_str(), spls[1].c_str(), spls[2].c_str(), spls[3].c_str(), argcount);
if (!hp.address)
{
ConsoleOutput("not find");
return false;
}
return NewHook_1(hp, name);
}
// 下面的是手动插入
if (emuaddr2jitaddr.find(hp.emu_addr) == emuaddr2jitaddr.end())
{
delayinsertadd(hp, name);
return true;
}
strcpy(hp.function, "");
wcscpy(hp.module, L"");
hp.type &= ~MODULE_OFFSET;
hp.address = emuaddr2jitaddr[hp.emu_addr].second;
hp.jittype = emuaddr2jitaddr[hp.emu_addr].first;
return NewHook_1(hp, name);
}
void RemoveHook(uint64_t addr, int maxOffset)
{
for (auto &hook : *hooks)
if (abs((long long)(hook.address - addr)) <= maxOffset)
return hook.Clear();
}
std::string LoadResData(LPCWSTR pszResID, LPCWSTR _type)
{
HMODULE hModule = hLUNAHOOKDLL;
HRSRC hRsrc = ::FindResourceW(hModule, pszResID, _type);
if (!hRsrc)
return "";
DWORD len = SizeofResource(hModule, hRsrc);
BYTE *lpRsrc = (BYTE *)LoadResource(hModule, hRsrc);
if (!lpRsrc)
return "";
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
BYTE *pmem = (BYTE *)GlobalLock(m_hMem);
memcpy(pmem, lpRsrc, len);
auto data = std::string((char *)pmem, len);
GlobalUnlock(m_hMem);
GlobalFree(m_hMem);
FreeResource(lpRsrc);
return data;
}