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:
恍兮惚兮 2024-03-23 10:11:57 +08:00
parent a02f862e8e
commit 867ea55bdc
11 changed files with 339 additions and 18 deletions

View File

@ -23,6 +23,7 @@ set(texthook_src
enginecontrol.cpp
embed_util.cc
hijackfuns.cc
veh_hook.cpp
)
add_subdirectory(util)
add_subdirectory(engines)

View File

@ -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);

View File

@ -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);
}

View File

@ -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))
{

View File

@ -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
View 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
View 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

View File

@ -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
};

View File

@ -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 {};
}

View File

@ -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);

View File

@ -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));