LunaHook-mirror/LunaHook/main.cc

396 lines
11 KiB
C++
Raw Normal View History

2024-02-07 20:59:24 +08:00
#include "MinHook.h"
2024-05-06 23:30:27 +08:00
void HIJACK();
2024-02-07 20:59:24 +08:00
void detachall();
HMODULE hLUNAHOOKDLL;
WinMutex viewMutex;
EmbedSharedMem *embedsharedmem;
namespace
{
2024-07-21 21:04:12 +08:00
AutoHandle<> hookPipe = INVALID_HANDLE_VALUE,
mappedFile = INVALID_HANDLE_VALUE,
mappedFile3 = INVALID_HANDLE_VALUE;
TextHook (*hooks)[MAX_HOOK];
2024-02-07 20:59:24 +08:00
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;
2024-07-21 21:04:12 +08:00
2024-02-07 20:59:24 +08:00
while (!hostPipe || !hookPipe)
{
// WinMutex connectionMutex(CONNECTING_MUTEX, &allAccess);
// std::scoped_lock lock(connectionMutex);
2024-07-21 21:04:12 +08:00
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);
2024-02-07 20:59:24 +08:00
}
DWORD mode = PIPE_READMODE_MESSAGE;
SetNamedPipeHandleState(hostPipe, &mode, NULL, NULL);
2024-07-21 21:04:12 +08:00
*(DWORD *)buffer = GetCurrentProcessId();
2024-02-07 20:59:24 +08:00
WriteFile(hookPipe, buffer, sizeof(DWORD), &count, nullptr);
ConsoleOutput(PIPE_CONNECTED);
2024-05-06 23:30:27 +08:00
HIJACK();
2024-07-21 21:04:12 +08:00
host_connected = true;
2024-02-07 20:59:24 +08:00
while (running && ReadFile(hostPipe, buffer, PIPE_BUFFER_SIZE, &count, nullptr))
2024-07-21 21:04:12 +08:00
switch (*(HostCommandType *)buffer)
2024-02-07 20:59:24 +08:00
{
case HOST_COMMAND_NEW_HOOK:
{
2024-07-21 21:04:12 +08:00
auto info = *(InsertHookCmd *)buffer;
2024-02-07 20:59:24 +08:00
static int userHooks = 0;
NewHook(info.hp, ("UserHook" + std::to_string(userHooks += 1)).c_str());
}
break;
case HOST_COMMAND_REMOVE_HOOK:
{
2024-07-21 21:04:12 +08:00
auto info = *(RemoveHookCmd *)buffer;
2024-02-07 20:59:24 +08:00
RemoveHook(info.address, 0);
}
break;
case HOST_COMMAND_FIND_HOOK:
{
2024-07-21 21:04:12 +08:00
auto info = *(FindHookCmd *)buffer;
if (*info.sp.text)
SearchForText(info.sp.text, info.sp.codepage);
else
SearchForHooks(info.sp);
2024-02-07 20:59:24 +08:00
}
break;
case HOST_COMMAND_DETACH:
{
running = false;
}
break;
}
}
2024-05-11 23:25:20 +08:00
2024-07-21 21:04:12 +08:00
if (dont_detach)
{
host_connected = false;
2024-02-07 20:59:24 +08:00
return Pipe(0);
2024-07-21 21:04:12 +08:00
}
else
{
2024-02-07 20:59:24 +08:00
MH_Uninitialize();
2024-07-21 21:04:12 +08:00
for (auto &hook : *hooks)
hook.Clear();
2024-02-07 20:59:24 +08:00
FreeLibraryAndExitThread(GetModuleHandleW(LUNA_HOOK_DLL), 0);
}
}
2024-07-21 21:04:12 +08:00
void TextOutput(const ThreadParam &tp, const HookParam &hp, TextOutput_T *buffer, int len)
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
memcpy(&buffer->tp, &tp, sizeof(tp));
memcpy(&buffer->hp, &hp, sizeof(hp));
2024-02-07 20:59:24 +08:00
WriteFile(hookPipe, buffer, sizeof(TextOutput_T) + len, DUMMY, nullptr);
}
void ConsoleOutput(LPCSTR text, ...)
{
ConsoleOutputNotif buffer;
va_list args;
va_start(args, text);
vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
2024-10-03 14:53:59 +08:00
void WarningOutput(LPCSTR text, ...)
{
WarningNotif buffer;
va_list args;
va_start(args, text);
vsnprintf(buffer.message, MESSAGE_SIZE, text, args);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
2024-09-09 21:46:53 +08:00
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];
}
2024-07-21 21:04:12 +08:00
void NotifyHookFound(HookParam hp, wchar_t *text)
2024-02-07 20:59:24 +08:00
{
2024-07-26 19:30:04 +08:00
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)))
{
2024-09-09 21:46:53 +08:00
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);
}
2024-07-26 19:30:04 +08:00
}
2024-02-07 20:59:24 +08:00
HookFoundNotif buffer(hp, text);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
void NotifyHookRemove(uint64_t addr, LPCSTR name)
{
2024-07-21 21:04:12 +08:00
if (name)
ConsoleOutput(REMOVING_HOOK, name);
2024-02-07 20:59:24 +08:00
HookRemovedNotif buffer(addr);
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
2024-07-21 21:04:12 +08:00
void NotifyHookInserting(uint64_t addr, wchar_t hookcode[])
2024-02-07 20:59:24 +08:00
{
HookInsertingNotif buffer(addr);
2024-07-21 21:04:12 +08:00
wcscpy(buffer.hookcode, hookcode);
2024-02-07 20:59:24 +08:00
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
}
BOOL WINAPI DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID)
{
2024-07-21 21:04:12 +08:00
switch (fdwReason)
2024-02-07 20:59:24 +08:00
{
case DLL_PROCESS_ATTACH:
{
2024-07-21 21:04:12 +08:00
hLUNAHOOKDLL = hModule;
2024-02-07 20:59:24 +08:00
viewMutex = WinMutex(ITH_HOOKMAN_MUTEX_ + std::to_wstring(GetCurrentProcessId()), &allAccess);
2024-07-21 21:04:12 +08:00
if (GetLastError() == ERROR_ALREADY_EXISTS)
return FALSE;
2024-02-07 20:59:24 +08:00
DisableThreadLibraryCalls(hModule);
2024-07-21 21:04:12 +08:00
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);
2024-02-07 20:59:24 +08:00
memset(*ptr, 0, sz);
};
2024-07-21 21:04:12 +08:00
hooks = (decltype(hooks))new TextHook[MAX_HOOK];
VirtualProtect((LPVOID)hooks, sizeof(TextHook) * MAX_HOOK, PAGE_EXECUTE_READWRITE, DUMMY);
createfm(mappedFile3, (void **)&embedsharedmem, sizeof(EmbedSharedMem), EMBED_SHARED_MEM + std::to_wstring(GetCurrentProcessId()));
2024-02-07 20:59:24 +08:00
MH_Initialize();
CloseHandle(CreateThread(nullptr, 0, Pipe, nullptr, 0, nullptr)); // Using std::thread here = deadlock
2024-07-21 21:04:12 +08:00
}
2024-02-07 20:59:24 +08:00
break;
case DLL_PROCESS_DETACH:
{
MH_Uninitialize();
2024-07-21 21:04:12 +08:00
detachall();
delete[] hooks;
2024-02-07 20:59:24 +08:00
UnmapViewOfFile(embedsharedmem);
}
break;
}
return TRUE;
}
2024-07-21 21:04:12 +08:00
int HookStrLen(HookParam *hp, BYTE *data)
{
if (data == 0)
return 0;
2024-07-21 21:04:12 +08:00
if (hp->type & CODEC_UTF16)
return wcsnlen((wchar_t *)data, TEXT_BUFFER_SIZE) * 2;
else if (hp->type & CODEC_UTF32)
return u32strlen((uint32_t *)data) * 4;
else
2024-07-21 21:04:12 +08:00
return strnlen((char *)data, TEXT_BUFFER_SIZE);
}
static std::mutex maplock;
2024-07-21 21:04:12 +08:00
void jitaddraddr(uintptr_t em_addr, uintptr_t jitaddr, JITTYPE jittype)
{
std::lock_guard _(maplock);
2024-07-21 21:04:12 +08:00
emuaddr2jitaddr[em_addr] = {jittype, jitaddr};
jitaddr2emuaddr[jitaddr] = {jittype, em_addr};
}
2024-07-21 21:04:12 +08:00
bool NewHook_1(HookParam &hp, LPCSTR lpname)
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
if (hp.emu_addr)
ConsoleOutput("%p => %p", hp.emu_addr, hp.address);
2024-07-21 21:04:12 +08:00
if (++currentHook >= MAX_HOOK)
{
2024-02-07 20:59:24 +08:00
ConsoleOutput(TOO_MANY_HOOKS);
return false;
}
2024-07-21 21:04:12 +08:00
if (lpname && *lpname)
strncpy_s(hp.name, lpname, HOOK_NAME_SIZE - 1);
2024-07-21 21:04:12 +08:00
wcscpy_s(hp.hookcode, HOOKCODE_LEN, HookCode::Generate(hp, GetCurrentProcessId()).c_str());
2024-02-07 20:59:24 +08:00
if (!(*hooks)[currentHook].Insert(hp))
{
2024-07-21 21:04:12 +08:00
ConsoleOutput(InsertHookFailed, WideStringToString(hp.hookcode).c_str());
2024-02-07 20:59:24 +08:00
(*hooks)[currentHook].Clear();
return false;
}
2024-07-21 21:04:12 +08:00
else
{
NotifyHookInserting(hp.address, hp.hookcode);
2024-02-07 20:59:24 +08:00
return true;
}
}
2024-04-01 13:56:20 +08:00
static std::mutex delayinsertlock;
2024-07-21 21:04:12 +08:00
void delayinsertadd(HookParam hp, std::string name)
{
2024-04-01 13:56:20 +08:00
std::lock_guard _(maplock);
2024-07-21 21:04:12 +08:00
delayinserthook[hp.emu_addr] = {name, hp};
ConsoleOutput(INSERTING_HOOK, name.c_str(), hp.emu_addr);
2024-04-01 13:56:20 +08:00
}
2024-07-21 21:04:12 +08:00
void delayinsertNewHook(uintptr_t em_address)
{
if (delayinserthook.find(em_address) == delayinserthook.end())
return;
2024-04-01 13:56:20 +08:00
std::lock_guard _(maplock);
2024-07-21 21:04:12 +08:00
auto h = delayinserthook[em_address];
2024-04-01 13:56:20 +08:00
delayinserthook.erase(em_address);
2024-07-21 21:04:12 +08:00
NewHook(h.second, h.first.c_str());
2024-04-01 13:56:20 +08:00
}
2024-07-21 21:04:12 +08:00
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.unityfunctioninfo, ":");
if (spls.size() != 5)
{
2024-05-09 15:30:31 +08:00
ConsoleOutput("invalid");
return false;
}
2024-09-14 11:09:51 +08:00
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);
2024-07-21 21:04:12 +08:00
if (!hp.address)
{
2024-05-09 15:30:31 +08:00
ConsoleOutput("not find");
2024-05-09 07:23:06 +08:00
return false;
2024-05-09 15:30:31 +08:00
}
2024-07-21 21:04:12 +08:00
return NewHook_1(hp, name);
2024-05-09 07:23:06 +08:00
}
2024-07-21 21:04:12 +08:00
// 下面的是手动插入
if (emuaddr2jitaddr.find(hp.emu_addr) == emuaddr2jitaddr.end())
{
delayinsertadd(hp, name);
2024-04-01 13:56:20 +08:00
return true;
2024-04-01 13:42:59 +08:00
}
2024-07-21 21:04:12 +08:00
strcpy(hp.function, "");
wcscpy(hp.module, L"");
hp.type &= ~MODULE_OFFSET;
2024-04-01 13:56:20 +08:00
2024-07-21 21:04:12 +08:00
hp.address = emuaddr2jitaddr[hp.emu_addr].second;
hp.jittype = emuaddr2jitaddr[hp.emu_addr].first;
return NewHook_1(hp, name);
}
2024-02-07 20:59:24 +08:00
void RemoveHook(uint64_t addr, int maxOffset)
{
2024-07-21 21:04:12 +08:00
for (auto &hook : *hooks)
if (abs((long long)(hook.address - addr)) <= maxOffset)
return hook.Clear();
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
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);
2024-02-07 20:59:24 +08:00
GlobalFree(m_hMem);
2024-07-21 21:04:12 +08:00
FreeResource(lpRsrc);
2024-02-07 20:59:24 +08:00
return data;
2024-07-21 21:04:12 +08:00
}
2024-07-21 21:04:12 +08:00
void context_get(hook_stack *stack, PCONTEXT context)
{
#ifndef _WIN64
stack->eax = context->Eax;
stack->ecx = context->Ecx;
stack->edx = context->Edx;
stack->ebx = context->Ebx;
stack->esp = context->Esp;
stack->ebp = context->Ebp;
stack->esi = context->Esi;
stack->edi = context->Edi;
stack->eflags = context->EFlags;
stack->retaddr = *(DWORD *)context->Esp;
#else
stack->rax = context->Rax;
stack->rbx = context->Rbx;
stack->rcx = context->Rcx;
stack->rdx = context->Rdx;
stack->rsp = context->Rsp;
stack->rbp = context->Rbp;
stack->rsi = context->Rsi;
stack->rdi = context->Rdi;
stack->r8 = context->R8;
stack->r9 = context->R9;
stack->r10 = context->R10;
stack->r11 = context->R11;
stack->r12 = context->R12;
stack->r13 = context->R13;
stack->r14 = context->R14;
stack->r15 = context->R15;
stack->eflags = context->EFlags;
stack->retaddr = *(DWORD64 *)context->Rsp;
#endif
}
2024-07-21 21:04:12 +08:00
void context_set(hook_stack *stack, PCONTEXT context)
{
#ifndef _WIN64
context->Eax = stack->eax;
context->Ecx = stack->ecx;
context->Edx = stack->edx;
context->Ebx = stack->ebx;
context->Esp = stack->esp;
context->Ebp = stack->ebp;
context->Esi = stack->esi;
context->Edi = stack->edi;
context->EFlags = stack->eflags;
#else
context->Rax = stack->rax;
context->Rbx = stack->rbx;
context->Rcx = stack->rcx;
context->Rdx = stack->rdx;
context->Rsp = stack->rsp;
context->Rbp = stack->rbp;
context->Rsi = stack->rsi;
context->Rdi = stack->rdi;
context->R8 = stack->r8;
context->R9 = stack->r9;
context->R10 = stack->r10;
context->R11 = stack->r11;
context->R12 = stack->r12;
context->R13 = stack->r13;
context->R14 = stack->r14;
context->R15 = stack->r15;
context->EFlags = stack->eflags;
#endif
}