mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-11-23 05:45:37 +08:00
breakpoint
Update texthook.cc Update texthook.cc Update veh_hook.cpp 1 1 Update veh_hook.cpp Update veh_hook.cpp 1 Update monocommon.hpp
This commit is contained in:
parent
a02f862e8e
commit
867ea55bdc
@ -23,6 +23,7 @@ set(texthook_src
|
||||
enginecontrol.cpp
|
||||
embed_util.cc
|
||||
hijackfuns.cc
|
||||
veh_hook.cpp
|
||||
)
|
||||
add_subdirectory(util)
|
||||
add_subdirectory(engines)
|
||||
|
@ -100,13 +100,13 @@ bool checkiscurrentgame(const emfuncinfo& em){
|
||||
template<int index>
|
||||
void simpleutf8getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto address=emu_arg(stack)[index];
|
||||
hp->type=USING_STRING|CODEC_UTF8|NO_CONTEXT;
|
||||
hp->type=USING_STRING|CODEC_UTF8|NO_CONTEXT|BREAK_POINT;
|
||||
*data=address;*len=strlen((char*)address);
|
||||
}
|
||||
template<int index,DWORD _type=0>
|
||||
void simpleutf16getter(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len){
|
||||
auto address=emu_arg(stack)[index];
|
||||
hp->type=USING_STRING|CODEC_UTF16|NO_CONTEXT|_type;
|
||||
hp->type=USING_STRING|CODEC_UTF16|NO_CONTEXT|BREAK_POINT|_type;
|
||||
*data=address;*len=wcslen((wchar_t*)address)*2;
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ bool yuzusuyu::attach_function()
|
||||
|
||||
HookParam hpinternal;
|
||||
hpinternal.address=entrypoint;
|
||||
hpinternal.type=CODEC_UTF16|USING_STRING|NO_CONTEXT;
|
||||
hpinternal.type=CODEC_UTF16|USING_STRING|NO_CONTEXT|BREAK_POINT;
|
||||
hpinternal.text_fun=(decltype(hpinternal.text_fun))op.hookfunc;
|
||||
hpinternal.filter_fun=(decltype(hpinternal.filter_fun))op.filterfun;
|
||||
NewHook(hpinternal,op.hookname);
|
||||
|
@ -11,6 +11,9 @@ std::unordered_set<uint64_t>inserted_addr;
|
||||
void NewHook_check(HookParam& hp,LPCSTR n){
|
||||
std::lock_guard _(mutex);
|
||||
if(inserted_addr.find(hp.address)==inserted_addr.end()){
|
||||
#ifdef _WIN64
|
||||
hp.type|=BREAK_POINT;
|
||||
#endif
|
||||
NewHook(hp,n);
|
||||
inserted_addr.insert(hp.address);
|
||||
}
|
||||
|
@ -169,8 +169,7 @@ bool NewHook(HookParam hp, LPCSTR lpname)
|
||||
}
|
||||
if (lpname && *lpname) strncpy_s(hp.name, lpname, HOOK_NAME_SIZE - 1);
|
||||
ConsoleOutput(INSERTING_HOOK, hp.name);
|
||||
RemoveHook(hp.address, 0);
|
||||
|
||||
|
||||
wcscpy_s(hp.hookcode,HOOKCODE_LEN,HookCode::Generate(hp, GetCurrentProcessId()).c_str());
|
||||
if (!(*hooks)[currentHook].Insert(hp))
|
||||
{
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "ithsys/ithsys.h"
|
||||
#include "MinHook.h"
|
||||
#include"Lang/Lang.h"
|
||||
#include"veh_hook.h"
|
||||
extern WinMutex viewMutex;
|
||||
|
||||
// - Unnamed helpers -
|
||||
@ -94,15 +95,39 @@ namespace { // unnamed
|
||||
|
||||
// - TextHook methods -
|
||||
|
||||
uintptr_t getasbaddr(const HookParam &hp){
|
||||
auto address=hp.address;
|
||||
if (hp.type & MODULE_OFFSET)
|
||||
{
|
||||
if (hp.type & FUNCTION_OFFSET)
|
||||
{
|
||||
if (FARPROC function = GetProcAddress(GetModuleHandleW(hp.module), hp.function)) address += (uint64_t)function;
|
||||
else return ConsoleOutput(FUNC_MISSING), false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HMODULE moduleBase = GetModuleHandleW(hp.module)) address += (uint64_t)moduleBase;
|
||||
else return ConsoleOutput(MODULE_MISSING), false;
|
||||
}
|
||||
}
|
||||
return address;
|
||||
}
|
||||
bool TextHook::Insert(HookParam hp)
|
||||
{
|
||||
|
||||
auto addr=getasbaddr(hp);
|
||||
RemoveHook(addr, 0);
|
||||
|
||||
local_buffer=new BYTE[PIPE_BUFFER_SIZE];
|
||||
{
|
||||
std::scoped_lock lock(viewMutex);
|
||||
this->hp = hp;
|
||||
address = hp.address;
|
||||
address = addr;
|
||||
}
|
||||
|
||||
|
||||
if (hp.type & DIRECT_READ) return InsertReadCode();
|
||||
if (hp.type & BREAK_POINT) return InsertBreakPoint();
|
||||
return InsertHookCode();
|
||||
}
|
||||
|
||||
@ -248,17 +273,61 @@ void TextHook::Send(uintptr_t lpDataBase)
|
||||
|
||||
_InterlockedDecrement((long*) & useCount);
|
||||
}
|
||||
void TextHook::breakpointcontext(PCONTEXT context){
|
||||
#ifdef _WIN64
|
||||
auto stack=new hook_stack;
|
||||
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;
|
||||
auto lpDataBase=(uintptr_t)stack+sizeof(hook_stack)-sizeof(uintptr_t);
|
||||
Send(lpDataBase);
|
||||
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
|
||||
}
|
||||
bool TextHook::InsertBreakPoint()
|
||||
{
|
||||
//MH_CreateHook 64位unity/yuzu-emu经常 MH_ERROR_MEMORY_ALLOC
|
||||
return add_veh_hook(location,std::bind(&TextHook::breakpointcontext,this,std::placeholders::_1), 0);
|
||||
}
|
||||
bool TextHook::RemoveBreakPoint()
|
||||
{
|
||||
return remove_veh_hook(location);
|
||||
}
|
||||
bool TextHook::InsertHookCode()
|
||||
{
|
||||
// jichi 9/17/2013: might raise 0xC0000005 AccessViolationException on win7
|
||||
// Artikash 10/30/2018: No, I think that's impossible now that I moved to minhook
|
||||
if (hp.type & MODULE_OFFSET) // Map hook offset to real address
|
||||
if (hp.type & FUNCTION_OFFSET)
|
||||
if (FARPROC function = GetProcAddress(GetModuleHandleW(hp.module), hp.function)) address += (uint64_t)function;
|
||||
else return ConsoleOutput(FUNC_MISSING), false;
|
||||
else if (HMODULE moduleBase = GetModuleHandleW(hp.module)) address += (uint64_t)moduleBase;
|
||||
else return ConsoleOutput(MODULE_MISSING), false;
|
||||
|
||||
|
||||
VirtualProtect(location, 10, PAGE_EXECUTE_READWRITE, DUMMY);
|
||||
void* original;
|
||||
@ -326,6 +395,7 @@ void TextHook::Clear()
|
||||
{
|
||||
if (address == 0) return;
|
||||
if (hp.type & DIRECT_READ) RemoveReadCode();
|
||||
if (hp.type & BREAK_POINT) RemoveBreakPoint();
|
||||
else RemoveHookCode();
|
||||
NotifyHookRemove(address, hp.name);
|
||||
std::scoped_lock lock(viewMutex);
|
||||
|
176
LunaHook/veh_hook.cpp
Normal file
176
LunaHook/veh_hook.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
/**
|
||||
veh_hook Vectored Exception Handler hooking library
|
||||
Version: 24-March-2008
|
||||
**/
|
||||
// #define WINVER 0x0501
|
||||
// #define _WIN32_WINNT 0x0501
|
||||
#include <windows.h>
|
||||
#include "veh_hook.h"
|
||||
#include<mutex>
|
||||
static veh_list_t* list = NULL;
|
||||
char int3bp[] = "\xCC";
|
||||
std::mutex vehlistlock;
|
||||
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type)
|
||||
{
|
||||
std::lock_guard _(vehlistlock);
|
||||
//static veh_list_t* list = NULL;
|
||||
DWORD oldProtect;
|
||||
if (list == NULL) list = new_veh_list();
|
||||
if (list == NULL) return false;
|
||||
void* handle = AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)veh_dispatch);
|
||||
veh_node_t* newnode = insert_veh_node(list, origFunc, newFunc, handle, hook_type);
|
||||
|
||||
// For memory hooks especially, we need to know the address of the start of the relevant page.
|
||||
MEMORY_BASIC_INFORMATION mem_info;
|
||||
VirtualQuery(origFunc, &mem_info, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
newnode->baseAddr = mem_info.BaseAddress;
|
||||
|
||||
VirtualProtect(origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &newnode->OldProtect);
|
||||
memcpy((void*)(&newnode->origBaseByte), (const void*)origFunc, sizeof (BYTE));
|
||||
memcpy((void*)origFunc, (const void*)&int3bp, sizeof (BYTE));
|
||||
VirtualProtect(origFunc, sizeof(int), newnode->OldProtect, &oldProtect);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remove_veh_hook(void* origFunc)
|
||||
{
|
||||
std::lock_guard _(vehlistlock);
|
||||
if (list == NULL) return false;
|
||||
veh_node_t* node = get_veh_node(list, origFunc, true);
|
||||
if (node == NULL) return false;
|
||||
DWORD _p;
|
||||
VirtualProtect(node->origFunc, sizeof(int), PAGE_EXECUTE_READWRITE, &_p);
|
||||
memcpy((void*)node->origFunc, (const void*)(&node->origBaseByte), sizeof(char));
|
||||
VirtualProtect(node->origFunc, sizeof(int), node->OldProtect, &_p);
|
||||
RemoveVectoredExceptionHandler(node->handle);
|
||||
return remove_veh_node(list, origFunc);
|
||||
}
|
||||
|
||||
bool remove_veh_node(veh_list_t* list, void* origFunc)
|
||||
{
|
||||
veh_node_t* searchnode;
|
||||
veh_node_t* lastsearchnode = NULL;
|
||||
searchnode = list->head;
|
||||
|
||||
while (searchnode != NULL)
|
||||
{
|
||||
if (searchnode->origFunc == origFunc)
|
||||
{
|
||||
if (lastsearchnode == NULL)
|
||||
{
|
||||
list->head = searchnode->next;
|
||||
if (list->tail == searchnode) list->tail = searchnode->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastsearchnode->next = searchnode->next;
|
||||
}
|
||||
delete (searchnode);
|
||||
return true;
|
||||
}
|
||||
lastsearchnode = searchnode;
|
||||
searchnode = searchnode->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo)
|
||||
{
|
||||
|
||||
DWORD oldProtect;
|
||||
void* Addr = ExceptionInfo->ExceptionRecord->ExceptionAddress;
|
||||
ULONG Code = ExceptionInfo->ExceptionRecord->ExceptionCode;
|
||||
|
||||
if (Code != STATUS_BREAKPOINT && Code != STATUS_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH;
|
||||
// Try to find the node associated with the address of the current exception, continue searching for handlers if not found;
|
||||
veh_node_t* currnode ;
|
||||
{
|
||||
std::lock_guard _(vehlistlock);
|
||||
currnode = get_veh_node(list, Addr, false);
|
||||
}
|
||||
if (currnode == NULL) return EXCEPTION_CONTINUE_SEARCH;
|
||||
DWORD hooktype = currnode->hooktype;
|
||||
// Pre-callback functions:
|
||||
if (Code == STATUS_BREAKPOINT && hooktype == VEH_HK_INT3)
|
||||
{
|
||||
//(Temporarily) remove the int3 breakpoint
|
||||
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect);
|
||||
memcpy((void*)Addr, (const void*)(&currnode->origBaseByte), sizeof (char));
|
||||
currnode->newFunc(ExceptionInfo->ContextRecord);
|
||||
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect);
|
||||
ExceptionInfo->ContextRecord->EFlags |= 0x100;
|
||||
}
|
||||
else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_INT3)
|
||||
{
|
||||
// Restore the INT3 breakpoint
|
||||
VirtualProtect(Addr, sizeof(int), PAGE_EXECUTE_READWRITE, &currnode->OldProtect);
|
||||
memcpy((void*)currnode->origFunc, (const void*)&int3bp, sizeof (BYTE));
|
||||
VirtualProtect(Addr, sizeof(int), currnode->OldProtect, &oldProtect);
|
||||
ExceptionInfo->ContextRecord->EFlags &= ~0x00000100; // Remove TRACE from EFLAGS
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_HW)
|
||||
{
|
||||
currnode->newFunc(ExceptionInfo->ContextRecord);
|
||||
}
|
||||
else if (Code == STATUS_SINGLE_STEP && hooktype == VEH_HK_MEM)
|
||||
{
|
||||
|
||||
currnode->newFunc(ExceptionInfo->ContextRecord);
|
||||
}
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
veh_list_t* new_veh_list()
|
||||
{
|
||||
veh_list_t* newlist = (veh_list_t*)malloc(sizeof(veh_list_t));
|
||||
if (newlist == NULL) return NULL;
|
||||
newlist->head = NULL;
|
||||
newlist->tail = NULL;
|
||||
return newlist;
|
||||
}
|
||||
veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type)
|
||||
{
|
||||
if (list == NULL) return NULL;
|
||||
/* create a new node and fill in the blanks */
|
||||
veh_node_t* newnode = new veh_node_t;
|
||||
if (newnode == NULL) return NULL;
|
||||
newnode->origFunc = origFunc;
|
||||
newnode->newFunc = newFunc;
|
||||
newnode->handle = handle;
|
||||
newnode->OldProtect = PAGE_EXECUTE_READWRITE;
|
||||
newnode->next = NULL;
|
||||
newnode->hooktype=hook_type;
|
||||
if (list->head == NULL)
|
||||
{
|
||||
list->head = newnode;
|
||||
list->tail = newnode;
|
||||
}
|
||||
else
|
||||
{
|
||||
list->tail->next = newnode;
|
||||
list->tail = newnode;
|
||||
}
|
||||
return newnode;
|
||||
}
|
||||
|
||||
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, bool exactmatch)
|
||||
{
|
||||
veh_node_t* newnode;
|
||||
veh_node_t* closestnode = NULL;
|
||||
if (list == NULL) return NULL;
|
||||
newnode = list->head;
|
||||
MEMORY_BASIC_INFORMATION mem_info;
|
||||
VirtualQuery(origFunc, &mem_info, sizeof(MEMORY_BASIC_INFORMATION));
|
||||
while (newnode != NULL)
|
||||
{
|
||||
|
||||
if (newnode->origFunc == origFunc)
|
||||
{
|
||||
return newnode;
|
||||
}
|
||||
if (!exactmatch) if (newnode->baseAddr == mem_info.BaseAddress) closestnode = newnode;
|
||||
newnode = newnode->next;
|
||||
}
|
||||
|
||||
return closestnode;
|
||||
}
|
57
LunaHook/veh_hook.h
Normal file
57
LunaHook/veh_hook.h
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
veh_hook Vectored Exception Handler hooking library
|
||||
Version: 24-March-2008
|
||||
**/
|
||||
|
||||
#ifndef LIST_T_H_INCLUDED
|
||||
#define LIST_T_H_INCLUDED
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include<functional>
|
||||
// VEH Hooking types
|
||||
#define VEH_HK_INT3 0
|
||||
#define VEH_HK_MEM 1
|
||||
#define VEH_HK_HW 2
|
||||
// -
|
||||
|
||||
#define OPCODE_INT3 "\xCC"
|
||||
|
||||
|
||||
//typedef void (*pfvoid)();
|
||||
//typedef void (*newFuncType)(PCONTEXT);
|
||||
using newFuncType = std::function<void(PCONTEXT)>;
|
||||
|
||||
typedef struct veh_node
|
||||
{
|
||||
void* origFunc;
|
||||
newFuncType newFunc;
|
||||
void* handle;
|
||||
DWORD hooktype;
|
||||
void* baseAddr; // Address of the page in which origFunc resides.
|
||||
BYTE origBaseByte;
|
||||
DWORD OldProtect;
|
||||
struct veh_node* next;
|
||||
} veh_node_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
veh_node_t* head;
|
||||
veh_node_t* tail;
|
||||
} veh_list_t;
|
||||
|
||||
// VEH hook interface functions for creating and removing hooks.
|
||||
bool add_veh_hook(void* origFunc, newFuncType newFunc, DWORD hook_type);
|
||||
bool remove_veh_hook(void* origFunc);
|
||||
|
||||
// The VEH dispathing function is called by Windows every time an exception is encountered.
|
||||
// the function dispatches calls to the correct inctercept function.
|
||||
LONG CALLBACK veh_dispatch(PEXCEPTION_POINTERS ExceptionInfo);
|
||||
|
||||
// Functions used internally by the library.
|
||||
veh_list_t* new_veh_list();
|
||||
veh_node_t* insert_veh_node(veh_list_t* list, void* origFunc, newFuncType newFunc, void* handle, DWORD hook_type);
|
||||
bool remove_veh_node(veh_list_t* list, void* origFunc);
|
||||
veh_node_t* get_veh_node(veh_list_t* list, void* origFunc, bool exactmatch);
|
||||
|
||||
#endif // LIST_T_H_INCLUDED
|
@ -56,7 +56,9 @@ enum HookParamType : uint64_t
|
||||
EMBED_BEFORE_SIMPLE=0x200000,
|
||||
EMBED_AFTER_NEW=0x400000,
|
||||
EMBED_AFTER_OVERWRITE=0x800000,
|
||||
EMBED_CODEC_UTF16=0x4000000
|
||||
EMBED_CODEC_UTF16=0x4000000,
|
||||
|
||||
BREAK_POINT=0x8000000
|
||||
};
|
||||
|
||||
|
||||
|
@ -255,7 +255,10 @@ namespace
|
||||
}
|
||||
|
||||
}
|
||||
HCode += L"H";
|
||||
if(hp.type&BREAK_POINT)
|
||||
HCode+=L"B";
|
||||
else
|
||||
HCode += L"H";
|
||||
|
||||
if (hp.type & CODEC_UTF16||hp.type & CODEC_UTF32)
|
||||
{
|
||||
@ -328,7 +331,14 @@ namespace HookCode
|
||||
code.erase(std::find(code.begin(), code.end(), L'/'), code.end()); // legacy/AGTH compatibility
|
||||
Trim(code);
|
||||
if (code[0] == L'R') return ParseRCode(code.erase(0, 1));
|
||||
else if (code[0] == L'H') return ParseHCode(code.erase(0, 1));
|
||||
else if (code[0] == L'B'||code[0] == L'H'){
|
||||
auto isbreakpoint=code[0] == L'B';
|
||||
auto hpo=ParseHCode(code.erase(0, 1));
|
||||
if(isbreakpoint && hpo.has_value()){
|
||||
hpo.value().type|=BREAK_POINT;
|
||||
}
|
||||
return hpo;
|
||||
}
|
||||
else if (code[0] == L'E') return ParseECode(code.erase(0, 1));
|
||||
return {};
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ private:
|
||||
void Read();
|
||||
bool InsertHookCode();
|
||||
bool InsertReadCode();
|
||||
bool InsertBreakPoint();
|
||||
bool RemoveBreakPoint();
|
||||
void breakpointcontext(PCONTEXT);
|
||||
void Send(uintptr_t dwDatabase);
|
||||
int GetLength(hook_stack* stack, uintptr_t in); // jichi 12/25/2013: Return 0 if failed
|
||||
int HookStrlen(BYTE* data);
|
||||
|
@ -84,7 +84,7 @@ struct HookParam
|
||||
UINT codepage; // text encoding
|
||||
short length_offset; // index of the string length
|
||||
ALIGNPTR(uint64_t __1,uintptr_t padding); // padding before string
|
||||
DWORD user_value; // 7/20/2014: jichi additional parameters for PSP games
|
||||
ALIGNPTR(uint64_t __10,uintptr_t user_value);
|
||||
ALIGNPTR(uint64_t __2,void(*text_fun)(hook_stack* stack, HookParam* hp, uintptr_t* data, uintptr_t* split, size_t* len))
|
||||
ALIGNPTR(uint64_t __3,bool(*filter_fun)(void* data, size_t* len, HookParam* hp)); // jichi 10/24/2014: Add filter function. Return false to skip the text
|
||||
ALIGNPTR(uint64_t __6,bool (*hook_before)(hook_stack* stack,void* data, size_t* len,uintptr_t*role));
|
||||
|
Loading…
Reference in New Issue
Block a user