2024-05-06 23:30:27 +08:00
2024-02-07 20:59:24 +08:00
# include "MinHook.h"
namespace
{
SearchParam sp ;
constexpr int MAX_STRING_SIZE = 500 , CACHE_SIZE = 749993 , GOOD_PAGE = - 1 ;
struct HookRecord
{
uint64_t address = 0 ;
2024-07-21 21:04:12 +08:00
uint64_t em_addr = 0 ;
int argidx = 0 ;
2024-02-07 20:59:24 +08:00
uintptr_t padding = 0 ;
int offset = 0 ;
2024-03-31 19:00:26 +08:00
JITTYPE jittype ;
2024-02-07 20:59:24 +08:00
char text [ MAX_STRING_SIZE ] = { } ;
} ;
std : : unique_ptr < HookRecord [ ] > records ;
long recordsAvailable ;
uint64_t signatureCache [ CACHE_SIZE ] = { } ;
long sumCache [ CACHE_SIZE ] = { } ;
uintptr_t pageCache [ CACHE_SIZE ] = { } ;
# ifndef _WIN64
BYTE trampoline [ ] =
2024-07-21 21:04:12 +08:00
{
0x9c , // pushfd
0x60 , // pushad
0x68 , 0 , 0 , 0 , 0 , // push @addr ; after this a total of 0x28 bytes are pushed
0x8d , 0x44 , 0x24 , 0x28 , // lea eax,[esp+0x28]
0x50 , // push eax ; stack
0xbb , 0 , 0 , 0 , 0 , // mov ebx,@Send
0xff , 0xd3 , // call ebx
0x83 , 0xc4 , 0x08 , // add esp, 0x8 ; doesn't matter which register
0x61 , // popad
0x9d , // popfd
0x68 , 0 , 0 , 0 , 0 , // push @original
0xc3 // ret ; basically absolute jmp to @original
2024-02-07 20:59:24 +08:00
} ;
constexpr int addr_offset = 3 , send_offset = 13 , original_offset = 25 , registers = 8 ;
# else
BYTE trampoline [ ] = {
2024-07-21 21:04:12 +08:00
0x9c , // push rflags
0x50 , // push rax
0x53 , // push rbx
0x51 , // push rcx
0x52 , // push rdx
0x54 , // push rsp
0x55 , // push rbp
0x56 , // push rsi
0x57 , // push rdi
2024-02-07 20:59:24 +08:00
0x41 , 0x50 , // push r8
0x41 , 0x51 , // push r9
0x41 , 0x52 , // push r10
0x41 , 0x53 , // push r11
0x41 , 0x54 , // push r12
0x41 , 0x55 , // push r13
0x41 , 0x56 , // push r14
0x41 , 0x57 , // push r15
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
// https://stackoverflow.com/questions/43358429/save-value-of-xmm-registers
2024-07-21 21:04:12 +08:00
0x48 , 0x83 , 0xec , 0x20 , // sub rsp,0x20
0xf3 , 0x0f , 0x7f , 0x24 , 0x24 , // movdqu [rsp],xmm4
0xf3 , 0x0f , 0x7f , 0x6c , 0x24 , 0x10 , // movdqu [rsp+0x10],xmm5
2024-02-07 20:59:24 +08:00
0x48 , 0x8d , 0x8c , 0x24 , 0xa8 , 0x00 , 0x00 , 0x00 , // lea rcx,[rsp+0xa8]
2024-07-21 21:04:12 +08:00
0x48 , 0xba , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // mov rcx,@addr
0x48 , 0xb8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , // mov rax,@Send
0x48 , 0x89 , 0xe3 , // mov rbx,rsp
0x48 , 0x83 , 0xe4 , 0xf0 , // and rsp,0xfffffffffffffff0 ; align stack
0xff , 0xd0 , // call rax
0x48 , 0x89 , 0xdc , // mov rsp,rbx
0xf3 , 0x0f , 0x6f , 0x6c , 0x24 , 0x10 , // movdqu xmm5,XMMWORD PTR[rsp + 0x10]
0xf3 , 0x0f , 0x6f , 0x24 , 0x24 , // movdqu xmm4,XMMWORD PTR[rsp]
0x48 , 0x83 , 0xc4 , 0x20 , // add rsp,0x20
0x41 , 0x5f , // pop r15
0x41 , 0x5e , // pop r14
0x41 , 0x5d , // pop r13
0x41 , 0x5c , // pop r12
0x41 , 0x5b , // pop r11
0x41 , 0x5a , // pop r10
0x41 , 0x59 , // pop r9
0x41 , 0x58 , // pop r8
0x5f , // pop rdi
0x5e , // pop rsi
0x5d , // pop rbp
0x5c , // pop rsp
0x5a , // pop rdx
0x59 , // pop rcx
0x5b , // pop rbx
0x58 , // pop rax
0x9d , // pop rflags
0xff , 0x25 , 0x00 , 0x00 , 0x00 , 0x00 , // jmp qword ptr [rip]
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // @original
2024-02-07 20:59:24 +08:00
} ;
constexpr int addr_offset = 50 , send_offset = 60 , original_offset = 126 , registers = 16 ;
# endif
}
2024-07-21 21:04:12 +08:00
bool IsBadReadPtr ( void * data )
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
if ( data > records . get ( ) & & data < records . get ( ) + sp . maxRecords )
return true ;
2024-02-07 20:59:24 +08:00
uintptr_t BAD_PAGE = ( uintptr_t ) data > > 12 ;
2024-07-21 21:04:12 +08:00
auto & cacheEntry = pageCache [ BAD_PAGE % CACHE_SIZE ] ;
if ( cacheEntry = = BAD_PAGE )
return true ;
if ( cacheEntry = = GOOD_PAGE )
return false ;
2024-02-07 20:59:24 +08:00
__try
{
2024-07-21 21:04:12 +08:00
volatile char _ = * ( char * ) data ;
2024-02-07 20:59:24 +08:00
cacheEntry = GOOD_PAGE ;
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
if ( GetExceptionCode ( ) = = EXCEPTION_GUARD_PAGE )
{
MEMORY_BASIC_INFORMATION info ;
VirtualQuery ( data , & info , sizeof ( info ) ) ;
VirtualProtect ( data , 1 , info . Protect | PAGE_GUARD , DUMMY ) ;
}
cacheEntry = BAD_PAGE ;
}
return cacheEntry = = BAD_PAGE ;
}
2024-07-21 21:04:12 +08:00
void DoSend ( int i , uintptr_t address , char * str , uintptr_t padding , JITTYPE jittype = JITTYPE : : PC , uintptr_t em_addr = 0 )
2024-02-07 20:59:24 +08:00
{
2024-03-31 19:00:26 +08:00
str + = padding ;
2024-07-21 21:04:12 +08:00
if ( IsBadReadPtr ( str ) | | IsBadReadPtr ( str + MAX_STRING_SIZE ) )
return ;
2024-03-31 19:00:26 +08:00
__try
2024-02-07 20:59:24 +08:00
{
2024-03-31 19:00:26 +08:00
int length = 0 , sum = 0 ;
2024-07-21 21:04:12 +08:00
for ( ; ( str [ length ] | | str [ length + 1 ] ) & & length < MAX_STRING_SIZE ; length + = 2 )
sum + = * ( uint16_t * ) ( str + length ) ;
2024-03-31 19:00:26 +08:00
if ( length > STRING & & length < MAX_STRING_SIZE - 1 )
2024-02-07 20:59:24 +08:00
{
2024-03-31 19:00:26 +08:00
// many duplicate results with same address, offset, and third/fourth character will be found: filter them out
uint64_t signature = ( ( uint64_t ) i < < 56 ) | ( ( uint64_t ) ( str [ 2 ] + str [ 3 ] ) < < 48 ) | address ;
2024-07-21 21:04:12 +08:00
if ( signatureCache [ signature % CACHE_SIZE ] = = signature )
return ;
2024-03-31 19:00:26 +08:00
signatureCache [ signature % CACHE_SIZE ] = signature ;
// if there are huge amount of strings that are the same, it's probably garbage: filter them out
// can't store all the strings, so use sum as heuristic instead
2024-07-21 21:04:12 +08:00
if ( _InterlockedIncrement ( sumCache + ( sum % CACHE_SIZE ) ) > 25 )
return ;
2024-03-31 19:00:26 +08:00
long n = sp . maxRecords - _InterlockedDecrement ( & recordsAvailable ) ;
if ( n < sp . maxRecords )
2024-02-07 20:59:24 +08:00
{
2024-03-31 19:00:26 +08:00
records [ n ] . jittype = jittype ;
records [ n ] . padding = padding ;
2024-07-21 21:04:12 +08:00
if ( jittype = = JITTYPE : : PC )
2024-02-07 20:59:24 +08:00
{
records [ n ] . address = address ;
2024-07-21 21:04:12 +08:00
records [ n ] . offset = i * sizeof ( char * ) ;
2024-02-07 20:59:24 +08:00
}
2024-03-31 19:00:26 +08:00
else
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
records [ n ] . em_addr = em_addr ;
records [ n ] . argidx = i ;
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
for ( int j = 0 ; j < length ; + + j )
records [ n ] . text [ j ] = str [ j ] ;
2024-03-31 19:00:26 +08:00
records [ n ] . text [ length ] = 0 ;
}
if ( n = = sp . maxRecords )
{
spDefault . maxRecords = sp . maxRecords * 2 ;
ConsoleOutput ( OUT_OF_RECORDS_RETRY ) ;
2024-02-07 20:59:24 +08:00
}
}
}
2024-07-21 21:04:12 +08:00
__except ( EXCEPTION_EXECUTE_HANDLER )
{
}
2024-03-31 19:00:26 +08:00
}
2024-07-21 21:04:12 +08:00
void Send ( char * * stack , uintptr_t address )
2024-03-31 19:00:26 +08:00
{
// it is unsafe to call ANY external functions from this, as they may have been hooked (if called the hook would call this function making an infinite loop)
// the exceptions are compiler intrinsics like _InterlockedDecrement
2024-07-21 21:04:12 +08:00
if ( recordsAvailable < = 0 )
return ;
for ( int i = - registers ; i < 10 ; + + i )
for ( auto padding : { uintptr_t { } , sp . padding } )
{
DoSend ( i , address , stack [ i ] , padding ) ;
}
2024-03-31 19:00:26 +08:00
}
2024-07-21 21:04:12 +08:00
void SafeSendJitVeh ( hook_stack * stack , uintptr_t address , uintptr_t em_addr , JITTYPE jittype )
{
2024-03-31 19:00:26 +08:00
__try
2024-07-21 21:04:12 +08:00
{
for ( int i = 0 ; i < 16 ; i + + )
2024-03-31 19:00:26 +08:00
{
2024-07-21 21:04:12 +08:00
char * str = 0 ;
2024-03-31 19:00:26 +08:00
switch ( jittype )
{
2024-07-21 21:04:12 +08:00
# ifdef _WIN64
2024-03-31 19:00:26 +08:00
case JITTYPE : : YUZU :
2024-07-21 21:04:12 +08:00
str = ( char * ) YUZU : : emu_arg ( stack ) [ i ] ;
2024-03-31 19:00:26 +08:00
break ;
2024-04-07 14:18:39 +08:00
case JITTYPE : : VITA3K :
2024-07-21 21:04:12 +08:00
str = ( char * ) VITA3K : : emu_arg ( stack ) [ i ] ;
2024-04-07 14:18:39 +08:00
break ;
2024-04-07 18:35:50 +08:00
case JITTYPE : : RPCS3 :
2024-07-21 21:04:12 +08:00
str = ( char * ) RPCS3 : : emu_arg ( stack ) [ i ] ;
2024-04-07 18:35:50 +08:00
break ;
2024-07-21 21:04:12 +08:00
# endif
2024-03-31 19:00:26 +08:00
case JITTYPE : : PPSSPP :
2024-07-21 21:04:12 +08:00
str = ( char * ) PPSSPP : : emu_arg ( stack ) [ i ] ;
2024-03-31 19:00:26 +08:00
break ;
default :
return ;
}
2024-07-21 21:04:12 +08:00
DoSend ( i , address , str , 0 , jittype , em_addr ) ;
2024-03-31 19:00:26 +08:00
}
2024-07-21 21:04:12 +08:00
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
}
2024-03-31 19:00:26 +08:00
}
2024-07-21 21:04:12 +08:00
std : : unordered_map < uintptr_t , uint64_t > addresscalledtime ;
bool safeautoleaveveh = false ;
bool SendJitVeh ( PCONTEXT context , uintptr_t address , uintptr_t em_addr , JITTYPE jittype )
{
if ( safeautoleaveveh )
return true ;
if ( recordsAvailable < = 0 )
return false ;
if ( addresscalledtime . find ( address ) = = addresscalledtime . end ( ) )
addresscalledtime [ address ] = 0 ;
auto tm = GetTickCount64 ( ) ;
if ( tm - addresscalledtime [ address ] < 100 )
return false ;
addresscalledtime [ address ] = tm ;
auto stack = std : : make_unique < hook_stack > ( ) ;
context_get ( stack . get ( ) , context ) ;
SafeSendJitVeh ( stack . get ( ) , address , em_addr , jittype ) ;
2024-03-31 19:00:26 +08:00
return true ;
2024-02-07 20:59:24 +08:00
}
2024-03-04 13:30:31 +08:00
std : : vector < uintptr_t > GetFunctions ( uintptr_t module )
2024-02-07 20:59:24 +08:00
{
2024-07-21 21:04:12 +08:00
if ( ! module )
return { } ;
IMAGE_DOS_HEADER * dosHeader = ( IMAGE_DOS_HEADER * ) module ;
if ( dosHeader - > e_magic ! = IMAGE_DOS_SIGNATURE )
return { } ;
IMAGE_NT_HEADERS * ntHeader = ( IMAGE_NT_HEADERS * ) ( module + dosHeader - > e_lfanew ) ;
if ( ntHeader - > Signature ! = IMAGE_NT_SIGNATURE )
return { } ;
2024-02-07 20:59:24 +08:00
DWORD exportAddress = ntHeader - > OptionalHeader . DataDirectory [ IMAGE_DIRECTORY_ENTRY_EXPORT ] . VirtualAddress ;
2024-07-21 21:04:12 +08:00
if ( ! exportAddress )
return { } ;
IMAGE_EXPORT_DIRECTORY * exportDirectory = ( IMAGE_EXPORT_DIRECTORY * ) ( module + exportAddress ) ;
2024-03-04 13:30:31 +08:00
std : : vector < uintptr_t > functions ;
2024-02-07 20:59:24 +08:00
for ( int i = 0 ; i < exportDirectory - > NumberOfNames ; + + i )
2024-07-21 21:04:12 +08:00
// char* funcName = (char*)(module + *(DWORD*)(module + exportDirectory->AddressOfNames + i * sizeof(DWORD)));
functions . push_back ( module + * ( DWORD * ) ( module + exportDirectory - > AddressOfFunctions +
sizeof ( DWORD ) * * ( WORD * ) ( module + exportDirectory - > AddressOfNameOrdinals + i * sizeof ( WORD ) ) ) ) ;
2024-02-07 20:59:24 +08:00
return functions ;
}
2024-07-21 21:04:12 +08:00
void mergevector ( std : : vector < uintptr_t > & v1 , std : : vector < uintptr_t > & v2 )
{
for ( auto addr : v2 )
{
auto it = std : : find ( v1 . begin ( ) , v1 . end ( ) , addr ) ;
if ( it = = v1 . end ( ) )
{
2024-02-07 20:59:24 +08:00
v1 . push_back ( addr ) ;
2024-07-21 21:04:12 +08:00
}
2024-02-07 20:59:24 +08:00
}
}
2024-07-21 21:04:12 +08:00
void SearchForHooks_Return ( )
{
2024-03-31 19:00:26 +08:00
ConsoleOutput ( HOOK_SEARCH_FINISHED , sp . maxRecords - recordsAvailable ) ;
for ( int i = 0 , results = 0 ; i < sp . maxRecords ; + + i )
{
HookParam hp ;
hp . codepage = sp . codepage ;
2024-07-21 21:04:12 +08:00
hp . jittype = records [ i ] . jittype ;
2024-03-31 19:00:26 +08:00
hp . padding = records [ i ] . padding ;
2024-07-21 21:04:12 +08:00
if ( records [ i ] . jittype = = JITTYPE : : PC )
2024-03-31 19:00:26 +08:00
{
2024-07-21 21:04:12 +08:00
if ( ! records [ i ] . address )
continue ;
2024-03-31 19:00:26 +08:00
hp . offset = records [ i ] . offset ;
hp . type = CODEC_UTF16 | USING_STRING ;
hp . address = records [ i ] . address ;
}
else
{
2024-07-21 21:04:12 +08:00
if ( ! records [ i ] . em_addr )
continue ;
hp . emu_addr = records [ i ] . em_addr ;
hp . type = CODEC_UTF16 | USING_STRING | BREAK_POINT ;
hp . argidx = records [ i ] . argidx ;
2024-03-31 19:00:26 +08:00
}
2024-07-21 21:04:12 +08:00
NotifyHookFound ( hp , ( wchar_t * ) records [ i ] . text ) ;
if ( + + results % 100'000 = = 0 )
ConsoleOutput ( ResultsNum , results ) ;
2024-03-31 19:00:26 +08:00
}
records . reset ( ) ;
2024-07-21 21:04:12 +08:00
for ( int i = 0 ; i < CACHE_SIZE ; + + i )
signatureCache [ i ] = sumCache [ i ] = 0 ;
2024-03-31 19:00:26 +08:00
}
2024-07-21 21:04:12 +08:00
void initrecords ( )
{
2024-03-31 19:00:26 +08:00
do
2024-07-21 21:04:12 +08:00
try
{
records = std : : make_unique < HookRecord [ ] > ( recordsAvailable = sp . maxRecords ) ;
}
catch ( std : : bad_alloc )
{
ConsoleOutput ( SearchForHooks_ERROR , sp . maxRecords / = 2 ) ;
}
2024-03-31 19:00:26 +08:00
while ( ! records & & sp . maxRecords ) ;
}
2024-02-07 20:59:24 +08:00
void SearchForHooks ( SearchParam spUser )
{
std : : thread ( [ = ]
2024-07-21 21:04:12 +08:00
{
2024-02-07 20:59:24 +08:00
static std : : mutex m ;
std : : scoped_lock lock ( m ) ;
* ( void * * ) ( trampoline + send_offset ) = Send ;
2024-03-31 19:00:26 +08:00
ConsoleOutput ( HOOK_SEARCH_INITIALIZING , 0. ) ;
2024-02-07 20:59:24 +08:00
sp = spUser . length = = 0 ? spDefault : spUser ;
sp . codepage = spUser . codepage ;
2024-03-31 19:00:26 +08:00
initrecords ( ) ;
2024-02-07 20:59:24 +08:00
2024-03-04 13:30:31 +08:00
std : : vector < uintptr_t > addresses ;
2024-04-02 11:51:55 +08:00
if ( sp . jittype = = JITTYPE : : PC )
2024-03-31 19:00:26 +08:00
{
if ( * sp . boundaryModule ) {
auto [ minaddr , maxaddr ] = Util : : QueryModuleLimits ( GetModuleHandleW ( sp . boundaryModule ) ) ;
if ( sp . address_method = = 0 ) {
sp . minAddress = min ( max ( minaddr , sp . minAddress ) , maxaddr ) ;
sp . maxAddress = max ( min ( maxaddr , sp . maxAddress ) , minaddr ) ;
}
else if ( sp . address_method = = 1 ) {
auto maxoff = maxaddr - minaddr ;
sp . minAddress = minaddr + min ( sp . minAddress , maxoff ) ;
sp . maxAddress = minaddr + min ( sp . maxAddress , maxoff ) ;
}
//std::tie(sp.minAddress, sp.maxAddress) = Util::QueryModuleLimits(GetModuleHandleW(sp.boundaryModule));
2024-02-07 20:59:24 +08:00
}
2024-03-31 19:00:26 +08:00
if ( * sp . exportModule ) addresses = GetFunctions ( ( uintptr_t ) GetModuleHandleW ( sp . exportModule ) ) ;
if ( * sp . boundaryModule ) {
auto _addresses = GetFunctions ( ( uintptr_t ) GetModuleHandleW ( sp . boundaryModule ) ) ;
mergevector ( addresses , _addresses ) ;
2024-02-07 20:59:24 +08:00
}
2024-03-31 19:00:26 +08:00
std : : vector < uintptr_t > addresses1 ;
if ( sp . search_method = = 0 ) {
for ( auto & addr : addresses1 = Util : : SearchMemory ( sp . pattern , sp . length , PAGE_EXECUTE , sp . minAddress , sp . maxAddress ) )
addr + = sp . offset ;
}
2024-08-26 00:50:10 +08:00
else if ( sp . search_method = = 1 ) {
auto checklength = 3 ;
auto checker = [ checklength ] ( DWORD k ) {
if ( k = = 0xcccccccc
| | k = = 0x90909090
| | k = = 0xccccccc3
| | k = = 0x909090c3
)
return true ;
DWORD t = k & 0xff0000ff ;
if ( t = = 0xcc0000c2 | | t = = 0x900000c2 )
return true ;
if ( checklength = = 4 ) return false ;
k > > = 8 ;
if ( k = = 0xccccc3 | | k = = 0x9090c3 )
return true ;
if ( checklength = = 3 ) return false ;
// t = k & 0xff;
// if (t == 0xc2)
// return true;
k > > = 8 ;
if ( k = = 0xccc3 | | k = = 0x90c3 )
return true ;
if ( checklength = = 2 ) return false ;
k > > = 8 ;
if ( k = = 0xc3 )
return true ;
return false ;
} ;
for ( uintptr_t addr = sp . minAddress & ~ 0xf ; addr < sp . maxAddress ; addr + = 0x10 ) {
if ( IsBadReadPtr ( ( void * ) ( addr - 0x10 ) , 0x110 ) ) {
addr + = 0x100 - 0x10 ;
2024-05-13 00:16:54 +08:00
continue ;
}
2024-08-26 00:50:10 +08:00
auto need = checker ( * ( DWORD * ) ( addr - 4 ) ) ;
if ( need )
addresses1 . push_back ( addr ) ;
}
2024-03-31 19:00:26 +08:00
}
else if ( sp . search_method = = 2 ) {
for ( uintptr_t addr = sp . minAddress ; addr < sp . maxAddress ; addr + + ) {
2024-08-26 00:50:10 +08:00
if ( IsBadReadPtr ( ( void * ) addr , 0x100 ) ) {
addr + = 0x100 - 1 ;
2024-05-13 00:16:54 +08:00
continue ;
}
2024-03-31 19:00:26 +08:00
if ( ( ( * ( BYTE * ) addr ) = = 0xe8 ) ) {
auto off = * ( DWORD * ) ( addr + 1 ) ;
auto funcaddr = addr + 5 + off ;
if ( sp . minAddress < funcaddr & & sp . maxAddress > funcaddr ) {
auto it = std : : find ( addresses1 . begin ( ) , addresses1 . end ( ) , funcaddr ) ;
addresses1 . push_back ( funcaddr ) ;
}
2024-02-07 20:59:24 +08:00
}
2024-03-31 19:00:26 +08:00
}
}
mergevector ( addresses , addresses1 ) ;
2024-02-07 20:59:24 +08:00
2024-03-31 19:00:26 +08:00
auto limits = Util : : QueryModuleLimits ( GetModuleHandleW ( LUNA_HOOK_DLL ) ) ;
addresses . erase ( std : : remove_if ( addresses . begin ( ) , addresses . end ( ) , [ & ] ( auto addr ) { return addr > limits . first & & addr < limits . second ; } ) , addresses . end ( ) ) ;
2024-02-07 20:59:24 +08:00
2024-03-31 19:00:26 +08:00
auto trampolines = ( decltype ( trampoline ) * ) VirtualAlloc ( NULL , sizeof ( trampoline ) * addresses . size ( ) , MEM_COMMIT , PAGE_READWRITE ) ;
VirtualProtect ( trampolines , addresses . size ( ) * sizeof ( trampoline ) , PAGE_EXECUTE_READWRITE , DUMMY ) ;
std : : vector < uintptr_t > mherroridx ;
for ( int i = 0 ; i < addresses . size ( ) ; + + i )
{
void * original ;
//避免MH_RemoveHook时移除原本已有hook
if ( MH_CreateHook ( ( void * ) addresses [ i ] , trampolines [ i ] , & original ) ! = MH_OK ) {
mherroridx . push_back ( i ) ;
}
MH_QueueEnableHook ( ( void * ) addresses [ i ] ) ;
memcpy ( trampolines [ i ] , trampoline , sizeof ( trampoline ) ) ;
* ( uintptr_t * ) ( trampolines [ i ] + addr_offset ) = addresses [ i ] ;
* ( void * * ) ( trampolines [ i ] + original_offset ) = original ;
if ( i % 2500 = = 0 ) ConsoleOutput ( HOOK_SEARCH_INITIALIZING , 1 + 98. * i / addresses . size ( ) ) ;
}
2024-02-07 20:59:24 +08:00
//避免MH_RemoveHook时移除原本已有hook
2024-03-31 19:00:26 +08:00
for ( int i = 0 ; i < mherroridx . size ( ) ; i + + ) {
auto reverseidx = mherroridx [ mherroridx . size ( ) - 1 - i ] ;
addresses . erase ( addresses . begin ( ) + reverseidx ) ;
2024-02-07 20:59:24 +08:00
}
2024-03-31 19:00:26 +08:00
ConsoleOutput ( HOOK_SEARCH_INITIALIZED , addresses . size ( ) ) ;
MH_ApplyQueued ( ) ;
ConsoleOutput ( HOOK_SEARCH_STARTING ) ;
ConsoleOutput ( MAKE_GAME_PROCESS_TEXT , sp . searchTime / 1000 ) ;
Sleep ( sp . searchTime ) ;
for ( auto addr : addresses ) MH_QueueDisableHook ( ( void * ) addr ) ;
MH_ApplyQueued ( ) ;
Sleep ( 1000 ) ;
for ( auto addr : addresses ) MH_RemoveHook ( ( void * ) addr ) ;
VirtualFree ( trampolines , 0 , MEM_RELEASE ) ;
SearchForHooks_Return ( ) ;
}
else
2024-02-07 20:59:24 +08:00
{
2024-03-31 23:28:09 +08:00
safeautoleaveveh = false ;
2024-04-02 11:51:55 +08:00
int i = 0 ;
std : : vector < uint64_t > successaddr ;
2024-04-02 10:40:03 +08:00
uintptr_t minemaddr = - 1 , maxemaddr = 0 ;
2024-04-02 11:51:55 +08:00
ConsoleOutput ( HOOK_SEARCH_INITIALIZED , jitaddr2emuaddr . size ( ) ) ;
2024-04-02 10:40:03 +08:00
for ( auto addr : jitaddr2emuaddr ) {
2024-04-02 11:51:55 +08:00
minemaddr = min ( minemaddr , addr . second . second ) ;
maxemaddr = max ( maxemaddr , addr . second . second ) ;
2024-04-02 10:40:03 +08:00
}
2024-04-02 11:51:55 +08:00
ConsoleOutput ( " %p %p " , minemaddr , maxemaddr ) ;
ConsoleOutput ( " %p %p " , sp . minAddress , sp . maxAddress ) ;
2024-03-31 19:00:26 +08:00
for ( auto addr : jitaddr2emuaddr ) {
2024-04-02 11:51:55 +08:00
if ( addr . second . second > sp . maxAddress | | addr . second . second < sp . minAddress ) continue ;
2024-03-31 19:00:26 +08:00
i + = 1 ;
//addresses.push_back(addr.first);
if ( add_veh_hook ( ( void * ) addr . first , std : : bind ( SendJitVeh , std : : placeholders : : _1 , addr . first , addr . second . second , addr . second . first ) ) )
successaddr . push_back ( addr . first ) ;
if ( i % 2500 = = 0 ) ConsoleOutput ( HOOK_SEARCH_INITIALIZING , 1 + 98. * i / jitaddr2emuaddr . size ( ) ) ;
}
2024-04-02 11:51:55 +08:00
ConsoleOutput ( HOOK_SEARCH_INITIALIZED , i ) ;
2024-03-31 19:00:26 +08:00
ConsoleOutput ( MAKE_GAME_PROCESS_TEXT , sp . searchTime / 1000 ) ;
Sleep ( sp . searchTime ) ;
2024-03-31 23:28:09 +08:00
// for(auto addr:successaddr){
// remove_veh_hook((void*)addr);
// }
safeautoleaveveh = true ;
2024-03-31 19:00:26 +08:00
SearchForHooks_Return ( ) ;
2024-07-21 21:04:12 +08:00
} } )
. detach ( ) ;
2024-02-07 20:59:24 +08:00
}
2024-07-21 21:04:12 +08:00
void SearchForText ( wchar_t * text , UINT codepage )
2024-02-07 20:59:24 +08:00
{
bool found = false ;
char utf8Text [ PATTERN_SIZE * 4 ] = { } ;
WideCharToMultiByte ( CP_UTF8 , 0 , text , PATTERN_SIZE , utf8Text , PATTERN_SIZE * 4 , nullptr , nullptr ) ;
char codepageText [ PATTERN_SIZE * 4 ] = { } ;
2024-07-21 21:04:12 +08:00
if ( codepage ! = CP_UTF8 )
2024-02-07 20:59:24 +08:00
WideCharToMultiByte ( codepage , 0 , text , PATTERN_SIZE , codepageText , PATTERN_SIZE * 4 , nullptr , nullptr ) ;
2024-07-21 21:04:12 +08:00
if ( strlen ( utf8Text ) < 4 | | ( ( codepage ! = CP_UTF8 ) & & ( strlen ( codepageText ) < 4 ) ) | | wcslen ( text ) < 4 )
return ConsoleOutput ( NOT_ENOUGH_TEXT ) ;
2024-02-07 20:59:24 +08:00
ConsoleOutput ( HOOK_SEARCH_STARTING ) ;
2024-03-04 13:30:31 +08:00
auto GenerateHooks = [ & ] ( std : : vector < uintptr_t > addresses , HookParamType type )
2024-02-07 20:59:24 +08:00
{
for ( auto addr : addresses )
{
2024-07-21 21:04:12 +08:00
if ( abs ( ( long long ) ( utf8Text - addr ) ) < 20000 )
continue ; // don't add read code if text is on this thread's stack
2024-02-07 20:59:24 +08:00
found = true ;
HookParam hp ;
hp . type = DIRECT_READ | type ;
hp . address = addr ;
hp . codepage = codepage ;
NewHook ( hp , " Search " ) ;
}
} ;
GenerateHooks ( Util : : SearchMemory ( utf8Text , strlen ( utf8Text ) , PAGE_READWRITE ) , CODEC_UTF8 ) ;
2024-07-21 21:04:12 +08:00
if ( codepage ! = CP_UTF8 )
2024-02-07 20:59:24 +08:00
GenerateHooks ( Util : : SearchMemory ( codepageText , strlen ( codepageText ) , PAGE_READWRITE ) , USING_STRING ) ;
GenerateHooks ( Util : : SearchMemory ( text , wcslen ( text ) * sizeof ( wchar_t ) , PAGE_READWRITE ) , CODEC_UTF16 ) ;
2024-07-21 21:04:12 +08:00
if ( ! found )
ConsoleOutput ( COULD_NOT_FIND ) ;
2024-02-07 20:59:24 +08:00
}