mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-11-23 13:55:36 +08:00
323 lines
9.1 KiB
C++
323 lines
9.1 KiB
C++
|
|
#include "MinHook.h"
|
|
void HIJACK();
|
|
void detachall();
|
|
HMODULE hLUNAHOOKDLL;
|
|
WinMutex viewMutex;
|
|
EmbedSharedMem *embedsharedmem;
|
|
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);
|
|
|
|
ConsoleOutput(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_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(ThreadParam tp, TextOutput_T*buffer, int len)
|
|
{
|
|
buffer->tp=tp;
|
|
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);
|
|
}
|
|
|
|
void NotifyHookFound(HookParam hp,wchar_t*text)
|
|
{
|
|
wcscpy_s(hp.hookcode,HOOKCODE_LEN, HookCode::Generate(hp, GetCurrentProcessId()).c_str());
|
|
HookFoundNotif buffer(hp, text);
|
|
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
|
}
|
|
void NotifyHookRemove(uint64_t addr, LPCSTR name)
|
|
{
|
|
if (name) ConsoleOutput(REMOVING_HOOK, name);
|
|
HookRemovedNotif buffer(addr);
|
|
WriteFile(hookPipe, &buffer, sizeof(buffer), DUMMY, nullptr);
|
|
}
|
|
void NotifyHookInserting(uint64_t addr)
|
|
{
|
|
HookInsertingNotif buffer(addr);
|
|
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);
|
|
};
|
|
createfm(mappedFile,(void**)&hooks,MAX_HOOK * sizeof(TextHook),ITH_SECTION_ + std::to_wstring(GetCurrentProcessId()));
|
|
createfm(mappedFile3,(void**)&embedsharedmem, sizeof(EmbedSharedMem),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( );
|
|
UnmapViewOfFile(hooks);
|
|
UnmapViewOfFile(embedsharedmem);
|
|
}
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
int HookStrLen(HookParam* hp,BYTE* data){
|
|
if(data==0)return 0;
|
|
|
|
if(hp->type&CODEC_UTF16)
|
|
return wcslen((wchar_t*)data)*2;
|
|
else if(hp->type&CODEC_UTF32)
|
|
return u32strlen((uint32_t*)data)*4;
|
|
else
|
|
return strlen((char*)data);
|
|
|
|
}
|
|
static std::mutex maplock;
|
|
void jitaddraddr(uintptr_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(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(InsertHookFailed,WideStringToString(hp.hookcode).c_str());
|
|
(*hooks)[currentHook].Clear();
|
|
return false;
|
|
}
|
|
else{
|
|
NotifyHookInserting(hp.address);
|
|
return true;
|
|
}
|
|
}
|
|
static std::mutex delayinsertlock;
|
|
void delayinsertadd(HookParam hp,std::string name){
|
|
std::lock_guard _(maplock);
|
|
delayinserthook[hp.emu_addr]={name,hp};
|
|
ConsoleOutput(INSERTING_HOOK, name.c_str(),hp.emu_addr);
|
|
}
|
|
void delayinsertNewHook(uintptr_t em_address){
|
|
if(delayinserthook.find(em_address)==delayinserthook.end())return;
|
|
std::lock_guard _(maplock);
|
|
auto h=delayinserthook[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.unityfunctioninfo,":");
|
|
if(spls.size()!=5){
|
|
ConsoleOutput("invalid");
|
|
return false;
|
|
}
|
|
hp.address = tryfindmonoil2cpp(spls[0].c_str(),spls[1].c_str() ,spls[2].c_str(),spls[3].c_str(),std::stoi(spls[4]));
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
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
|
|
}
|
|
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
|
|
}
|